6.4. Building Display Filter Expressions
Prev | Chapter 6. Working With Captured Packets | Next

## 6.4. Building Display Filter Expressions

Wireshark provides a display filter language that enables you to precisely control which packets are displayed. They can be used to check for the presence of a protocol or field, the value of a field, or even compare two fields to each other. These comparisons can be combined with logical operators, like `and` and `or`, and parentheses into complex expressions.

The following sections will go into the display filter functionality in more detail.

| Tip
There are many display filter examples on the Wireshark Wiki Display Filter page at: https://wiki.wireshark.org/DisplayFilters.

### 6.4.1. Display Filter Fields

The simplest display filter is one that displays a single protocol. To only display packets containing a particular protocol, type the protocol into Wireshark’s display filter toolbar. For example, to only display TCP packets, type `tcp` into Wireshark’s display filter toolbar. Similarly, to only display packets containing a particular field, type the field into Wireshark’s display filter toolbar. For example, to only display HTTP requests, type `http.request` into Wireshark’s display filter toolbar.

You can filter on any protocol that Wireshark supports. You can also filter on any field that a dissector adds to the tree view, if the dissector has added an abbreviation for that field. A full list of the available protocols and fields is available through the menu item View → Internals → Supported Protocols.

### 6.4.2. Comparing Values

You can build display filters that compare values using a number of different comparison operators. For example, to only display packets to or from the IP address 192.168.0.1, use `ip.addr==192.168.0.1`.

A complete list of available comparison operators is shown in Table 6.6, “Display Filter comparison operators”.

| Tip
English and C-like operators are interchangeable and can be mixed within a filter string. Beginning in Wireshark 5.0, the English forms of operators (but not field, function, or macro names, or the first characters in escape sequences) are case-insensitive.

Table 6.6. Display Filter comparison operators

English | Alias | C-like | Description | Example
--- | --- | --- | --- | ---
`eq` | `any_eq` | `==` | Equal (any if more than one) | `ip.src == 10.0.0.5`
`ne` | `all_ne` | `!=` | Not equal (all if more than one) | `ip.src != 10.0.0.5`
| `all_eq` | `===` | Equal (all if more than one) | `ip.src === 10.0.0.5`
| `any_ne` | `!==` | Not equal (any if more than one) | `ip.src !== 10.0.0.5`
`gt` |  | `>` | Greater than | `frame.len > 10`
`lt` |  | `<` | Less than | `frame.len < 128`
`ge` |  | `>=` | Greater than or equal to | `frame.len ge 0x100`
`le` |  | `<=` | Less than or equal to | `frame.len <= 0x20`
`contains` |  |  | Protocol, field or slice contains a value | `sip.To contains "a1762"`
`matches` |  | `~` | Protocol or text field matches a Perl-compatible regular expression | `http.host matches "acme\\.(org|com|net)"`

| Note
The meaning of `!=` (all not equal) was changed in Wireshark 3.6. Before it used to mean "any not equal".

All protocol fields have a type. Section 6.4.2.1, “Display Filter Field Types” provides a list of the types with examples of how to use them in display filters.

#### 6.4.2.1. Display Filter Field Types

Unsigned integer

  Can be 8, 16, 24, 32, or 64 bits. You can express integers in decimal, octal, hexadecimal or binary. The following display filters are equivalent:

  `ip.len le 1500`

  `ip.len le 02734`

  `ip.len le 0x5dc`

  `ip.len le 0b10111011100`

Signed integer
  Can be 8, 16, 24, 32, or 64 bits. As with unsigned integers you can use decimal, octal, hexadecimal or binary.
Boolean

  Can be `1` or `True`, `0` or `False`.

  A Boolean field is present regardless if its value is true or false. For example, `tcp.flags.syn` is present in all TCP packets containing the flag, whether the SYN flag is 0 or 1. To only match TCP packets with the SYN flag set, you need to use `tcp.flags.syn == 1` or `tcp.flags.syn == True`.

Ethernet address

  6 bytes separated by a colon (:), dot (.), or dash (-) with one or two bytes between separators:

  `eth.dst == ff:ff:ff:ff:ff:ff`

  `eth.dst == ff-ff-ff-ff-ff-ff`

  `eth.dst == ffff.ffff.ffff`

IPv4 address

  `ip.addr == 192.168.0.1`

  Classless InterDomain Routing (CIDR) notation can be used to test if an IPv4 address is in a certain subnet. For example, this display filter will find all packets in the 129.111 Class-B network:

  `ip.addr == 129.111.0.0/16`

