Tutorial: Plugin summary files
Contents
When all data is processed or T2 is interrupted by ^C or a signal, then the end report is printed. At the same time certain global information can be printed by your plugin. Before we start doing this, clean out your plugin .so directory if this is the first tutorial you follow. Then all unnecessary plugins should be deleted from the plugin folder ./tranalyzer/plugins and compile basicFlow, basicStats and txtSink.
$ t2build -e
Are you sure you want to empty the plugin folder '/home/wurst/.tranalyzer/plugins' (y/N)? y
Plugin folder emptied
$ t2build basicFlow txtSink
...
Compiling the basicFlow took now a bit longer, because t2 had to rebuild the subnetfiles for geolocation. ‘t2build -e’ also removes the subnetfile. You can also use a rm, which does not remove the old subnetfile:
$ rm ~/.tranalyzer/plugins/*.so
$ t2build basicFlow txtSink
Then the compilation will be considerable faster, as the subnetfile already exists.
If you didn’t read the tutorials before, here is the basis plugin which we will extend: tcpWin
The annonymized sample pcap can be downloaded here: annoloc2.pcap. Please extract it under your data folder, if you not already have. Now you are all set for summary file programming.
Summary files
Every plugin can produce a summary of traffic content. Let’s produce a file which lists all IP’s with their maximal winThCnts, so we could find the IP’s having the largest L4 trouble. In order to do so, we need to define all necessary variables global to the plugin.
Move to the tcpWin plugin and open tcpWin.c
$ tran
$ cd tcpWin/src
$ vim tcpWin.c
For the matter of simplicity we just have arrays and a global index. Just add the lines marked by <–
...
/
* Plugin variables that may be used by other plugins (MUST be declared in
* the header file as 'extern tcpWinFlow_t *tcpWinFlows;'
*/
tcpWinFlow_t *tcpWinFlows;
...
// window size counts
gwz_t gwz; // <--
...
Now go to the onFlowTerminate callback. First we need the pointer to the flow structure. To show the principal we just do a linear search whether we already have the IP stored and check whether its counter is greater than the potential existing, then we store the new data. Yes, it can be more elegant, using a hash or a tree. We will discuss T2 support for that matter in tutorial t2kunfu
void onFlowTerminate(unsigned long flowIndex) {
const flow_t * const flowP = &flows[flowIndex]; // <--
tcpWinFlow_t * const tcpWinFlowP = &tcpWinFlows[flowIndex];
const float f = (float)tcpWinFlowP->winThCnt/(float)tcpWinFlowP->pktTcpCnt; // produce a useful relative number
if (tcpWinFlowP->winThCnt && tcpWinFlowP->pktTcpCnt >= TCPWIN_MINPKTS) {
const int wzi = gwz.wzi;
if (wzi < TCPWIN_MAXWSCNT) { // 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
gwz.tcpCnt[i] = tcpWinFlowP->pktTcpCnt; // save tcp packet count
gwz.wzCnt[i] = f; // save relative count
if (i == wzi) {
gwz.wzip[i] = flowP->srcIP; // save IP
gwz.wzi++; // increment global window size counter
}
}
}
if (tcpWinFlowP->stat) { // update the global vars
winStatG |= tcpWinFlowP->stat;
winThCntG += tcpWinFlowP->winThCnt;
}
}
#if BLOCK_BUF == 0
OUTBUF_APPEND_U8(main_output_buffer, tcpWinFlowP->stat);
OUTBUF_APPEND_U32(main_output_buffer, tcpWinFlowP->winThCnt);
OUTBUF_APPEND_U32(main_output_buffer, tcpWinFlowP->tcpWinInit);
OUTBUF_APPEND_U32(main_output_buffer, tcpWinFlowP->winThCnt);
OUTBUF_APPEND_FLT(main_output_buffer, f);
#endif // BLOCK_BUF == 0
}
onApplicationTerminate not only serves to free flow memory but also to produce all kinds of global output into specialized files. The code below stores the IP and its count. Just add it after the free command.
void onApplicationTerminate() {
free(tcpWinFlows); // free the tcpWin Flows
// open TCPWIN statistics file
FILE *fp;
int i;
char srcIP[INET6_ADDRSTRLEN];
fp = t2_open_file(baseFileName, TCPWIN_FNSUP, "w");
if (UNLIKELY(!fp)) { // if file cannot be opened print warning and return;
T2_PWRN("tcpWin", "Failed to allocate memory for: %s", TCPWIN_FNSUP);
return;
}
fprintf(fp, "# IP\tpktTcpCnt\twinRelThCnt\n"); // print header
for (i = 0; i < gwz.wzi; i++) {
T2_IP_TO_STR(gwz.wzip[i], 4, srcIP, INET6_ADDRSTRLEN); // transfer IP to string
fprintf(fp, "%s\t%"PRIu32"\t%f\n", srcIP, gwz.tcpCnt[i], gwz.wzCnt[i]); // print in file
}
fclose(fp);
}
Now open tcpWin.h and add the maximal size of the global IP/window size count array and the appendix of the global file. Just add the lines and gwz_t typdef marked by <–
// plugin defines
#define TCPWIN_THRES 1 // tcp Window threshold for packet counts
#define TCPWIN_MINPKTS 200 // <-- 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_FNSUP "_tcpwin.txt" // <-- Summary file: file name supplement
// Status variable: stat
#define TCPWIN_THU 0x1 // TCPWIN threshold undershoot
// plugin structures
typedef struct { // <-- Global file
ipAddr_t wzip[TCPWIN_MAXWSCNT]; // IP Address array
uint32_t tcpCnt[TCPWIN_MAXWSCNT]; // window size count
float wzCnt[TCPWIN_MAXWSCNT]; // window size count
int wzi; // window size index
} gwz_t;
So you are all set. Compile and run t2:
shell
shell $ t2build tcpWin … $ t2 -r ~/data/annoloc2.pcap -w ~/results … ```
Open your results cmd window and look what t2 produced
$ ls
annoloc2_flows.txt annoloc2_headers.txt annoloc2_tcpwin.txt
Actually we did not need the txtSink, so we generated *a _flows.txt* and *_headers.txt* file but now also a *_tcpwin.txt* file. When you open that file you will see all IP’s and their counts
tcol annoloc2_tcpwin.txt
# IP pktTcpCnt winRelThCnt
36.89.79.225 538 0.001859
201.9.148.42 1332 0.000751
193.87.239.57 365 0.016438
200.32.26.254 250 0.016000
70.5.118.83 415 0.002410
138.212.190.117 2309 0.000433
216.237.125.166 429 0.489510
138.212.185.150 4465 0.002016
138.212.188.99 1134 0.000882
193.87.5.62 235 0.140426
200.44.192.225 315 0.196825
138.212.186.191 251 0.247012
138.212.184.48 1081 0.001850
209.147.223.37 244 0.004098
133.26.84.187 2079 0.009620
138.212.188.66 249 0.004016
138.212.186.160 205 0.229268
192.224.45.42 719 0.002782
201.123.124.98 340 0.041176
193.87.97.162 843 0.011862
201.98.31.61 388 0.164948
219.127.165.87 670 0.001493
193.87.112.223 957 0.005225
201.98.215.67 618 0.001618
83.128.136.224 977 0.002047
193.86.108.236 847 0.035419
If the file is too big you may sort for the 3rd column.
sort -nr -k3,3 annoloc2_tcpwin.txt | tcol
216.237.125.166 429 0.489510
138.212.186.191 251 0.247012
138.212.186.160 205 0.229268
200.44.192.225 315 0.196825
201.98.31.61 388 0.164948
193.87.5.62 235 0.140426
201.123.124.98 340 0.041176
193.86.108.236 847 0.035419
193.87.239.57 365 0.016438
200.32.26.254 250 0.016000
193.87.97.162 843 0.011862
133.26.84.187 2079 0.009620
193.87.112.223 957 0.005225
209.147.223.37 244 0.004098
138.212.188.66 249 0.004016
192.224.45.42 719 0.002782
70.5.118.83 415 0.002410
83.128.136.224 977 0.002047
138.212.185.150 4465 0.002016
36.89.79.225 538 0.001859
138.212.184.48 1081 0.001850
201.98.215.67 618 0.001618
219.127.165.87 670 0.001493
138.212.188.99 1134 0.000882
201.9.148.42 1332 0.000751
138.212.190.117 2309 0.000433
# IP pktTcpCnt winRelThCnt
So half of the packets the host 216.237.125.166 asked the opposite IP to stop sending packets. Now add the destination address and improve the measure by adding the WS option. That’s your job now. Let yourself inspire by the tcpFlags plugin of t2. Have fun!