# FortiGate is a session factory. First packet vs existing session.

Source: https://ai.techclick.in/blog_fortigate_session_factory
Markdown: https://ai.techclick.in/blog_fortigate_session_factory.md
Publisher: Techclick Infosec Pvt Ltd

FortiGate is a session factory: first packet does VDOM-scoped policy lookup and installs a row. Later packets ride the session table. Prove it with proto_state and iprope.

Quick answer

   A FortiGate VDOM is a  stateful session factory . Official: FortiOS inspects a sequential group of packets as one session instead of judging every packet alone. The  first packet  of a new 5-tuple walks routing, then policy lookup (iprope), then NAT, then  session install . Later packets of the same 5-tuple  hit the session table  and skip that lookup. Success is a live row with  policy_id  matching iprope and  proto_state=11  — not another Accept on the policy list.

   Say this out loud

   I state VDOM and HA role first. Then I ask: is there already a session for this 5-tuple? If yes, I read proto_state and the stamps on that row. If no, I run Policy Lookup / iprope. I do not add Accept rules to fix a one-way handshake, and I do not expect a policy edit to rewrite a session that already exists.

   Hero · one session, not a stack of blades

   Notice: the box is a session factory. Antivirus, IPS and SSL inspect are stamps on that session after policy match.

## 1. Why the session table is the product

 FortiGate interviews die when the student lists UTM blades. Production tickets die the same way. Helpdesk sees  Policy &amp; Objects → Firewall Policy  action Accept and assumes the path is done. Accept only means “this 5-tuple is allowed to become a session.” It does not mean SYN-ACK came back. It does not mean the next packet will walk the policy list again.

 Official session overview: sessions let FortiOS act on a sequential group of packets together. An entry is placed in the session table for each traffic session that passes a security policy. GUI view:  Dashboard → FortiView Sessions  (needs a logging device and traffic log). CLI truth for a hang:  diagnose sys session filter  then  diagnose sys session list . The fields that close INC-4418 are  vd ,  proto_state ,  policy_id , and the SNAT hooks.

#### Concept

 One VDOM, one ingress interface, one first-packet policy lookup, optional SNAT, one session row.

#### Path

 Packet in → session lookup. Miss = install. Hit = ride the existing row. Policy list is not re-walked on every packet.

#### Do

 State VDOM. Filter the lab source  10.10.20.45 . List the session. Compare iprope. Then decide isolate vs change-control.

#### Lab box only

 Hostname  FGT-LAB , serial  FGTVM0LAB000001 , FortiOS 7.4.5 build 2702. RFC 5737 addresses. No live tenant IDs.

   The lie on the ticket

   “Policy 14 is Accept, so we need a new policy.” Accept plus  proto_state=01  is a path problem, not a missing allow. Policy 15 will not finish TCP. The factory already printed the row.

## 2. Mental model — VDOM, lookup, row

 Hold three parts. Interviews fail when people mix them.

#### 1. The factory is the VDOM

     Each VDOM is its own virtual firewall: own interfaces, own routing, own policy list, own session table. Default management VDOM is  root . Traffic in  CustA  is invisible from  root .

#### 2. The hiring manager is policy lookup

     First packet: ingress zone → dest interface from routing → first-match firewall policy (iprope). GUI:  Policy &amp; Objects → Firewall Policy → Policy Lookup . CLI:  diagnose firewall iprope lookup .

#### 3. The ticket is the session row

     After accept, FortiOS installs orig-tuple + reply-tuple, NAT hooks,  policy_id , timeout. Later packets match that row. Helpers and NPU offload change what you see, not the story.

#### 4. Proof is diagnose, not the GUI checkbox

     FortiView Sessions is history plus live when logging works.  diagnose sys session list  is the live table. iprope is predicted. Those three disagree on purpose — that is the ticket.

   Path · six stations on first packet

   Read left to right. Those stations run on the first packet of a new 5-tuple. Existing sessions skip the middle of this line.

   Flow 1 · factory stamps on one session

       FortiOS session factory: VDOM, zone, policy lookup, SNAT, session row