IPv6 address

  `ipv6.addr == ::1`

  As with IPv4 addresses, IPv6 addresses can match a subnet.

Text string

  `http.request.uri == "https://www.wireshark.org/"`

  Strings are a sequence of bytes. Functions like `lower()` use ASCII, otherwise no particular encoding is assumed. String literals are specified with double quotes. Characters can also be specified using escape sequences as in C or C++:

  Table 6.7. Display Filter Escape Sequences in Character and String Literals

  `\'` | single quote
  `\"` | double quote
  `\\` | backslash
  `\a` | audible bell
  `\b` | backspace
  `\f` | form feed
  `\n` | line feed
  `\r` | carriage return
  `\t` | horizontal tab
  `\v` | vertical tab
  `\ddd` | arbitrary octal value
  `\xhh` | arbitrary hexadecimal value
  `\uhhhh` | Unicode codepoint U+hhhh
  `\Uhhhhhhhh` | Unicode codepoint U+hhhhhhhh

  where `h` and `d` are hex and octal numerical digits respectively:

  `dns.qry.name contains "www.\x77\x69\x72\x65\x73\x68\x61\x72\x6b.org"`

  Alternatively, a raw string syntax can be used. Such strings are prefixed with `r` or `R` and treat backslash as a literal character.

  `http.user_agent matches r"\(X11;"`

  Paired directional ("smart" or "curly") double quotes can be used in lieu of straight double quotes. This is mostly to handle example filters copied from webpages that helpfully replace straight quotes, but it possible to include straight double quotes unescaped in directional double quote enclosed raw string literals. A right directional double quote can be escaped in a string literal opened by a left directional double quote.

Date and time

  `frame.time == "Sep 26, 2004 23:18:04.954975"`

  `ntp.xmt ge "2020-07-04 12:34:56"`

  The value of an absolute time field is expressed as a string, using one of the two formats above. Fractional seconds can be omitted or specified up to nanosecond precision; extra trailing zeros are allowed but not other digits. The string cannot take a time zone suffix, and is always parsed as in the local time zone, even for fields that are displayed in UTC.

  In the first format, the abbreviated month names must be in English regardless of locale. In the second format, any number of time fields may be omitted, in the order from least significant (seconds) to most, but at least the entire date must be specified:

  `frame.time < "2022-01-01"`

  In the second format, a `T` may appear between the date and time as in ISO 8601, but not when less significant times are dropped.

#### 6.4.2.2. Some Examples

    udp contains 81:60:03

The display filter above matches packets that contains the 3-byte sequence 0x81, 0x60, 0x03 anywhere in the UDP header or payload.

    sip.To contains "a1762"

The display filter above matches packets where the SIP To-header contains the string "a1762" anywhere in the header.

    http.host matches "acme\\.(org|com|net)"

The display filter above matches HTTP packets where the HOST header contains acme.org, acme.com, or acme.net. Comparisons are case-insensitive.

    tcp.flags & 0x02

That display filter will match all packets that contain the “tcp.flags” field with the 0x02 bit, i.e., the SYN bit, set.

#### 6.4.2.3. Possible Pitfalls Using Regular Expressions

String literals containing regular expressions are parsed twice. Once by Wireshark’s display filter engine and again by the PCRE2 library. It’s important to keep this in mind when using the `matches` operator with regex escape sequences and special characters.

For example, the filter expression `frame matches "AB\x43"` uses the string `"ABC"` as input pattern to PCRE. However, the expression `frame matches "AB\\x43"` uses the string `"AB\x43"` as the pattern. In this case both expressions give the same result because Wireshark and PCRE both support the same byte escape sequence (0x43 is the ASCII hex code for `C`).

An example where this fails badly is `foo matches "bar\x28"`. Because 0x28 is the ASCII code for `(` the pattern input to PCRE is `"bar("`. This regular expression is syntactically invalid (missing closing parenthesis). To match a literal parenthesis in a display filter regular expression it must be escaped (twice) with backslashes.

| Tip
Using raw strings avoids most problems with the `matches` operator and double escape requirements.

### 6.4.3. Combining Expressions

You can combine filter expressions in Wireshark using the logical operators shown in Table 6.8, “Display Filter Logical Operations”

Table 6.8. Display Filter Logical Operations

English | C-like | Description | Example
--- | --- | --- | ---
`and` | `&&` | Logical AND | `ip.src==10.0.0.5 and tcp.flags.fin`
`or` | `||` | Logical OR | `ip.src==10.0.0.5 or ip.src==192.1.1.1`
`xor` | `^^` | Logical XOR | `tr.dst[0:3] == 0.6.29 xor tr.src[0:3] == 0.6.29`
`not` | `!` | Logical NOT | `not llc`
`[…​]` |  | Subsequence | See “Slice Operator” below.
`in` |  | Set Membership | `http.request.method in {"HEAD", "GET"}`. See “Membership Operator” below.

