Stop Guessing, Start Sniffing: The FortiGate Sniffer & tcpdump Filter Cheat Sheet

The FortiGate has a built-in packet sniffer, diagnose sniffer packet, that understands the same filter syntax as tcpdump. This cheat sheet collects the filters we use most, from simple host and port matches to TCP flags and protocols such as IPsec, RADIUS and CAPWAP.


Syntax

This is how to use it:

diagnose sniffer packet <interface> "<filter>" <verbose> <count> <tsformat> <frame size>
<interface>Name of the network interface to capture (or “any”).
Default if left empty: any
<filter>Flexible logical filters for sniffer (or “none”).
Be sure to use quotation marks!
Default if left empty: none
<verbose>1: print header of packets
2: print header and data from IP of packets
3: print header and data from Ethernet of packets (if available)
4: print header of packets with interface name
5: print header and data from IP of packets with interface name
6: print header and data from Ethernet of packets (if available) with interface name
Default if not defined: 1
<count>How many packets should be captured?
0 = unlimited; stop with Ctrl + C
Default if not defined: 0
<tsformat>Format of timestamp:
a: absolute UTC time, yyyy-mm-dd hh:mm:ss.ms
l: absolute LOCAL time, yyyy-mm-dd hh:mm:ss.ms
otherwise: relative to the start of sniffing, ss.ms
Default if not defined: relative time from start of capture
<frame size>Set the frame size that is printed before truncation.
Defaults to the interface MTU.
Default if not defined: interface MTU

A full example is:

diagnose sniffer packet any "host 10.22.37.241 and proto 1" 4 5 a

This captures ICMP packets (protocol 1, e.g. ping) to or from the host 10.22.37.241 on all interfaces, and stops after 5 packets.

  • any: sniff on all interfaces.
  • "host 10.22.37.241 and proto 1": only packets with that IP as source or destination that are ICMP.
  • 4: print the packet headers with the interface name and direction (in/out).
  • 5: stop after 5 packets.
  • a: show absolute UTC timestamps.

Operators

Parentheses

Parentheses group conditions and make complex filters readable.

Example:

(src 1.1.1.1 and dst 2.2.2.2) or (src 2.2.2.2 and dst 1.1.1.1)

Logical Operators

And-Operator: “and” or “&&“

Or-Operator: “or” or “||“

Example:

(src 1.1.1.1 && dst 2.2.2.2) || (src 2.2.2.2 && dst 1.1.1.1)

Negation

To negate one or more parameters of the filter, one can use ‘not‘ or ‘!‘.

Example:

(not icmp) and ((src 1.1.1.1 and dst 2.2.2.2) or (src 2.2.2.2 and dst 1.1.1.1))

Filter Examples

Basics

# Filter for a protocol like ip, ip6, icmp, icmp6, udp, tcp, esp, gre, arp, rarp, stp, slow (lacp, oam, ossp), ...
icmp
proto 1

# Filter for a VLAN ID (IEEE 802.1Q)
vlan 123

# Filter for a host
host 1.1.1.1
src 1.1.1.1

# Filter a subnet like 192.168.1.x
net 192.168.1
net 192.168.1.0/24

# Filter a subnet like 10.x.x.x
net 10
net 10 mask 255

# Filter for a port
port 80
dst port 80
portrange 80-88

Layer 2

# Filter for a MAC address
# Must specify interface, not working on 'any'
ether host a1:b2:c3:d4:e5:f6
ether src a1:b2:c3:d4:e5:f6

# Filter for a part of a MAC address [a1:b2:c3:d4:e5:f6]
ether[6:4]=0xa1b2c3d4

# Filter for multiple parts of a MAC address [a1:b2:c3:d4:e5:f6]
# (ether[6:4]=0xa1b2c3d4): Matches the first 4 bytes of the Source MAC.
# (ether[10:2]=0xe5f6): Matches the final 2 bytes of the Source MAC.
ether[6:4]=0xa1b2c3d4

# Filter for layer 2 broadcast packets
ether broadcast

# Filter for layer 2 multicast packets
ether multicast
ether[0] & 1 != 0

TCP flags

# Filter for TCP packets with the SYN bit set, regardless of other flags.
tcp[13] & 2 != 0

# Filter for TCP packets with SYN set and ACK not set. Filters only for the initial SYN of a handshake (new connection attempts). SYN-ACK replies are excluded.
tcp[tcpflags] & tcp-syn !=0 and tcp[tcpflags] & tcp-ack == 0

# Filter for TCP packets with the RST bit set.
tcp[13] & 4 != 0

# Filter start and end packets (SYN and FIN packets) of a TCP session. Includes other flags set with SYN or FIN like SYN-ACK or FIN-ACK.
tcp[tcpflags] & (tcp-syn|tcp-fin) != 0

# Filter for the TCP packets with flags RST and ACK both set. (Filter only the RST and ACK flags, if the result is "RST and ACK are set", match)
tcp[tcpflags] & (tcp-rst|tcp-ack) == (tcp-rst|tcp-ack)

# Filter for all IPv4 HTTP packets to and from port 80 that contain data (exclude SYN, FIN and ACK-only packets)
tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)

