If you've spent any time configuring user authentication on... Full Story
By Manny Fernandez
September 25, 2026
diagnose firewall iprope: Reading the FortiGate Policy Engine From the Kernel Up
What the kernel actually enforces, how to read it, and the troubleshooting workflows that make it worth knowing
Executive Summary
Every FortiGate admin knows show firewall policy. Far fewer know what happens after you type end. FortiOS compiles each policy into kernel rule entries, called iprope entries, grouped by function (forward traffic, local-in, VIP, implicit, shaping, and more). The packet path is evaluated against those compiled entries, not against your CLI text.
diagnose firewall iprope is the window into that compiled table. It shows what the kernel is really enforcing (including resolved FQDN and dynamic address ranges), per-policy packet and hit counters, a policy match simulator, and a live “top” view of your busiest rules. If you have ever asked “why is this traffic hitting that policy?” or “is this rule even used?”, this is the command family you want.
| Item | Detail |
|---|---|
| Objective | Understand every diagnose firewall iprope subcommand, decode its output, and apply it to real troubleshooting and policy hygiene workflows |
| Audience | FortiGate administrators, SEs, and SOC/NOC engineers comfortable in the FortiOS CLI |
| Tested against | FortiOS 7.0 through 7.6 CLI syntax (8.0 CLI reference lists the same subcommands). Output layout shifts slightly between builds. |
| Lab addressing | 10.0.0.0/16 for internal LANs, 198.18.0.0/15 for public/transit |
1. What iprope Actually Is
Think of config firewall policy as source code and iprope as the compiled binary. When a policy is saved, FortiOS translates it into a kernel entry: interface names become interface indexes, address objects become numeric IP ranges, services become protocol and port tuples, and security profile settings become flags. Those entries live in numbered policy groups, and the kernel walks the relevant group when a new session needs a verdict.
Three things follow from that:
- The kernel view can differ from the config view. An FQDN that never resolved, an empty address group, or a dynamic address with no members compiles to something that will not match what you expect.
iprope listshows you the truth. - Hidden policies exist. Implicit deny, local-in rules generated from interface
allowaccess, VIP handling, and similar entries live in their own groups and are visible here even when the GUI hides them. - Counters live at the kernel. The Bytes, Hit Count, and Last Used columns in the GUI are read from these same counters.
config vdom then edit <vdom>) or you will be reading the wrong table. IPv6 has a parallel command tree: diagnose firewall iprope6 with the same subcommands.2. Subcommand Map
| Subcommand | What it does | Typical use |
|---|---|---|
list [group] [id] |
Dumps compiled kernel entries for a group (or all groups) | Verify what is actually enforced, check resolved objects |
show <group> <id> [id...] |
Per-policy statistics: packets, bytes, offload counters, hit count, first/last hit | Is this rule used? Is traffic offloaded? |
clear <group> [id...] |
Resets statistics for one or more policies | Clean before/after test |
lookup <5-tuple> <intf> ... |
Simulates the policy match for a flow | Which policy will this traffic hit? |
state |
Engine allocation counters and the list of active groups | Discover group IDs, health snapshot |
top <group> <sort> ... |
Live ranked view of the busiest policies | Find the rules carrying the load |
appctrl ... |
Kernel-side application control list data | Legacy app control troubleshooting |
3. Policy Groups: The Numbers That Matter
Most iprope subcommands take a group ID. Group IDs are hexadecimal, and the leading zeros are optional, so 100004 and 00100004 are the same group. These are the ones you will use most:
| Group | Contents |
|---|---|
00100004 |
Standard firewall policies (forward traffic). This is your config firewall policy table and the group you will use 90% of the time. |
00100001 |
Local-in policies (traffic destined to the FortiGate itself) |
00100000 |
VIP-related firewall policy entries |
00100002 |
Static SNAT entries |
0010000e |
Implicit policies as shown in the GUI |
00100015 |
Traffic shaping policies |
diagnose firewall iprope state on your build; the total group number line and the hex IDs after it tell you exactly which groups exist. Then list each one you are curious about.4. iprope list: The Compiled Policy Table
Syntax
diagnose firewall iprope list # every group (long!)
diagnose firewall iprope list 100004 # all forward policies
diagnose firewall iprope list 100004 12 # only policy ID 12
On a busy firewall the unfiltered output is thousands of lines. Scope it by group and ID, or pipe through FortiOS grep with context lines:
diagnose firewall iprope list 100004 | grep -A 15 "index=12 "
Sample output
Representative output for a LAN-to-internet policy with NAT and security profiles (exact lines vary by build):
FGT-EDGE (root) # diagnose firewall iprope list 100004 12
policy index=12 uuid_idx=731 action=accept
flag (8050108): redir nat master use_src pol_stats
flag2 (4000): resolve_sso
flag3 (a0): link-local best-route
schedule(always)
cos_fwd=255 cos_rev=255
group=00100004 av=00004e20 au=00000000 split=00000000
host=4 chk_client_info=0x0 app_list=0 ips_view=0
misc=0 dd_type=0 dd_mode=0
zone(1): 9 -> zone(1): 5
source(1): 10.0.10.0-10.0.10.255, uuid_idx=402,
dest(1): 0.0.0.0-255.255.255.255, uuid_idx=6,
service(1):
[6:0x0:0/(0,65535)->(443,443)] helper:auto
Field reference
| Field | Meaning | What to look for |
|---|---|---|
index |
Policy ID from config firewall policy |
Matches edit <id>, not the GUI sequence number |
uuid_idx |
Kernel index of the policy UUID | Correlates with UUID-based logging |
action |
accept or deny | A deny you did not expect is a config problem, not a kernel one |
flag / flag2 / flag3 |
Hex bitmask plus decoded names | nat means SNAT is on; pol_stats means counters are collected; redir typically appears when traffic is handed to an inspection daemon. Compare against a known-good policy rather than memorizing bits. |
schedule(...) |
Attached schedule | A recurring or one-time schedule outside its window means the entry will not match |
group |
Group this entry belongs to | Confirms you are reading the right table |
zone(n): A -> zone(n): B |
Ingress and egress interface indexes | Map indexes to names with diagnose netlink interface list |
source(n) / dest(n) |
Resolved IP ranges, count in parentheses | The single most useful line. FQDN, geo, and dynamic objects show their resolved ranges here. A count of 0 or a missing range means the object resolved to nothing. |
service(n) |
[proto:flags:src-ports->dst-ports] tuples |
Protocol 0 means any. (0,65535) source port is normal. |
To translate the zone indexes into interface names:
diagnose netlink interface list | grep "index=9 "
diagnose netlink interface list | grep "index=5 "
5. iprope show: Per-Policy Statistics
Syntax
diagnose firewall iprope show 100004 12
diagnose firewall iprope show 100004 12 14 27 31 # several IDs at once
diagnose firewall iprope show 100001 3 # a local-in policy
There is a practical limit on how many IDs one command accepts (community reports put it around a dozen), so batch large audits.
Sample output
FGT-EDGE (root) # diagnose firewall iprope show 100004 12
idx=12 pkts/bytes=14709/18777329 asic_pkts/asic_bytes=8087/10413737
nturbo_pkts/nturbo_bytes=8087/10413737 flag=0x0
hit count:19 (4 7 0 1 1 3 3 0) first:2026-09-17 17:09:00
last:2026-09-23 17:23:40 established session count:0
first est:2026-09-17 17:11:20 last est:2026-09-23 17:23:40
| Field | Meaning |
|---|---|
pkts/bytes |
Traffic counted against the policy. On NP-equipped hardware, the CPU-path counts are typically the smaller number. |
asic_pkts/asic_bytes |
Traffic handled by the NP processor (hardware offload) |
nturbo_pkts/nturbo_bytes |
Traffic accelerated through nTurbo (IPS/flow inspection fast path) |
hit count |
Number of times the policy was matched for a new session |
(4 7 0 1 ...) |
Seven-day rolling counter: the current day plus the previous seven days of hit counts, so you can see trend, not just a lifetime total |
first / last |
First and most recent hit timestamps |
established session count |
Sessions currently active on this policy |
first est / last est |
First and most recent established session timestamps |
pkts barely moves while asic_pkts climbs, the policy is working and the NP is doing the heavy lifting. If asic_pkts stays at 0 on hardware that should offload, check whether a proxy-based profile, a session helper, or auto-asic-offload disable is keeping the traffic on the CPU.6. iprope clear: Reset the Counters
diagnose firewall iprope clear 100004 12 # one policy
diagnose firewall iprope clear 100004 3 12 48 4 # several policies
diagnose firewall iprope clear 100004 # EVERY policy in the group
Clearing only zeros the statistics; the policy itself is untouched. It is also the same reset as right-clicking a policy in the GUI and choosing Clear Counters, so the GUI Hit Count and Last Used columns reset too.
clear with a group and no policy ID wipes the counters for the whole group. If someone is relying on hit counts for an unused-rule audit, you just destroyed their data. These counters survive a reboot, so they are often the only long-term usage record on a box without FortiAnalyzer.7. iprope lookup: The Policy Match Simulator
lookup answers “which policy would this flow hit?” without sending a packet. It is the CLI equivalent of the GUI Policy Lookup tool (renamed Policy Match in 7.4).
Syntax
diagnose firewall iprope lookup <src_ip> <src_port> <dst_ip> <dst_port> \
<protocol> <src_interface> [<pol_type>] [<auth_type>] [<user/group>] \
[<server>] [<user-db>] [<group-attr-type>]
| Argument | Notes |
|---|---|
src_ip / src_port |
Client address and port. Port 0 is fine for most lookups. |
dst_ip / dst_port |
Destination. For ICMP, this field takes type/code, for example 8/0 for echo request. |
protocol |
Protocol number (6 TCP, 17 UDP, 1 ICMP). Many builds also accept tcp/udp; numbers are the safe choice. |
src_interface |
The ingress interface name, exactly as FortiOS names it (port5, internal, a VLAN, a tunnel, ssl.root) |
pol_type |
Newer builds: policy (firewall policy) or proxy (explicit proxy policy) |
auth arguments |
Newer builds: auth type (ldap, saml, local, group), user or group name, server, user database, and group attribute type, for identity-based policies |
The argument list grew across releases. Type the command through the interface name and press ? to see exactly what your build accepts.
Examples
# HTTPS from a LAN client to a public server
diagnose firewall iprope lookup 10.0.10.25 51514 198.18.40.10 443 6 port5
<src [10.0.10.25-51514] dst [198.18.40.10-443] proto 6 dev port5>
matches policy id: 12
# DNS over UDP
diagnose firewall iprope lookup 10.0.10.25 0 198.18.53.53 53 17 port5
<src [10.0.10.25-0] dst [198.18.53.53-53] proto 17 dev port5> matches policy id: 14
# ICMP echo request (type/code in the dst_port field)
diagnose firewall iprope lookup 10.0.10.25 0 198.18.40.10 8/0 1 port5
# Explicitly test a firewall policy (not a proxy policy) on newer builds
diagnose firewall iprope lookup 10.0.10.25 0 198.18.40.10 443 6 port5 policy
matches policy id: 0 means implicit deny.** Nothing in the table matched. Before you blame the policy, check the gotchas in section 11: a missing route, the wrong VRF, or an identity-based policy are the usual reasons a correct-looking rule is skipped.Remember that lookup is a simulation. It is excellent for “what should happen”, but when a real flow misbehaves, confirm with a flow trace (section 10), which reports the policy the packet actually hit.
8. iprope state: Engine Snapshot and Group Discovery
diagnose firewall iprope state
The output includes allocation counters for the policy engine (iprope entries, shapers, users, nodes, policies) and a total group number line followed by the hex IDs of every active group. Two practical uses:
- Group discovery. The IDs listed here are the valid arguments for
list,show, andtopon this build. - Health snapshot. Fortinet includes
diagnose firewall iprope statein its own high-CPU and high-memory automation stitch examples, so it belongs in any diagnostic capture script you run through an automation stitch CLI action.
9. iprope top: Your Busiest Rules, Live
Newer builds (the 7.6 and 8.0 CLI references list it) add a top-style view of policy statistics within a group.
diagnose firewall iprope top <group> <sort_key> [delay_sec] [count] [iterations]
| Argument | Values |
|---|---|
sort_key |
pkts, asic-pkts, hit-count, nturbo-pkts, tcp-ses, udp-ses, sctp-ses, all-ses, each also available with a -rate suffix (for example hit-count-rate) |
delay_sec |
Refresh interval, default 5 |
count |
Number of policies to display, default 10 |
iterations |
Number of refreshes, default unlimited. Press Ctrl+C to exit an unlimited run. |
# Top 10 forward policies by new-session rate, refresh every 5s, 3 cycles
diagnose firewall iprope top 100004 hit-count-rate 5 10 3
# Which rules are carrying the most CPU-path packets right now?
diagnose firewall iprope top 100004 pkts-rate 2 15
The -rate keys are the interesting ones during an incident: they show what is hot right now rather than what has accumulated since the last counter reset. A sudden spike in pkts-rate on a rule that should be offloaded is a strong hint about a CPU problem.
10. Practitioner Workflows
Workflow A: “Why is this traffic hitting the wrong policy?”
Goal: go from symptom to root cause in three commands.
# 1. What SHOULD happen?
diagnose firewall iprope lookup 10.0.10.25 0 198.18.40.10 443 6 port5
# 2. What does the kernel think that policy contains?
diagnose firewall iprope list 100004 12
# 3. What DOES happen to a real packet?
diagnose debug reset
diagnose debug flow filter addr 198.18.40.10
diagnose debug flow filter port 443
diagnose debug flow show function-name enable
diagnose debug flow trace start 20
diagnose debug enable
# ...generate traffic, then look for "Allowed by Policy-N"
# or "Denied by forward policy check"
diagnose debug disable
diagnose debug reset
If the lookup and the flow trace disagree, the difference is almost always routing (the trace shows the egress interface the route actually selected) or identity (the trace was for an unauthenticated user).
Workflow B: Unused and shadowed rule audit
Goal: find policies with zero or stale hits before a cleanup.
# Batch the IDs you want to review
diagnose firewall iprope show 100004 3 4 7 9 12 14 18 21 22 27
# Look for: hit count:0, or a 'last:' date months in the past,
# or a rolling counter of (0 0 0 0 0 0 0 0) over a busy week
A policy that never gets hits while a broader policy above it is busy is a shadowing candidate. Confirm with lookup using a flow that the lower policy was written for; if the answer is the upper policy ID, the lower one is shadowed.
Workflow C: Did that FQDN or dynamic address actually resolve?
diagnose firewall iprope list 100004 31 | grep -A 3 "dest("
# Cross-check the object itself
diagnose firewall fqdn list-ip
diagnose firewall dynamic list
If dest(0) appears, or the ranges do not include the IP you expect, the policy cannot match that destination no matter how correct the config looks. Fix DNS (for FQDN objects) or the connector (for dynamic objects) first.
Workflow D: Audit what can reach the FortiGate itself
diagnose firewall iprope list 100001
# Compare with the configured local-in policies
show firewall local-in-policy
Group 00100001 includes entries you never typed, derived from interface allowaccess and enabled services. It is a fast way to confirm that management exposure on a WAN interface is what you think it is.
Workflow E: Confirm a FortiManager install landed
show firewall policy 12
diagnose firewall iprope list 100004 12
If the config shows the new address object but the kernel source() or dest() ranges still reflect the old one, the install did not fully apply, or an object in the new policy failed to resolve.
Workflow F: Controlled before and after test
diagnose firewall iprope clear 100004 12
# ...generate a known test flow from 10.0.10.25...
diagnose firewall iprope show 100004 12
# See the sessions riding the policy right now
diagnose sys session filter clear
diagnose sys session filter policy 12
diagnose sys session list
11. Troubleshooting and Gotchas
| Symptom | Likely cause | Fix |
|---|---|---|
lookup returns policy 0 for traffic that clearly should match |
No route to the destination (egress interface cannot be resolved), wrong VRF, or the policy requires user/group identity | Check get router info routing-table details <dst>; add the auth arguments on newer builds; confirm with debug flow |
lookup fails or errors on ICMP |
Destination port field syntax | Use type/code in the dst_port field (for example 8/0) with protocol 1; fall back to the GUI Policy Match tool |
show counters never move |
Wrong VDOM, wrong group, or you are looking only at pkts while traffic is offloaded |
Enter the right VDOM, confirm the group with state, and read asic_pkts |
list shows dest(0) or unexpected ranges |
FQDN unresolved, empty address group, dynamic object with no members | diagnose firewall fqdn list-ip, diagnose firewall dynamic list, fix DNS or the connector |
| “Invalid” or empty output for a group | Group ID typo or group not present on this build | Group IDs are hex; run diagnose firewall iprope state for the valid list |
| Hit counts disappeared | Someone ran clear with no policy ID |
Nothing to recover locally; pull historical usage from FortiAnalyzer logs |
12. Related Commands
| Command | Why you would pair it with iprope |
|---|---|
diagnose debug flow ... |
Ground truth for a real packet: routing decision and actual policy hit |
diagnose sys session filter policy <id> |
List live sessions on a policy |
diagnose netlink interface list |
Map zone() indexes to interface names |
diagnose firewall proute list |
Policy routes, the iprope sibling for PBR |
diagnose firewall fqdn list-ip |
Verify FQDN object resolution |
diagnose firewall dynamic list |
Verify dynamic (SDN/EMS/fabric) address membership |
diagnose firewall iprope6 ... |
The IPv6 mirror of every command in this post |
13. Quick Reference
# Discover groups on this build
diagnose firewall iprope state
# Compiled entry for forward policy 12
diagnose firewall iprope list 100004 12
# Stats for one or more policies
diagnose firewall iprope show 100004 12 14
# Reset stats (ALWAYS give an ID unless you mean the whole group)
diagnose firewall iprope clear 100004 12
# Which policy will this flow hit?
diagnose firewall iprope lookup 10.0.10.25 0 198.18.40.10 443 6 port5
# Live top 10 by new-session rate
diagnose firewall iprope top 100004 hit-count-rate 5 10
# Local-in table (includes allowaccess-derived entries)
diagnose firewall iprope list 100001
# IPv6 equivalents
diagnose firewall iprope6 lookup <args>
diagnose firewall iprope6 show 100004 12
Bottom line: show firewall policy tells you what you asked for. diagnose firewall iprope tells you what the kernel is doing about it. When those two disagree, the kernel wins every time.
Recent posts
-
-
DNS is one of those technologies that quietly underpins... Full Story
-
BGP issues on FortiGate firewalls usually trace back to... Full Story
-
Every time your laptop talks to your router, a... Full Story
-
If you've spent any time configuring NAT on a... Full Story
-
If you have spent any time configuring firewall policies... Full Story
-
High availability on FortiGate is one of those features... Full Story
-
If you've configured SD-WAN on a FortiGate, you've almost... Full Story
-
FortiLink is the management protocol that turns a FortiSwitch... Full Story
-
FortiSwitches are pretty rock solid from Mean Time Between... Full Story
-
This is a quicky tip. Have you ever gone... Full Story
-
DNS is one of those quiet pieces of internet... Full Story
-
This article is an updated version of the previous... Full Story
-
You will add ns2 as a secondary (slave) BIND9... Full Story
-
In the process of deploying my lab, I needed... Full Story
-
RFC 8805, used to be known as Self-Correcting IP... Full Story
-
Years back, I wrote an article about certificate pinning. ... Full Story
-
FortiGates have the ability to send alerts to Microsoft... Full Story
-
In this post, I am going to walk through... Full Story
-
Troubleshooting VoIP on a FortiGate can feel like trying... Full Story
-
Prior to FortiOS 7.0, there were three commands to... Full Story
-
In this post, I am going to go over... Full Story
-
What we are going to do: We are going... Full Story
-
Choosing between FGCP (FortiGate Clustering Protocol) and FGSP (FortiGate... Full Story
-
Creating a VLAN on macOS (The "Pro" Move) A... Full Story
-
This blog post explores the logic behind how macOS... Full Story
-
Pretty Fly for a Wi-Fi Tell My Wi-Fi Love... Full Story
-
Part of my daily gig is creating BoMs (Bill-of-Materials)... Full Story
-
ICMP introduces several security risks, but careful filtering, rate... Full Story
-
The command diag debug application dhcps -1 enables full... Full Story
-
In the world of FortiOS, execute tac report is... Full Story
-
LLDP; What is it The Link Layer Discovery Protocol... Full Story
-
What it actually does When you run diagnose fdsm... Full Story
-
Monkey Bites are bite-sized, high-impact security insights designed for... Full Story
-
I have run macOS in macOS with Parallels but... Full Story
-
Don't be confused with my other FortiNAC posts where... Full Story
-
This is the third session in a multi-part article... Full Story
-
Today I was configuring key-based authentication on a FortiGate... Full Story
-
Netcat, often called the "Swiss Army knife" of networking,... Full Story
-
At its core, IEEE 802.1X is a network layer... Full Story
-
In case you did not see the previous FortiNAC... Full Story
-
This is our 5th session where we are going... Full Story
-
Now that we have Wireshark installed and somewhat configured,... Full Story
-
The Philosophy of Packet Analysis Troubleshooting isn't about looking... Full Story
-
Read, audit, rewrite, and generate FortiOS configuration with two... Full Story
-
Executive Summary Objective: Get HopMatrix installed, verified, and working... Full Story
-
What the kernel actually enforces, how to read it,... Full Story