Course menu

Module 4: Firewall Packet ProcessingLesson 4.1 (1 of 1 in this module)1 of 1 in the Fortinet Fundamentals course

Understanding FortiGate firewall packet flow

First packet versus established session, the session table, routing, policy, NAT, inspection, offloading and return traffic, with the commands that show each step.

Intermediate · 30 min read

Written for FortiOS 7.6 · FortiOS 7.4: concepts unchanged

Exam domain: NSE 4 (FortiOS 7.6) · Deployment and system configurationFundamentals

Before this: Firewall basics, NAT and PAT, What a FortiGate is

What you will learn

After this lesson, you can explain what a FortiGate does with the first packet of a session and with every packet after it, predict where a packet will be translated, allowed or dropped, and choose the command that shows each step on a real FortiGate.

  • First packet vs session
  • Routing, policy and NAT order
  • Offloading
  • Diagnosing packet flow

Packet flow is the sequence of checks and actions a FortiGate applies to a packet between the interface it arrives on and the interface it leaves from. The first packet of a connection goes through the full sequence on the CPU: session lookup, destination NAT, routing, policy, inspection and source NAT. That creates a session, and later packets in either direction match the session instead, often in hardware.

In simple terms: The first packet of a conversation is examined carefully and the decision is written down. Every later packet just shows its ticket.

A real-life situation

At Elmside Logistics, a fictional company, users say a new supplier portal "doesn't work" while everything else does. One engineer adds a route, another adds a policy, a third disables a security profile. None of it helps, because nobody knows where the FortiGate is dropping the traffic. An engineer who understands packet flow asks one question at a time: did the packet arrive, which session did it match, where was it routed, which policy matched, was it translated, and did the reply come back? Each answer comes from one command. This lesson explains the path those questions follow.

The examples use the course lab:

port1203.0.113.0/30port210.0.1.0/24port310.0.2.0/24InternetISP gateway 203.0.113.1FGT1FortiGatePC1LAN · 10.0.1.10WEB1DMZ · 10.0.2.10
  1. 1. Outbound: PC1 (10.0.1.10) opens a web page on 198.51.100.80. Policy 3 allows it with source NAT to 203.0.113.2.
  2. 2. Inbound: A visitor reaches WEB1 (10.0.2.10) through the virtual IP 203.0.113.20.

Why packet flow matters

A firewall makes several separate decisions for each new connection, in a fixed order. Each decision depends on the ones before it: the policy lookup needs the outgoing interface, which comes from routing, which needs the real destination, which depends on whether destination NAT changed it. If you know the order, a symptom points straight at one step. If you don't, every change is a guess, and guesses on a production firewall cause outages.

Two paths: the first packet and every packet after it

A FortiGate is a stateful firewall. It doesn't make a full decision for every packet. It makes one for the first packet of a connection, records the result as a session, and then matches later packets in both directions against that session.

First packet (no session yet)Later packets (session exists)
WhereCPU, the "slow path"CPU fast path, or a network processor if the session was offloaded
LookupsDestination NAT, route, reverse path, policyNone: the session already holds the answers
ResultA new session, or a dropForwarded and translated according to the session
Security profilesStart inspectingKeep inspecting the session's data, in both directions

This is why a FortiGate needs no policy for return traffic, why most packets cost far less work than the first one, and why a policy change mostly matters to new connections.

The first packet, step by step

Here is the path for the common case: a FortiGate in NAT mode, policies with their own NAT setting (policy NAT, the default), and flow-based inspection. The example is PC1's first packet to a web server: a TCP SYN from 10.0.1.10:51544 to 198.51.100.80:443, arriving on port2.

