How to run a packet capture on a Fortigate (CLI)

This is a quick reference guide showing how to run a packet capture on a Fortigate. it is important to remember that the packet capture will only show packets that are being handled via the Kernal (Not being offloaded to an ASIC) you can however disable this on the policy as follows:

1 – Disable ASIC offload for traffic (Optional)

I have put optional as you don’t need to but ensures you get the packets to look at.

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

2 – Setup the capture

The syntax is a spin off tcpdump, essentially it is tcpdump under the hood but most filters will work. the syntax is as follows, options and verbose level are optional. I ussually use verbose 4 so I can see the interface names

diagnose sniffer packet <interface> "<options>" <verbose level> <count> <timestamp format>

all flags / options apart from interface are optional

interface – The actual interface you want the sniffer to run on or capture packets on, you can use the word any for all interfaces or specify the name of the interface

options – The tcpdump filter options you want to use, these must be surrounded by double or single quotes

verbose level – This can be a number between 1 and 6 and is defined as follows:

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 intf name

count – limit of packets you want to count, when this number is reached sniffer will stop, use 0 for unlimited

timestamp format – The format for timestamp, by default it is the number in seconds and milliseconds from when you started the capture to when the displayed packet is recieved on the listening interface. Other options are a or l, a for absolute time and l for local time.

3 – example 1 – all icmp

This example is to capture all icmp traffic and show the interface name

diagnose sniffer packet any "icmp" 4

I setup a test ping to the Fortigate whilst the sniffer was running

Brierley-FW01 # diagnose sniffer packet any "icmp" 4
Using Original Sniffing Mode
interfaces=[any]
filters=[icmp]
2.216830 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
2.216853 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply
3.221063 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
3.221086 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply
4.233794 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
4.233816 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply
5.244740 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
5.244761 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply

So with the verbose 4 flag I can see the request is coming in on port 2 (The icmp echo request) and the reply is being sent out via port 2. This makes sense as I a pinging the interface itself. I also get the timestamp right at the beginning which is by default relative to the time you started sniffing, so in my case, it was 2.216830 seconds after I entered the command that I received the echo request. You can change this so it shows an actual timestamp.

Brierley-FW01 # diagnose sniffer packet any "icmp" 4 0 l
Using Original Sniffing Mode
interfaces=[any]
filters=[icmp]
2021-01-25 09:39:15.604359 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
2021-01-25 09:39:15.604412 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply
2021-01-25 09:39:16.608767 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
2021-01-25 09:39:16.608788 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply
2021-01-25 09:39:17.619909 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
2021-01-25 09:39:17.619931 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply
2021-01-25 09:39:18.630056 port2 in 172.16.10.200 -> 172.16.10.2: icmp: echo request
2021-01-25 09:39:18.630079 port2 out 172.16.10.2 -> 172.16.10.200: icmp: echo reply

Same example however I add an additional flag which again is optional. 0 for the number of packets (Which means unlimited) and l for local time, this uses the time local to the Firewall defined under system time.
You can now see I have some output with an actual timestamp.

Other examples

These are some examples for the filter (The bit between the quotes) common ones which are good and I use most times. Obviously you can get extremely complex with it but here are a few examples

By ip address (Either source or destination)

diagnose sniffer packet any "host 10.1.1.1" 4

Replace 10.1.1.1 with the IP address.

By network

so if you want to sniff track to or from 10.1.1.0/24 you would use this

diagnose sniffer packet any "net 10.1.1.0/24" 4

Replace the network with any you need

By port number

This is useful if you are looking for traffic on a certain port

diagnose sniffer packet any "port 2222" 4

Again replace the port number with whatever port you need. This is for both TCP & UDP.

source or destination

Use this if you want to see traffic as the source or the destination. Useful if you only want initiatng traffic to be shown.

diagnose sniffer packet any "src 10.1.1.1" 4
diagnose sniffer packet any "dst 10.1.1.1" 4

Protocol

You can filter by protocol e.g. tcp, udp icmp and so on

diagnose sniffer packet any "tcp" 4

This for example would show only TCP traffic

Using AND

So if you need source = 10.1.1.1 and destination = 8.8.8.8 and its icmp you could string them together.

AND logic says both must be true.

diagnose sniffer packet any "src 10.1.1.1 and dst 8.8.8.8 and icmp

Using OR

The logic of or is if one of the statement is true, whereas AND you need both to be true.

diagnose sniffer packet any "src 10.1.1.1 or src 10.1.1.2" 4

So if the source is either 10.1.1.1 or 10.1.1.2 this also means if there is traffic from both of these then it will show as the filter is run against each packet.

Combining AND and OR

So lets say you need the source is 10.1.1.1 or 10.1.1.2 and the port is 22 and the protocol is tcp you would have to use brackets as follows.

diagnose sniffer packet any "(src 10.1.1.1 or src 10.1.1.2) and (port 22 and tcp)" 4

Notice how I put them in brackets, this bit is done first so I am saying source is 10.1.1.1 or 10.1.1.2 AND port is 22 and its tcp.

If you don’t use brackets its will still take it as a valid filter but it won’t yield what you want it to.

Using ! to negate

You can negate most things, so anything but this , not this.
So all ports except port 22 would be

diagnose sniffer packet any "!port 22" 4

Again you could add multiple to this list.

Thoughts?

So that’s a brief info into what you could potentially use the Fortigate’s built in packet capture for.
It comes in handy when troubleshooting a firewall issue. Couple this with a packet flow (More on that another time) and you can debug most situations for firewall policies.
It is also useful for routing , you may sometimes receive the traffic on the incorrect interface which will cause the reverse path lookup to fail as an anti-spoofing mechanism that most stateful firewall’s incorporate.

Thanks for reading, if you have any questions about this or need some help on a specific filter please feel free to leave a comment or get in touch.
If you are interested in looking more into the filters then look at tcpdump most of these will work.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s