Tutorial: Domain Name Service (DNS)

This tutorial discusses the plugin dnsDecode.


Before we start we need to prepare T2. If you did not complete the tutorials before just follow the procedure described below.

First I recommend to set T2 into a pristine state by removing all unnecessary or older plugins from the default plugin folder ~/.tranalyzer/plugins. Just as a precaution if you have some old plugins or files there. If you like to keep them, please copy them away.

$ t2build -e
Are you sure you want to empty the plugin folder '/home/wurst/.tranalyzer/plugins' (y/N)? y
Plugin folder emptied

Then compile the following plugins

$ t2build tranalyzer2 basicFlow dnsDecode txtSink


If you did not create a separate data and results directory yet, please do it now in another cmd window, it facilitates your workflow:

$ mkdir ~/data ~/results

Download the sample pcap here: dns-cname.pcap. Now you’re all set.


Let’s look at the plugin configuration first:

$ dnsDecode
$ vi src/dnsDecode.h

DNS_MODE controls the depth of the dns record analysis. If you are only interested in the request and answer records set it to DNS_MODE=2. Here we leave it at the default value 4, so all entries.

The constant DNS_HEXON and DNS_TYPE control the type output in the flow file. While the first produces a bit field representation of all dnsTypes, the latter controls the additional representation of the dns query and answer types flow output. For the time being we leave all off or default.

DNS_HDRMD controls the output of the Operational and Return codes.

Normally the output of all relevant dns entries are in vector form, so that all different columns can be matched, s. below. If DNS_AGGR=1 all columns will be uniquely aggregated, now different columns cannot be matched, but the output is more concise. We leave it at the default value.

DNS_WHO enables the decoding of the dns IP records according to country and organization. It requires SUBNET_ON=1 in tranalyzer.h. So make sure it is set:

$ t2conf tranalyzer2 -G SUBNET_ON

MAL_TEST and MAL_TYPE control the detection of malicious domains in the request record. We come back to it later.

So run t2 on the supplied pcap in default configuration including packet mode.

$ t2 -r ~/data/dns-cname.pcap -w ~/results/ -s
Tranalyzer 0.8.10 (Anteater), Tarantula. PID: 30999
[INF] Creating flows for L2, IPv4, IPv6
Active plugins:
    01: basicFlow, 0.8.10
    02: tcpStates, 0.8.10
    03: dnsDecode, 0.8.10
    04: txtSink, 0.8.10
[INF] IPv4 Ver: 5, Rev: 16122020, Range Mode: 0, subnet ranges loaded: 406077 (406.08 K)
[INF] IPv6 Ver: 5, Rev: 17122020, Range Mode: 0, subnet ranges loaded: 51069 (51.07 K)
Processing file: /home/wurst/data/dns-cname.pcap
Link layer type: Ethernet [EN10MB/1]
Dump start: 1464026534.044641 sec (Mon 23 May 2016 18:02:14 GMT)
Dump stop : 1464026534.074417 sec (Mon 23 May 2016 18:02:14 GMT)
Total dump duration: 0.029776 sec
Finished processing. Elapsed time: 0.000163 sec
Finished unloading flow memory. Time: 0.000243 sec
Percentage completed: 100.00%
Number of processed packets: 2
Number of processed bytes: 670
Number of raw bytes: 670
Number of pcap bytes: 726
Number of IPv4 packets: 2 [100.00%]
Number of A packets: 1 [50.00%]
Number of B packets: 1 [50.00%]
Number of A bytes: 84 [12.54%]
Number of B bytes: 586 [87.46%]
Average A packet load: 84.00
Average B packet load: 586.00
dnsDecode: Aggregated dnsStat=0x0001
dnsDecode: Aggregated dnsHFlg=0x99, dnsOpC=0x0001, dnsRetC=0x0001
dnsDecode: Number of DNS packets: 2 [100.00%]
dnsDecode: Number of DNS Q packets: 1 [50.00%]
dnsDecode: Number of DNS R packets: 1 [50.00%]
Headers count: min: 3, max: 3, average: 3.00
Number of UDP packets: 2 [100.00%]
Number of UDP bytes: 670 [100.00%]
Number of processed   flows: 2
Number of processed A flows: 1 [50.00%]
Number of processed B flows: 1 [50.00%]
Number of request     flows: 1 [50.00%]
Number of reply       flows: 1 [50.00%]
Total   A/B    flow asymmetry: 0.00
Total req/rply flow asymmetry: 0.00
Number of processed   packets/flows: 1.00
Number of processed A packets/flows: 1.00
Number of processed B packets/flows: 1.00
Number of processed total packets/s: 67.17
Number of processed A+B   packets/s: 67.17
Number of processed A     packets/s: 33.58
Number of processed   B   packets/s: 33.58
Number of average processed flows/s: 67.17
Average full raw bandwidth: 180011 b/s (180.01 Kb/s)
Average full bandwidth : 180011 b/s (180.01 Kb/s)
Max number of flows in memory: 2 [0.00%]
Memory usage: 0.01 GB [0.02%]
Aggregated flowStat=0x0400000000004000
[INF] IPv4 flows

