Working with FlowViewer and flow-print (from the flow-tools suite), if you filter some NetFlow data by TCP flags you may notice a weird behaviour, like the one in the following picture:
Here I applied a filter on TCP Flags = 27, but on the output I had the “Fl” (Flag) column reporting 3! What’s up? Is 3 a kind of alias for 27? Is this a math puzzle? None of this!
First off, why did I filter for 27?
Well, NetFlow records contain a field reporting the cumulative OR-ed TCP flags seen on the flow. For example, in a regular TCP connection a client would send a SYN, then an ACK, then other optional PSHs and ACKs and finally a FIN. The table on the left reports a summary of TCP flags with their binary and decimal values.
If we “sum” (using the OR binary operator) all the flags used in a TCP connection (SYN [2] + ACK [16] + PSH [8] + FIN [1]) we have 27.
For example, if we try to connect to a port where no daemon is listening on, our client would send a SYN packet while the server would reply with a RST/ACK packet: in this scenario we would have 2 flows:
1) client-to-server: TCP Flags = 2 (just SYN [2]);
2) server-to-client: TCP Flags = 20 (RST [4] + ACK [16])
Now we know how TCP Flags work in NetFlow, but why 27 = 3???
Let’s start debugging FlowViewer using the DEBUG_VIEWER file into the Flow_Working directory; it tells us what FlowViewer executes in the background:
NETFLOWBOX:/usr/lib/cgi-bin/FlowViewer_3.3.1# cat Flow_Working/DEBUG_VIEWER
The output tells us the “hidden” command it uses, and we try to run it:
NETFLOWBOX:/usr/lib/cgi-bin/FlowViewer_3.3.1# /usr/bin/flow-cat -t "03/08/2010 08:44:59" -T "03/08/2010 16:50:01" /var/flows/MYROUTER/2010/2010-03/2010-03-08 | /usr/bin/flow-nfilter -f /usr/lib/cgi-bin/FlowViewer_3.3.1/Flow_Working/FlowViewer_filter_165206 -FFlow_Filter | /usr/bin/flow-print -f5 Start End Sif SrcIPaddress SrcP DIf DstIPaddress DstP P Fl Pkts Octets 0308.10:34:43.799 0308.10:34:44.995 66 192.168.0.154 1888 59 192.168.1.184 1433 6 3 15 2032 0308.11:00:31.339 0308.11:00:32.419 66 192.168.0.154 2472 59 192.168.1.184 1433 6 3 15 2034 0308.11:03:15.899 0308.11:03:16.715 66 192.168.0.154 2533 59 192.168.1.184 1433 6 3 15 2034 0308.11:18:00.811 0308.11:18:01.719 66 192.168.0.154 2877 59 192.168.1.184 1433 6 3 15 2042 0308.11:22:52.407 0308.11:22:53.483 66 192.168.0.154 3004 59 192.168.1.184 1433 6 3 15 2034 0308.11:26:47.751 0308.11:27:28.367 66 192.168.0.154 3107 59 192.168.1.184 1433 6 3 1420 1963241 0308.11:36:46.107 0308.11:36:47.195 66 192.168.0.154 3287 59 192.168.1.184 1433 6 3 15 2034 0308.11:41:42.115 0308.11:41:43.815 66 192.168.0.154 3297 59 192.168.1.184 1433 6 3 15 2034
Here it is, the antepenultimate column is the “Fl” (Flag), and it is = 3!
So, let’s go deep in the command; it uses flow-cat to merge some NetFlow data files, then it passes the output to the flow-nfilter and, finally, it runs flow-print with the -f5 argument.
The f option just tells flow-print how to format data… Well, let’s try to use another format (man flow-print is our friend here!): let’s switch to -f1!
NETFLOWBOX:/usr/lib/cgi-bin/FlowViewer_3.3.1# /usr/bin/flow-cat -t "03/08/2010 08:44:59" -T "03/08/2010 16:50:01" /var/flows/MYROUTER/2010/2010-03/2010-03-08 | /usr/bin/flow-nfilter -f /usr/lib/cgi-bin/FlowViewer_3.3.1/Flow_Working/FlowViewer_filter_165206 -FFlow_Filter | /usr/bin/flow-print -f1 Sif SrcIPaddress DIf DstIPaddress Pr SrcP DstP Pkts Octets StartTime EndTime Active B/Pk Ts Fl 0042 192.168.0.154 003b 192.168.1.184 06 760 599 15 2032 0308.10:34:43.799 0308.10:34:44.995 1.196 135 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 9a8 599 15 2034 0308.11:00:31.339 0308.11:00:32.419 1.080 135 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 9e5 599 15 2034 0308.11:03:15.899 0308.11:03:16.715 0.816 135 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 b3d 599 15 2042 0308.11:18:00.811 0308.11:18:01.719 0.908 136 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 bbc 599 15 2034 0308.11:22:52.407 0308.11:22:53.483 1.076 135 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 c23 599 1420 1963241 0308.11:26:47.751 0308.11:27:28.367 40.616 1382 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 cd7 599 15 2034 0308.11:36:46.107 0308.11:36:47.195 1.088 135 00 1b 0042 192.168.0.154 003b 192.168.1.184 06 ce1 599 15 2034 0308.11:41:42.115 0308.11:41:43.815 1.700 135 00 1b
This format is not on a single line, but two lines are used for each NetFlow record; the TCP Flags values are in the second line of each record, in the last field, and they are in hex, and … well, they are set on “1b” = 27 (decimal)! So, it’s “just” an output issue. If we check the source code, we can understand why we see 3 instead of 27:
from flow-print.c:
int format5(struct ftio *ftio, int options) { [...] while ((rec = ftio_read(ftio))) { [...] cur.tcp_flags = ((u_int8*)(rec+fo.tcp_flags)); [...] printf("%-5u %-15.15s %-5u %-5u %-15.15s %-5u %-3u %-2d %-10lu %-10lun", (u_int)*cur.input, fmt_buf1, (u_int)*cur.srcport, (u_int)*cur.output, fmt_buf2, (u_int)*cur.dstport, (u_int)*cur.prot, (u_int)*cur.tcp_flags & 0x7, (u_long)*cur.dPkts, (u_long)*cur.dOctets);
This is the format5 routine used to print NetFlow data when the -f5 option is given; please note line 19. It takes the full TCP Flags value, applies a 0x7 mask with the AND binary operator and finally it prints the result. The 0x7 value in binary is 0000 0111; it means that, whatever original flag is, the routine always uses the last 3 bit only. Here it is the “27 = 3” puzzle’s solution: 27 (decimal) = 0001 1011, so it only considers last 3 bits, 011 = 3 (decimal).
Back to our previous examples…
A client connecting to a “closed” port will produce a flow record with just a SYN: binary 0000 0010, decimal 2, no problems here, 3 bits are enough for a full representation even in flow-print.
The server receiving a connection request for a closed port will produce a flow with a RST + ACK: binary 0000 0100 + 0001 0000 = 0001 0100, decimal 20; here we’ll have just the 3-bits view of the number, so flow-print will report decimal 4 (binary 100).
Of course, this output format issue may make troubleshooting and analysis quite difficult; every suspect behaviour has to be analyzed through the command line with the -f1 option of flow-print.
UPDATE: you may be interested in FlowGraph too, a tool that allows to dynamically build graphs based on previously collected netflow data and to use them in a web-based front-end, adding details about Autonomous System Number holders, IPv4 and IPv6 prefixes, inet(6)num objects, netnames from RIPE Stat.
Latest posts by Pier Carlo Chiodi (see all)
- Good MANRS for IXPs route servers made easier - 11 December 2020
- Route server feature-rich and automatic configuration - 13 February 2017
- Large BGP Communities playground - 15 September 2016
For NetFlow reporting, please consider Scrutinizer as well from plixer.com
Jake
Man… You’re awesome!
Thanks wonderful post and guide helped me a lot.