Tutorial: Plugin Alarm Mode

As detailed in alarm mode tutorial T2 is capable to operate in a plugin controlled flow release. The regex_pcre and dnsDecode plugins are an example. In order to implement this feature in your own plugin, specialized macros are supplied, which will be detailed in this tutorial. First switch on the ALARM_MODE in tranalyzer.h.

$ cd ~/tranalyzer2/tranalyzer2/src
$ vi tranalyzer.h
....
...
// Tranalyzer User Operational modes

// Operation modes, Plugins which use these modes have to be recompiled

#define ALARM_MODE 1 // only flow output if an Alarm based plugin fires
#define ALARM_AND  0 // if (ALARM_MODE == 1) then 1: AND, 0: OR
...

Or use the following t2conf command:

$ t2conf tranalyzer2 -D ALARM_MODE=1
$

Then reset your plugin directory into a pristine state and compile the following basic plugins:

$ t2build -e
...
$ t2build tranalyzer2 basicFlow tcpStates txtSink
...
$

If you did not read the tutorials before, here is the basis plugin which we will extend: tcpWin

The anonymized sample pcap can be downloaded here: faf-exercise.pcap. Please extract it under your data folder: ~/data, if you haven’t already. Now you are all set for the alarm mode.

Implementing the alarm capability

If your plugin wants to contribute information to the alarm mode, then global variables and a T2_REPORT_ALARMS(numAlarms) macros have to be added.

So open tcpWin.c in an editor and add two global variables after the tcpWinFlows definition. Look for the <-- markers below.

Add at the beginning in the global plugin block count variables for the endreport:

Then add in the onFlowTerminate(...) callback the lines marked by <-- which triggers an alarm if the threshold count is > 0. You can replace the variable in T2_REPORT_ALARMS(...) by any other logical statement or variable.

For just to make alarm mode work, you only need the The macro T2_REPORT_ALARMS(...). The rest is for convenience. It implements the following state-machine:

The variable supOut is a global switch suppressing the output. numAlarms denotes the aggregate of all flow alarms. numAlarmFlows denotes the number of flows which bear an alarm. If ALARM_MODE is not active the latter global counts will still reported. As we count the number of alarm flows in the macro, you may at the present version only use it ONCE onFlowTerminate EXOR onFlowGenerate, but NOT during packet callbacks. This will be fixed in a later 0.8.X version.

So your plugin can reimplement any state-machine you want and control the output suppression to your liking. The easiest would be to set supOut = 1, then no flow would ever appear in the flow file, rather useless, right.

If you set ALARM_AND to 1 in tranalyzer.h then any plugin can reset a flow terminate, so all plugins implementing ALARM_MODE must agree.

For reporting add a pluginReport where the number of alarms and alarm flows are printed.

C void pluginReport(FILE *stream) { if (winThFlows) T2_FPLOG(stream, "tcpWin", "%"PRIu32" alarms in %"PRIu32" flows below win threshold %d", winAlarms, winThFlows, TCPWIN_THRES); }C

Now save tcpWin.c, compile it and execute T2

$ t2build tcpWin
...
$ t2 -r ~/data/faf-exercise.pcap -w ~/results/
================================================================================
Tranalyzer 0.8.5 (Anteater), Tarantula. PID: 2448
================================================================================
[INF] Creating flows for L2, IPv4, IPv6 [ALARM]
Active plugins:
    01: basicFlow, 0.8.5
    02: tcpStates, 0.8.5
    03: tcpWin, 0.8.5
    04: txtSink, 0.8.5
[INF] basicFlow: IPv4 Ver: 3, Rev: 01072019, Range Mode: 0, subnet ranges loaded: 312743 (312.74 K)
[INF] basicFlow: IPv6 Ver: 3, Rev: 01072019, Range Mode: 0, subnet ranges loaded: 21494 (21.49 K)
Processing file: /home/stefan/tranalyzer-website/tranalyzer/download/data/faf-exercise.pcap
Link layer type: Ethernet [EN10MB/1]
Dump start: 1258544215.037210 sec (Wed 18 Nov 2009 11:36:55 GMT)
Dump stop : 1258594491.683288 sec (Thu 19 Nov 2009 01:34:51 GMT)
Total dump duration: 50276.646078 sec (13h 57m 56s)
Finished processing. Elapsed time: 0.003720 sec
Finished unloading flow memory. Time: 0.003725 sec
Percentage completed: 100.00%
Number of processed packets: 5902 (5.90 K)
Number of processed bytes: 4993414 (4.99 M)
Number of raw bytes: 4993414 (4.99 M)
Number of pcap bytes: 5087870 (5.09 M)
Number of IPv4 packets: 5902 (5.90 K) [100.00%]
Number of A packets: 1986 (1.99 K) [33.65%]
Number of B packets: 3916 (3.92 K) [66.35%]
Number of A bytes: 209315 (209.31 K) [4.19%]
Number of B bytes: 4784099 (4.78 M) [95.81%]
Average A packet load: 105.40
Average B packet load: 1221.68 (1.22 K)
--------------------------------------------------------------------------------
tcpStates: Aggregated anomaly flags: 0x4a
tcpWin: 4 alarms in 1 flows below win threshold 1
--------------------------------------------------------------------------------
Headers count: min: 3, max: 3, average: 3.00
Number of TCP packets: 5902 (5.90 K) [100.00%]
Number of TCP bytes: 4993414 (4.99 M) [100.00%]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Number of processed   flows: 72
Number of processed A flows: 36 [50.00%]
Number of processed B flows: 36 [50.00%]
Number of request     flows: 36 [50.00%]
Number of reply       flows: 36 [50.00%]
Total   A/B    flow asymmetry: 0.00
Total req/rply flow asymmetry: 0.00
Number of processed   packets/flows: 81.97
Number of processed A packets/flows: 55.17
Number of processed B packets/flows: 108.78
Number of processed total packets/s: 0.12
Number of processed A+B packets/s: 0.12
Number of processed A   packets/s: 0.04
Number of processed   B packets/s: 0.08
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Number of average processed flows/s: 0.00
Average full raw bandwidth: 795 b/s
Average full bandwidth : 792 b/s
Max number of flows in memory: 18 [0.01%]
Memory usage: 0.05 GB [0.08%]
Aggregate flow status: 0x0002000000004000
[WRN] 4 alarms in 1 [1.39%] flows
[INF] IPv4
$