1. Ingress
The packet arrives on an interface. IP header checks; DoS policies if configured. Inbound IPsec is decrypted here.
2. Session lookup
Does it match an existing session? If yes, take the fast path. If no, continue on the slow path.
3. Destination NAT
If the destination matches a virtual IP, rewrite it to the internal address now.
4. Routing and reverse path check
Find the outgoing interface for the (possibly translated) destination; check the source is reachable back through the arrival interface.
5. Firewall policy
Top-down, first match on interfaces, source, destination, service, schedule and user. No match: implicit deny. Match: create the session.
6. Security inspection
Profiles on the matching policy inspect the session's data as it flows.
7. Source NAT
If the policy has NAT on, translate the source (interface address or IP pool).
8. Egress
Encrypt into an IPsec tunnel if needed, apply traffic shaping, and send.
The first packet of a new session on a FortiGate in NAT mode with policy NAT and flow-based inspection. Other modes change parts of this order (see 'When the order is different').

1. Ingress

The SYN arrives on port2. Before anything else, the FortiGate checks that the IP header is well-formed and, if a DoS policy is configured on the interface, counts the packet against its thresholds (floods are stopped here, before they cost policy lookups). If the packet were ESP arriving on an IPsec tunnel, it would be decrypted at this point, and the inner packet would continue as if it had arrived on the tunnel interface.

2. Session lookup

The FortiGate looks for a session with the same protocol, addresses and ports, in either direction. For this SYN there is none, so it continues on the slow path. For every later packet of this connection there will be one, and steps 3 to 5 are skipped.

3. Destination NAT

If the destination matched the external address (and port) of a virtual IP, it would be rewritten here to the internal server's address. Doing this before routing and policy is what makes publishing servers work: the route lookup finds the server's real interface, and the policy is written towards it. The SYN's destination, 198.51.100.80, matches no VIP, so nothing changes.

4. Routing and the reverse path check

The FortiGate looks up 198.51.100.80 in its routing table. The best match is the default route via 203.0.113.1 on port1, so port1 becomes the outgoing interface. That matters for the next step: policies are selected by incoming and outgoing interface, so routing decides which policies are even considered. (A policy route or SD-WAN rule, if configured, is checked before the routing table.)

At the same time the FortiGate runs the reverse path forwarding (RPF) check on the source: is 10.0.1.10 reachable back through port2? It is, through the connected route. A source that isn't reachable through its arrival interface is likely spoofed, and is dropped here, before any policy. By default the check is loose: any route back through that interface, including a default route, passes.

5. Firewall policy

Policies for port2 → port1 are checked from the top of the list. The first policy whose incoming and outgoing interfaces, source, destination, service, schedule and (if set) users all match decides. On FGT1 that is policy 3, LAN-to-Internet. If none matched, the packet would reach the implicit deny (policy 0) and be dropped; no session would be created, so each retry would repeat the whole lookup.

An accept creates the session. From now on the session carries the decision: the policy ID, the interfaces, the NAT to apply, the security profiles, and a timer that is refreshed by traffic. If the policy requires a user group and the source isn't authenticated yet, the FortiGate handles authentication at this point (for example by redirecting a web request to the captive portal).

6. Security inspection

If the policy has security profiles, they now inspect the session. In flow-based mode, the IPS engine examines packets as they pass, in a single pass, without holding whole files; a match can block or reset the session. In proxy-based mode, content is buffered and reassembled (for example a whole file) before it is scanned and released. This SYN carries no data, so there is nothing to inspect yet; the data that follows is.

7. Source NAT

Policy 3 has NAT enabled with no IP pool, so the source is rewritten to port1's address, 203.0.113.2, keeping the source port if it is free. The session records the mapping, so the replies can be translated back without any lookup. Source NAT happens late on purpose: the policy was matched on the original source, so you write policies with your internal addresses.

8. Egress

The packet leaves port1 towards 203.0.113.1. If the outgoing interface were an IPsec tunnel, it would be encrypted first; if a traffic shaper applied, it would be queued accordingly.

Inside the session table

The session is the heart of stateful forwarding, and you can read it. Filter first, so you see only what you are investigating:

diagnose sys session filter clear diagnose sys session filter src 10.0.1.10 diagnose sys session filter dport 443 diagnose sys session list