### 6.4.4. Slice Operator

Wireshark allows you to select a subsequence of byte arrays (including protocols) or text strings in rather elaborate ways. After a label you can place a pair of brackets `[]` containing a comma separated list of range specifiers.

    eth.src[0:3] == 00:00:83

The example above uses the `n:m` format to specify a single range. In this case `n` is the beginning offset and `m` is the length of the range being specified.

    eth.src[1-2] == 00:83

The example above uses the `n-m` format to specify a single range. In this case `n` is the beginning offset and `m` is the ending offset.

    eth.src[:4] == 00:00:83:00

The example above uses the `:m` format, which takes everything from the beginning of a sequence to offset `m`. It is equivalent to `0:m`.

    eth.src[4:] == 20:20

The example above uses the `n:` format, which takes everything from offset `n` to the end of the sequence.

    eth.src[2] == 83

The example above uses the `n` format to specify a single range. In this case the element in the sequence at offset `n` is selected. This is equivalent to `n:1`.

    eth.src[0:3,1-2,:4,4:,2] ==
    00:00:83:00:83:00:00:83:00:20:20:83

Wireshark allows you to string together single ranges in a comma separated list to form compound ranges as shown above.

You can use the slice operator on a protocol name, too, to slice the bytes associated with that protocol. The `frame` protocol can be useful, encompassing all the captured data (not including secondary data sources like decrypted data.)

Offsets can be negative, indicating an offset from the end of a field.

    frame[-4:4] == 0.1.2.3
    frame[-4:] == 0.1.2.3

The two examples above both check the last four bytes of a frame.

Slices of string fields yield strings, and are indexed on codepoint boundaries after conversion of the string to UTF-8, not bytes.

    http.content_type[0:4] == "text"
    smpp.message_text[:10] == "Абвгдеёжзи"

The second example above will match regardless of whether the original string was in Windows-1251, UTF-8, or UTF-16, so long as the converted string starts with those ten characters.

Byte slices can be directly compared to strings; this converts the string to the corresponding UTF-8 byte sequence. To compare string slices with byte sequences, use the `@` operator, below.

### 6.4.5. The Layer Operator

A field can be restricted to a certain layer in the protocol stack using the layer operator (`#`), followed by a decimal number:

    ip.addr#2 == 192.168.30.40

matches only the inner (second) layer in the packet. Layers use simple stacking semantics and protocol layers are counted sequentially starting from 1. For example, in a packet that contains two IPv4 headers, the outer (first) source address can be matched with `ip.src#1` and the inner (second) source address can be matched with `ip.src#2`.

For more complicated ranges the same syntax used with slices is valid:

    tcp.port#[2-4]

means layers number 2, 3 or 4 inclusive. The hash symbol is required to distinguish a layer range from a slice.

### 6.4.6. The At Operator

By prefixing the field name with an at sign (`@`) the comparison is done against the raw packet data for the field.

A character string must be decoded from a source encoding during dissection. If there are decoding errors the resulting string will usually contain replacement characters:

    browser.comment == "string is ����"

The at operator allows testing the raw undecoded data:

    @browser.comment == 73:74:72:69:6e:67:20:69:73:20:aa:aa:aa:aa

The syntactical rules for a bytes field type apply to the second example.

| Note
When a bytes field is compared with a literal string, it is compared with the UTF-8 representation of that string. The at operator compares a string field with the actual byte representation in the original encoding, which may not be UTF-8. As an example, SMPP has a bytes field, `smpp.message`, and a string field, `smpp.message_text`, that refer to the same data. If the first four characters of the message is the string "Test" in the UTF-16 encoding, the following filters all match.
    smpp.message[:8] == 00:54:00:65:00:73:00:74
    smpp.message[:8] == "\x00T\x00e\x00s\x00t"
    smpp.message_text[:4] == "Test"
    smpp.message_text[:4] == "\x54\x65\x73\x74"
    @smpp.message_text[:8] == 00:54:00:65:00:73:00:74
    @smpp.message_text[:8] == "\x00T\x00e\x00s\x00t"
The following filters do NOT match.
    @smpp.message_text[:4] == "\x00T\x00e\x00s\x00t"
    smpp.message[:4] == "Test"
    smpp.message[:8] == "Test"
    @smpp.message_text[:4] == "Test"
    @smpp.message_text[:8] == "Test"
