Advanced display filtering

Wireshark has a lot of display filters, and the filtering engine is really powerful. You can filter on almost anything in a packet, and ever since the filter box started suggesting possible filter expressions it got really easy to find the one you wanted.

We don’t even need the excellent “Wireshark Display Filter” cheat sheets from anymore (well, Jeremy still has a lot of other, really helpful cheat sheets, so check them out).

Basic filtering

As I said, in really old Wireshark versions, the filter box did not yet help with finding the correct filter, so it often took quite some time to get the filter expression right. My buddy Eddi used to impress people with the speed he could tell what the correct filter name was for a field in the decode, but that was just some Wireshark sleigh of hand – whenever you select a field, the status bar will show the according filter in the lower left corner. Nobody ever saw that he simply picked the correct filter syntax from there, and everyone was very impressed with his Wireshark skills, “memorizing” all these filter expressions 🙂

Here’s an example for reading the filter name for the Maximum Segment Size value:

Instead of reading the filter name from the status bar and typing it into the filter field you can also right click on the MSS field and select “Apply as filter” from the pop-up menu. I myself usually only type filters by hand if it’s faster than finding a field I can use with the pop-up menu. One of the most frequent filters I use is the TCP Conversation filter: find a packet belonging to a conversation I want to look at, and use the pop-up menu of the packet list to filter for it:


This will result in an absolute TCP filter, including both IP addresses and ports. Unfortunately, the developer version 1.99 of the coming Wireshark version 2.0 still does not have this pop-up menu option, so I’m stuck with 1.12.4 for the time being.

Filtering on packet dependencies

While Wireshark can filter on a lot of things, it can’t filter on packet dependencies, at least not without some tricks. And even with all the tricks it may still be impossible to use display filters to determine certain things about a trace. Let’s take a look at two examples and how to filter for them:

TCP Three Way Handshake

Filtering for the packets of a TCP three way handshake may sound like a simple task, but it isn’t.  The first two packets are easy, because those are the only two that have the SYN flag set. To find these, simply filter on “tcp.flags.syn==1“. But what about the third packet? It has only the ACK flag, but that’s also true for all other packets following the handshake, so we can’t just use that flag (at least not alone). Now, Wireshark beginners often try to find a filter expression that looks at packet dependencies, e.g. like “filter a packet that has a sequence number equal to the sequence of the previous SYN packet of the same connection plus one.” – and such a filter does not exist. You simply cannot filter on things in two different packets at the same time. Filters always look at a single packet at a time.

The workaround for filtering for the packet we want is to filter on values that can only be found in a packet that is the third packet of a three way handshake:

  1. We know that the sequence number is one higher than in the SYN packet. Since the initial sequence number is random we would have a problem, but fortunately, Wireshark offers relative sequence numbers (turned on by default). This means that every SYN has a relative sequence number of zero, and the third packet will have a sequence number of one. So we filter on “tcp.seq==1“. And since we must have acknowledged the SYN/ACK from the server we know that the ACK number must also be one, which leads to a better filter: “tcp.seq==1 and tcp.ack==1“.Unfortunately, many packets can have a relative sequence number of one, because if the client (which initiated the connection, thus being the sender of the first and third packet) does not send any data (e.g. when receiving FTP-Data), the sequence will stay at one for the whole connection. So we need more fields to filter on that only appear in the third handshake packet.
  2. We can exclude all packets that contain a TCP payload, because the third packet is empty (this may change with new rapid connection setup implementations in the future, but for the time being, it is empty). So we add the zero payload length to our filter: “tcp.seq==1 and tcp.ack==1 and tcp.len==0
  3. The next problem is that this filter will also show all empty ACK packets where we haven’t seen the SYN and SYN/ACK packet in the trace (because they weren’t captured early enough), so we need to find a way to make sure we only accept ACK packets where we have the SYN and SYN/ACK in the trace. There is an easy trick to do this, but it only works since Wireshark version 1.12 and later: Wireshark 1.12 is the first version to calculate initial RTT for all TCP conversations when it has the full three way handshake. So if the iRTT field is available, we know that we have seen the SYN and SYN/ACK packet. The final filter for the third handshake packet is: “tcp.seq==1 and tcp.ack==1 and tcp.len==0 and tcp.analysis.initial_rtt“.