Services

# DHCP (Dynamic Host Configuration Protocol for IPv4)
# UDP/67 Server and relay agent (clients send to this port)
# UDP/68 Client (servers reply to this port)
udp port 67 or udp port 68

# DHCPv6 (Dynamic Host Configuration Protocol for IPv6)
# UDP/547 DHCPv6 server and relay agent
# UDP/546 DHCPv6 client
udp port 547 or udp port 546
ip6 and (udp port 546 or udp port 547)

# DNS (Domain Name System Protocol)
# UDP/53 Classic DNS
# TCP/53 Classic DNS if the answer is truncated, or for zone transfers
# UDP/853 DoQ (QUIC)
# TCP/853 DoT (TLS)
# UDP/443 DoH3 (QUIC)
# TCP/443 DoH, usually DNSCrypt and Oblivious DoH
# !!! Please note that port 443 (TCP and UDP) also matches HTTPS traffic !!!
# UDP/5353 mDNS
# UDP/5355 LLMNR
# TCP/5355 LLMNR
port 53 or port 853 or port 443 or port 5353 or port 5355

# RADIUS (Remote Authentication Dial-In User Service Protocol)
# UDP/1812 Authentication
# UDP/1813 Accounting
# UDP/3799 CoA/Disconnect
# UDP/2083 RADIUS over DTLS
# TCP/2083 RadSec (RADIUS over TLS on TCP)
udp port 1812 or udp port 1813 or udp port 3799 or port 2083

# LDAP (Lightweight Directory Access Protocol)
# UDP/389 CLDAP: connectionless LDAP, used by Active Directory
# TCP/389 LDAP
# TCP/636 LDAPS
port 389 or tcp port 636

# CAPWAP (Control And Provisioning of Wireless Access Points Protocol)
# UDP/5246 Control
# UDP/5247 Data
udp port 5246 or udp port 5247
udp portrange 5246-5247

# SNMP (Simple Network Management Protocol)
# UDP/161 SNMP Polling
# UDP/162 SNMP Traps
udp port 161 or udp port 162
udp portrange 161-162

# OFTP (Optimized Fabric Transfer Protocol)
# UDP/514 Logging over Fortinet OFTP (Reliable Logging = Disabled)
# UDP/514 Syslog RFC 5424
# TCP/514 Logging over Fortinet OFTP (Reliable Logging = Enabled or SSL Encrypted Transfer)
udp port 514 or tcp port 514
port 514

# SIP (Session Initiation Protocol)
# UDP/5060 SIP cleartext
# TCP/5060 SIP cleartext over TCP
# TCP/5061 SIP over TLS
port 5060
udp port 5060 and tcp portrange 5060-5061

# LLDP (Link Layer Discovery Protocol)
ether proto 0x88CC

# NTP (Network Time Protocol)
udp port 123

# SSH (Secure Shell)
tcp port 22

# OSPF (Open Shortest Path First)
proto 89

# BGP (Border Gateway Protocol)
tcp port 179

# Filter for layer 3 broadcast packets (IP broadcast)
ip broadcast

Tunnels

# IPsec VPN
# UDP/500 IKE (Internet Key Exchange Protocol)
# ESP Data: ESP (Encapsulating Security Payload - IP Protocol No. 50)
# UDP/4500 Data: IKE & ESP over NAT-Traversal
# Please note that that custom ports and TCP encapsulation can also be used.
udp port 500 or udp port 4500 or esp
udp port 500 or udp port 4500 or proto 50

# VXLAN (Virtual Extensible LAN)
# UDP/4789 VXLAN
udp port 4789

# VXLAN: Filter for a specific decimal VNI (example: 1234)
udp port 4789 and udp[11:4] = 1234

# VXLAN: Filter for a hex source IP address in inner header (example: 0x0A0A0A0A = 10.10.10.10)
udp port 4789 and udp[42:4] = 0x0A0A0A0A

# VXLAN: Filter for a hex destination IP address in inner header (example: 0x0A0A0A0A = 10.10.10.10)
udp port 4789 and udp[46:4] = 0x0A0A0A0A

# VXLAN: Filter for ICMP protocol in inner header
udp port 4789 and udp[39] = 1

# VXLAN: Filter for ICMP and an IP address (source or destination) (example: 0x0A0A0A0A = 10.10.10.10)
udp port 4789 and ((udp[42:4] = 0x0A0A0A0A or udp[46:4] = 0x0A0A0A0A) and udp[39] = 1)

# GRE: Filter for ICMP inside GRE
# For a plain 4-byte GRE header. With a GRE key they shift by +4!
proto 47 and ip[33]=0x01

# GRE: Filter for a hex destination IP address inside GRE (example: 0x0A0A0A0A = 10.10.10.10)
proto 47 and ip[40:4] = 0x0A0A0A0A

# GRE: Filter for a hex source IP address inside GRE (example: 0x0A0A0A0A = 10.10.10.10)
proto 47 and ip[36:4] = 0x0A0A0A0A

