Developing Tranalyzer plugins in C++
Contents
This tutorial gives you an introduction into plugin development for T2 in C++.
Why writing a plugin in C++
- Some people prefer higher level languages
- Some libraries or tools only work with C++
The one magic command for the busy people
The simplest way to create a C++ plugin is to use the t2plugin script with the -c
and --cpp
options (123 is the plugin number):
C++ plugin 'myPluginName' created
Differences between a C and a C++ plugin
Writing a Tranalyzer plugin in C++ is fundamentally not different from doing it in C. Therefore, this tutorial only highlights the differences or areas where special attention is required. The reader will be referred to the relevant C tutorials for all aspects which do not differ.
- Include
t2Plugin.hpp
instead oft2Plugin.h
- Prefix all callbacks with
T2_API
- Adapt the files from the build system
Include t2Plugin.hpp instead of t2Plugin.h
The first major difference between a C and a C++ plugin is the name of the file to include in order to have access to T2 functionality:
#include "t2Plugin.hpp"
Prefix all callbacks with T2_API
When implementing a Tranalyzer callback in your C++ file, make sure to prefix it with T2_API
:
T2_API void t2OnNewFlow(packet_t *packet, unsigned long flowIndex) { ... }
T2_API void t2OnLayer2(packet_t *packet, unsigned long flowIndex) { ... }
T2_API void t2OnLayer4(packet_t *packet, unsigned long flowIndex) { ... }
T2_API void t2OnFlowTerminate(unsigned long flowIndex, outputBuffer_t *buf) { ... }
T2_API void t2BufferToSink(outputBuffer_t *buf, binary_value_t *bv) { ... }
Note that the T2_PLUGIN_INIT(...)
and T2_PLUGIN_INIT_WITH_DEPS(...)
macros already take care of the T2_API
keyword and can be used as for a C plugin.
Build systems
No matter which build system you use (autotools, cmake or meson), make sure to adapt your filenames, e.g.:
t2PSkel.c
—>t2PSkel.cpp
t2PSkel.h
—>t2PSkel.hpp
The changes are suffixed with # <----
.
Autotools
Edit src/Makefile.am as follows:
- Replace all references to
CFLAGS
withCXXFLAGS
.
cat src/Makefile.am
lib_LTLIBRARIES = libt2PSkel.la
libt2PSkel_la_SOURCES = \
t2PSkel.cpp # <----
# ../../../utils/t2buf.c # if you uncomment this line, do not
# # forget to append a backslash above!
libt2PSkel_la_CXXFLAGS = \ # <----
-I$(top_srcdir)/../../utils \
-I$(top_srcdir)/../../tranalyzer2/src
# -I$(top_srcdir)/../tcpFlags/src # tell the compiler where to find header
# # files from dependent plugins
# # !!! if you uncomment this line, do not
# # !!! forget to append a backslash above
if APPLE
libt2PSkel_la_CXXFLAGS += -D_DARWIN_C_SOURCE # macOS specific flags <----
else
libt2PSkel_la_CXXFLAGS += -D_GNU_SOURCE # <----
endif
libt2PSkel_la_LDFLAGS = -shrext .so # extension for shared library
# (without this flag, would be '.dylib' on macOS)
CMake:
Edit CMakeLists.txt as follows:
- Change
LANGUAGES
fromC
toCXX
. - Change
C_STANDARD
toCXX_STANDARD
and replace the 99 with the desired C++ standard, e.g., 11.
cat CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
# If your plugin has only one file named src/pluginName.c,
# then this is the only line you need to change.
set(_plugin_name t2PSkel)
#set(_plugin_number 999)
project(${_plugin_name}
HOMEPAGE_URL "https://tranalyzer.com"
VERSION 0.8.11
LANGUAGES CXX # <----
)
# ---------------------------------------------------------------------------- #
# Find libraries #
# ---------------------------------------------------------------------------- #
#find_package(Threads REQUIRED)
#find_package(Threads QUIET)
#find_package(PkgConfig REQUIRED)
#pkg_check_modules(MY_NAME REQUIRED module_name)
# ---------------------------------------------------------------------------- #
# Source files #
# ---------------------------------------------------------------------------- #
add_library(${_plugin_name}
MODULE
${_plugin_name}.cpp # <----
src/#../../utils/t2buf.c
)
# ---------------------------------------------------------------------------- #
# C standard to use #
# ---------------------------------------------------------------------------- #
set_target_properties(${_plugin_name}
PROPERTIES
CXX_STANDARD 11 # <----
#C_EXTENSIONS ON # <---- you can either comment or remove
#C_STANDARD_REQUIRED ON # <---- those two lines
)
# ---------------------------------------------------------------------------- #
# Include directories (-I ...) #
# ---------------------------------------------------------------------------- #
target_include_directories(${_plugin_name}
PRIVATE
../../utils
../../tranalyzer2/src#../tcpFlags/src # tell the compiler where to find header
# files from dependent plugins
#${MY_NAME_INCLUDE_DIRS}
)
# ---------------------------------------------------------------------------- #
# Compile options #
# ---------------------------------------------------------------------------- #
target_compile_options(${_plugin_name}
PRIVATE
-Wall
-Wextra
-Wundef
)
# ---------------------------------------------------------------------------- #
# Compile definitions (-D ...) #
# ---------------------------------------------------------------------------- #
#target_compile_definitions(${_plugin_name}
# PRIVATE
# PLUGIN_NUMBER=${_plugin_number}
#)
if (APPLE)
target_compile_definitions(${_plugin_name}
PRIVATE
_DARWIN_C_SOURCE
)set_target_properties(${_plugin_name}
PROPERTIES
LINK_FLAGS "-undefined dynamic_lookup"
)elseif (UNIX)
target_compile_definitions(${_plugin_name}
PRIVATE
_GNU_SOURCE
)endif()
# ---------------------------------------------------------------------------- #
# Libraries (-l ..., -L) #
# ---------------------------------------------------------------------------- #
#target_link_libraries(${_plugin_name}
# PRIVATE
# m
# ${MY_NAME_LIBRARIES}
# ${MY_NAME_LDFLAGS}
#)
# ---------------------------------------------------------------------------- #
# Installation #
# ---------------------------------------------------------------------------- #
set_target_properties(${_plugin_name}
PROPERTIES
#PREFIX ""
#OUTPUT_NAME "${_plugin_number}_${_plugin_name}"
OUTPUT_NAME "${_plugin_name}"
SUFFIX ".so"
)
Meson
Edit meson.build as follows:
- Change all language references from
c
tocpp
. - Replace
c_std=gnu99
withcpp_std=11
(or any desired C++ standard).
cat meson.build
't2PSkel', 'cpp', # <----
project('0.8.11',
version: 'GPLv2+',
license:
default_options: ['warning_level=2',
'buildtype=release',
'cpp_std=c++11' # <----
],#meson_version: '>= 0.45.0',
)
= meson.project_name()
plugin_name #plugin_number = '999'
= meson.get_compiler('cpp') # <----
cc = host_machine.system()
os #perl = find_program('perl')
if os == 'darwin'
'-D_DARWIN_C_SOURCE', language: 'cpp') # <----
add_project_arguments(elif os == 'linux'
'-D_GNU_SOURCE', language: 'cpp') # <----
add_project_arguments(#elif os == 'windows'
# message('You are using Windows...')
#else
# warning('OS not recognized...')
endif
= cc.find_library('m')
libm = dependency('threads')
threads_dep = dependency('zlib', version: '>=1.2.8', required: false)
zlib_dep if zlib_dep.found()
'ZLIB >= 1.2.8 found')
message(else
'ZLIB >= 1.2.8 not found')
warning(
endif
= [
deps
libm,
threads_dep,
]
= include_directories(
inc '..', '..', 'utils'),
join_paths('..', '..', 'tranalyzer2', 'src'),
join_paths(#join_paths('..', 'tcpFlags', 'src'), # tell the compiler where to find header
# files from dependent plugins
)
#subdir('doc')
= [
src 'src', plugin_name + '.cpp'), # <----
join_paths(#join_paths('..', '..', 'utils', 't2buf.c'),
]
#cmd = run_command(perl, '-nle', 'print $1 if /^#define\s+T2PSKEL_VAR1\s+(\d+).*$/', 'src/' + plugin_name + '.hpp') # <----
#if cmd.returncode() != 0
# error('Could not determine value of \'T2PSKEL_VAR1\' in \'src/' + plugin_name + '.hpp\'') # <----
#endif
shared_module(plugin_name,
sources: src,
dependencies: deps,
include_directories: inc,#name_prefix: plugin_number + '_',
'so',
name_suffix: )
Summary
Implementing a Tranalyzer plugin in C++ does not require much overhead.
The main difference is the inclusion of t2Plugin.hpp
instead of t2Plugin.h
and the T2_API
keyword before every Tranalyzer callback functions.
The next tutorial will teach you how to develop a plugin in Rust
See also
- Plugin programming cheatsheet
- The basics: your first flow plugin
- Plugin end report
- Plugin monitoring
- Plugin packet mode
- Plugin summary files
- Plugin geo labeling
- Plugin dependencies
- Plugin alarm mode
- Plugin force mode
- Plugin pcap extraction
- Plugin flow timeout
- Plugin sink
- Developing Tranalyzer plugins in Rust