Note the info in the plugin block and the warning at the end of the T2 report. Decoding the aggregated flow status, we see that you indeed set the FL_ALARM bit in globalStat.

tawk -V flowStat=0x0002000000004000

The flowStat column with value 0x0002000000004000 is to be interpreted as follows:

   bit | flowStat              | Description
   =============================================================================
    14 | 0x0000 0000 0000 4000 | IPv4
    49 | 0x0002 0000 0000 0000 | Alarm mode & pcapd dumps packets from this flow to new pcap if not -e option

Looking into faf-exercise_flows.txt shows that out of 72 flows only one was released producing four alarms. As you set the FL_ALARM onFlowTerminate and the flowStat is printed by basicFlow, being executed before tcpWin we do not see the bit.

$ tcol faf-exercise_flows.txt
%dir  flowInd  flowStat            timeFirst          timeLast           duration   numHdrDesc  numHdrs  hdrDesc       srcMac             dstMac             ethType  ethVlanID  srcIP          srcIPCC  srcIPWho           srcPort  dstIP          dstIPCC  dstIPWho  dstPort  l4Proto  tcpStates  tcpWinStat  tcpWinThCnt
A     36       0x0000000000004000  1258594163.408285  1258594191.015208  27.606923  1           3        eth:ipv4:tcp  00:08:74:38:01:b4  00:19:e3:e7:5d:23  0x0800              192.168.1.105  09       "Private network"  49330    143.166.11.10  us       "Dell"    64334    6        0x42       0x01        4
$

If you want to see the alarm bit set in the flowStat you have to set in the packet callback. Just comment out the T2_SET_STATUS statement in onFlowTerminate and add it in claimLayer4Information below where the <– is present.

void claimLayer4Information(packet_t *packet, unsigned long flowIndex) {
        const flow_t * const flowP = &flows[flowIndex];
        if (flowP->layer4Protocol != L3_TCP) return; // process only TCP

        // only 1. frag packet will be processed
        if (!t2_is_first_fragment(packet)) return;

        tcpWinFlow_t * const tcpWinFlowP = &tcpWinFlows[flowIndex];
        const tcpHeader_t * const tcpHeader = (tcpHeader_t*)packet->layer4Header;
        const uint32_t tcpWin = ntohs(tcpHeader->window);

        if (tcpWin < TCPWIN_THRES) {                    // is windowsize below threshold?
                tcpWinFlowP->winThCnt++;                // count the packet
                tcpWinFlowP->stat |= TCPWIN_THU;        // set the status bit

          	T2_SET_STATUS(&flows[flowIndex], FL_ALARM);	// <-- Set the alarm bit in flow and global
        }

}

Save the file, recompile, rerun t2 and reopen faf-exercise_flows.txt

$ t2build tcpWin
...
$ t2 -r ~/data/faf-exercise.pcap -w ~/results/
...
$ tcol faf-exercise_flows.txt
%dir  flowInd  flowStat            timeFirst          timeLast           duration   numHdrDesc  numHdrs  hdrDesc       srcMac             dstMac             ethType  ethVlanID  srcIP          srcIPCC  srcIPWho           srcPort  dstIP          dstIPCC  dstIPWho  dstPort  l4Proto  tcpStates  tcpWinStat  tcpWinThCnt
A     36       0x0002000000004000  1258594163.408285  1258594191.015208  27.606923  1           3        eth:ipv4:tcp  00:08:74:38:01:b4  00:19:e3:e7:5d:23  0x0800              192.168.1.105  09       "Private network"  49330    143.166.11.10  us       "Dell"    64334    6        0x42       0x01        4
$ 

See now it is set.

Play a bit around and improve the program, e.g. modify the alarm condition if more than one win threshold occurrences happen.

And do not forget to reset the alarm mode for the next tutorial

$ t2conf tranalyzer2 -D ALARM_MODE=0
$ t2build -R
$

If you want to separate the functionality of your alarm mode from other modes such as force mode, then you have to surround your code with ALARM_MODE pragmas as shown below:

C #if ALARM_MODE == 1 T2_SET_STATUS(&flows[flowIndex], FL_ALARM); #endif // ALARM_MODE == 1shell

Have fun!

The next tutorial will teach you how to implement the Force mode