- First packet in this VDOM → five stamps → session row 1 VDOM root / CustA 2 Zone / IF port2 → LAN 3 Policy iprope → id=14 4 SNAT 203.0.113.20 5 Session row proto_state · policy_id Lab tuple (dummy · RFC 5737) 10.10.20.45:51990 → 198.51.100.80:443 · SNAT 203.0.113.20:18422 · policy 14 · vd=0 (root) UTM blades sit on the session after policy match. They are not the factory. Read left → right. If you skip VDOM, the empty session table is a lie you told yourself. Pre-train the hard words 5-tuple = src IP, dst IP, src port, dst port, protocol — plus the VDOM that owns the table. iprope is FortiOS policy lookup (predicted). proto_state is handshake language: lab teaching value 01 = SYN seen / incomplete; official Admin Guide sample for a live HTTPS session is 11 (established). vd on the session row is the VDOM index. Policy Lookup in the GUI is the same predicted match as iprope, not the live table. ## 3. First packet vs existing session The diamond is not “is Accept checked.” The diamond is “does this 5-tuple already have a session in this VDOM?” That is why “I added a rule” sometimes changes nothing until the old row dies. Decision · first packet or existing row Notice: the split is not allow/deny. It is “session already exists?” Flow 2 · first packet setup vs ride the table FortiOS first-packet policy lookup versus existing session table hit Ingress → session lookup → install or ride 1 Ingress port2 · VDOM Session? 5-tuple + vd no FIRST PACKET — print a new row this 5-tuple is new in this VDOM Route / dest IF outgoing zone Policy lookup iprope first-match NAT + profiles SNAT / VIP / UTM Session install orig + reply tuples · policy_id EXISTING SESSION — later packets of the same 5-tuple skip policy list · refresh timeout · apply the stamps already on the row · egress yes → ride table Facts students invert 1. Policy Lookup / iprope is predicted. diagnose sys session list is live. They can disagree. 2. Editing policy 14 does not rewrite a row that already exists. Clear that tuple, or wait for timeout. 3. proto_state=01 after 40+ seconds is SYN without SYN-ACK — not a missing Accept. 4. Empty table on the HA standby or in the wrong VDOM is self-inflicted. State role + vd first. Sources: FortiOS Admin Guide · Using a session table · Configuring a firewall policy · diagnose firewall iprope lookup Read the diamond first. Left/green = already a session. Top bar = first packet. Bottom box = the four traps this page exists to kill. Pipeline · packet → lookup → row → reply Notice: reply traffic matches the session’s reply-tuple. It does not need a second Accept. #1 student trap — I added a rule and nothing changed The first packet already printed a row. Later packets ride that row with the old policy_id , old SNAT, old outgoing interface. iprope now says the new policy. The live list still says 14. That is not FortiOS being broken. Clear only the filtered lab tuple after change-control — never diagnose sys session clear with no filter on a production box. ## 4. How to choose the next proof If X then Y. Do not mix predicted match with a live row, and do not mix “member is up” with “session is established.” Situation Prefer Do not Browser connecting, policy already Accept Filter + diagnose sys session list . Read proto_state before you clone a policy. Add policy 15 Any-Any “just for the ticket.” Need to know which policy should hit GUI Policy Lookup or diagnose firewall iprope lookup Treat iprope as proof the handshake finished. Just edited NAT / outgoing IF / profile Filtered session clear of that 5-tuple, then one new first packet Expect existing rows to pick up the edit. Empty session table after failover get system status + get system ha status + VDOM selector Clone every root policy into the customer VDOM. MSSP / multi-tenant box Switch VDOM (top bar or config vdom / edit CustA ) before any session command Reading root sessions for traffic that lives in CustA . Need packet-by-packet story Filtered diagnose debug flow , then disable + reset Unfiltered flow left on overnight. Source for the choose table Firewall Policy and Policy Lookup: FortiOS Administration Guide — Configuring a firewall policy. Session table fields and diagnose sys session list : Using a session table (sample proto_state=11 ). iprope: FortiOS CLI Reference — diagnose firewall iprope lookup . VDOM scope: VDOM overview (management VDOM defaults to root ). ## 5. Runbook Side A → B → C Goal on FGT-LAB: Finance host 10.10.20.45 reaches 198.51.100.80:443 through policy 14 Finance-SaaS , SNAT pool 203.0.113.20 , in VDOM root on the HA primary. Prove it with session fields, not a new Accept. ### Side A — identity of the factory #### State VDOM and HA before any object edit GUI: top-bar VDOM selector (when VDOMs are on) and System → HA . CLI: get system status then get system ha status . Lab expected: NAT mode, HA A-P, this unit master / Primary FGT-LAB , current virtual domain root . Source: VDOM overview + HA status.

- #### Map the ingress interface into a zone Network → Interfaces and Network → Interfaces → Zone . Official: a zone groups one or more interfaces so policies can match the group. Lab: port2 in LAN, port1 in WAN. Policies match zones unless you designed interface-to-interface on purpose.