Filters combine. Always clear old ones first; an old filter left in place is a classic reason for 'no sessions'.

Example output · based on Fortinet documentation; exact format varies by model and FortiOS version
FGT1 # diagnose sys session list
session info: proto=6 proto_state=01 duration=41 expire=3559 timeout=3600 flags=00000000 ...
...
state=log may_dirty f00
statistic(bytes/packets/allow_err): org=2103/12/1 reply=48211/39/1 tuples=2
...
orgin->sink: org pre->post, reply pre->post dev=5->3/3->5 gwy=203.0.113.1/10.0.1.10
hook=post dir=org act=snat 10.0.1.10:51544->198.51.100.80:443(203.0.113.2:51544)
hook=pre dir=reply act=dnat 198.51.100.80:443->203.0.113.2:51544(10.0.1.10:51544)
...
misc=0 policy_id=3 ...
npu_state=0x...
npu info: flag=0x00/0x00, offload=0/0, ips_offload=0/0, ...
total session 1
Illustrative output, trimmed. Read it like this: proto=6 is TCP and proto_state=01 means established; expire counts down and is reset by traffic; dev=5->3/3->5 are the incoming and outgoing interface indexes for each direction; gwy is the next hop each way; the act=snat and act=dnat lines show the translation in brackets for the original and reply directions; policy_id=3 names the policy. The npu fields say whether the session is offloaded; zeros mean it isn't. The exact field names vary between releases and models.

Later packets and return traffic

When the web server answers, the SYN-ACK arrives on port1 addressed to 203.0.113.2:51544. The session lookup finds the session in its reply direction, and everything follows from the entry: the destination is translated back to 10.0.1.10:51544 (the reverse of the source NAT), the packet leaves port2, and the session's security profiles inspect the reply data. There is no routing lookup for the decision, no VIP check, and no policy lookup. That is why replies need no policy of their own, and why a reply that arrives on the wrong interface is a problem (see asymmetric routing below).

Hardware offloading

Most hardware FortiGates have network processors (NPs). Once a session is established on the CPU, the FortiGate can hand it to the NP: the NP keeps a copy of the session and forwards matching packets itself, translating addresses on the way, at line rate and without CPU work. Content processors (CPs) separately accelerate encryption and some inspection work for the CPU.

  • The first packets of every session are always handled by the CPU; only established sessions are offloaded.
  • Offload needs both interfaces to be served by the NP, and a session that doesn't need CPU processing. Proxy-based inspection keeps a session on the CPU; how much flow-based inspection can be offloaded depends on the NP generation.
  • FortiGate VMs have no NP: their "fast path" is in software.
  • Offloaded packets are invisible to the CPU, so the sniffer and debug flow stop seeing them after the start of the session. This surprises many engineers during troubleshooting.
Model and release specific

Which sessions can be offloaded, and with which features, depends on the NP generation of your model and on the FortiOS release. The concepts in this lesson are the same in FortiOS 7.4 and 7.6; the exact capabilities are in the hardware acceleration guide for your release.

Explore it yourself

Pick a scenario and step through it. Watch which stages each packet uses, which it skips, and where its addresses change.

Educational model · simplified FortiOS 7.6 behaviour for the chosen scenario (NAT mode, policy NAT, flow-based inspection). Not a FortiGate.

Choose a packet

Arrives on port2 (LAN): 10.0.1.10:51544 → 198.51.100.80:443 (TCP SYN)
  1. Ingress· processed
  2. Session lookup
  3. Destination NAT
  4. Routing
  5. Policy
  6. Inspection
  7. Source NAT
  8. Egress

Step 1 of 8 · Ingress

The SYN arrives on port2

The interface receives the frame. Basic checks run on the IP header (a malformed header is dropped here), and a DoS policy would be checked if one were configured on port2.

Packet now: 10.0.1.10:51544 → 198.51.100.80:443 (TCP SYN)

See it on a FortiGate: diagnose sniffer packet port2 'host 10.0.1.10 and port 443' 4