To filter on all three way handshake packets: “tcp.flags.syn==1 or (tcp.seq==1 and tcp.ack==1 and tcp.len==0 and tcp.analysis.initial_rtt)” – keep in mind that this will show the handshake packets of any conversation, so there may be more than one set. If the filter doesn’t work for you, check if you have enable absolute sequence numbers.

Finding echo request packets that weren’t answered

Trying to find unanswered pings is another interesting problem, because it’s once again something where two packets are involved – the ICMP echo request and the resulting ICMP echo response. Filtering on the relationship between those two is not directly possible as we know by now, but fortunately there is a work around available, too. The Wireshark developers added a metadata field (meaning, it shows something that is not present in the bytes of the actual packet) to the decode showing in which packet a ping was answered:


You can identify those metadata fields easily since they’re written in square brackets. Many other protocols have similar metadata fields, helping you with finding the matching request/response pairs, so if you need to filter on those, look at the packet decode to see if there are any that you can use for the protocol you’re looking at (e.g. DNS).

So we can just filter for all ICMP echo request packets where the “response in” field does not exist, and find all unanswered pings: “icmp.type==8 and not icmp.resp_in“. There is also another metadata field that explicitly states if no response was seen, so you could filter for that, too: “icmp.type==8 and icmp.resp_not_found“.

Thinking outside the box

Some problems are better solved with tools other than Wireshark. Think of duplicate packets that were captured on a SPAN port with multiple source ports – Wireshark can’t tell duplicates apart, because they’re the same, byte by byte. There’s just nothing to filter on that would tell the difference. In that case, use editcap instead, which comes as a command line tool with Wireshark.

Or you might try to compare two captures taken at different locations – it’s not really possible to filter for things like “packets that are seen on one side, but not the other”. Instead, you could export the conversation statistics to a text file or a comma separated list, and compare the two exports with a text diff tool to see where the differences are. Just make sure the sorting is the same for all files, or it will be hard to work through the lists.

One thing I often do is try to see where TCP connections have trouble during session start and session finish. There may be issues like refused connection attempts (try to find reset packets that are a response to a SYN, and not just a normal session close – again something where relative sequence numbers come in handy), repeated SYNs before a SYN-ACK shows up, and other problems. With Wireshark, there aren’t many expert messages telling you about these (not yet, at least). So for connection status diagnostics I usually use the TCP conversation statistics in TraceWrangler, which tries to identify handshake and teardown problems when gathering conversation statistics and shows them in the “Status” column to the right:


Final words

If you try to filter on something about packet relationships you need to find fields that allows you to do that by just looking at a single packet at a time. Often, others had the same problem like you do and a merciful developer added a metadata field that helps, so you can filter on that. Most request/response packet pairs contain metadata references to each other, so you can filter on those.

If you really need to do complex filtering, you could also take a look at MATE, which is an extension for the display filter engine. I was always to lazy to find out how it works 🙂


Discussions — 2 Responses

  • Herwig June 3, 2015 on 11:28 pm

    Another quite basic task is tcp retransmission troubleshooting.
    It is a simple thing to create a filter showing us all tcp retransmissions (“tcp.analysis.retransmission”), but we may also want to see if there is the original TCP packet with same sequence number as the retransmission.

    This is important to prove that the packet was dropped on a different network segment.

    So we would need a filter showing all retransmission AND the original packet with same seq number as the retransmission.

    I found no way to do this in wireshark/tshark, so I wrote a shell script with a loop to filter based on another filter –> but this is awful slow….

    • Jasper Bongertz Herwig June 4, 2015 on 11:19 am

      yes, that’s a typical example. Sometimes it would be nice to be able to filter and see related packets, but at the moment this can’t be done within Wireshark itself.