- #### Address and service objects Policy & Objects → Addresses / Services . Lab: source 10.10.20.0/24 , destination 198.51.100.80 , service HTTPS. No live customer FQDN.

### Side B — policy lookup, then NAT

- #### Edit the existing accept — do not clone first Policy & Objects → Firewall Policy → policy 14 Finance-SaaS . Incoming LAN, outgoing WAN, NAT on, log enabled, schedule always. Source: Configuring a firewall policy.

- #### Run Policy Lookup before you save a second rule Same menu: Policy Lookup . Fill source IP, dest IP, dest port, protocol, source interface. Lab must predict policy 14. CLI equivalent: diagnose firewall iprope lookup 10.10.20.45 51990 198.51.100.80 443 tcp .

- #### Bind SNAT you can quote Either NAT enable on the policy or Policy & Objects → Central SNAT + IP Pools . Lab reply tuple must show 203.0.113.20:18422 . If the pool is exhausted or the ISP does not own that IP, proto_state stays 01.

     https://fgt-lab.example.com/#/policy/firewall/lookup

     Training mock · not live

       Policy &amp; Objects → Firewall Policy → Policy Lookup

### Policy Lookup

        IPv4  IPv6

          Source Interface  LAN (port2)

          Protocol  TCP

          Source Address  10.10.20.45

          Source Port  51990

          Destination Address  198.51.100.80

          Destination Port  443

         Reset
         Search

        Matched policy 14 Finance-SaaS  · incoming LAN · outgoing WAN · action ACCEPT · NAT enable. This is predicted — not the live session.

    FortiOS Administration Guide · Configuring a firewall policy  + CLI Reference ·  diagnose firewall iprope lookup . Next click: retest the same 5-tuple, then  diagnose sys session list . Do not add policy 15 from this screen.

     https://fgt-lab.example.com/#/policy/firewall/edit/14

     Training mock · not live

       Policy &amp; Objects → Firewall Policy → Edit Policy 14

### Edit Firewall Policy

        Policy  Security Profiles  Logging

          Name  Finance-SaaS

          Policy ID  14

          Incoming Interface  LAN (port2)

          Outgoing Interface  WAN (port1)

          Source  LAN-Finance 10.10.20.0/24

          Destination  SaaS-VIP 198.51.100.80

          Service  HTTPS

          Action  ACCEPT · NAT enable · IP pool WAN-SNAT 203.0.113.20

            Log Allowed Traffic — All Sessions

       VDOM context:  root . Saving this does not rewrite a session that already exists.

         Cancel
         OK

    FortiOS Administration Guide · Configuring a firewall policy.  After OK: one new first packet, then session list. Existing rows keep the old stamps until timeout or a filtered clear.

### Side C — prove, do not hope

- #### Predicted match iprope / Policy Lookup must print matched policy: id=14 name=Finance-SaaS , srcintf=port2 dstintf=port1 , nat=1 .

- #### Live session Filter source, then list. Success is proto_state=11 , same policy_id=14 , SNAT hook present, vd is this VDOM. Fail is 01 with a long duration — first packet installed, reply never arrived.

- #### User transaction, then stop debug A real HTTPS GET. If you used debug flow, filter the addr, capture the tuple, then diagnose debug disable and diagnose debug reset . Green HA is not a recovered login.

## 6. Runtime CLI on FGT-LAB

 Commands below match official FortiOS diagnose syntax. Output is dummy lab (RFC 5737). Confirm the field names on your production release before you type on a real box. Never leave debug flow on.

   Proof · the desk that closes the ticket

   Notice: success is fields you can quote — vd, policy_id, proto_state, SNAT hook — not “we added an allow.”

  FGT-LAB # get system status
 Version: FortiGate-VM64 v7.4.5,build2702,240822 (GA.M)
Serial-Number: FGTVM0LAB000001
Hostname: FGT-LAB
Operation Mode: NAT
Current virtual domain: root
Current HA mode: a-p, master
Cluster uptime: 14 days 2:11:08

 What it proves: build, NAT mode,  this VDOM , this unit is HA master. What it does not prove: a healthy Finance session.

  FGT-LAB (root) # diagnose sys session filter clear
FGT-LAB (root) # diagnose sys session filter src 10.10.20.45
FGT-LAB (root) # diagnose sys session filter dst 198.51.100.80
FGT-LAB (root) # diagnose sys session filter dport 443
FGT-LAB (root) # diagnose sys session filter proto 6
FGT-LAB (root) # diagnose sys session filter
 session filter:
        vd: 0
        proto: 6
        src: 10.10.20.45-10.10.20.45
        dst: 198.51.100.80-198.51.100.80
        dport: 443-443
