NFTables.Expr.Payload (NFTables v0.8.2)
View SourceRaw payload matching functions for deep packet inspection.
This module provides functions to match arbitrary bytes at specific offsets within packet headers, bypassing protocol-specific parsing. This is essential for custom protocols, deep packet inspection (DPI), and advanced packet manipulation.
Important: Bit-Level Operations
All offsets and lengths are specified in BITS, not bytes!
To convert: byte_offset * 8 = bit_offset
Example: Byte offset 12 = Bit offset 96 (12 × 8)
Base References
:ll- Link layer (Ethernet header start):nh- Network header (IP header start):th- Transport header (TCP/UDP header start):ih- Inner header (for tunneled packets)
Common Use Cases
- Custom protocol matching
- Deep packet inspection
- Protocol extension headers
- Tunneled packet inspection
- Advanced DPI rules
Import
import NFTables.Expr.PayloadFor more information, see the nftables payload expressions wiki.
Summary
Functions
Match raw payload bytes at specific offset.
Extract raw payload value for use in other operations.
Match raw payload with bitwise AND mask.
Functions
@spec payload_raw(NFTables.Expr.t(), atom(), non_neg_integer(), pos_integer(), term()) :: NFTables.Expr.t()
Match raw payload bytes at specific offset.
Allows matching arbitrary bytes at specific offsets within packet headers. Remember: offsets and lengths are in bits, not bytes!
Parameters
builder- Expression builderbase- Base reference point (:ll,:nh,:th,:ih)offset- Bit offset from base (not bytes!)length- Number of bits to matchvalue- Value to match against (integer, binary, or string)
Examples
# Match DNS port (53) using raw payload at transport header offset 16 bits
udp()
|> payload_raw(:th, 16, 16, 53)
|> accept()
# Match IPv4 source address 192.168.1.1 (network header, byte 12-15 = bits 96-127)
payload_raw(:nh, 96, 32, <<192, 168, 1, 1>>)
|> drop()
# Match IPv6 next header field (routing header = 43)
protocol(:ipv6)
|> payload_raw(:nh, 48, 8, 43)
|> drop()
# Match first 4 bytes of HTTP GET request (inner header)
tcp()
|> dport(80)
|> payload_raw(:ih, 0, 32, "GET ")
|> log("HTTP GET")
|> accept()
# Match TCP SYN flag (transport header byte 13, bit 1)
payload_raw(:th, 104, 8, 0x02)
|> log("SYN packet")Offset Calculation Examples
TCP Header
- Source port: byte 0-1 = bits 0-15
- Dest port: byte 2-3 = bits 16-31
- Sequence: byte 4-7 = bits 32-63
- Flags: byte 13 = bits 104-111
IPv4 Header
- Protocol: byte 9 = bits 72-79
- Source IP: byte 12-15 = bits 96-127
- Dest IP: byte 16-19 = bits 128-159
Notes
- Network byte order (big endian) is assumed
- Values can be integers, binaries, or strings
- For string values, they're converted to bytes
@spec payload_raw_expr(atom(), non_neg_integer(), pos_integer()) :: map()
Extract raw payload value for use in other operations.
Returns a payload expression that can be used as a key or value in set operations, packet mangling, or other advanced matching. This is a lower-level function that doesn't directly add to the builder.
Parameters
base- Base reference (:ll,:nh,:th,:ih)offset- Bit offset from baselength- Number of bits to extract
Examples
# Extract source IP as raw payload for set matching
key = payload_raw_expr(:nh, 96, 32)
# Use in advanced matching
custom_match(key, "value")Use Cases
- Set lookup keys
- Dynamic value extraction
- Packet mangling sources
- Advanced rule compositions
@spec payload_raw_masked( NFTables.Expr.t(), atom(), non_neg_integer(), pos_integer(), integer(), integer() ) :: NFTables.Expr.t()
Match raw payload with bitwise AND mask.
Allows checking specific bits within a field using bitwise operations. Useful for flag checking, field masking, and partial field matching.
How It Works
- Extract bits from packet:
field = packet[offset:offset+length] - Apply mask:
masked = field & mask - Compare:
masked == value
Parameters
builder- Expression builderbase- Base reference (:ll,:nh,:th,:ih)offset- Bit offset from baselength- Number of bitsmask- Bitmask to apply (integer)value- Value to match after masking
Examples
# Check TCP SYN flag (bit 1 in TCP flags byte at offset 104 bits)
tcp()
|> payload_raw_masked(:th, 104, 8, 0x02, 0x02)
|> accept()
# Check IP DF (Don't Fragment) flag (bit 14 in flags field)
payload_raw_masked(:nh, 48, 16, 0x4000, 0x4000)
|> drop()
# Check if specific bit is set in custom protocol
payload_raw_masked(:ih, 8, 8, 0x80, 0x80)
|> counter()
|> accept()
# Match TCP flags: SYN+ACK (check bits 0 and 1)
payload_raw_masked(:th, 104, 8, 0x12, 0x12)
|> log("SYN-ACK")TCP Flags Reference
TCP flags byte (offset 104 bits / byte 13):
0x01- FIN0x02- SYN0x04- RST0x08- PSH0x10- ACK0x20- URG
Use Cases
- TCP flag checking (SYN, ACK, FIN, RST)
- IP flag inspection (DF, MF)
- Custom protocol bit flags
- Selective field matching
- Partial value extraction