FortiGate
FortiGate Next Generation Firewall utilizes purpose-built security processors and threat intelligence security services from FortiGuard labs to deliver top-rated protection and high performance, including encrypted traffic.
vdralio
Staff
Staff
Article Id 195448

Description

 

This article describes how to configure Hairpin NAT.

Hair-pinning also known as NAT loopback is a technique where a machine accesses another machine on the LAN or DMZ via an external network.

Traffic goes through the LAN interface to the Internet, then goes back to the same interface, connecting to it is External IP. Traffic is then forwarded by Fortigate through a virtual IP to the local destination of LAN or DMZ.

 


hairpin_diag.png

 


Scope

 

FortiGate.

 

Solution

 

If the external IP belongs to FortiGate (IP address of an external interface), FortiGate will require a different set of rules when the external IP is just from range, but not directly configured on FortiGate’s interfaces. In all examples, traffic will be flowing like this: Client -> external IP -> FortiGate -> internal IP -> Server.

 

Example 1:

 

External IP is the same as the external interface and uses VIP1 from the diagram. In this example, does not matter if extintf is any or wan.

 

config firewall vip
    edit "VIP1"
        set extip 20.0.0.1
        set extintf "any"
        set portforward enable
        set mappedip "172.16.1.2"
        set extport 10443
        set mappedport 10443
     next
end

 

config firewall vip
    edit "VIP1"
        set extip 20.0.0.1
        set extintf "wan"
        set portforward enable
        set mappedip "172.16.1.2"
        set extport 10443
        set mappedport 10443
    next
end

 

In both scenarios, extintf any or WAN, needs to have two firewall policies. One is to allow access from LAN to WAN and the second policy from WAN to DMZ.

 

config firewall policy
    edit 1
        set name "AllLan1"
        set srcintf "lan"
        set dstintf "wan"
        set srcaddr "all"
        set dstaddr "all"
        set action accept
        set schedule "always"
        set service "ALL"
        set logtraffic all
        set nat enable
    next
    edit 3
        set name "VIP"
        set srcintf "wan"
        set dstintf "dmz"
        set srcaddr "all"
        set dstaddr "VIP1"
        set action accept
        set schedule "always"
        set service "ALL"
        set logtraffic all
    next
end

 

Example 2:

 

The external IP address is from the same subnet but does not belong to FortiGate directly.

Use VIP2 from the diagram. There are two options to select extintf: any or specific.

 

Option 1:

 

config firewall vip
    edit "VIP2"
        set extip 20.0.0.2
        set extintf "any"
        set portforward enable
        set mappedip "172.16.1.2"
        set extport 10443
        set mappedport 10443
    next
end

 

If the interface is any, there will be just one firewall policy from LAN to DMZ with VIP2 as the destination address.

 

config firewall policy
    edit 3
        set name "VIP"
        set srcintf "lan"
        set dstintf "dmz"
        set srcaddr "all"
        set dstaddr "VIP2"
        set action accept
        set schedule "always"
        set service "ALL"
        set logtraffic all
    next
end

 

Note:

If srcintf-filter to VIP2 is configured, the LAN port will need to be a member of that filter.

In that case, the same firewall policy as the previous one will be enough.

If LAN will not be a member of the filter, but only WAN, hairpin will not work even if firewall policies are corrected when srcintf will be WAN directly (next option).

 

Option 2:

With option 2, WAN is an external interface.

There is a need to have the same set of firewall policies as in Example 1. One is to allow access from LAN to WAN and the second policy is from WAN to DMZ.

 

config firewall vip
    edit "VIP2"
        set extip 20.0.0.2
        set extintf "wan"
        set portforward enable
        set mappedip "172.16.1.2"
        set extport 10443
        set mappedport 10443
    next
end

 

config firewall policy
    edit 3
        set name "VIP"
        set srcintf "wan"
        set dstintf "dmz"
        set srcaddr "all"
        set dstaddr "VIP2"
        set action accept
        set schedule "always"
        set service "ALL"
        set logtraffic all
    next
    edit 1
        set name "AllLan1"
        set srcintf "lan"
        set dstintf "wan"
        set srcaddr "all"
        set dstaddr "all"
        set action accept
        set schedule "always"
        set service "ALL"
        set logtraffic all
        set nat enable
    next
end

 

In all examples, hairpin traffic will never leave FortiGate.

Depending on the configuration, from the debug flow, it may look like traffic is coming from WAN after it is coming from LAN.