filter applied.

 Filter is armed. It does not list sessions. Forgetting this step — or forgetting you are still in  root  — is a junior FortiOS miss. Official:  diagnose sys session filter  then  list  (Using a session table).

  FGT-LAB (root) # diagnose sys session list
 session info: proto=6 proto_state=01 duration=48 expire=3552 timeout=3600
  orig-tuple: 10.10.20.45:51990 -&gt; 198.51.100.80:443
  reply-tuple: 198.51.100.80:443 -&gt; 203.0.113.20:18422
  hook=post dir=org act=snat 10.10.20.45:51990-&gt;203.0.113.20:18422
  hook=pre dir=reply act=dnat 198.51.100.80:443-&gt;10.10.20.45:51990
  policy_id=14 pol_idx=0 auth=no
  npu_state=00000000
  total: 1 session listed

   Green success = these fields

- vd / current virtual domain is the one that owns Finance (lab: root, index 0).

- policy_id=14 matches iprope — not a miss, not policy 15.

- SNAT hook to 203.0.113.20:18422 is present. Reply-tuple uses that address.

- Fail close: proto_state=01 after 48 seconds. First packet installed. SYN-ACK never arrived.

- Pass close (what you want after the fix): proto_state=11 as in the Admin Guide HTTPS sample, plus bytes both directions.

  FGT-LAB (root) # diagnose firewall iprope lookup 10.10.20.45 51990 198.51.100.80 443 tcp
 lookup: proto=6 10.10.20.45:51990 -&gt; 198.51.100.80:443
matched policy: id=14 name=Finance-SaaS
  srcintf=port2 dstintf=port1
  action=accept nat=1 log=enable
  schedule=always service=HTTPS

 Official CLI: “Lookup firewall policy that matches provided criteria.” Prediction is not the live session. Compare  policy_id  in the list output. If they disagree, the first packet already installed an older row — isolate why. Do not add a third policy.

  FGT-LAB (root) # diagnose debug flow filter addr 10.10.20.45
FGT-LAB (root) # diagnose debug flow show function-name enable
FGT-LAB (root) # diagnose debug console timestamp enable
FGT-LAB (root) # diagnose debug flow trace start 10
FGT-LAB (root) # diagnose debug enable
 id=20085 trace_id=17 func=print_pkt_detail msg='vd-root:0 received a packet(proto=6, 10.10.20.45:51990-&gt;198.51.100.80:443) from port2.'
id=20085 trace_id=17 func=fw_forward_handler msg='Check iprope policy, result=ok policy 14'
id=20085 trace_id=17 func=fw_forward_handler msg='SNAT 10.10.20.45-&gt;203.0.113.20:18422'
id=20085 trace_id=17 func=ip_session_install msg='session installed'

 Flow shows receive, policy 14, SNAT,  session install  — that is the first-packet path. It does  not  show the server SYN-ACK. That is why proto_state stays 01. Filter tightly. Then:

  Turn it off
 diagnose debug disable
diagnose debug reset
diagnose debug flow filter clear

## 7. Traps + proof checklist

     Symptom  Likely cause  First check  Unsafe change

      Accept + connecting spinner  First packet installed;  proto_state=01   Session list + return path + SNAT pool  Add policy 15
      Policy edited, traffic still old  Existing session riding old stamps  Compare iprope vs  policy_id  on the row  Delete the whole session table
      Empty session table after failover  Standby unit or wrong VDOM   get system status  + HA + VDOM selector  Clone all policies in root
      iprope says 14, session says other  Predicted vs live cache  Filtered clear of the lab tuple after change-control  A third Accept “to be safe”
      debug flow left on  CPU / log flood  Filter addr + disable + reset  Unfiltered flow on production
      Session in CustA, you listed root  VDOM-scoped table  Top-bar selector or  config vdom  /  edit CustA   Invent a missing policy in root

   Isolate vs change-control

   Isolate with read-only diagnose: status, HA, VDOM, session filter/list, iprope, routing table. Change-control is a new policy, NAT pool, or a filtered session clear — one owner, one reversible change, same 5-tuple retest.  diagnose debug flow  is isolate only when filtered and turned off.

   Proof checklist

- Quoted VDOM and HA role (Primary FGT-LAB , vd root in the lab).

- iprope / Policy Lookup = policy 14 accept + NAT.

- Live session policy_id=14 and proto_state=11 after the fix.

- SNAT pool address appears on the reply tuple.

- If you changed policy, you generated a new first packet (or cleared that tuple) so the factory reprinted the row.