When the order is different

The sequence above is not universal. These configurations change it:

ConfigurationWhat changes
Central NATVIPs are applied automatically and policies use the real server address. Source NAT comes from the central SNAT table after the policy decision, not from the policy.
Policy-based NGFW modeSecurity policies can match applications, so the final decision may be made after the first packets, once the application is identified; SSL inspection and authentication are handled by a separate policy first.
Transparent modeThe FortiGate bridges: frames are forwarded by MAC address within a forwarding domain, with no IP routing step, but policies still apply.
IPsecInbound ESP is decrypted at ingress and the inner packet is processed as arriving on the tunnel interface; outbound traffic is encrypted at egress.
Traffic to the FortiGate itselfManagement, ping to its interfaces, VPN negotiation and routing protocols are local traffic, checked against administrative access and local-in policies, not forward policies.
Policy routes and SD-WANThey are consulted before the routing table at step 4, and can choose a different outgoing interface.

Diagnostic commands for each step

QuestionCommand
Did the packet arrive, and did it leave?diagnose sniffer packet any 'host 10.0.1.10' 4
Which route will it use?get router info routing-table details 198.51.100.80
Which policy should it match?Policy & Objects › Firewall Policy › Policy Lookup
What did the FortiGate decide?diagnose debug flow … (below)
Is there a session, translated how, offloaded?diagnose sys session list (with filters)
diagnose debug reset diagnose debug flow filter addr 198.51.100.80 diagnose debug flow show function-name enable diagnose debug console timestamp enable diagnose debug flow trace start 20 diagnose debug enable

Reproduce the problem with a new connection, read the trace, then stop it with diagnose debug disable.

⚠ Use debug safely on production FortiGates

Always set a filter and a packet count before diagnose debug enable; an unfiltered trace on a busy firewall loads the CPU and floods the console. Finish with diagnose debug disable and diagnose debug reset. The sniffer is also CPU work: filter it tightly and stop it with Ctrl+C.

Example output · based on Fortinet documentation; exact format varies by model and FortiOS version
FGT1 # (debug flow for PC1's first packet, trimmed)
msg="vd-root:0 received a packet(proto=6, 10.0.1.10:51544->198.51.100.80:443) from port2. flag [S], ..."
msg="allocate a new session-0003a1f2"
msg="find a route: flag=04000000 gw-203.0.113.1 via port1"
msg="Allowed by Policy-3: SNAT"
msg="SNAT 10.0.1.10->203.0.113.2:51544"
Illustrative output. The lines follow the slow path in order: received on port2, no session so a new one is allocated, route found via port1, policy 3 matched with source NAT, and the translation applied.

Common packet-flow problems

"no session matched": asymmetric routing

A reply (or a later packet) arrives on an interface the session doesn't expect, or arrives without the FortiGate ever seeing the first packet, because traffic leaves through one firewall or path and comes back through another. The FortiGate finds no session for a packet that isn't a new connection, and drops it. Debug flow shows no session matched.

Show the fix

Fix the routing so both directions pass through the same FortiGate (and the same interfaces): check the routes on neighbouring routers and the server's default gateway. FortiOS has a setting that permits asymmetric traffic (set asymroute enable under config system settings), but it weakens stateful protection and is a last resort, not a fix.

"reverse path check fail, drop"

A new connection arrives from a source the FortiGate can't route back through the arrival interface, typically a new subnet behind an internal router that nobody added a route for.

Show the fix

Add the missing route for that subnet via the correct interface and next hop. Don't weaken the check: the drop is correct, and the route is what's missing.

"Denied by forward policy check (policy 0)"

No policy matched, often because routing chose a different outgoing interface than the policy expects.

Show the fix

Check the route first (it decides the outgoing interface), then Policy Lookup for the exact connection, then policy order. Add or correct the policy only after you know which interface pair is being used.

The sniffer shows the start of a connection, then nothing

The session was offloaded to the NP after the first packets, so later packets bypass the CPU where the sniffer and debug flow run. The traffic may be working perfectly.