So the aggregated dnsStat tels us that there is dns, fine. The dns header flags show that there are responses, so the dns requests are successful. There is no cryptographic checking and recursion exists. The dns Operation flags denote that there is only standard queries. And the dns Return flags flag no error, good. Nothing unusual for 2016.

$ tawk -V dnsStat=0x0001 dnsHFlg=0x99 dnsOpC=0x0001 dnsRetC=0x0001

The dnsStat column with value 0x0001 is to be interpreted as follows:

   bit | dnsStat | Description
     0 | 0x0001  | DNS ports detected

The dnsHFlg column with value 0x99 is to be interpreted as follows:

   bit | dnsHFlg | Short   | Description
    0  |   0x01  |   CD    | Checking Disabled
    3  |   0x08  |   RA    | Recursive query support available
    4  |   0x10  |   RD    | Recursion desired
    7  |   0x80  |   QR    | 0: Query; 1: Response

The dnsOpC column with value 0x0001 is to be interpreted as follows:

   bit | dnsOpC  | Description
     0 | 0x0001  | Standard query

The dnsRetC column with value 0x0001 is to be interpreted as follows:

   bit | dnsRetC | Short           | Description
     0 | 0x0001  | No error        | Request completed successfully


In the flow file you see the query and all answer names. Every column element matches all the others. So e.g. faux.org belongs to dnsAtype 1 with dnsATTL 3090, so easy to parse with tawk using the split function. All types are numbers or bit fields, which can be configured. s. next paragraph.

$ cd ~/results
$ tcol dns-cname_flows.txt
%dir  flowInd  flowStat            timeFirst          timeLast           duration  numHdrDesc  numHdrs  hdrDesc       srcMac             dstMac             ethType  ethVlanID  srcIP          srcIPCC  srcIPOrg           srcPort  dstIP          dstIPCC  dstIPOrg           dstPort  l4Proto  tcpStatesAFlags  dnsStat  dnsHdrOPField  dnsHFlg_OpC_RetC    dnsCntQu_Asw_Aux_Add  dnsAAAqF  dnsQname         dnsAname                                                                                                                                          dnsAPname                                                           dns4Aaddress                                                                                                  dns6Aaddress                                                        dnsQType  dnsQClass  dnsAType                    dnsAClass              dnsATTL                                                dnsMXpref              dnsSRVprio             dnsSRVwgt              dnsSRVprt              dnsOptStat
A     1        0x0400000000004000  1464026534.044641  1464026534.044641  0.000000  1           3        eth:ipv4:udp  52:03:37:51:c2:a2  fe:e1:ba:d0:64:19  0x0800      04       "Private network"  39838    04       "Private network"  53       17       0x00             0x0001   0x0110         0x11_0x0001_0x0001  1_0_0_1               0         "ssh.fiaux.org"  ""                                                                                                                                                ""                                                                                                                                                                                                                                   1         1          41                          0                      0                                                      0                      0                      0                      0                      0x00008000
B     1        0x0400000000004001  1464026534.074417  1464026534.074417  0.000000  1           3        eth:ipv4:udp  fe:e1:ba:d0:64:19  52:03:37:51:c2:a2  0x0800        04       "Private network"  53  04       "Private network"  39838    17       0x00             0x0001   0x8190         0x99_0x0001_0x0001  1_4_2_5               17.54839  "ssh.fiaux.org"  "ssh.fiaux.org";"ssh.fiaux.org";"fiaux.org";"fiaux.org";"fiaux.org";"fiaux.org";"ns18.ovh.net";"ns18.ovh.net";"dns18.ovh.net";"dns18.ovh.net";""  "fiaux.org";"";"";"";"ns18.ovh.net";"dns18.ovh.net";"";"";"";"";"";;;;;;;;;;  ::;::;::;::;::;::;::;2001:41d0:1:198a::1;::;2001:41d0:1:4a8a::1;::  1         1          5;46;1;46;2;2;1;28;1;28;41  1;1;1;1;1;1;1;1;1;1;0  20737;20737;3090;3090;3090;3090;3090;3090;3090;3090;0  0;0;0;0;0;0;0;0;0;0;0  0;0;0;0;0;0;0;0;0;0;0  0;0;0;0;0;0;0;0;0;0;0  0;0;0;0;0;0;0;0;0;0;0  0x00000000;0x00000000;0x00000000;0x00000000;0x00000000;0x00000000;0x00000000;0x00000000;0x00000000;0x00000000;0x00008000

