Introduction

Berkeley Packet Filter (BPF) expressions describe the packets that a filter should match. X4B uses the familiar libpcap expression language for BPF match conditions in custom Layer 4 rules.

A BPF expression only selects packets. The Layer 4 rule's target determines what X4B does with a matching packet.

Start with a single condition

A condition, also called a primitive, tests one packet property. Begin with the narrowest condition that describes the traffic you want:

ExpressionMatches
tcpTCP packets
udpUDP packets
tcp dst port 443TCP packets sent to destination port 443
udp port 53UDP packets whose source or destination port is 53
tcp src portrange 0-1023TCP packets from source ports 0 through 1023
src host 192.0.2.10Packets from one source address
src net 192.0.2.0/24Packets from a source network
greater 1000Packets at least 1,000 bytes long
less 1000Packets no more than 1,000 bytes long

Direction matters. src port 53 checks only the source port, dst port 53 checks only the destination port, and port 53 accepts either direction. Add tcp or udp when the transport protocol matters.

Combine conditions with logical operators

Use and, or, and not to build a rule from smaller conditions.

AND: require every condition

and matches only when both sides are true:

udp and dst port 53

This matches UDP packets sent to port 53. A TCP packet sent to port 53 does not match, and neither does a UDP packet sent to another port.

Add further conditions when all of them must apply:

tcp and dst port 443 and greater 1000

OR: allow alternatives

or matches when either side is true:

tcp dst port 80 or tcp dst port 443

This matches TCP traffic sent to either web port. Repeat qualifiers such as tcp dst port in each branch. Although libpcap can infer omitted qualifiers in some expressions, repeating them makes the intended match easier to review.

NOT: exclude a condition

not reverses the condition that follows it:

tcp and not dst port 22

This matches TCP packets except those sent to destination port 22.

Use parentheses when negating more than one alternative:

udp and not (src port 53 or dst port 53)

This matches UDP traffic only when neither endpoint uses port 53.

Use parentheses to make the logic explicit

Parentheses group conditions and make the order of evaluation unambiguous:

(tcp dst port 80 or tcp dst port 443) and greater 1000

The packet must be larger than 1,000 bytes and must be TCP traffic sent to port 80 or 443.

In libpcap syntax, not has the highest precedence. and and or have equal precedence and are evaluated from left to right. This differs from many programming languages, where and commonly binds more tightly than or.

For example:

tcp or udp and dst port 53

is evaluated as:

(tcp or udp) and dst port 53

It is not evaluated as tcp or (udp and dst port 53). Always add parentheses when an expression mixes and and or, even if the expression already appears to work.

Match flags, lengths, and packet bytes

Use TCP flag constants to select handshake packets:

ExpressionMatches
tcp[tcpflags] == tcp-synTCP packets with only SYN set
tcp[tcpflags] == (tcp-syn|tcp-ack)TCP packets with SYN and ACK set

Packet accessors use protocol[offset:length]. The length can be 1, 2, or 4 bytes:

udp[8:4] = 0x53414d50

For UDP, offset 8 begins immediately after the UDP header, so this expression compares the first four payload bytes. A packet that is too short for a requested byte range does not match.

Use bitmasks when only some bits matter. This expression matches TCP packets with SYN set, even if other flags are also present:

tcp[tcpflags] & tcp-syn != 0

Keep byte checks readable by grouping alternatives:

udp[8:4] = 0x53414d50 and (udp[18:1] = 0x70 or udp[18:1] = 0x69 or udp[18:1] = 0x63)

Build and review a rule

  1. Write one condition and confirm that it describes the intended protocol or port.
  2. Add one logical branch at a time.
  3. Put parentheses around every group that mixes and and or.
  4. Use src and dst explicitly unless either direction is intentional.
  5. Save only after the editor reports that the expression is valid.
  6. Keep the expression as small and specific as practical. Very large expressions may be rejected.

The editor checks syntax and compilation, but a valid expression can still select the wrong traffic. Read each branch aloud before applying a DROP rule, and begin with a narrowly scoped rule where possible.

Common patterns

GoalExpression
DNS traffic in either directionudp port 53
Inbound HTTPS traffictcp dst port 443
Inbound HTTP or HTTPS traffictcp and (dst port 80 or dst port 443)
Small UDP packetsudp and less 100
TCP SYN with no other flagstcp[tcpflags] == tcp-syn
Any packet with TCP SYN settcp[tcpflags] & tcp-syn != 0
Source network except SSHsrc net 192.0.2.0/24 and not tcp dst port 22
IP header contains optionsip[0] & 0x0f != 5

MicroBPF

MicroBPF is the limited form of BPF used by X4B to select packets for capture and other small tasks. You can write familiar libpcap expressions such as udp port 1234 (source or destination port), dst port 1234, or udp portrange 1000-2000.

Combine conditions with and, or, and not, or check bytes at a known position, for example udp[8:4] = 0x6d6a6974. Use payload[10:4] = 0x12345678 for a raw check without choosing a protocol. payload[...] also works in arithmetic, bitmasks, and comparisons with other fields. Ordinary filter expressions capture matching packets and reject the rest. Very large expressions may be rejected. Packet reads need a known maximum position within the configured capture length. A packet must be long enough for the deepest check in the expression, even when another condition could match earlier.

udp and tcp check the protocol in the IP header, so udp port 1234 will not match a TCP packet with the same port. Port checks and checks of transport or application data are supported; IP-address and MAC-address filters are unavailable. Data offsets start after the IP header, including any IP options: udp[8:4] checks four bytes after the UDP header. Non-initial IP fragments do not match. Expressions cannot change packets or remember previous packets. Advanced return expressions can return constants or selected packet bytes, but cannot return a calculated value. To access bytes at a set location in the packet, use payload[offset:length].

MicroBPF is used in Troubleshooting Packet Captures and in certain cases in Layer 4 rules transparently. It is not used in the Layer 4 rule editor, which uses full BPF expressions.

In Troubleshooting, select PCAP Capture and optionally enter a Capture expression (MicroBPF). Leave it blank to capture all packets matching the selected traffic type. The expression further restricts that traffic; it does not replace the filtering location or traffic selector. Capture filters can inspect up to 1,500 transport-relative bytes and compile to at most 64 instruction records, including return metadata.