Show how to see the whole session

Check the session list: offload fields show it was offloaded. If you must capture the whole conversation, disable offload on a test policy that matches only your test traffic:

config firewall policy edit 30 set auto-asic-offload disable next end

Re-enable it (set auto-asic-offload enable) when finished.

⚠ This moves traffic onto the CPU

Every session matching that policy is now processed by the CPU. On a busy policy this can raise CPU load sharply. Use a narrow test policy, in a maintenance window, and switch offload back on afterwards.

Best practices

  • Troubleshoot in packet-flow order: arrival, session, route, policy, NAT, reply. Change one thing at a time.
  • Test with a new connection after every change; existing sessions may still carry the old decision.
  • Filter every diagnostic, limit debug traces, and always disable debug output when finished.
  • Make sure servers and neighbouring routers send replies back through the same FortiGate.
  • Know which of your sessions are offloaded before relying on sniffer captures.

🛠 Practical exercise: trace one connection end to end

On a FortiGate VM in a lab, start a sniffer on the LAN and WAN interfaces filtered for one test host, run debug flow for the same host with a trace count of 20, and open one HTTPS site. Match each debug line to a stage in this lesson, then find the session in diagnose sys session list and identify the translated address and the policy ID. Finally, try a connection your policies don't allow and compare the output. Write down which stage the second connection stopped at, and why.

Key takeaways

✅ Key takeaways
  • The first packet takes the slow path: session lookup, destination NAT, routing and RPF, policy, inspection, source NAT, egress.
  • The resulting session carries every decision; later packets and replies just match it.
  • Destination NAT comes before routing and policy; source NAT comes after the policy.
  • Established sessions can be offloaded to an NP, which hides them from the sniffer and debug flow.
  • Central NAT, NGFW policy mode, transparent mode, IPsec and local traffic change parts of the order.

Check yourself

Predict · scenario 1

An Internet visitor connects to a VIP (203.0.113.20 → WEB1 10.0.2.10). Which address does the routing lookup use?

Predict · scenario 2

PC1's TCP session to a web server is established. Which lookups does the server's next reply packet go through?

Predict · scenario 3

Debug flow for a new connection shows a route found via port1 and then "Denied by forward policy check (policy 0)". What do you know?

Predict · scenario 4

Replies from a server arrive on a different FortiGate interface from the one the requests left, and are dropped with "no session matched". What is the real fix?

Predict · scenario 5

A sniffer shows the first few packets of a large download and then nothing, while the download completes normally. Most likely?

Next in the FortiGate Administration course, these steps are applied to policies in How firewall policies work and diagnosed in Which policy did it hit?.

Official documentation

Links open Fortinet's documentation library for the release; open the named guide and section. RouteLearn is an independent educational resource, not affiliated with or endorsed by Fortinet. Fortinet, FortiGate, FortiOS, FortiManager and FortiGuard are trademarks of Fortinet, Inc. Example output on this page is illustrative.

FAQ

Is there one official order of operations for every FortiGate?
No. The order in this lesson is the common case: NAT mode, policy-based NAT and flow-based inspection. Central NAT, the policy-based NGFW mode, transparent mode, IPsec tunnels and traffic addressed to the FortiGate itself all change parts of it, and hardware models differ in what they can offload. Fortinet's own description of the packet path is the reference for your release and model.
Why doesn't changing a policy affect a connection immediately?
By default FortiOS marks existing sessions to be checked again when the policy table changes, so most changes take effect quickly. Offloaded sessions and some session types can keep going until they are re-evaluated or time out. When testing a change, start a new connection, or clear the specific sessions with a filtered diagnose sys session clear in a maintenance window.
Do security profiles see offloaded traffic?
Not the parts that bypass the CPU. Sessions that need CPU-based inspection, such as proxy-based inspection, generally stay on the CPU, and what can be offloaded with flow-based inspection depends on the network processor generation. Check your model's hardware acceleration guide before relying on either.