| Description | This article describes which service to allow in the inbound VIP firewall policy when virtual IP port forwarding is configured with a different external port than the internal port. |
| Scope | FortiOS v5.6 and later. |
| Solution |
This article assumes the following topology:
Create a VIP object as shown below:
config firewall vip edit "web" set extip 10.0.20.2 set mappedip "10.1.1.2" set extintf "port1" set portforward enable set extport 8080 set mappedport 80 next end
In the above configuration, 10.0.20.2 is the external WAN IP and 10.1.1.2 is the internal web server. The incoming traffic is on port 8080, which is mapped internally to port 80.
For the inbound firewall policy, a common mistake is to allow the external port in the inbound firewall policy as shown below:
config firewall policy edit 2 set name "inbound" set srcintf "port1" set dstintf "port2" set action accept set srcaddr "all" set dstaddr "web" set schedule "always" set service "web_8080" next end edit "web_8080" set tcp-portrange 8080 next end
The flow trace logs show the traffic matches the implicit deny policy 0, not the above policy. id=65308 trace_id=1 func=init_ip_session_common line=6028 msg="allocate a new session-00000043, tun_id=0.0.0.0" id=65308 trace_id=1 func=iprope_dnat_check line=5303 msg="in-[port1], out-[]" id=65308 trace_id=1 func=iprope_dnat_tree_check line=824 msg="len=1" id=65308 trace_id=1 func=__iprope_check_one_dnat_policy line=5168 msg="checking gnum-100000 policy-1" id=65308 trace_id=1 func=get_new_addr line=1239 msg="find DNAT: IP-10.1.1.2, port-80" id=65308 trace_id=1 func=__iprope_check_one_dnat_policy line=5258 msg="matched policy-1, act=accept, vip=1, flag=100, sflag=2000000" id=65308 trace_id=1 func=iprope_dnat_check line=5315 msg="result: skb_flags-02000000, vid-1, ret-matched, act-accept, flag-00000100" id=65308 trace_id=1 func=fw_pre_route_handler line=184 msg="VIP-10.1.1.2:80, outdev-port1" id=65308 trace_id=1 func=__ip_session_run_tuple line=3435 msg="DNAT 10.0.20.2:8080->10.1.1.2:80" id=65308 trace_id=1 func=__vf_ip_route_input_rcu line=2012 msg="find a route: flag=00000000 gw-0.0.0.0 via port2" id=65308 trace_id=1 func=iprope_fwd_check line=794 msg="in-[port1], out-[port2], skb_flags-020000c0, vid-1, app_id: 0, url_cat_id: 0" id=65308 trace_id=1 func=__iprope_tree_check line=524 msg="gnum-100004, use int hash, slot=28, len=2" id=65308 trace_id=1 func=__iprope_check_one_policy line=2059 msg="checked gnum-100004 policy-2, ret-no-match, act-accept" id=65308 trace_id=1 func=__iprope_check_one_policy line=2059 msg="checked gnum-100004 policy-0, ret-matched, act-accept" id=65308 trace_id=1 func=__iprope_user_identity_check line=1833 msg="ret-matched" id=65308 trace_id=1 func=__iprope_check_one_policy line=2277 msg="policy-0 is matched, act-drop" id=65308 trace_id=1 func=iprope_fwd_check line=831 msg="after iprope_captive_check(): is_captive-0, ret-matched, act-drop, idx-0" id=65308 trace_id=1 func=iprope_fwd_auth_check line=850 msg="after iprope_captive_check(): is_captive-0, ret-matched, act-drop, idx-0" id=65308 trace_id=1 func=fw_forward_handler line=835 msg="Denied by forward policy check (policy 0)"
DNAT occurs before the firewall policy lookup, which leads to the traffic not matching the firewall policy. As shown in the above debug logs, the DNAT converts the public IP and port to the internal IP and port. This shows that the internal port (service), which is HTTP (port 80) in this case, needs to be allowed rather than the external port.
The following is the modified firewall policy with HTTP as the allowed service:
config firewall policy edit 2 set name "inbound" set uuid 7e44221a-1506-51ee-ca6b-9064ea17fad2 set srcintf "port1" set dstintf "port2" set action accept set srcaddr "all" set dstaddr "web" set schedule "always" set service "HTTP" next end
id=65308 trace_id=16 func=print_pkt_detail line=5842 msg="vd-root:0 received a packet(proto=6, 10.0.20.20:54710->10.0.20.2:8080) tun_id=0.0.0.0 from port1. flag [S], seq 145684743, ack 0, win 64240" id=65308 trace_id=16 func=init_ip_session_common line=6028 msg="allocate a new session-00000053, tun_id=0.0.0.0" id=65308 trace_id=16 func=iprope_dnat_check line=5303 msg="in-[port1], out-[]" id=65308 trace_id=16 func=iprope_dnat_tree_check line=824 msg="len=1" id=65308 trace_id=16 func=__iprope_check_one_dnat_policy line=5168 msg="checking gnum-100000 policy-1" id=65308 trace_id=16 func=get_new_addr line=1239 msg="find DNAT: IP-10.1.1.2, port-80" id=65308 trace_id=16 func=__iprope_check_one_dnat_policy line=5258 msg="matched policy-1, act=accept, vip=1, flag=100, sflag=2000000" id=65308 trace_id=16 func=iprope_dnat_check line=5315 msg="result: skb_flags-02000000, vid-1, ret-matched, act-accept, flag-00000100" id=65308 trace_id=16 func=fw_pre_route_handler line=184 msg="VIP-10.1.1.2:80, outdev-port1" id=65308 trace_id=16 func=__ip_session_run_tuple line=3435 msg="DNAT 10.0.20.2:8080->10.1.1.2:80" id=65308 trace_id=16 func=__vf_ip_route_input_rcu line=2012 msg="find a route: flag=00000000 gw-0.0.0.0 via port2" id=65308 trace_id=16 func=iprope_fwd_check line=794 msg="in-[port1], out-[port2], skb_flags-020000c0, vid-1, app_id: 0, url_cat_id: 0" id=65308 trace_id=16 func=__iprope_tree_check line=524 msg="gnum-100004, use int hash, slot=28, len=2" id=65308 trace_id=16 func=__iprope_check_one_policy line=2059 msg="checked gnum-100004 policy-2, ret-matched, act-accept" id=65308 trace_id=16 func=__iprope_user_identity_check line=1833 msg="ret-matched" id=65308 trace_id=16 func=__iprope_check line=2307 msg="gnum-4e20, check-00000000b2769f66" id=65308 trace_id=16 func=__iprope_check_one_policy line=2059 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept" id=65308 trace_id=16 func=__iprope_check_one_policy line=2059 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept" id=65308 trace_id=16 func=__iprope_check_one_policy line=2059 msg="checked gnum-4e20 policy-6, ret-no-match, act-accept" id=65308 trace_id=16 func=__iprope_check line=2324 msg="gnum-4e20 check result: ret-no-match, act-accept, flag-00000000, flag2-00000000" id=65308 trace_id=16 func=__iprope_check_one_policy line=2277 msg="policy-2 is matched, act-accept" id=65308 trace_id=16 func=iprope_fwd_check line=831 msg="after iprope_captive_check(): is_captive-0, ret-matched, act-accept, idx-2" id=65308 trace_id=16 func=iprope_fwd_auth_check line=850 msg="after iprope_captive_check(): is_captive-0, ret-matched, act-accept, idx-2" id=65308 trace_id=16 func=fw_forward_handler line=1000 msg="Allowed by Policy-2:" id=65308 trace_id=16 func=ip_session_confirm_final line=3087 msg="npu_state=0x100, hook=4" |
The Fortinet Security Fabric brings together the concepts of convergence and consolidation to provide comprehensive cybersecurity protection for all users, devices, and applications and across all network edges.
Copyright 2025 Fortinet, Inc. All Rights Reserved.