Plugin geo labeling
Contents
Introduction
Since version 0.8.8, all subnet processing is provided by the core. Meaning that every plugin can now profit from its services and no dependencies to basicFlow are necessary anymore. Thus, it became easier to write your own geo plugins. This is what we will do now in this tutorial. Moreover an introduction to the IPv4/6 flow processing is integrated in the tutorial.
Getting started
Create folders for your data and results
If you have not created a separate data and results directory yet, please do it now. This will greatly facilitate your workflow:
mkdir ~/data ~/results
Reset tranalyzer2 and the plugins configuration
If you have followed the other tutorials, you may have modified some of the core and plugins configuration. To ensure your results match those in this tutorial, make sure to reset everything:
t2conf -a --reset
You can also clean all build files:
t2build -a -c
Empty the plugin folder
To ensure we are not left with some unneeded plugins or plugins which were built using different core configuration, it is safer to empty the plugins folder:
t2build -e -y
Are you sure you want to empty the plugin folder '/home/user/.tranalyzer/plugins' (y/N)? yes
Plugin folder emptied
Download the PCAP file
The PCAP file used in this tutorial can be downloaded here:
Please save it in your ~/data folder:
wget --no-check-certificate -P ~/data https://tranalyzer.com/download/data/annoloc2.pcap
Build tranalyzer2 and the required plugins
For this tutorial, we will need to build the core (tranalyzer2) and the following plugins:
As you may have modified some of the automatically generated files, it is safer to use the -r
and -f
options.
...
BUILDING SUCCESSFUL
Source code
In this tutorial, we will extend tcpWin07.tar.gz, the final version of the previous tutorial (Plugin summary files).
If you are impatient, you can download the final versions of the tcpWin plugin we will develop in this tutorial.
To use one of those plugins, just unpack it in the plugins folder of your T2 installation.
tranpl
tar -xf ~/Downloads/tcpWin08.tar.gz
And let t2_aliases
know about it:
source "$T2HOME/scripts/t2_aliases"
The core subnet processing
As subnet processing is now part of the core, the flow and packet structure provides an index to the global IPv4/6 subnet table. That means we have now also to take care of different IP versions and core configuration, which I avoided so far for simplicity.
tranalyzer2
vi src/flow.h
...
#if SUBNET_INIT != 0
uint32_t subnetNrSrc; // <--
uint32_t subnetNrDst; // <--
#endif // SUBNET_INIT != 0
...
Hence, the user can access the subnet index for the src and dest address via the flow structure:
flowP->subnetNrSrc
flowP->subnetNrDst
The same is accessible in the packet structure, see // <--
vi src/packet.h
...
#if ((SUBNET_INIT != 0) || (AGGREGATIONFLAG & (SUBNET | SRCIP | DSTIP)))
#if IPV6_ACTIVATE > 0
;
ipAddr_t srcIPC;
ipAddr_t dstIPC#else // IPV6_ACTIVATE == 0
;
ip4Addr_t srcIPC;
ip4Addr_t dstIPC#endif // IPV6_ACTIVATE == 0
uint32_t subnetNrSrc;
uint32_t subnetNrDst;
uint16_t srcPortC;
uint16_t dstPortC;
uint8_t l4ProtoC;
#endif // ((SUBNET_INIT != 0) || (AGGREGATIONFLAG & (SUBNET | SRCIP | DSTIP)))
...
In your program, e.g., at the t2OnLayer4()
callback, you access the index
via the packet structure:
packet->subnetNrSrc
packet->subnetNrDst
That’s it. So how do I convert this ominous index to viable subnet information? Easy, use the following macros (defined in $T2HOME/utils/subnetHL.h):
const uint32_t num = packet->subnetNrSrc;
const uint_fast8_t ipver = PACKET_IPVER(packet);
(dest, ipver, num) // Autonomous System Number
SUBNET_ASN(dest, ipver, num) // Country
SUBNET_LOC(dest, ipver, num) // County
SUBNET_CNTY(dest, ipver, num) // City
SUBNET_CTY(dest, ipver, num) // Organization
SUBNET_ORG(dest, ipver, num) // Hex code
SUBNET_NETID(dest, ipver, num) // Latitude
SUBNET_LAT(dest, ipver, num) // Longitude
SUBNET_LNG(dest, ipver, num) // Precision SUBNET_PREC
Your code must react to the following core switches, in order to avoid compiler errors or unexpected results if you reconfigure tranalyzer core.
It is advisable to read the following tutorials first, if you feel uneasy about these core configurations:
Enabling switches reside in tranalyzer.h and main.h:
Flag | Description | File |
---|---|---|
IPV6_ACTIVATE |
Controls the focus on IPv4/6 or both | tranalyzer.h |
SUBNET_ON |
Enables the subnet functions in the core | main.h |
AGGREGATIONFLAG |
Controls aggregation modes of flows. | main.h |
The code SUBNET=0x80 enables also subnet functions like SUBNET_ON . |
main.h | |
SUBNET_INIT |
Switch for plugin programmers enabling subnet functions. | main.h |
A logical OR of SUBNET_ON and SUBNET . |
main.h |
tranalyzer2
vi src/networkHeaders.h
...
/* ========================================================================== */
/* ------------------------ USER CONFIGURATION FLAGS ------------------------ */
/* ========================================================================== */
#define IPV6_ACTIVATE 2 // 0: IPv4 only
// 1: IPv6 only
// 2: dual mode
...
vi src/tranalyzer.h
...
/* ========================================================================== */
/* ------------------------ USER CONFIGURATION FLAGS ------------------------ */
/* ========================================================================== */
...
#define SUBNET_ON 1 // Core control of subnet function for plugins
/* -------------------------------------------------------------------------- */
/* -------------------- DO NOT EDIT THE FOLLOWING BLOCKS -------------------- */
/* -------------------------------------------------------------------------- */
// Aggregation modes
#define L4PROT 0x01
#define DSTPORT 0x02
#define SRCPORT 0x04
#define DSTIP 0x08
#define SRCIP 0x10
#define VLANID 0x20
#define SUBNET 0x80
// SUBNET mode: IP flow aggregation network masks
#define CNTRY_MSK 0xff800000
#define TOR_MSK 0x00400000
#define ORG_MSK 0x003fffff
#define NETIDMSK (CNTRY_MSK | ORG_MSK) // netID mask
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
// Flow Aggregation
#define AGGREGATIONFLAG 0x00 // each bit: 1: aggregation activated
// (see aggregation modes defined above)
...
/* ========================================================================== */
/* ------------------------- DO NOT EDIT BELOW HERE ------------------------- */
/* ========================================================================== */
...
#define SUBNET_INIT (SUBNET_ON | (AGGREGATIONFLAG & SUBNET))
#endif // T2_TRANALYZER_H_INCLUDED
We leave everything at default.
An important part for a programmer are the macros T2 supplies to facilitate subnet tests and information extraction. They also shield the user from the global table pointers defined in the core main.c. These pointers contain the IPv4/6 subnet file information according to the users configuration in subnetHL.h.
utils
vi src/subnetHL.h
...
#if SUBNET_INIT != 0
void *subnetTableP[2];
#if IPV6_ACTIVATE == 0 || IPV6_ACTIVATE == 2
*subnetTable4P;
subnettable4_t #endif
#if IPV6_ACTIVATE > 0
*subnetTable6P;
subnettable6_t #endif
#endif // SUBNET_INIT != 0
...
The definition of the IPv4/6 structs is located at the end of the subnetHL.h
in the utils folder. Note that CNTYCTY
is switched off by default, saving space
in the binary subnet file.
The said macros are defined in the middle part of subnetHL.h. Nevertheless, you may use the global pointers to access any info using the supplied index. Your choice.
utils
vi subnetHL.h
...
/* ========================================================================== */
/* ------------------------ USER CONFIGURATION FLAGS ------------------------ */
/* ========================================================================== */
#define SUBRNG 0 // IP range definition: 0: CIDR only, 1: Begin-End
#define CNTYCTY 0 // 1: add county, city
#define WHOADDR 0 // 1: add whois address info
#define SUB_MAP 1 // 1: mmap subnet, 0: normal read
#define CNTYLEN 14 // length of County record
#define CTYLEN 14 // length of City record
#define WHOLEN 30 // length of Organization record
#define ADDRLEN 30 // length of Address record
/* +++++++++++++++++++++ ENV / RUNTIME - conf Variables +++++++++++++++++++++ */
#define SUBNET_UNK "-" // Representation of unknown locations
/* ========================================================================== */
/* ------------------------- DO NOT EDIT BELOW HERE ------------------------- */
/* ========================================================================== */
...
That is all you need to know for now. Let’s implement geo stuff now.
Implementing IPv4/6 switches in t2OnFlowTerminate()
Open tcpGeoWin.c and scroll to t2OnFlowTerminate()
.
The other callbacks before are the same as in previous tutorials.
We want to detect all packets where the window size is below TCPWIN_THRES
and store it in the gwz
structure if the count for an IP address is higher
than the previous one.
As indicated by // <--
the flowP->subnetNrSrc
contains the subnet index for
the specific IP address provided by the core. That is all you need to access.
Easy he?
We store it in the gwz.sID[i]
for later processing. The macro FLOW_IS_IPV4
tests
the flow status for the IPv4/6 bit. We need it in order to store the IPv4/6 address
appropriately. The switch IPV6_ACTIVATE > 0
covers the different modes of tranalyzer
IPv4 only, IPv6 only or both. Same for the storage of the IP’s below.
The switch SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0
activates the code
only if core processes subnets and no aggregation mode is on, as we only
want the standard case here, where we have only one IP per flow.
Yes I could produce a simpler switch for that, will do that later.
tcpWin
vi src/tcpWin.c
...
void t2OnFlowTerminate(unsigned long flowIndex, outputBuffer_t *buf) {
const tcpWinFlow_t * const tcpWinFlowP = &tcpWinFlows[flowIndex];
float f = 0.0;
if (tcpWinFlowP->pktTcpCnt) {
= (float)tcpWinFlowP->winThCnt/(float)tcpWinFlowP->pktTcpCnt;
f += tcpWinFlowP->pktTcpCnt; // Count all TCP packets
pktTcpCnt }
(buf, tcpWinFlowP->stat);
OUTBUF_APPEND_U8(buf, tcpWinFlowP->ttl);
OUTBUF_APPEND_U8(buf, tcpWinFlowP->tcpWinInit);
OUTBUF_APPEND_U32(buf, tcpWinFlowP->winThCnt);
OUTBUF_APPEND_U32(buf, f);
OUTBUF_APPEND_FLT
const flow_t * const flowP = &flows[flowIndex];
if (!FLOW_IS_IPV4(flowP)) return; // IPv4 only
if (tcpWinFlowP->winThCnt == 0 || tcpWinFlowP->pktTcpCnt < TCPWIN_MINPKTS) return;
const int wzi = gwz.wzi; // store element count in const local variable, makes the compiler happy
if (wzi >= TCPWIN_MAXWSCNT) return; // If array full, stop saving
int i;
for (i = 0; i < wzi; i++) {
if (gwz.wzip[i].IPv4.s_addr == flowP->srcIP.IPv4.s_addr) break; // does IP exist?
}
if (f > gwz.wzCnt[i]) { // only update if count is greater than the previous one
.tcpCnt[i] = tcpWinFlowP->pktTcpCnt; // update TCP packet count
gwz.wzCnt[i] = f; // update relative count
gwzif (i == wzi) { // new one?
.wzip[i] = flowP->srcIP; // save new IP
gwz#if SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <--
.sID[i] = flowP->subnetNrSrc; // <-- save subnetID from core
gwz#endif // SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <--
.wzi++; // increment global window size counter
gwz}
}
}
One flow variable access and you have all subnet info you need.
The configuration is located in tcpGeoWin.h. Most of it we already know from
earlier tutorials. New is the subnet ID sID
in the gwz_t
struct.
Look for the // <--
vi src/tcpWin.h
...
/* ========================================================================== */
/* ------------------------ USER CONFIGURATION FLAGS ------------------------ */
/* ========================================================================== */
#define TCPWIN_THRES 1 // TCP window threshold for packet counts
#define TCPWIN_MINPKTS 50 // Summary file: minimal TCP packets seen to start saving process
#define TCPWIN_MAXWSCNT 100 // Summary file: maximal number of window size threshold count array elements
#define TCPWIN_SUFFIX "_tcpwin.txt" // Summary file: file name suffix
/* ========================================================================== */
/* ------------------------- DO NOT EDIT BELOW HERE ------------------------- */
/* ========================================================================== */
// plugin defines
// tcpWinStat status variable
#define TCPWIN_STAT_THU 0x1 // TCP window threshold undershoot
// Structure
typedef struct {
[TCPWIN_MAXWSCNT]; // IP address array
ipAddr_t wzip #if SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <--
uint32_t sID [TCPWIN_MAXWSCNT]; // <-- subnetID
#endif // SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <--
uint32_t tcpCnt[TCPWIN_MAXWSCNT]; // TCP packet count
float wzCnt [TCPWIN_MAXWSCNT]; // window size count
int wzi; // window size index
} gwz_t;
// Plugin structure
typedef struct { // always large variables first to limit memory fragmentation
uint32_t pktTcpCnt; // flow TCP packet count
uint32_t tcpWinInit; // initial window size
uint32_t winThCnt; // packet count window size below threshold
uint8_t ttl; // TTL
uint8_t stat; // status
} tcpWinFlow_t;
...
Adding subnet info to the summary file
After the free call for that tcpWinFlows
struct we open the
file TCPWIN_SUFFIX
. As above we select the output of
subnet info only if subnet activated and standard flow aggregation.
The macro T2_IP_TO_STR
converts IPv4/6 addresses to human
readable strings. SUBNET_LOC
and SUBNET_WHO
select the country code
and the organization given the stored subnet index. That is
all you need, and you are done. Look for // <--
vi src/tcpWin.c
void t2Finalize() {
(tcpWinFlows);
free
// open tcpWin statistics file
FILE *fp = t2_fopen_with_suffix(baseFileName, TCPWIN_SUFFIX, "w");
if (UNLIKELY(!fp)) return; // return if file could not be opened
#if SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <-- compile only if SUBNET core is on and no aggregation mode
(fp, "# IP\tCntry\tOrg\tpktTcpCnt\twinRelThCnt\n"); // <-- print header
fprintf#else // SUBNET_ON == 0 || (AGGREGATIONFLAG & SUBNET) != 0 // <--
(fp, "# IP\tpktTcpCnt\twinRelThCnt\n"); // print header
fprintf#endif // SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <-- compile only if SUBNET core is on and no aggregation mode
char srcIP[INET_ADDRSTRLEN];
for (int i = 0; i < gwz.wzi; i++) {
(gwz.wzip[i].IPv4, srcIP, INET_ADDRSTRLEN); // convert IP to string
t2_ipv4_to_str#if SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <-- compile only if SUBNET core is on and no aggregation mode
char *loc, *org; // <--
(loc, 4, gwz.sID[i]); // <-- get country for IP
SUBNET_LOC(org, 4, gwz.sID[i]); // <-- get organization for IP
SUBNET_ORG(fp, "%s\t%s\t%s\t%" PRIu32 "\t%f\n", // <-- print in file
fprintf, loc, org, gwz.tcpCnt[i], gwz.wzCnt); // <--
srcIP#else // many IP's / flow // <--
(fp, "%s\t%" PRIu32 "\t%f\n", // print in file
fprintf, gwz.tcpCnt[i], gwz.wzCnt[i]);
srcIP#endif // SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0 // <--
}
(fp);
fclose}
Two macros and you are subnet ready.
Adding subnet info to t2PluginReport() callback
Adding subnet info in the end report is straightforward, using the same switches as above.
void t2PluginReport(FILE *stream) {
if (winThCntG) {
(stream, plugin_name, tcpWinStat);
T2_FPLOG_AGGR_HEX(stream, plugin_name,
T2_FPLOG_NUMP"Number of TCP winsize packets below threshold " STR(TCPWIN_THRES),
, pktTcpCnt);
winThCntG// <-- Add the following 'if'
if (gwz.wzi) {
uint32_t gzCM = gwz.wzCnt[0];
uint32_t gzi = 0;
// find IP with largest ipCnt
for (int i = 0; i < gwz.wzi; i++) {
if (gwz.wzCnt[i] > gzCM) {
= gwz.wzCnt[i];
gzCM = i;
gzi }
}
char srcIP[INET_ADDRSTRLEN];
(gwz.wzip[gzi].IPv4, srcIP, sizeof(srcIP));
t2_ipv4_to_str
#if SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0
char *loc, *org;
(loc, ipver, gwz.sID[gzi]); // <-- get country for IP
SUBNET_LOC(org, ipver, gwz.sID[gzi]); // <-- get organization for IP
SUBNET_ORG(stream, plugin_name, "IP: %s, country: %s, org: %s", srcIP, loc, org);
T2_FPLOG#else // many IP's / flow
(stream, plugin_name, "IP: %s", srcIP);
T2_FPLOG#endif // SUBNET_ON != 0 && (AGGREGATIONFLAG & SUBNET) == 0
}
}
}
After you edited the skeleton code you should compare your implementation with tcpWin08.tar.gz.
So you are all set. Compile and run t2
:
t2build tcpWin
t2 -r ~/data/annoloc2.pcap -w ~/results================================================================================ Tranalyzer 0.9.0 (Anteater), Cobra. PID: 17736, SID: 666 ================================================================================ [INF] Creating flows for L2, IPv4, IPv6 Active plugins: 01: basicFlow, 0.9.0 02: tcpGeoWin, 0.9.0 03: txtSink, 0.9.0 [INF] IPv4 Ver: 5, Rev: 09082023, Range Mode: 0, subnet ranges loaded: 481503 (481.50 K) [INF] IPv6 Ver: 5, Rev: 09082023, Range Mode: 0, subnet ranges loaded: 41497 (41.50 K) Processing file: /home/wurst/data/annoloc2.pcap Link layer type: Ethernet [EN10MB/1] Snapshot length: 66 Dump start: 1022171701.691172000 sec (Thu 23 May 2002 16:35:01 GMT) [WRN] snapL2Length: 54 - snapL3Length: 40 - IP length in header: 1500 ... -------------------------------------------------------------------------------- tcpWin: Aggregated tcpWinStat=0x01 tcpWin: Number of TCP winsize packets below threshold 1: 2415 (2.42 K) [0.25%] tcpWin: IP: 138.212.187.203, country: jp, org: ASAHI KASEI CORPORATION -------------------------------------------------------------------------------- ...
So you have the basicFlow geo location output and the tcpWin output in the end report as well as additional info in the *_tcpwin.txt* summary file.
If the file is too big you may sort by the 4th column, the TCP window threshold count (winRelThCnt
).
tawk -s '#' 't2sort(winRelThCnt)' ~/results/annoloc2_tcpwin.txt
# IP Country Org pktTcpCnt winRelThCnt
138.212.187.203 jp ASAHI KASEI CORPORATION 72 1.000000
36.152.156.46 cn China Mobile Communications Co 79 0.962025
216.237.125.166 us Infortech Corporation 429 0.489510
216.217.165.245 us Windstream Communications LLC 52 0.269231
138.212.186.191 jp ASAHI KASEI CORPORATION 251 0.247012
138.212.185.150 jp ASAHI KASEI CORPORATION 195 0.246154
138.212.186.160 jp ASAHI KASEI CORPORATION 205 0.229268
138.212.186.52 jp ASAHI KASEI CORPORATION 162 0.203704
200.44.192.225 ve CANTV Servicios 315 0.196825
201.98.31.61 mx Uninet SA de CV 388 0.164948
216.56.159.22 us WiscNet 95 0.157895
138.212.186.60 jp ASAHI KASEI CORPORATION 140 0.150000
201.9.136.60 br Telemar Norte Leste SA 197 0.142132
193.87.5.62 sk AS2607-MNT 235 0.140426
201.9.140.14 br Telemar Norte Leste SA 194 0.123711
19.112.1.129 us MAINT-APNIC-AP 78 0.115385
138.212.185.186 jp ASAHI KASEI CORPORATION 74 0.094595
212.88.230.156 be TELENET-OPS-MNT 131 0.045802
201.123.124.98 mx Gestión de direccionamiento 340 0.041176
193.86.108.236 cz AS13036-MNT 847 0.035419
138.212.185.98 jp ASAHI KASEI CORPORATION 133 0.030075
200.50.55.138 cl TELEFONICA CHILE SA 87 0.022989
200.50.132.98 bb Infinetworx Caribbean Inc 111 0.018018
193.87.239.57 sk Provider Local Registry 365 0.016438
83.42.68.176 es Telefonica de Espana SAU 62 0.016129
200.32.26.254 ar Telecom Argentina SA 250 0.016000
19.123.222.7 us MAINT-APNIC-AP 72 0.013889
138.212.188.204 jp ASAHI KASEI CORPORATION 73 0.013699
193.87.97.162 sk AS2607-MNT 843 0.011862
138.212.191.84 jp ASAHI KASEI CORPORATION 92 0.010870
133.26.84.187 jp Meiji University 2079 0.009620
209.132.7.75 us Simple Network Communications 114 0.008772
193.104.31.16 fr OVER-LINK-MNT 133 0.007519
193.87.112.223 sk AS2607-MNT 957 0.005225
209.147.223.37 us Institutions of Higher Learnin 244 0.004098
138.212.188.66 jp ASAHI KASEI CORPORATION 249 0.004016
192.224.45.42 us CDK Global 719 0.002782
70.5.118.83 us Sprint Fort Worth POP 415 0.002410
83.128.136.224 nl CAIW Internet 977 0.002047
36.89.79.225 id PT Telekomunikasi Indonesia 538 0.001859
138.212.184.48 jp ASAHI KASEI CORPORATION 1081 0.001850
201.98.215.67 mx Uninet SA de CV 618 0.001618
219.127.165.87 jp IPSTAR Company Limited 670 0.001493
138.212.188.99 jp ASAHI KASEI CORPORATION 1134 0.000882
201.9.148.42 br Telemar Norte Leste SA 1332 0.000751
138.212.190.117 jp ASAHI KASEI CORPORATION 2309 0.000433
If you like to access the county and city information, you need to switch on CNTYCTY
in subnetHL.h and recompile with t2build -R -f
.
Exercise: Add County and City info to the end report. What do you need to configure in the core so that this info is added to the subnet table?
Query the IP tables
Assume that a protocol response contains an IP, such as DNS. From that IP you want to know whois behind it, then you need to query the IP tables yourself.
In order to do so you have to call the core functions subnet_testHL4
and subnet_testHL6
for IPv4 and 6 addresses shown below. The return value is the subnetID
you can use
to fetch the geo and whois data as already indicated above.
if (subnetTable4P) {
;
ipAddr_t ipconst uint32_t subnetID1 = subnet_testHL4(subnetTable4P, ip.IPv4x[0]); // subnet test on IPv4 address
;
ip4Addr_t ip4const uint32_t subnetID2 = subnet_testHL4(subnetTable4P, ip4]); // subnet test on IPv4 address
}
if (subnetTable6P) {
;
ipAddr_t ipuint32_t subnetID = subnet_testHL6(subnetTable6P, ip); // subnet test on IPv6 address
}
As you can see in the code above, subnetTable[46]P
may not exist depending on the configuration of T2,
so to make things simpler, just use the following macros instead:
uint32_t subnetID;
;
ipAddr_t ip;
ip4Addr_t ip4
(subnetID, ip4);
SUBNET_TEST_IP4(subnetID, ip);
SUBNET_TEST_IP4
(subnetID, ip);
SUBNET_TEST_IP6
(subnetID, ip, 4); // For IPv4
SUBNET_TEST_IP(subnetID, ip, 6); // For IPv6 SUBNET_TEST_IP
It is beneficial to store IPv4 and 6 addresses in one structure, if in dual mode. On the other hand
if only IPv4 addresses are processed the ip4Addr_t
structure does not waste 48 bits.
I advise to use the t2 structures as the macros rely on them.
The relevant address structures are defined in ipaddr.h, as shown in the extract below.
tranalyzer2
vi src/ipaddr.h
...
typedef union {
uint32_t IPv4x[4];
struct in_addr IPv4; // IPv4 address
struct in6_addr IPv6; // IPv6 address
uint64_t IPv6L[2]; // IPv6 address 2*64 bit max chunk for masking ops
} __attribute__((packed)) ipAddr_t;
typedef struct {
uint8_t ver; // version
;
ipAddr_t addr} ipVAddr_t;
typedef union {
uint32_t IPv4x[1];
struct in_addr IPv4;
} __attribute__((packed)) ip4Addr_t;
...
Instead of using the subnet indexes from the packet structure you can now define your own
and use the SUBNET_TEST_IP[46]()
macros or the subnet_testHL[46]()
functions.
Try it on tcpWin, it should produce the same output.
Conclusion
Have fun experimenting with subnet info!
You can download the final version of the tcpWin plugin.
The next tutorial will teach you all about plugin dependencies
Have fun writing plugins!
See also
- Plugin programming cheatsheet
- The basics: your first flow plugin
- Plugin end report
- Plugin monitoring
- Plugin packet mode
- Plugin summary files
- Plugin dependencies
- Plugin alarm mode
- Plugin force mode
- Plugin pcap extraction
- Plugin flow timeout
- Plugin sink
- Developing Tranalyzer plugins in C++
- Developing Tranalyzer plugins in Rust