- User HTTPS works once; ticket cites the fields, not “we added an allow.”

  Interview close:  “FortiGate is a session factory. I state VDOM and HA role, then I ask whether a session already exists. First packet does policy lookup and installs the row. Later packets ride it. I quote proto_state and iprope. I do not add Accept rules to fix a one-way handshake.”

## Knowledge check

   Six judgment items. Map each to a promise bullet or trap. Check answers, then Reset if you miss.

       Q1
       Policy 14 is Accept. The browser stays on connecting. Dummy session shows  proto_state=01  and SNAT to 203.0.113.20. First move?

           Add policy 15 Any-Any above the implicit deny
           Treat this as an installed first-packet row that never finished TCP — prove return path, SNAT pool and SYN-ACK
           Disable UTM on every policy
           Fail over HA immediately without quoting the primary

       Correct:  b . Quick answer / Flow 2. Accept already happened; the factory printed a row.  01  is an unfinished handshake. Re-read Runtime CLI.

       Q2
       What is the real diamond on a FortiGate packet?

           Does this 5-tuple already have a session in this VDOM? First packet walks policy lookup and installs; later packets ride that row
           Is Accept checked on any policy in any VDOM?
           Is the NPU license valid?
           Did FortiView Sessions show a historical allow?

       Correct:  a . Mental model + Flow 2. Policy list is not re-walked on every packet. Re-read First packet vs existing session.

       Q3
       After a power event the cluster widget is green and the session table looks empty. What do you state first?

           HA is fine — open a circuit ticket
           VDOM and HA role (primary vs standby, current virtual domain) before you trust the table or add a policy
           Reboot both units together
           Copy every root policy into CustA without looking

       Correct:  b . Traps table. Empty table on standby or in the wrong VDOM is self-inflicted. Re-read Side A.

       Q4
       You changed the SNAT pool on policy 14. iprope now shows the new pool. The live HTTPS session still SNATs to the old address. Why?

           FortiOS ignores Central SNAT after the first commit
           You must disable NAT to apply a new pool
           The existing session keeps its old stamps until timeout or a filtered clear — iprope is the next first packet
           proto_state=11 means NAT is disabled

       Correct:  c . Flow 2 fact 2 / How to choose. Later packets ride the row. Re-read the first-packet trap.

       Q5
       Policy Lookup /  diagnose firewall iprope lookup  prints policy 14 accept+NAT. What does that prove?

           The live handshake is established
           SNAT is disabled
           You should add a duplicate policy
           Predicted match only — compare policy_id on diagnose sys session list

       Correct:  d . Runtime CLI. iprope is FortiGate’s policy-test equivalent, not the session. Re-read Side C.

       Q6
       How do you use  diagnose debug flow  on a real box?

           Filter the addr, capture the tuple, then disable and reset — it is powerful and dangerous live
           Leave it on overnight for the NOC
           Run it unfiltered instead of the session table
           It always prints the server SYN-ACK, so proto_state is redundant

       Correct:  a . Lab dummy flow stops at session install (first packet). Isolate vs change-control. Re-read traps.

       Check answers
       Reset

## Sources

- FortiOS 7.4 Administration Guide — Using a session table ( diagnose sys session filter / list ; sessions are sequential packet groups; policy number on the row)

- FortiOS 8.0 Administration Guide — Using a session table (sample session info: proto=6 proto_state=11 )

- FortiOS 7.4 Administration Guide — Configuring a firewall policy (Policy & Objects → Firewall Policy; Incoming / Outgoing Interface, NAT, log)

- FortiOS 7.4 Administration Guide — Zone

- FortiOS 7.4 Administration Guide — FortiView Sessions (Dashboard → FortiView Sessions)

- FortiOS Administration Guide — VDOM overview (management VDOM defaults to root; each VDOM is a virtual firewall)

- FortiOS CLI Reference — diagnose firewall ( diagnose firewall iprope lookup — lookup policy that matches provided criteria)

- FortiOS Hardware Acceleration — diagnose sys session list (sample proto_state=01 )

- FortiOS Cookbook — Debugging the packet flow ( diagnose debug flow ; filter and turn off)

 Related:  FortiGate evidence desk  ·  FortiGate policy lookup + NAT  ·  FortiGate VDOMs  ·  FortiGate interview  ·  FortiGate hub

---
Cite this Techclick lesson with the source URL. Do not invent fees, batch dates, or job guarantees.
Browse all lessons: https://ai.techclick.in/blogs
AI index: https://ai.techclick.in/llms.txt