The first filter above does not match because of operator precedence left-to-right; `@smpp.message_text` is converted to bytes before the slice operator is applied, so the length of the necessary slice is 8. The other filters do not match because the literal string "Test" is always converted to its 4 octet UTF-8 representation when comparing against bytes, and it does not match the UTF-16 representation of the field bytes.

### 6.4.7. Membership Operator

Wireshark allows you to test a field for membership in a set of values or fields. After the field name, use the `in` operator followed by the set items surrounded by braces `{}`. For example, to display packets with a TCP source or destination port of 80, 443, or 8080, you can use `tcp.port in {80, 443, 8080}`. Set elements must be separated by commas. The set of values can also contain ranges: `tcp.port in {443,4430..4434}`.

| Note
The display filter
    tcp.port in {80, 443, 8080}
is equivalent to
    tcp.port == 80 || tcp.port == 443 || tcp.port == 8080
However, the display filter
    tcp.port in {443, 4430..4434}
is not equivalent to
    tcp.port == 443 || (tcp.port >= 4430 && tcp.port <= 4434)
This is because comparison operators are satisfied when any field matches the filter, so a packet with a source port of 56789 and destination port of port 80 would also match the second filter since `56789 >= 4430 && 80 <= 4434` is true. In contrast, the membership operator tests a single field against the range condition.

Sets are not just limited to numbers, other types can be used as well:

    http.request.method in {"HEAD", "GET"}
    ip.addr in {10.0.0.5 .. 10.0.0.9, 192.168.1.1..192.168.1.9}
    frame.time_delta in {10 .. 10.5}

### 6.4.8. Arithmetic operators

You can perform the arithmetic operations on numeric fields shown in Table 6.9, “Display Filter Arithmetic Operations”

Table 6.9. Display Filter Arithmetic Operations

Name | Syntax | Alternative | Description
--- | --- | --- | ---
Unary minus | `-A` |  | Negation of A
Addition | `A + B` |  | Add B to A
Subtraction | `A - B` |  | Subtract B from A
Multiplication | `A * B` |  | Multiply A times B
Division | `A / B` |  | Divide A by B
Modulo | `A % B` |  | Remainder of A divided by B
Bitwise AND | `A & B` | `A bitand B` | Bitwise AND of A and B

An unfortunate quirk in the filter syntax is that the subtraction operator must be preceded by a space character, so "`A-B`" must be written as "`A -B`" or "`A - B`".

Arithmetic expressions can be grouped using curly braces.

For example, frames where capture length resulted in truncated TCP options:

    frame.cap_len < { 14 +  ip.hdr_len + tcp.hdr_len }

### 6.4.9. Functions

The display filter language has a number of functions to convert fields, see Table 6.10, “Display Filter Functions”.

Table 6.10. Display Filter Functions

Function | Description
--- | ---
`upper` | Converts a string field to uppercase.
`lower` | Converts a string field to lowercase.
`len` | Returns the byte length of a string or bytes field.
`count` | Returns the number of field occurrences in a frame.
`string` | Converts a non-string field to a string.
`vals` | Converts a field value to its value string, if it has one.
`dec` | Converts an unsigned integer field to a decimal string.
`hex` | Converts an unsigned integer field to a hexadecimal string.
`float` | Converts a field to single precision floating point.
`double` | Converts a field to double precision floating point.
`max` | Return the maximum value for the arguments.
`min` | Return the minimum value for the arguments.
`abs` | Return the absolute value for the argument.

The `upper()` and `lower()` functions can used to force case-insensitive matches: `lower(http.server) contains "apache"`.

To find HTTP requests with long request URIs: `len(http.request.uri) > 100`. Note that the `len()` function yields the string length in bytes rather than (multi-byte) characters.

Usually an IP frame has only two addresses (source and destination), but in case of ICMP errors or tunneling, a single packet might contain even more addresses. These packets can be found with `count(ip.addr) > 2`.

The `string()` function converts a field value to a string, suitable for use with operators like `matches` or `contains`. Integer fields are converted to their decimal representation. It can be used with IP/Ethernet addresses (as well as others), but not with string or byte fields.

For example, to match odd frame numbers:

    string(frame.number) matches "[13579]$"

To match IP addresses ending in 255 in a block of subnets (172.16 to 172.31):

    string(ip.dst) matches r"^172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]{1,3}\.255"

The `vals()` function converts an integer or boolean field value to a string using the field’s associated value string, if it has one.

