Understanding Wireshark Capture Filters

In Wireshark, there are capture filters and display filters. Capture filters only keep copies of packets that match the filter. Display filters are used when you’ve captured everything, but need to cut through the noise to analyze specific packets or flows.

Capture filters and display filters are created using different syntaxes. Display filters use a syntax of boolean operators and fields that intuitively describe what you’re filtering on. Display filters aren’t that hard to write once you’ve created a few. Capture filters use a syntax of byte offsets, hex values, and masks coupled with booleans to filter. Capture filters are less intuitive, as they are cryptic when compared to display filters.

In this post, I am going to focus on a capture filter I created to solve a specific problem. I wanted the Wireshark to capture IP packets with a non-zero DSCP value. This seemed more efficient than using a display filter, since I wasn’t certain I’d find any packets like this on my home lab network where I was performing the capture.

Breaking Down The Capture Filter

While researching, I found this page from the Wireshark blog that got me some of the way to my goal. However, I tweaked the formula. The capture filter I ended up writing to capture only IP packets with a non-zero DSCP field is as follows.

1

<strong>ip and(notip[1]&amp;0xfc==0x0)</strong>

Let’s break this capture filter down.

“ip” – IPv4 packets only.

“and” – boolean operator. Here, we’re saying that the packet must be both “ip” and “the condition in parentheses following the and.”

“not” – boolean operator. In our expression, we’re using “not” because we want to ignore packets where the condition “ip[1] & 0xfc == 0x0” is true.

“ip[1]” – the second byte of the IP packet. In the PCAP filter language, the bit in brackets defines which part of the protocol you’re interested in. Here, we’ve identified the protocol as IP, with an offset of 1. If we’d had ip[0], we’d be interested in the first byte (no offset). Instead, we’ve selected ip[1], referring to the second byte (offset of 1). If you check out RFC791, the second byte of the IP packet is the Type of Service (ToS) byte.
The ToS byte includes 6 bits for the differentiated services code point per RFC2474 and 2 bits for explicit congestion notification, per RFC3168.

“&” – a bitwise AND operator. When comparing 2 binary numbers with AND, you should know that 0 AND 0 returns 0, 0 AND 1 returns 0, 1 AND 0 returns 0, and 1 AND 1 returns 1. In other words, you only get back a 1 when both binary values being compared are 1s. In this case, we’ll be comparing the contents of the ToS byte (ip[1]) with the hex value of 0xfc. More on the hex value next.

“0xfc” = a hex value. For our purposes, we need to know what this value is in binary to make sense of it. Using a calculator or online conversion tool, you’ll find that hex 0xfc is equal to binary 11111100.That means we’re using bitwise AND to compare the 8 bits in ip[1] with the 8 bits 11111100. 0xfc is helpful here in that it’s masking out the ECN bits (the last two bits in the ToS byte) since we don’t care about them. Remember that AND only returns 1 when both values compared are 1s. Therefore, setting the final two bits to 0 in the comparison value means the result for those last 2 bits will always be 0.

“==” – a comparison operator that means “is equal to”. What two values are we testing to be equal to each other? The first value is the result of the “ip[1] & 0xfc” operation. The second value is the hex number 0x0.

“0x0” is a hex value that translates, as you probably expect, into binary 00000000.

Putting It All Together

Now, let’s condense that breakdown into plain English. We want to capture IPv4 packets with a non-zero value in the DSCP field. To do it, we’re telling the capture filter to keep only those IPv4 packets that, when the ToS byte is AND’ed with 11111100, gets back something other than zero.

How do we tell the capture filter to look at the ToS byte? We know that the ToS byte is the second byte in the IP header. Therefore, we use the protocol type “ip” to tell the capture filter where to start. Then we tell it an offset of 1 so that it will start one byte in, i.e. the second byte.

Now that we know what we’re looking at, we tell the capture filter what we want that value to be or not be. We want the value of the DSCP field specifically to be anything but zero, and we wrote an bitwise AND comparison to test for it.

Let’s think through a couple of examples. If the ToS byte is 00000000, what would the result of the AND operation be?

1

2

3

4

00000000&lt;ToS bytewith DSCP value of CS0(0)+ECN of0

11111100&lt;0xFC

--------&lt;AND

00000000&lt;RESULT is0x0

That packet would not be captured, because the result is equal to 0x0, but we stipulated that the expression must NOT be true. Let’s try another.

1

2

3

4

10101100&lt;ToS bytewith DSCP value of EF(43)+ECN of0

11111100&lt;0xFC

--------&lt;AND

10101100&lt;RESULT is0xAC

That packet would be captured, because the result is not equal to 0x0.

The View From The Hot Aisle

Most of the time, I use Wireshark to capture all packets and examine what I need using a display filter. But once in a while, a capture filter seems like a cleaner way to go. Making sense of the capture filter syntax can be daunting, but walking through an example item by item helps bring clarity.

For a more in-depth understanding of the concepts I touched on here, read through the links below. Good luck writing your Wireshark capture filters!

Bitwise Operators in C and C++: A Tutorial. In networking as well as programming, AND, OR, and XOR bitwise operators come up often enough that should be comfortable with them. For example, XOR comes up in link aggregation hashing.