This debug flow is for Example 2, option 2 scenario:

 

2022-05-27 14:17:47 id=20085 trace_id=169 func=print_pkt_detail line=5664 msg="vd-root:0 received a packet(proto=6, 192.168.1.2:55940->20.0.0.2:10443) from lan. flag [S], seq 1916321154, ack 0, win 29200"

2022-05-27 14:17:47 id=20085 trace_id=169 func=init_ip_session_common line=5834 msg="allocate a new session-00001cab"

2022-05-27 14:17:47 id=20085 trace_id=169 func=iprope_dnat_check line=4880 msg="in-[lan], out-[]"

2022-05-27 14:17:47 id=20085 trace_id=169 func=get_new_addr line=1163 msg="find DNAT: IP-172.16.1.2, port-10443"

2022-05-27 14:17:47 id=20085 trace_id=169 func=iprope_fwd_check line=748 msg="in-[lan], out-[wan], skb_flags-02000000, vid-1, app_id: 0, url_cat_id: 0"

2022-05-27 14:17:48 id=20085 trace_id=169 func=get_new_addr line=1163 msg="find SNAT: IP-20.0.0.1(from IPPOOL), port-55940"

2022-05-27 14:17:48 id=20085 trace_id=169 func=fw_pre_route_handler line=181 msg="VIP-172.16.1.2:10443, outdev-unknown"

2022-05-27 14:17:48 id=20085 trace_id=169 func=__ip_session_run_tuple line=3427 msg="DNAT 20.0.0.2:10443->172.16.1.2:10443"

2022-05-27 14:17:48 id=20085 trace_id=169 func=vf_ip_route_input_common line=2581 msg="find a route: flag=04000000 gw-172.16.1.2 via dmz"

2022-05-27 14:17:48 id=20085 trace_id=169 func=iprope_fwd_check line=748 msg="in-[wan], out-[dmz], skb_flags-020000c0, vid-1, app_id: 0, url_cat_id: 0"

2022-05-27 14:17:48 id=20085 trace_id=169 func=fw_forward_handler line=777 msg="Allowed by Policy-3:"

 

During the evaluation process, the first policy does SNAT, but since the traffic processing is not complete, the action of the second policy (the last one matched) takes precedence.
The traffic will not be SNAT-ed if there's no SNAT in the second policy ID (ID 3 in the example above). If SNAT is required, an IP pool has to be created and 'called' in the second policy that is being evaluated: Policy ID 3:

 

config firewall policy
    edit 3
        set name "VIP"
        set srcintf "wan"
        set dstintf "dmz"
        set srcaddr "all"
        set dstaddr "VIP2"
        set action accept
        set schedule "always"
        set service "ALL"
        set logtraffic all

        set nat enable

        set ippool enable

        set poolname <pool-name>

    next

 

Example 3:

 

Configuring Hairpin NAT when central NAT is enabled requires creating the corresponding VIP for NAT:

 

config firewall vip
    edit "VIP2"
        set extip 20.0.0.2
        set extintf "any"
        set mappedip "172.16.1.2"
    next
end

 

Port-forwarding can be added in the VIP configuration according to the setup.

 

An address object has to be created for the server in the DMZ - it will be used as a destination in the policy instead of VIP, unlike the setup without central NAT enabled:

 

config firewall address
    edit "server-VIP2"
        set subnet 172.16.1.2 255.255.255.255
    next
end

 

Next, a firewall policy and a corresponding central NAT entry have to be configured:

 

config firewall policy
    edit 1
        set name "VIP"
        set srcintf "lan"
        set dstintf "dmz"
        set srcaddr "all"
        set dstaddr "server-VIP2"
        set action accept
        set schedule "always"
        set service "ALL"
    next
end

 

config firewall central-snat-map
    edit 1
        set srcintf "lan"
        set dstintf "dmz"
        set orig-addr "all"
        set dstaddr "server-VIP2"
    next
end

 

The NAT-ed session can be checked with the following command:

 

get sys session list | grep 20.0.0.2
PROTO   EXPIRE  SOURCE         SOURCE-NAT        DESTINATION  DESTINATION-NAT
icmp    58      192.168.1.2:1  172.16.1.1:60723  20.0.0.2:8   172.16.1.2:1

 

Related Articles:

Technical Tip: Firewall does not block incoming WAN to LAN 

Technical Note: Using an auto hairpin to browse a webpage

Technical Tip: How to disable source NAT to enable a hairpin policy or one-arm firewal