The `double()` function converts certain field types to doubles, including floats, doubles (a no-op), integers, booleans, times (absolute times are converted to seconds since the UN*X epoch), and the special IEEE 11073 Personal Health Devices floating point formats. The results can be used with further arithmetic operations and, like other filters, placed in a custom column.

The functions `max()` and `min()` take any number of arguments of the same type and returns the largest/smallest respectively of the set.

    max(tcp.srcport, tcp.dstport) <= 1024

### 6.4.10. Field References

An expression of the form `${proto.field}` is called a field reference. Its value is read from the corresponding field in the currently selected frame in the GUI. This is a powerful way to build dynamic filters, such as frames since the last five minutes to the selected frame:

    frame.time_relative >= ${frame.time_relative} - 300

or all HTTP packets whose `+ip.dst` value equals the "A" record of the DNS response in the current frame:

    http && ip.dst eq ${dns.a}

The notation of field references is similar to that of macros but they are syntactically distinct. Field references, like other complex filters, make excellent use cases for macros, saved filters, and filter buttons

### 6.4.11. Implicit type conversions

In addition to the implicit conversion of string literals for comparison with byte array fields (including protocols) mentioned above, integer and boolean fields with value strings can be compared with one of the strings that corresponds with a value.

If there is a unique reverse mapping from the string literal into a numeric value, the string is converted into that number and the comparison function is applied using arithmetic rules. If the mapping is not unique, then equality and inequality can be tested, but not the ordered comparisons.

This is in contrast with the `string()` and `vals()` functions, which convert the field value to a string and applies string (lexicographic) comparisons, as well as work with all operators that take strings. Therefore the following two filters give the same result:

    gtpv2.message_type <= 35
    gtpv2.message_type <= "Modify Bearer Response"

whereas

    vals(gtpv2.message_type) <= "Modify Bearer Response"

matches all messages whose value string precedes "Modify Bearer Response" in lexicographical order, and

    string(gtpv2.message_type) <= "35"

matches all messages such that the message type comes before "35" in lexicographical order, i.e. would also match "170" (the message type for "Release Access Bearers Request.")

For the `contains` and `matches` operators, which operate on strings (or byte arrays in the case of `contains`), fields on the left hand side are implicitly converted to their value strings for comparison. (To compare a field with a byte array, use the raw/at (`@`) operator.)

### 6.4.12. Sometimes Fields Change Names

As protocols evolve they sometimes change names or are superseded by newer standards. For example, DHCP extends and has largely replaced BOOTP and TLS has replaced SSL. If a protocol dissector originally used the older names and fields for a protocol the Wireshark development team might update it to use the newer names and fields. In such cases they will add an alias from the old protocol name to the new one in order to make the transition easier.

For example, the DHCP dissector was originally developed for the BOOTP protocol but as of Wireshark 3.0 all of the `bootp` display filter fields have been renamed to their `dhcp` equivalents. You can still use the old filter names for the time being, e.g., `bootp.type` is equivalent to `dhcp.type` but Wireshark will show the warning “"bootp" is deprecated” when you use it. Support for the deprecated fields may be removed in the future.

### 6.4.13. Some protocol names can be ambiguous

In some particular cases relational expressions (equal, less than, etc.) can be ambiguous. The filter name of a protocol or protocol field can contain any letter and digit in any order, possibly separated by dots. That can be indistinguishable from a literal value (usually numerical values in hexadecimal). For example the semantic value of `fc` can be the protocol Fibre Channel or the number `0xFC` in hexadecimal because the `0x` prefix is optional for hexadecimal numbers.

Any value that matches a registered protocol or protocol field filter name is interpreted semantically as such. If it doesn’t match a protocol name the normal rules for parsing literal values apply.

So in the case of `fc` the lexical token is interpreted as "Fibre Channel" and not `0xFC`. In the case of `fd` it would be interpreted as `0xFD` because it is a well-formed hexadecimal literal value (according to the rules of display filter language syntax) and there is no protocol registered with the filter name `fd`.

How ambiguous values are interpreted may change in the future. To avoid this problem and resolve the ambiguity there is additional syntax available. Values prefixed with a dot are always treated as a protocol name. The dot stands for the root of the protocol namespace and is optional). Values prefixed with a colon are always interpreted as a byte array.

    frame[10:] contains .fc or frame[10] == :fc

If you are writing a script, or you think your expression may not be giving the expected results because of the syntactical ambiguity of some filter expression it is advisable to use the explicit syntax to indicate the correct meaning for that expression.

Prev | Up | Next
6.3. Filtering Packets While Viewing | Home | 6.5. The “Display Filter Expression” Dialog Box