hairpin nat not working

Hi. I’m struggling with the hairpin NAT configuration. Config is pretty standart, I have 5.xx.xx.xx external public ip on ether1 and 192.168.0.0/16 lan on ether2. I want to access local server 192.168.0.100 from inside, using 5.xx.xx.xx public ip. I’ve read tons of posts related to hairpin, and of course wiki article, but still cannot get it working.

 /ip firewall export
# sep/08/2012 13:53:10 by RouterOS 5.20
# software id = 5YZB-F2IZ
#
/ip firewall address-list
add address=192.168.0.100 disabled=no list=smtp_allow
add address=192.168.7.60 disabled=no list=smtp_allow
/ip firewall connection tracking
set enabled=yes generic-timeout=10m icmp-timeout=10s tcp-close-timeout=10s tcp-close-wait-timeout=10s tcp-established-timeout=1d tcp-fin-wait-timeout=10s tcp-last-ack-timeout=10s \
    tcp-syn-received-timeout=5s tcp-syn-sent-timeout=5s tcp-syncookie=no tcp-time-wait-timeout=10s udp-stream-timeout=3m udp-timeout=10s
/ip firewall filter
add action=accept chain=input comment="default configuration" disabled=no protocol=icmp
add action=accept chain=input comment="default configuration" connection-state=established disabled=no
add action=accept chain=input comment="default configuration" connection-state=related disabled=no
add action=accept chain=input comment=remote_admin disabled=no dst-port=41256 protocol=tcp
add action=accept chain=input disabled=no dst-port=41294 protocol=tcp
add action=drop chain=input comment="default configuration" disabled=no in-interface=ether1-gateway
add action=drop chain=forward comment=smtp_outgoing_drop disabled=no dst-port=25 out-interface=ether1-gateway protocol=tcp src-address-list=!smtp_allow
/ip firewall nat
add action=masquerade chain=srcnat connection-type="" disabled=no dst-address=192.168.0.100 out-interface=ether2-master-local src-address=192.168.0.0/16
add action=masquerade chain=srcnat comment="default configuration" disabled=no out-interface=ether1-gateway to-addresses=0.0.0.0
add action=dst-nat chain=dstnat comment=http disabled=no dst-port=80 in-interface=ether1-gateway protocol=tcp to-addresses=192.168.0.100
/ip firewall service-port
set ftp disabled=no ports=21
set tftp disabled=no ports=69
set irc disabled=no ports=6667
set h323 disabled=no
set sip disabled=no ports=5060,5061 sip-direct-media=yes
set pptp disabled=no



/interface print detail
Flags: D - dynamic, X - disabled, R - running, S - slave
 0  R  name="ether1-gateway" type="ether" mtu=1500 l2mtu=1598 max-l2mtu=4074

 1  R  name="ether2-master-local" type="ether" mtu=1500 l2mtu=1598 max-l2mtu=4074

 2  R  name="ether3-slave-local" type="ether" mtu=1500 l2mtu=1598 max-l2mtu=4074

 3     name="ether4-slave-local" type="ether" mtu=1500 l2mtu=1598 max-l2mtu=4074

 4     name="ether5-slave-local" type="ether" mtu=1500 l2mtu=1598 max-l2mtu=4074

 5     name="wlan1" type="wlan" mtu=1500 l2mtu=2290

 6  R  name="bridge-local" type="bridge" mtu=1500 l2mtu=1598



/ip address print detail
Flags: X - disabled, I - invalid, D - dynamic
 0   ;;; default configuration
     address=192.168.0.99/16 network=192.168.0.0 interface=wlan1 actual-interface=bridge-local

 1 D address=5.x.x.x/23 network=5.x.x.0 interface=ether1-gateway actual-interface=ether1-gateway
add action=masquerade chain=srcnat connection-type="" disabled=no dst-address=192.168.0.100 out-interface=ether2-master-local src-address=192.168.0.0/16

This should be using the 5.X.X.X address as the dst-address

Nick.

Already tried that, didn’t work either.

The configuration depends on whether your public IP is static or dynamic.

My public address is DHCP, but stays the same.

Anyway, if I put public ip there, it contradicts the example in wiki. Also, IMHO the order is dst-nat → src-nat, so after my request to 5.xx.xx.xx dst address is translated to 192.168.0.100 (according to port forward rule), and then src-nat rule kicks in.

/ip firewall nat
add action=dst-nat chain=dstnat comment=http disabled=no dst-port=80 in-interface=ether1-gateway protocol=tcp to-addresses=192.168.0.100

>

Can you reach the server from outside? I suspect that, since the rule above does not specify on which port to send the traffic.
It should be like this:

