Normally wouldn’t recommend, as it means packets goes in various directions that normal routing commands (get router info routing-table all etc.) don’t pick up the subtleties. But sometime the network needs to fix application issues or implement specific architecture. In this case some services could not be configured to use an apprpriate proxy, so traffic from them needed to be manually directed down an alternate path.

Doc suggests that anything defined in a PBR takes precedence of the routing table. That’s not entirely true.

See Reddit: Fortigate policy route issues with 6.4.4 : fortinet (

What this means is that you need a RIB entry (kernel route) that you can see to the destination that the PBR is going to select. But this needs to be a lower priority (higher number) so it’s normally never used. Say you want to normally route Internet traffic via WAN ae0, but have a specific PBR to route some Internet traffic over a particular IPSEC tunnel. You would need something like this in the Kernel routing table.

FW # get router info routing-table static
Routing table for VRF=0
S* [10/0] via, ae0
                  [10/0] is directly connected, IPSecTunnel, [250/0]

There are 2 static routes with the same admin distance. Same admin distance means they both end up in the kernel. Second route will never normally be used as it’s priority is 250 (higher number == lower priority)

The PBR essential flicks between the routes that are available.

Some diag commands. They seems to be all over the place

To list Policy routes: diagnose firewall proute list

FW # diagnose firewall proute list
list route policy info(vf=root):

id=1 dscp_tag=0xff 0xff flags=0x0 tos=0x00 tos_mask=0x00 protocol=0 sport=0-0 iif=43 41 dport=0-65535 oif=45(IPSecTunnel)

hit_count=27153 last_used=2022-05-23 16:29:02

Above says anything from internal interfaces 41 or 43 and destined to Internet IP blocks, any port should go out interface 45 (IPSecTunnel)

To test one use diagnose ip route match

NRVBFW # diagnose ip proute match Interface_Name 6 443
dst= src= smac=00:00:00:00:00:00 iif=43 protocol=6 dport=443
id=00000001 type=Policy Route

If the above says something like – no kernel route exists, then you haven’t get a RIB entry for the PBR to use.

e.g I remove the low priority route leaving

Routing table for VRF=0
S    *> [10/0] via, ae0

ip route match shows

FW # diagnose ip proute match Interface_Name 6 443
dst= src= smac=00:00:00:00:00:00 iif=43 protocol=6 dport=443
No matching policy routes in kernel

See also this new feature in 6.4 – Auxiliary Sessions: FortiOS Release Notes | FortiGate / FortiOS 6.4.4 | Fortinet Documentation Library

There is also a bug with the 6.4 releases (718512). Only fixed in 7.0.1, where sessions don’t match the reverse traffic. I’ve hit this with UDP PBR, if the forward session expires and the next packet in is a reply. What it does is basically revert the same behavior from 6.2.x below wherein the reply traffic will do a policy route lookup once more which was removed at 6.4.x.

Fun and Games with Fortigate Policy Based Routing

One thought on “Fun and Games with Fortigate Policy Based Routing

  • 2023-09-27 at 8:41 pm

    I solved my problem by changing the role of the interface to WAN.


Leave a Reply

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