# GRE: Filter for a hex source IP address and IP protocol TCP (= IP proto No. 6) inside GRE (example: 0x0A0A0A0A = 10.10.10.10)
proto 47 and ip[36:4] = 0x0A0A0A0A and ip[33] = 0x06

Good to know

TCP/UDP byte filters only match IPv4

Filters that look into the transport header, such as tcp[13] & 2 != 0 or tcp[tcpflags], only match IPv4 packets. IPv6 traffic is silently ignored, so an empty capture does not mean there is no traffic. For IPv6 you have to count from the start of the IPv6 header instead, for example ip6[6] = 6 and ip6[53] & 2 != 0 for the SYN bit (40 bytes IPv6 header + 13). This only works for packets without extension headers.

Offloaded traffic is invisible

Sessions that are offloaded to an NP processor bypass the CPU, and the sniffer only sees the first packets of the session. If your capture shows a SYN and SYN-ACK and then nothing, this is the likely reason. For troubleshooting, disable offloading temporarily:

config firewall policy
    edit <id>
        set auto-asic-offload disable
    next
end

For IPsec tunnels, use set npu-offload disable in the phase1-interface. The change only affects new sessions, so clear or re-establish the existing one.

config vpn ipsec phase1-interface
    edit <phase1-name>
        set npu-offload disable
    next
end

Re-enable offloading afterwards, because it costs performance.

You can find more detailed information about hardware offloading on the FortiGate in our Blog post FortiGate hardware acceleration step-by-step troubleshooting.

Other reasons why traffic is invisible

While traffic that is blocked from ACLs is seen in the sniffer, it is invisible in the flowtrace. This is documented here.

Traffic blocked by DoS Policies: Fortinet’s NP7 troubleshooting guide warns that the sniffer leaves out packets that a DoS policy drops, even when the drop happens in the kernel. To confirm, watch the counters in diagnose ips anomaly list and the anomaly logs under Log & Report > Security Events.

Traffic that fails NP header checks: The anomaly checks on the network processor (fp-anomaly) drop packets in hardware. In this case the traffic is not visible in the sniffer utility.

Traffic restricted by the host protection engine (HPE): Rate limits traffic to the CPU on NP6 and NP7, and drops the excess in hardware. In this case the traffic is not visible in the sniffer utility.

Put the filter in quotes

As soon as a filter contains a space, it must be enclosed in single quotes: 'host 10.1.1.10 and port 443'. Without them the CLI treats the second word as the next parameter.

Exclude your own session

If you sniff with a broad filter over SSH, you capture your own session, and every printed line generates new packets. Add and not port 22 (or your admin port), or filter narrowly from the start.

Keep filters narrow on busy devices

The sniffer runs on the CPU. A broad filter on a busy firewall raises the load and drops packets from the output. Use a specific filter and a packet count, and run it over SSH, not over the serial console, which is too slow for the output.

If the sniffer utility has discarded some packets and did not print them on the console, the summary shows a non-zero value for “packets dropped by kernel”:

FGT # diag sniffer packet any
interfaces=[any]
filters=[none]

[...]

118 packets received by filter
36 packets dropped by kernel

Interface “any” versus a specific interface

With any and verbosity 4 or higher you see the interface name and direction (in/out) for each packet, which is ideal for following a packet through the firewall. The MAC addresses shown with any are not the real ones, though. For layer 2 troubleshooting and ether filters, sniff on the specific interface.

If you have the “any” interface in use and filter for Ethernet/MAC addresses, you will see the following message:

pcap_compile: ethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel

If you have the “any” interface in use and filter for broadcast traffic, you will see the following message:

pcap_compile: not a broadcast link

Think of NAT and tunnels

A packet changes on its way through the FortiGate. After source NAT, a filter on the client IP no longer matches the outgoing packet, so filter on the destination or the port instead. With IPsec you see cleartext on the tunnel interface and only ESP on the WAN interface.

VLAN tags

On a VLAN interface the packets are already untagged, so vlan 123 matches nothing there. To see tagged frames, sniff on the physical interface. The position in the filter also matters: everything after the vlan keyword refers to the content of the tagged frame, so write vlan 123 and host 10.1.1.10, not the other way round.

The sniffer shows what, not why

The sniffer captures incoming packets before any policy decision. A packet that shows up inbound has reached the FortiGate; it does not mean it was allowed. If a packet comes in but never leaves, diagnose debug flow shows the reason. And if you need the capture in Wireshark, use verbosity 6 and convert the output, or use the packet capture in the GUI to directly download a pcap file to open in Wireshark.


Missing Something?

We really appreciate your feedback on our blog posts! Please feel free to leave a comment if you think something is missing, or if you simply enjoy our content.

Further Reading

FortiOS CLI Reference: https://docs.fortinet.com/document/fortigate/8.0.0/cli-reference/303299696/diagnose-sniffer

Fortinet KB article: https://community.fortinet.com/fortigate-3/packet-capture-sniffer-99739

Man-page of tcpdump: https://www.tcpdump.org/manpages/pcap-filter.7.html

A collection of advanced tcpdump filters: https://www.wains.be/pub/networking/tcpdump_advanced_filters.txt

Loading

Leave a Reply

Your email address will not be published. Required fields are marked *