```text
/ip firewall nat
add action=dst-nat chain=dstnat comment=http disabled=no dst-port=80 in-interface=ether1-gateway protocol=tcp to-addresses=192.168.0.100 to-ports=80

Yes, from outside works fine. I suppose to-port is not needed if you are redirecting traffic to the same port.

One configuration for hairpin NAT with static IP is:

/ip firewall nat
add action=masquerade chain=srcnat comment=NAT disabled=no
add action=dst-nat chain=dstnat comment="SSH" disabled=no dst-address=5.x.x.x dst-port=22 protocol=tcp to-addresses=192.168.x.x to-ports=22

Then try to change the hairpin nat for one PC only, not for the whole subnet, for example only for the 192.168.0.10.

/ip firewall nat
add action=masquerade chain=srcnat connection-type="" disabled=no dst-address=192.168.0.100 out-interface=ether2-master-local src-address=192.168.0.10

Also, I see you have a bridge port. Is the ether2 port included in bridge? If yes, you either remove ether2 from bridge or in the hairpin nat rule, as outgoing-port you set the bridge.

Already tried that, doesn’t work.

Also, I see you have a bridge port. Is the ether2 port included in bridge? If yes, you either remove ether2 from bridge or in the hairpin nat rule, as outgoing-port you set the bridge.

I do have a bridge, and ether2 is in it, but I didn’t set it explicitly, it is a result of default config with quickset. I want to use it as a typical home router (1 wan, 4 lan+wifi), so I think bridging ether2+wlan1 is correct?

In the masquerade rule for the hairpin nat you haven’t specified dst-port. I noticed that now
So, you should try:

/ip firewall nat
add action=masquerade chain=srcnat disabled=no dst-address=192.168.0.100 protocol=tcp dst-port=80 out-interface=ether2-master-local src-address=192.168.0.0/16

I’ve already tried that, when following wiki article… IMHO here dst-port also acts only as a narrowing filter, so that only http traffic is masqueraded, not all traffic coming to that host.

Well, at this point, all I can say is that I have tried hairpin nat successfully as per wiki.
I guess sth could be with your routing table, if it is not default.
May be it could be useful to see your routes as well /ip route print

 /ip route print
Flags: X - disabled, A - active, D - dynamic, 
C - connect, S - static, r - rip, b - bgp, o - ospf, m - mme, 
B - blackhole, U - unreachable, P - prohibit 
 #      DST-ADDRESS        PREF-SRC        GATEWAY            DISTANCE
 0 ADS  0.0.0.0/0                          5.xx.xx.xx                1
 1 X S  0.0.0.0/0                          192.168.34.254            1
 2 ADC  5.xx.xx.xx/23      5.xx.xx.xx     ether1-gateway            0
 3 ADC  192.168.0.0/16     192.168.0.99    bridge-local              0

Not much here either… As I said, the config is pretty simple, typical NAT for internal users plus a few port forwards.

Ok, I see that the connected route for network 192.168.0.0/16 goes through interface bridge-local.
On the other hand, in /ip address, the address 192.168.0.99 is assigned to the wireless interface, and
in the hairpin nat rule as outgoing interface is assigned the ether2 one.

My opinion is that you should assign the IP address on the bridge-local, and also change the out-interface
on the hairpin nat rule to the bridge-local.

Yup, this also caught my eye. Probably a leftover from quickset config in CPE mode.

Changed the interface address, modified the rule - nothing. Changed rule’s destination ip to external ip - nothing.

Well, I am out of ideas :frowning:. How about reset with no defaults and start all over from scratch?

I’m thinking about it too.

Just made a full reset, used AP quickset. Also upgraded to 5.21. Added just one port forward to internal server at port 80, and a hairpin rule. Still doesn’t work :frowning:

Allright, a few beers later I’ve mastered the damn thing. However…

This combination works fine:
chain=dstnat action=dst-nat to-addresses=192.168.0.100 protocol=tcp dst-address=5.20.146.53 dst-port=80
chain=srcnat action=masquerade to-addresses=192.168.0.99 src-address=192.168.7.60 dst-address=192.168.0.100 out-interface=bridge-local

But this one does not work:
chain=dstnat action=dst-nat to-addresses=192.168.0.100 protocol=tcp in-interface=ether1-gateway dst-port=80
chain=srcnat action=masquerade to-addresses=192.168.0.99 src-address=192.168.7.60 dst-address=192.168.0.100 out-interface=bridge-local

I’ve created all my port forwards using “in-interface=ether1-gateway”, to isolate my rules from external IP change. But as far as I understand, hairpin request does not go in through “ether1-gateway”, therefore my usual rule does not work. Is it possible to use interfaces instead of specific IP addresses?