Packet Captures and DNS
@ Chris Suttles · Wednesday, May 15, 2019 · 34 minute read · Update at May 25, 2020

Overview

During troubleshooting, you might find it useful to determine what is happening on the wire. While tcpdump is a great tool for capturing packets, it's does not offer the same level of filtering capability as tshark. While it may be easier to simply copy a capture file locally and use wireshark, sometimes restrictions prevent this approach.

Capture and Save with tcpdump

Capturing and saving to disk is my favorite way to review wire traffic. I believe it makes analysis easier, since you might be able to use the wireshark gui (if you are allowed to retrieve the capture from the machine), or if using tshark locally, you can use two pass filtering and have more flexibility in choosing filters for analysis. For those interested in focusing on tshark, the following section covers doing this same thing with tshark. You can skip ahead and leave tcpdump to the UNIX operating systems where it came from without missing anything. For those of you that see the value in tcpdump (a big plus is that it's everywhere), read on.

sudo tcpdump -s0 -nnpi lo -w /tmp/lo-port-53.pcap 'port 53'


Let's step through this command and understand what it does.

       -s snaplen
       --snapshot-length=snaplen
              Snarf  snaplen  bytes  of  data from each packet rather than the
              default of 262144 bytes.  Packets truncated because of a limited
              snapshot  are  indicated  in the output with ``[|proto]'', where
              proto is the name of the protocol level at which the  truncation
              has  occurred.  Note that taking larger snapshots both increases
              the amount of time it takes to process packets and, effectively,
              decreases  the amount of packet buffering.  This may cause pack‐
              ets to be lost.  You should limit snaplen to the smallest number
              that will capture the protocol information you're interested in.
              Setting snaplen to 0 sets it to the default of 262144, for back‐
              wards compatibility with recent older versions of tcpdump.

We use -s0 to capture the full packet, regardless of tcpdump version (old versions used a much smaller default). It is also possible to set this much lower (i.e 512 for most DNS traffic) to get smaller capture files; this can be very useful for long running captures to spot traffic patterns.

  -n Don't  convert  host  addresses  to  names.  This can be used to
              avoid DNS lookups.

-nn Don't convert protocol and port numbers etc. to names either.


We use -nn to prevent hostname and port/protocol name resolution at the time of capture. This can happen later when reviewing the pcap; doing so at the time of capture generates unneeded DNS traffic, and unnecessary overhead while capturing, which can cause packets to be dropped instead of captured at high traffic volumes.

       -p
   --no-promiscuous-mode
              Don't  put  the  interface into promiscuous mode.  Note that the
              interface might be in promiscuous mode for  some  other  reason;
              hence,  `-p'  cannot  be used as an abbreviation for `ether host
              {local-hw-addr} or ether broadcast'.

       -i interface
--interface=interface
Listen  on interface.  If unspecified, tcpdump searches the sys‐
tem interface list for the lowest numbered, configured up inter‐
face  (excluding  loopback), which may turn out to be, for exam‐
ple, ``eth0''.

          On Linux systems with 2.2 or later kernels, an  <u>interface</u>  argu‐
          ment  of  ``any'' can be used to capture packets from all inter‐
          faces.  Note that captures on the ``any''  device  will  not  be
          done in promiscuous mode.

          If  the  <b>-D </b>flag is supported, an interface number as printed by
          that flag can be used as the <u>interface</u> argument, if no interface
          on the system has that number as a name.


We use -i lo to capture all the traffic traversing the loopback adapter. This gets both bind and authcore in authoritative, because the data path goes through addresses bound to the loopback adapter (thanks Docker!). It can also be useful to use -i any, but use caution as this can generate a very large capture file very quickly. A good rule of thumb is to capture as little traffic as possible to achieve your goal.

       -w file
              Write the raw packets to file rather than parsing  and  printing
              them  out.  They can later be printed with the -r option.  Stan‐
              dard output is used if file is ``-''.

We use -w /tmp/lo-port-53.pcap in this example to write the pcap file to the large file system we found in step 1, with a descriptive name of what it contains.

The 'port 53' argument is a BPF filter. Here's a great write up on the underpinnings of BPF bytecode, and an excellent write up on tcpdump filtering (and general use) by the venerable Daniel Miessler. This is the simplest style of BPF filter possible, which says we want all traffic on 'port 53' (the default port for Domain Name Server as defined by IANA). See also: man pcap-filter

Capture and Save with tshark

This section covers saving a capture to disk with tshark.

sudo tshark -s0 -npi lo -w /tmp/lo-port-53.pcap port 53

Let's step through this command and understand what it does.

       -s  <capture snaplen>
           Set the default snapshot length to use when capturing live data.
           No more than snaplen bytes of each network packet will be read into
           memory, or saved to disk.  A value of 0 specifies a snapshot length
           of 262144, so that the full packet is captured; this is the
           default.


We use -s0 to capture the full packet, regardless of tshark version (old versions used a much smaller default). It is also possible to set this much lower (i.e 512 for  most DNS traffic) to get smaller capture files; this can be very useful for long running captures to spot traffic patterns. This can be omitted instead of using -s0, since in more recent versions this is the default behavior.

       -n  Disable network object name resolution (such as hostname, TCP and
           UDP port names); the -N option might override this one.

We use -n  to prevent hostname and port/protocol name resolution at the time of capture. This can happen later when reviewing the pcap; doing so at the time of capture generates unneeded DNS traffic, and unnecessary overhead while capturing, which can cause packets to be dropped instead of captured at high traffic volumes.


       -p  Don't put the interface into promiscuous mode.  Note that the
           interface might be in promiscuous mode for some other reason;
           hence, -p cannot be used to ensure that the only traffic that is
           captured is traffic sent to or from the machine on which TShark is
           running, broadcast traffic, and multicast traffic to addresses
           received by that machine.

We prevent promiscuous mode, as not all cards support it, and we only need traffic that is actually addressed to us.

       -i  <capture interface> | -

We use -i lo  to capture all the traffic traversing the loopback adapter. It can also be useful to use  -i any , but use caution as this can generate a very large capture file very quickly. A good rule of thumb is to capture as little traffic as possible to achieve your goal.


       -w  <outfile> | -

We use -w /tmp/lo-port-53.pcap  in this example to write the pcap file to the large file system we found in step 1, with a descriptive name of what it contains. It's worth noting the -W  option here as well, which when combined with the -F  option will write the file in the specified format, like pcapng, which can include additional information, instead of the raw packets we write with -w


The 'port 53' argument is a BPF filter. Here's a great  write up on the underpinnings of BPF bytecode , and an  excellent write up on tcpdump filtering (and general use) by the venerable Daniel Miessler . This is the simplest style of BPF filter possible, which says we want all traffic on 'port 53' ( the default port for Domain Name Server as defined by IANA ). See also:  man pcap-filter

Analyze Traffic from a PCAP

Analysis of traffic saved in a packet capture is where tshark truly shines. With a saved pcap, you can use tshark to dissect traffic using all of the display filters available in wireshark. The wireshark site has an excellent reference for all of the available display filters, but of course the one we are most interested in is the DNS display filter reference.

The Wireshark project also provides a plethora of sample pcap files for analysis. For the examples below, we will be using the following sample captures:

  • dhcp-and-dyndns.pcap.gz  (libpcap) A sample session of a host doing dhcp first and then dyndns.
  • dns.cap (libpcap) Various DNS lookups.
  • dns-remoteshell.pcap Watch frame 22 Ethereal detecting DNS Anomaly caused by remoteshell riding on DNS port - DNS Anomaly detection made easy by ethereal .. Anith Anand
  • dns_port.pcap DNS running on a different port than 53.
  • dns+icmp.pcapng.gz DNS and ICMP saved in gzipped pcapng format.

Simple Protocol Filtering

Here's an example capture file we can use to demonstrate filters. First let's look at the contents of  dns+icmp.pcapng.gz. One of the many features of tshark is the ability to automatically read captures in gzip format, so we don't need to gunzip or specify any additional flags for tshark to read this compressed capture directly.

tshark -r dns+icmp.pcapng.gz
    1   0.000000 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
    2   5.001009 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
    3   5.006792 192.168.43.1 → 192.168.43.9 DNS 124 Standard query response 0x528e PTR 8.8.8.8.in-addr.arpa PTR google-public-dns-a.google.com
    4   5.013334 192.168.43.9 → 8.8.8.8      ICMP 98 Echo (ping) request  id=0xd73b, seq=0/0, ttl=64
    5   5.505538      8.8.8.8 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xd73b, seq=0/0, ttl=40 (request in 4)
    6   6.019290 192.168.43.9 → 8.8.8.8      ICMP 98 Echo (ping) request  id=0xd73b, seq=1/256, ttl=64
    7   6.153653      8.8.8.8 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xd73b, seq=1/256, ttl=40 (request in 6)
    8   7.015108 192.168.43.9 → 8.8.8.8      ICMP 98 Echo (ping) request  id=0xd73b, seq=2/512, ttl=64
    9   7.781987      8.8.8.8 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xd73b, seq=2/512, ttl=40 (request in 8)
   10   7.791410 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x695d PTR 4.4.8.8.in-addr.arpa
   11   7.979359 192.168.43.1 → 192.168.43.9 DNS 124 Standard query response 0x695d PTR 4.4.8.8.in-addr.arpa PTR google-public-dns-b.google.com
   12   7.983593 192.168.43.9 → 8.8.4.4      ICMP 98 Echo (ping) request  id=0xdb3b, seq=0/0, ttl=64
   13   8.984437 192.168.43.9 → 8.8.4.4      ICMP 98 Echo (ping) request  id=0xdb3b, seq=1/256, ttl=64
   14   9.323049      8.8.4.4 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xdb3b, seq=1/256, ttl=40 (request in 13)
   15   9.985425 192.168.43.9 → 8.8.4.4      ICMP 98 Echo (ping) request  id=0xdb3b, seq=2/512, ttl=64
   16  11.999365 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x833a PTR 2.2.2.4.in-addr.arpa
   17  12.073341 192.168.43.1 → 192.168.43.9 DNS 116 Standard query response 0x833a PTR 2.2.2.4.in-addr.arpa PTR b.resolvers.Level3.net
   18  12.078588 192.168.43.9 → 4.2.2.2      ICMP 98 Echo (ping) request  id=0xdd3b, seq=0/0, ttl=64
   19  12.148722      4.2.2.2 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xdd3b, seq=0/0, ttl=50 (request in 18)
   20  13.079308 192.168.43.9 → 4.2.2.2      ICMP 98 Echo (ping) request  id=0xdd3b, seq=1/256, ttl=64
   21  13.383662      4.2.2.2 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xdd3b, seq=1/256, ttl=50 (request in 20)
   22  14.079860 192.168.43.9 → 4.2.2.2      ICMP 98 Echo (ping) request  id=0xdd3b, seq=2/512, ttl=64
   23  15.280499      4.2.2.2 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xdd3b, seq=2/512, ttl=50 (request in 22)
   24  15.289472 192.168.43.9 → 192.168.43.1 DNS 77 Standard query 0x2121 A www.wireshark.org
   25  15.703377 192.168.43.1 → 192.168.43.9 DNS 93 Standard query response 0x2121 A www.wireshark.org A 174.137.42.65
   26  15.722009 192.168.43.9 → 192.168.43.1 DNS 77 Standard query 0x2c58 A www.wireshark.org
   27  15.865643 192.168.43.1 → 192.168.43.9 DNS 93 Standard query response 0x2c58 A www.wireshark.org A 174.137.42.65
   28  15.866126 192.168.43.9 → 174.137.42.65 ICMP 98 Echo (ping) request  id=0xe03b, seq=0/0, ttl=64
   29  16.636590 174.137.42.65 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xe03b, seq=0/0, ttl=48 (request in 28)
   30  16.867268 192.168.43.9 → 174.137.42.65 ICMP 98 Echo (ping) request  id=0xe03b, seq=1/256, ttl=64
   31  17.194006 174.137.42.65 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xe03b, seq=1/256, ttl=48 (request in 30)
   32  17.867597 192.168.43.9 → 174.137.42.65 ICMP 98 Echo (ping) request  id=0xe03b, seq=2/512, ttl=64
   33  18.138642 174.137.42.65 → 192.168.43.9 ICMP 98 Echo (ping) reply    id=0xe03b, seq=2/512, ttl=48 (request in 32)


We can see that the capture file is exactly as described; it's ICMP and DNS traffic. Let's pluck just the dns traffic out of this capture, using two pass filtering (-2), and using the dns display filter (-R dns). Note that for live captures, you can accomplish most of what can be done in a two-pass analysis ( -2 -R) with -Y.

       -2  Perform a two-pass analysis. This causes tshark to buffer output
           until the entire first pass is done, but allows it to fill in
           fields that require future knowledge, such as 'response in frame #'
           fields. Also permits reassembly frame dependencies to be calculated
           correctly.
       -R  <Read filter>
           Cause the specified filter (which uses the syntax of read/display
           filters, rather than that of capture filters) to be applied during
           the first pass of analysis. Packets not matching the filter are not
           considered for future passes. Only makes sense with multiple
           passes, see -2. For regular filtering on single-pass dissect see -Y
           instead.
       Note that forward-looking fields such as 'response in frame #'
       cannot be used with this filter, since they will not have been
       calculate when this filter is applied.

       -Y  <displaY filter>
Cause the specified filter (which uses the syntax of read/display
filters, rather than that of capture filters) to be applied before
printing a decoded form of packets or writing packets to a file.
Packets matching the filter are printed or written to file; packets
that the matching packets depend upon (e.g., fragments), are not
printed but are written to file; packets not matching the filter
nor depended upon are discarded rather than being printed or
written.

       Use this instead of -R for filtering using single-pass analysis. If
       doing two-pass analysis (see -2) then only packets matching the
       read filter (if there is one) will be checked against this filter.

tshark -r dns+icmp.pcapng.gz -2 -R dns
    1   0.000000 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
    2   5.001009 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
    3   5.006792 192.168.43.1 → 192.168.43.9 DNS 124 Standard query response 0x528e PTR 8.8.8.8.in-addr.arpa PTR google-public-dns-a.google.com
   10   7.791410 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x695d PTR 4.4.8.8.in-addr.arpa
   11   7.979359 192.168.43.1 → 192.168.43.9 DNS 124 Standard query response 0x695d PTR 4.4.8.8.in-addr.arpa PTR google-public-dns-b.google.com
   16  11.999365 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x833a PTR 2.2.2.4.in-addr.arpa
   17  12.073341 192.168.43.1 → 192.168.43.9 DNS 116 Standard query response 0x833a PTR 2.2.2.4.in-addr.arpa PTR b.resolvers.Level3.net
   24  15.289472 192.168.43.9 → 192.168.43.1 DNS 77 Standard query 0x2121 A www.wireshark.org
   25  15.703377 192.168.43.1 → 192.168.43.9 DNS 93 Standard query response 0x2121 A www.wireshark.org A 174.137.42.65
   26  15.722009 192.168.43.9 → 192.168.43.1 DNS 77 Standard query 0x2c58 A www.wireshark.org
   27  15.865643 192.168.43.1 → 192.168.43.9 DNS 93 Standard query response 0x2c58 A www.wireshark.org A 174.137.42.65

Managing Time

In the examples above, we see packets displayed with the default time format, which is 'relative'. Let's look at the -t option, which allows us to specify the date/time display format. This is very useful for correlating frames in a packet capture with logs and metrics, or data derived from them. If you are looking at a dashboard or logs based in UTC, it you probably want to use -t u for UTC time.

-t  a|ad|adoy|d|dd|e|r|u|ud|udoy
    Set the format of the packet timestamp printed in summary lines.
    The format can be one of:
        a absolute: The absolute time, as local time in your time zone, is
        the actual time the packet was captured, with no date displayed
        ad absolute with date: The absolute date, displayed as YYYY-MM-DD,
        and time, as local time in your time zone, is the actual time and
        date the packet was captured
        adoy absolute with date using day of year: The absolute date,
        displayed as YYYY/DOY, and time, as local time in your time zone,
        is the actual time and date the packet was captured
        d delta: The delta time is the time since the previous packet was
        captured
        dd delta_displayed: The delta_displayed time is the time since the
        previous displayed packet was captured
        e epoch: The time in seconds since epoch (Jan 1, 1970 00:00:00)
        r relative: The relative time is the time elapsed between the first
        packet and the current packet
        u UTC: The absolute time, as UTC, is the actual time the packet was
        captured, with no date displayed
        ud UTC with date: The absolute date, displayed as YYYY-MM-DD, and
        time, as UTC, is the actual time and date the packet was captured
        udoy UTC with date using day of year: The absolute date, displayed
        as YYYY/DOY, and time, as UTC, is the actual time and date the
        packet was captured
The default format is relative.

UTC Time

Let's look at the first three lines of our previous example in UTC time with -t u

tshark -t u -r dns+icmp.pcapng.gz -2 -R dns | head -n 3
1 22:45:12.269853 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
2 22:45:17.270862 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
3 22:45:17.276645 192.168.43.1 → 192.168.43.9 DNS 124 Standard query response 0x528e PTR 8.8.8.8.in-addr.arpa PTR google-public-dns-a.google.com

Local Time

Let's look at those same three example lines in local time (useful for "when did I get paged?") with -t a

tshark -t a -r dns+icmp.pcapng.gz -2 -R dns | head -n 3
1 17:45:12.269853 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
2 17:45:17.270862 192.168.43.9 → 192.168.43.1 DNS 80 Standard query 0x528e PTR 8.8.8.8.in-addr.arpa
3 17:45:17.276645 192.168.43.1 → 192.168.43.9 DNS 124 Standard query response 0x528e PTR 8.8.8.8.in-addr.arpa PTR google-public-dns-a.google.com

Use the DNS display filter on an alternate port

The default mapping of display filters/dissectors will not decode DNS traffic on an alternate port. Since sometimes you might need to look at DNS traffic over ports that are not the default (53), it's important to know how to override this behavior. We can do that by using the -d option.

       -d  <layer type>==<selector>,<decode-as protocol>
       Like Wireshark's Decode As... feature, this lets you specify how a
       layer type should be dissected.  If the layer type in question (for
       example, tcp.port or udp.port for a TCP or UDP port number) has the
       specified selector value, packets should be dissected as the
       specified protocol.
       Example: tshark -d tcp.port==8888,http will decode any traffic
       running over TCP port 8888 as HTTP.
       Example: tshark -d tcp.port==8888:3,http will decode any traffic
       running over TCP ports 8888, 8889 or 8890 as HTTP.
       Example: tshark -d tcp.port==8888-8890,http will decode any traffic
       running over TCP ports 8888, 8889 or 8890 as HTTP.
       Using an invalid selector or protocol will print out a list of
       valid selectors and protocol names, respectively.
       Example: tshark -d . is a quick way to get a list of valid
       selectors.
       Example: tshark -d ethertype==0x0800. is a quick way to get a list
       of protocols that can be selected with an ethertype.


Let's look at an example using the dns_port.pcap  sample capture.

First, let's examine the output with no display filter, and also try to apply the filter with the default port.

tshark -t u -r dns_port.pcap
    1 03:18:04.938672 192.168.50.50 → 192.168.0.1  UDP 75 65282 → 65333 Len=33
    2 03:18:04.945618  192.168.0.1 → 192.168.50.50 UDP 540 65333 → 65282 Len=498

tshark -t u -r dns_port.pcap -2 -R dns <no output>

Now let's tell tshark to apply the DNS display filter to our traffic so we can see what these frames contain. By specifying the UDP port in the first frame (65282) as DNS, we can correctly display the traffic using the DNS display filter. 

tshark -t u -d udp.port==65282,dns -r dns_port.pcap -2 -R dns
1 03:18:04.938672 192.168.50.50 → 192.168.0.1  DNS 75 Standard query 0x002b A us.pool.ntp.org
2 03:18:04.945618  192.168.0.1 → 192.168.50.50 DNS 540 Standard query response 0x002b A us.pool.ntp.org A 67.129.68.9 A 69.44.57.60 A 207.234.209.181 A 209.132.176.4 A 216.27.185.42 A 24.34.79.42 A 24.123.202.230 A 63.164.62.249 A 64.112.189.11 A 65.125.233.206 A 66.33.206.5 A 66.33.216.11 A 66.92.68.246 A 66.111.46.200 A 66.115.136.4 NS ns1.mailworx.net NS usenet.net.nz NS zbasel.fortytwo.ch NS aventura.bhms-groep.nl NS slartibartfast.bhms-groep.nl NS a.ns.madduck.net A 69.1.200.68 A 202.49.59.6

Now we can see the traffic in much more detail.

Getting Specific

How do we look for specific DNS things in a pcap? This is where tshark, and specifically the power of display filters, really shines. You can accomplish a lot of the same things with BPF, but it is much more cumbersome and less intuitive. Let's look at a few examples.

Find Queries by Type

It's easy to filter by query type. The dns.qry.type filter takes the following args and will return the query and responses that match the QType.

dns.qry.typeTypeUnsigned integer, 2 bytes

The IANA DNS parameter reference is very helpful for mapping QTypes to the unsigned integer value (AKA the wire format):  https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml

A Queries

tshark -r dhcp-and-dyndns.pcap.gz -t a -2 -R 'dns.qry.type == 1'
3 10:47:02.001067   10.20.20.4 → 10.20.20.1   DNS 79 Standard query 0x31a9 A router.far-far-away
4 10:47:02.001686   10.20.20.1 → 10.20.20.4   DNS 132 Standard query response 0x31a9 No such name A router.far-far-away SOA esel.sumpf.far-far-away
5 10:47:02.002032   10.20.20.4 → 10.20.20.1   DNS 79 Standard query 0x31aa A router.far-far-away
6 10:47:02.002529   10.20.20.1 → 10.20.20.4   DNS 132 Standard query response 0x31aa No such name A router.far-far-away SOA esel.sumpf.far-far-away
64 10:48:04.390038  10.20.20.20 → 10.20.20.1   DNS 76 Standard query 0x003c A sus.far-far-away
65 10:48:04.390503   10.20.20.1 → 10.20.20.20  DNS 129 Standard query response 0x003c No such name A sus.far-far-away SOA esel.sumpf.far-far-away
66 10:48:04.390767  10.20.20.20 → 10.20.20.1   DNS 76 Standard query 0x003d A sus.far-far-away
67 10:48:04.391024   10.20.20.1 → 10.20.20.20  DNS 129 Standard query response 0x003d No such name A sus.far-far-away SOA esel.sumpf.far-far-away

NS Queries

tshark -r dns.cap -t a -2 -R 'dns.qry.type == 2'
27 02:52:17.740166 192.168.170.8 → 192.168.170.20 DNS 67 Standard query 0x208a NS isc.org
29 02:52:17.758453 192.168.170.20 → 192.168.170.8 DNS 166 Standard query response 0x208a NS isc.org NS ns-ext.nrt1.isc.org NS ns-ext.sth1.isc.org NS ns-ext.isc.org NS ns-ext.lga1.isc.org

Note this is a different pcap than the other examples in this section.

SOA Queries

tshark -r dhcp-and-dyndns.pcap.gz -t a -2 -R 'dns.qry.type == 6'
    9 10:47:02.008151   10.20.20.4 → 10.20.20.1   DNS 239 Dynamic update 0x21eb SOA far-far-away ANY A 10.20.20.20 TXT TSIG
   11 10:47:02.090492   10.20.20.4 → 10.20.20.1   DNS 214 Dynamic update 0x21ec SOA 20.20.10.in-addr.arpa PTR PTR academy04.far-far-away TSIG

TSIG Queries

tshark -r dhcp-and-dyndns.pcap.gz -t a -2 -R 'dns.qry.type == 250'

This filter is the same with any QType, so just substitute the appropriate integer value for the QType you want.

Find Queries by Name

We can use the dns.qry.name display filter to look for queries and responses by name.

tshark -r dns.cap -t a -2 -R 'dns.qry.name == isc.org'
    1 02:52:17.740166 192.168.170.8 → 192.168.170.20 DNS 67 Standard query 0x208a NS isc.org
    2 02:52:17.758453 192.168.170.20 → 192.168.170.8 DNS 166 Standard query response 0x208a NS isc.org NS ns-ext.nrt1.isc.org NS ns-ext.sth1.isc.org NS ns-ext.isc.org NS ns-ext.lga1.isc.org

Find a Specific Frame

Sometimes you might want to pluck a specific frame or series of frames from a capture. You can do that with the frame filter. In the following example we filter for just frame 22, from the following sample capture:

  • dns-remoteshell.pcap Watch frame 22 Ethereal detecting DNS Anomaly caused by remoteshell riding on DNS port - DNS Anomaly detection made easy by ethereal .. Anith Anand
tshark -r dns-remoteshell.pcap -t a -2 -R 'frame.number == 22'
   22 19:50:42.040365  192.168.1.2 → 192.168.1.3  TCP 142 [TCP Retransmission] 53 → 1396 [PSH, ACK] Seq=1 Ack=1 Win=65535 Len=88

Here, we are looking at the specific frame mentioned as a remote shell masquerading as DNS port. This view doesn't tell us much besides that the DNS display filter didn't find valid information to decode. If you look at the output of the following command, filtering with just the DNS display filter, we can see that this frame is omitted:

tshark -r dns-remoteshell.pcap -t a -2 -R dns
    2 19:50:16.501471  192.168.1.3 → 192.168.1.1  DNS 84 Standard query 0x0001 PTR 1.1.168.192.in-addr.arpa
    4 19:50:16.504144  192.168.1.1 → 192.168.1.3  DNS 112 Standard query response 0x0001 PTR 1.1.168.192.in-addr.arpa PTR SpeedTouch.lan
    7 19:50:19.113417  192.168.1.3 → 192.168.1.1  DNS 75 Standard query 0x0002 A www.www.com.lan
    8 19:50:19.131199  192.168.1.1 → 192.168.1.3  DNS 75 Standard query response 0x0002 A www.www.com.lan
    9 19:50:19.132818  192.168.1.3 → 192.168.1.1  DNS 71 Standard query 0x0003 A www.www.com
   10 19:50:19.442482  192.168.1.1 → 192.168.1.3  DNS 87 Standard query response 0x0003 A www.www.com A 63.215.91.200

To see what is actually in this frame, which confirms it as a remote shell, look at "Dump Packet Hex and ASCII"

Find Responses by Type

tshark -t u -r dns.cap -2 -R 'dns.resp.type == 1'
    1 08:47:51.333401 192.168.170.20 → 192.168.170.8 DNS 298 Standard query response 0xf76f MX google.com MX 40 smtp4.google.com MX 10 smtp5.google.com MX 10 smtp6.google.com MX 10 smtp1.google.com MX 10 smtp2.google.com MX 40 smtp3.google.com A 216.239.37.26 A 64.233.167.25 A 66.102.9.25 A 216.239.57.25 A 216.239.37.25 A 216.239.57.26
    2 08:49:18.734862 192.168.170.20 → 192.168.170.8 DNS 90 Standard query response 0x75c0 A www.netbsd.org A 204.152.190.12
    3 08:52:17.733384 192.168.170.20 → 192.168.170.8 DNS 115 Standard query response 0xfee3 ANY www.isc.org AAAA 2001:4f8:0:2::d A 204.152.184.88

Find Responses by Time (length of time to respond)

This is most useful when combined with other options, so that the dns.time is actually displayed. See "Displaying Specific Fields" for an example.

tshark -r dns.cap -t a -2 -R 'dns.time > .06'
    1 02:47:51.333401 192.168.170.20 → 192.168.170.8 DNS 298 Standard query response 0xf76f MX google.com MX 40 smtp4.google.com MX 10 smtp5.google.com MX 10 smtp6.google.com MX 10 smtp1.google.com MX 10 smtp2.google.com MX 40 smtp3.google.com A 216.239.37.26 A 64.233.167.25 A 66.102.9.25 A 216.239.57.25 A 216.239.37.25 A 216.239.57.26
    2 02:47:59.452255 192.168.170.20 → 192.168.170.8 DNS 70 Standard query response 0x49a1 LOC google.com
    3 02:49:35.698849 192.168.170.20 → 192.168.170.8 DNS 102 Standard query response 0xf0d4 AAAA www.netbsd.org AAAA 2001:4f8:4:7:2e0:81ff:fe52:9a6b
    4 02:51:35.437491 192.168.170.20 → 192.168.170.8 DNS 75 Standard query response 0xbc1f AAAA www.example.com
    5 02:51:47.032976 192.168.170.20 → 192.168.170.8 DNS 79 Standard query response 0x266d No such name AAAA www.example.notginh
    6 02:52:17.733384 192.168.170.20 → 192.168.170.8 DNS 115 Standard query response 0xfee3 ANY www.isc.org AAAA 2001:4f8:0:2::d A 204.152.184.88

Find Responses by Name

tshark -r dns.cap -t a -2 -R 'dns.resp.name == google.com'
    1 02:47:46.496576 192.168.170.20 → 192.168.170.8 DNS 98 Standard query response 0x1032 TXT google.com TXT
    2 02:47:51.333401 192.168.170.20 → 192.168.170.8 DNS 298 Standard query response 0xf76f MX google.com MX 40 smtp4.google.com MX 10 smtp5.google.com MX 10 smtp6.google.com MX 10 smtp1.google.com MX 10 smtp2.google.com MX 40 smtp3.google.com A 216.239.37.26 A 64.233.167.25 A 66.102.9.25 A 216.239.57.25 A 216.239.37.25 A 216.239.57.26

Getting More Details

So far we've been looking at traffic at a pretty high level, but what there's a couple of ways we can get more detail.

Display Filter Decode

The first, and easiest way it to leverage the -O option.

       -O  <protocols>
           Similar to the -V option, but causes TShark to only show a detailed
           view of the comma-separated list of protocols specified, and show
           only the top-level detail line for all other protocols, rather than
           a detailed view of all protocols.  Use the output of "tshark -G
           protocols" to find the abbreviations of the protocols you can
           specify.

       -V  Cause TShark to print a view of the packet details.


The -V option is included for reference/completeness sake, but it is typically too verbose for tracing a protocol like DNS and is more useful when you want to look at lower level things (Ethernet/TCP), or do parsing with grep/awk/perl etc.

tshark -r dns.cap -t a -2 -R 'dns.qry.type == 2' -O dns
Frame 27: 67 bytes on wire (536 bits), 67 bytes captured (536 bits)
Ethernet II, Src: AsustekI_b1:0c:ad (00:e0:18:b1:0c:ad), Dst: QuantaCo_32:41:8c (00:c0:9f:32:41:8c)
Internet Protocol Version 4, Src: 192.168.170.8, Dst: 192.168.170.20
User Datagram Protocol, Src Port: 32797, Dst Port: 53
Domain Name System (query)
Transaction ID: 0x208a
Flags: 0x0100 Standard query
0... .... .... .... = Response: Message is a query
.000 0... .... .... = Opcode: Standard query (0)
.... ..0. .... .... = Truncated: Message is not truncated
.... ...1 .... .... = Recursion desired: Do query recursively
.... .... .0.. .... = Z: reserved (0)
.... .... ...0 .... = Non-authenticated data: Unacceptable
Questions: 1
Answer RRs: 0
Authority RRs: 0
Additional RRs: 0
Queries
isc.org: type NS, class IN
Name: isc.org
[Name Length: 7]
[Label Count: 2]
Type: NS (authoritative Name Server) (2)
Class: IN (0x0001)
[Response In: 29]

Frame 29: 166 bytes on wire (1328 bits), 166 bytes captured (1328 bits) Ethernet II, Src: QuantaCo_32:41:8c (00:c0:9f:32:41:8c), Dst: AsustekI_b1:0c:ad (00:e0:18:b1:0c:ad) Internet Protocol Version 4, Src: 192.168.170.20, Dst: 192.168.170.8 User Datagram Protocol, Src Port: 53, Dst Port: 32797 Domain Name System (response) Transaction ID: 0x208a Flags: 0x8180 Standard query response, No error 1... .... .... .... = Response: Message is a response .000 0... .... .... = Opcode: Standard query (0) .... .0.. .... .... = Authoritative: Server is not an authority for domain .... ..0. .... .... = Truncated: Message is not truncated .... ...1 .... .... = Recursion desired: Do query recursively .... .... 1... .... = Recursion available: Server can do recursive queries .... .... .0.. .... = Z: reserved (0) .... .... ..0. .... = Answer authenticated: Answer/authority portion was not authenticated by the server .... .... ...0 .... = Non-authenticated data: Unacceptable .... .... .... 0000 = Reply code: No error (0) Questions: 1 Answer RRs: 4 Authority RRs: 0 Additional RRs: 0 Queries isc.org: type NS, class IN Name: isc.org [Name Length: 7] [Label Count: 2] Type: NS (authoritative Name Server) (2) Class: IN (0x0001) Answers isc.org: type NS, class IN, ns ns-ext.nrt1.isc.org Name: isc.org Type: NS (authoritative Name Server) (2) Class: IN (0x0001) Time to live: 3600 Data length: 14 Name Server: ns-ext.nrt1.isc.org isc.org: type NS, class IN, ns ns-ext.sth1.isc.org Name: isc.org Type: NS (authoritative Name Server) (2) Class: IN (0x0001) Time to live: 3600 Data length: 14 Name Server: ns-ext.sth1.isc.org isc.org: type NS, class IN, ns ns-ext.isc.org Name: isc.org Type: NS (authoritative Name Server) (2) Class: IN (0x0001) Time to live: 3600 Data length: 9 Name Server: ns-ext.isc.org isc.org: type NS, class IN, ns ns-ext.lga1.isc.org Name: isc.org Type: NS (authoritative Name Server) (2) Class: IN (0x0001) Time to live: 3600 Data length: 14 Name Server: ns-ext.lga1.isc.org [Request In: 27] [Time: 0.018287000 seconds]

This view can be useful if you want to inspect the flags or TTL of a specific query (or set of queries), or other information not displayed in the default, summary view.

Dump Packet Hex and ASCII

To dump the contents of a frame in hex and ASCII, we can use the -x option.

       -x  Cause TShark to print a hex and ASCII dump of the packet data after
           printing the summary and/or details, if either are also being
           displayed.

tshark -r dns-remoteshell.pcap -t a -2 -R 'frame.number == 22' -x
0000  00 0e 35 78 0c 02 00 80 48 24 33 32 08 00 45 00   ..5x....H$32..E.
0010  00 80 07 cd 40 00 40 06 af 55 c0 a8 01 02 c0 a8   ....@.@..U......
0020  01 03 00 35 05 74 bd 0f 2f ed 23 c5 33 c0 50 18   ...5.t../.#.3.P.
0030  ff ff 4e 14 00 00 4d 69 63 72 6f 73 6f 66 74 20   ..N...Microsoft
0040  57 69 6e 64 6f 77 73 20 58 50 20 5b 56 65 72 73   Windows XP [Vers
0050  69 6f 6e 20 35 2e 31 2e 32 36 30 30 5d 0d 0a 28   ion 5.1.2600]..(
0060  43 29 20 43 6f 70 79 72 69 67 68 74 20 31 39 38   C) Copyright 198
0070  35 2d 32 30 30 31 20 4d 69 63 72 6f 73 6f 66 74   5-2001 Microsoft
0080  20 43 6f 72 70 2e 0d 0a 0d 0a 43 3a 5c 3e          Corp.....C:\>

Here we can see the confirmation that even though this frame is TCP over port 53, it is not DNS (as indicated by the text describing the sample capture).

For the sake of comparison, here's a hex/ASCII decode of a pair of real DNS frames. The first command is selecting the dns.qry.type 1 and frames numbered less than 11. The second command is dumping the hex/ASCII decodes of both frames.

tshark -r dns.cap -t a -2 -R 'dns.qry.type == 1 and frame.number < 11'
    9 02:49:18.685951 192.168.170.8 → 192.168.170.20 DNS 74 Standard query 0x75c0 A www.netbsd.org
   10 02:49:18.734862 192.168.170.20 → 192.168.170.8 DNS 90 Standard query response 0x75c0 A www.netbsd.org A 204.152.190.12
tshark -r dns.cap -t a -2 -R 'dns.qry.type == 1 and frame.number < 11' -x
0000  00 c0 9f 32 41 8c 00 e0 18 b1 0c ad 08 00 45 00   ...2A.........E.
0010  00 3c 00 00 40 00 40 11 65 43 c0 a8 aa 08 c0 a8   .<..@.@.eC......
0020  aa 14 80 1b 00 35 00 28 af 61 75 c0 01 00 00 01   .....5.(.au.....
0030  00 00 00 00 00 00 03 77 77 77 06 6e 65 74 62 73   .......www.netbs
0040  64 03 6f 72 67 00 00 01 00 01                     d.org.....

0000 00 e0 18 b1 0c ad 00 c0 9f 32 41 8c 08 00 45 00 .........2A...E. 0010 00 4c cf f9 00 00 80 11 95 39 c0 a8 aa 14 c0 a8 .L.......9...... 0020 aa 08 00 35 80 1b 00 38 a3 17 75 c0 81 80 00 01 ...5...8..u..... 0030 00 01 00 00 00 00 03 77 77 77 06 6e 65 74 62 73 .......www.netbs 0040 64 03 6f 72 67 00 00 01 00 01 c0 0c 00 01 00 01 d.org........... 0050 00 01 40 ef 00 04 cc 98 be 0c ..@.......

Displaying Specific Fields

Sometimes, you want to look at just a specific field or fields within DNS traffic, and viewing details as provided by the -O option is too verbose. This is where the combination of options -T and -e/-E are very useful. The -T option controls the output format and is very flexible. The -e and -E options control what fields and how to format them.

       -T  ek|fields|json|jsonraw|pdml|ps|psml|tabs|text
           Set the format of the output when viewing decoded packet data.  The
           options are one of:

           ek Newline delimited JSON format for bulk import into
           Elasticsearch.  It can be used with -j or -J including the JSON
           filter or with -x to include raw hex-encoded packet data.  If -P is
           specified it will print the packet summary only, with both -P and
           -V it will print the packet summary and packet details.  If neither
           -P or -V are used it will print the packet details only.  Example
           of usage to import data into Elasticsearch:

             tshark -T ek -j "http tcp ip" -P -V -x -r file.pcap > file.json
             curl -H "Content-Type: application/x-ndjson" -XPOST http://elasticsearch:9200/_bulk --data-binary "@file.json"

           Elastic requires a mapping file to be loaded as template for
           packets-* index in order to convert wireshark types to elastic
           types. This file can be auto-generated with the command "tshark -G
           elastic-mapping". Since the mapping file can be huge, protocols can
           be selected by using the option --elastic-mapping-filter:

             tshark -G elastic-mapping --elastic-mapping-filter ip,udp,dns

           fields The values of fields specified with the -e option, in a form
           specified by the -E option.  For example,

             tshark -T fields -E separator=, -E quote=d

           would generate comma-separated values (CSV) output suitable for
           importing into your favorite spreadsheet program.

           json JSON file format.  It can be used with -j or -J including the
           JSON filter or with -x option to include raw hex-encoded packet
           data.  Example of usage:
             tshark -T jsonraw -r file.pcap
             tshark -T jsonraw -j "http tcp ip" -x -r file.pcap

           pdml Packet Details Markup Language, an XML-based format for the
           details of a decoded packet.  This information is equivalent to the
           packet details printed with the -V option.  Using the --color
           option will add color attributes to pdml output.  These attributes
           are nonstandard.

           ps PostScript for a human-readable one-line summary of each of the
           packets, or a multi-line view of the details of each of the
           packets, depending on whether the -V option was specified.

           psml Packet Summary Markup Language, an XML-based format for the
           summary information of a decoded packet.  This information is
           equivalent to the information shown in the one-line summary printed
           by default.  Using the --color option will add color attributes to
           pdml output. These attributes are nonstandard.

           tabs Similar to the default text report except the human-readable
           one-line summary of each packet will include an ASCII horizontal
           tab (0x09) character as a delimiter between each column.

           text Text of a human-readable one-line summary of each of the
           packets, or a multi-line view of the details of each of the
           packets, depending on whether the -V option was specified.  This is
           the default.

       -e  <field>
           Add a field to the list of fields to display if -T
           ek|fields|json|pdml is selected.  This option can be used multiple
           times on the command line.  At least one field must be provided if
           the -T fields option is selected. Column names may be used prefixed
           with "_ws.col."

           Example: tshark -e frame.number -e ip.addr -e udp -e _ws.col.Info

           Giving a protocol rather than a single field will print multiple
           items of data about the protocol as a single field.  Fields are
           separated by tab characters by default.  -E controls the format of
           the printed fields.

       -E  <field print option>
           Set an option controlling the printing of fields when -T fields is
           selected.

           Options are:

           bom=y|n If y, prepend output with the UTF-8 byte order mark
           (hexadecimal ef, bb, bf). Defaults to n.

           header=y|n If y, print a list of the field names given using -e as
           the first line of the output; the field name will be separated
           using the same character as the field values.  Defaults to n.

           separator=/t|/s|<character> Set the separator character to use for
           fields.  If /t tab will be used (this is the default), if /s, a
           single space will be used.  Otherwise any character that can be
           accepted by the command line as part of the option may be used.

           occurrence=f|l|a Select which occurrence to use for fields that
           have multiple occurrences.  If f the first occurrence will be used,
           if l the last occurrence will be used and if a all occurrences will
           be used (this is the default).

           aggregator=,|/s|<character> Set the aggregator character to use for
           fields that have multiple occurrences.  If , a comma will be used
           (this is the default), if /s, a single space will be used.
           Otherwise any character that can be accepted by the command line as
           part of the option may be used.

           quote=d|s|n Set the quote character to use to surround fields.  d
           uses double-quotes, s single-quotes, n no quotes (the default).

Let's look at some examples that are useful for DNS. We'll start by printing fields that are pretty close to the default output, and also filter for a specific name.

tshark -e frame.number -e ip.addr -e udp -e _ws.col.Info -Tfields -r dns.cap -2 -R 'dns.qry.name == isc.org'
1       192.168.170.8,192.168.170.20    User Datagram Protocol, Src Port: 32797, Dst Port: 53   Standard query 0x208a NS isc.org
2       192.168.170.20,192.168.170.8    User Datagram Protocol, Src Port: 53, Dst Port: 32797   Standard query response 0x208a NS isc.org NS ns-ext.nrt1.isc.org NS ns-ext.sth1.isc.org NS ns-ext.isc.org NS ns-ext.lga1.isc.org

Next, let's trim things down and filter for just A type responses, and print only the query name and time.

tshark -r dns.cap -2 -R 'dns.resp.type == 1' -T fields -e dns.qry.name -e dns.time
google.com      0.832133000
www.netbsd.org  0.048911000
www.isc.org     0.072604000

Combining Filters into Expressions with Operators

We've covered this in a few examples, but it's so valuable that it is getting its own section. By now, the power of display filters for parsing a packet capture is very clear. When you add the logic operators to the mix and start chaining them together, it becomes possible to make very specific filters that will enable you to easily find the proverbial "needle in a haystack" within a packet capture. You can find the full reference for logic operators on the Wireshark website.

The AND Operator

In the first example we will find all AAAA queries by type, which took over .22 seconds for response.

tshark -r dns.cap -t a -2 -R 'dns.qry.type == 28 and dns.time > .22'
    1 02:49:35.698849 192.168.170.20 → 192.168.170.8 DNS 102 Standard query response 0xf0d4 AAAA www.netbsd.org AAAA 2001:4f8:4:7:2e0:81ff:fe52:9a6b
    2 02:51:35.437491 192.168.170.20 → 192.168.170.8 DNS 75 Standard query response 0xbc1f AAAA www.example.com

The OR Operator

Next, we will look for query types of IXFR or AXFR. There is no output to this command because this capture (indeed none of the sample captures) have IXFR or AXFR queries included.

tshark -r dns.cap -t a -2 -R 'dns.qry.type == 251 or dns.qry.type == 252'

It's important to note that you could accomplish this same goal with multiple display filter (-R) arguments, but doing a single display filter with the OR operator is more readable and more efficient.

Comparison Operators

We've already been using some simple comparison operators, but you can find the complete reference for comparison operators on the Wireshark website. We can build on some of our previous examples and get very specific. Let's add to the AND operator example. Here we will filter based on many criteria and operators: dns.time, dns.qry.type, and a grouped comparison for a time window using the absolute frame time. It's worth noting we could omit the parenthesis, but they are added for readability and explicit interpolation.

tshark -r dns.cap -t a -2 -R 'dns.qry.type == 28 and dns.time > .01 and ("2005-03-30 02:51:47" > frame.time >= "2005-03-30 02:51:35")'
    1 02:51:35.437491 192.168.170.20 → 192.168.170.8 DNS 75 Standard query response 0xbc1f AAAA www.example.com

Membership Operator

There's another powerful operator we can use to make our expressions very precise. The membership operator allows us to create groups of acceptable values and apply them to filters. Here's an example, building on our comparison operator example. Using the membership operator, we can look for both A and AAAA queries that also match our dns.time and frame.time criteria. Note that the frame.time is expressed with nanosecond precision.

tshark -r dns.cap -t a -2 -R 'dns.qry.type in { 1 28 } and dns.time > .01 and ("2005-03-30 2:49:35.698851" > frame.time >= "2005-03-30 02:49:18.734861")'
    1 02:49:18.734862 192.168.170.20 → 192.168.170.8 DNS 90 Standard query response 0x75c0 A www.netbsd.org A 204.152.190.12
    2 02:49:35.698849 192.168.170.20 → 192.168.170.8 DNS 102 Standard query response 0xf0d4 AAAA www.netbsd.org AAAA 2001:4f8:4:7:2e0:81ff:fe52:9a6b


Analyze Live Traffic

When analyzing live traffic, you can combine most of the filters and options described previously, with the following notable exceptions: you must use -Y in place of -2 -R, and filtering by frame number is not practical or desirable. Analyzing live traffic requires that you put some forethought into what you will capture and how, so that you get everything you need to accomplish your goal, without getting too much additional information and ruining the signal:noise ratio. Unless there is an urgent reason to look at live traffic, it's usually preferable to capture to disk so that you can do analysis later.

Social Links