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 (reddit.com)
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* 0.0.0.0/0 [10/0] via 192.168.4.254, 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)
source(2): 10.194.0.168-10.194.0.175 10.194.0.128-10.194.0.135
destination(7):
0.0.0.0-9.255.255.255
11.0.0.0-100.63.255.255
103.128.0.0-126.255.255.255
128.0.0.0-169.253.255.255
169.255.0.0-172.15.255.255
172.32.0.0-192.167.255.255
192.169.0.0-223.255.255.255
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 9.9.9.9 10.194.0.170 Interface_Name 6 443
dst=9.9.9.9 src=10.194.0.170 smac=00:00:00:00:00:00 iif=43 protocol=6 dport=443
id=00000001 type=Policy Route
seq-num=1
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 *> 0.0.0.0/0 [10/0] via 192.168.4.254, ae0
ip route match shows
FW # diagnose ip proute match 9.9.9.9 10.194.0.170 Interface_Name 6 443
dst=9.9.9.9 src=10.194.0.170 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.
I solved my problem by changing the role of the interface to WAN.