In the packet file besides the status and header info all IP’s extracted, the names can be identified in the l7Content. dnsHdr matches the header bit of the dnsRecord. In order to match any flow output with the packet, use the flowInd. To work with wireshark use the PktNo.

$ tcol dns-cname_packets.txt
%pktNo  flowInd  flowStat            time               pktIAT    flowDuration  numHdrs  hdrDesc       ethVlanID  srcMac             dstMac             ethType  srcIP          srcIPCC  srcIPOrg         srcPort  dstIP          dstIPCC  dstIPOrg         dstPort  l4Proto  tcpStatesAFlags  dnsIPs                                                                                 dnsStat  dnsHdr  dnsCntQu_Asw_Aux_Add  l7Content
1       1        0x0400000000004000  1464026534.044641  0.000000  0.000000      3        eth:ipv4:udp             52:03:37:51:c2:a2  fe:e1:ba:d0:64:19  0x0800  04       Private network  39838    04       Private network  53       17                                                                                                               0x0001   0x0110  1_0_0_1               .............ssh.fiaux.org.......)........
2       1        0x0400000000004001  1464026534.074417  0.000000  0.000000      3        eth:ipv4:udp             fe:e1:ba:d0:64:19  52:03:37:51:c2:a2  0x0800    04       Private network  53  04       Private network  39838    17              ;;2001:41d0:1:198a::1;;2001:41d0:1:4a8a::1;  0x0001   0x8190  1_4_2_5               .............ssh.fiaux.org.............Q.............Q.........Q.WO$.W'...!.fiaux.org.eKSqL.1.~.V.........s.Y.?.C.B%i\..p.Dd.,..o........q.r<..%GO....7..+.(?...1..`.}'h..D..V..X/^.{.cR3.....O..5..K3..x...R..6...W...K..........N/.U.K................Q.WO$.W'...!.fiaux.org.....\t..$........b...v....R..E.d....>........>.....Ql.\r..vQA....-.!X%..+.w....Gr....L.)$....e......\t.....z.-XN\.zUNH...~..>.D...K.............ns18.ovh.net..............dns18.............................. .A......................................... .A...J...........)........

If you want more of an aggreagated overview, and a bit more human readable output, you can switch all constants on in dnsDecode.h. We combine these features with the whois labeling capability in order to shorten the tutorial.

IP whois labeling

In order to label all IP addresses being returned in the answer record, switch on DNS_WHO. Moreover all constants will be switched on to demonstrates the human readable output.

Here goes the switching frenzy. recompile and rerun t2

$ t2conf dnsDecode -D DNS_HEXON=1 -D DNS_HDRMD=2 -D DNS_TYPE=1 -D DNS_AGGR=1 -D DNS_WHO=1 && t2build dnsDecode
$ t2 -r ~/data/dns-cname.pcap -w ~/results/

The flow file reveals now an aggreagated view, the opationi and return codes bit fields are now replaced by human readable text. We added the dnsType Bitfield, just to show you the format, it is useful when selecting special records with tawk.

The same will work in the non aggregated mode. I leave that as an exercise for the reader.

Alarm mode of dnsDecode

The alarm mode of the plugin is described here: plugin-alarm-register-and-control

Don’t forget to reset the plugin configuration for the next tutorial.

$ t2conf dnsDecode --reset && t2build dnsDecode

Have fun analyzing.