Community discussions

MikroTik App
 
User avatar
LincolnG
newbie
Topic Author
Posts: 26
Joined: Mon Dec 21, 2015 11:02 pm
Location: Catalunya

Script to change hairpin NAT rule DST.Address when public IP changes.

Tue Jan 26, 2016 6:57 pm

I have my routerboard setup to use DDNS cloud services. And a hairpin NAT rule so that when users inside the LAN type the web address of an internal website not to route outside the network, but forward to the local address.

Note: The router sits between another nat and the internet, so the WAN of the router is not the public IP.

The problem is that when the public ip does change the DST.Address in the NAT rule must be changed manually (the router doesn't allow this address to be a URL like xxxxxxe.sn.mynetname.net which of course would make it easy as this address resolves to my public ip.

How can I pickup my public ip from /ip cloud (or another way) save it as a variable (or file) and then set the hairpin NAT rule DST.address to that ip?

Thanks in advance..
 
User avatar
ZeroByte
Forum Guru
Forum Guru
Posts: 4047
Joined: Wed May 11, 2011 6:08 pm

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Tue Jan 26, 2016 7:21 pm

Instead of using a script, you should build your NAT rules so that they always "just work" even with a dynamic public IP.

Since your IP is dynamic, I'm assuming that you only have 1 address at any time - if you have multiples, then those wouldn't normally be dynamic....

The way most people set up dstnat pinholes is like this:
/ip firewall nat add chain=dstnat dst-address=192.0.2.12 protocol=tcp dst-port=80,443 action=dst-nat to-address=192.168.1.80

This is fine for a public static IP of 192.0.2.12 - but if your IP is dynamic, you can do something cool:
/ip firewall nat add chain=dstnat dst-address-type=local dst-address=!192.168.0.0/16 action=dst-nat to-address=192.168.1.80

Of course if you're using private IP addresses in the 10.x.x.x range, you would change the dst-address=!10.0.0.0/8 or !172.16.0.0/12 - etc.

Anyway, the idea is "if the target IP is my own IP address, but not one of my LAN IP addresses" - this will work no matter what the public IP address is, and no matter how often it changes. No script required. This only works for a single public IP, though. If you have multiples, then you're probably going to need a script. You could put unique comments on each pinhole dstnat rule so that your script can easily select the right rule based on the comment - e.g. /ip firewall nat set [ find where comment="webserver" ] dst-address=new.ip.address
 
dadaniel
Member Candidate
Member Candidate
Posts: 227
Joined: Fri May 14, 2010 11:51 pm

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Wed Jan 27, 2016 10:32 am

Is there a script that creates hairpin-rules based on existing port forwards?
 
User avatar
LincolnG
newbie
Topic Author
Posts: 26
Joined: Mon Dec 21, 2015 11:02 pm
Location: Catalunya

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Wed Jan 27, 2016 1:57 pm

The scripting is driving me mad :(

I put commands into the terminal and they work, I put them into a script and they don't. For example, if I put each of these lines into the terminal they work and I'm left with an empty file called public-ip.txt

/file remove "public-ip.txt"
/file print file="public-ip.txt"
/file set "public-ip.txt" contents=""

However, if I create and run a script with exactly the same commands, only the first two lines actually appear to run and I'm left with a file called public-ip.txt with 390b .

Also, if I run this command from terminal

/tool fetch url="http://api.ipify.org/\3Fformat=text" dst-path="/public-ip.txt" mode=http

It works perfectly and my public-ip.txt file contains my public ip, however if I do the same from a script - nothing happens.

What's going on!!
 
User avatar
ZeroByte
Forum Guru
Forum Guru
Posts: 4047
Joined: Wed May 11, 2011 6:08 pm

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Wed Jan 27, 2016 8:45 pm

Is there a script that creates hairpin-rules based on existing port forwards?
There's no need. Use the method I explained whenever you create the port forwards.
The hairpin rule has nothing to do with the WAN IP:

/ip firewall nat
add chain=srcnat out-interface=LAN src-address=192.168.0.0/16 action=masquerade

(or use your specific LAN range e.g. 192.168.88.0/24)

For dynamic-ip-proof(tm) filter rules - if you want to allow all traffic on nat port maps, then just add this rule to the forward chain:
/ip firewall filter add chain=forward connection-nat-state=dstnat action=accept
The scripting is driving me mad
I do actually use a script for DDNS updates though, but I don't store the current one in a file - I use a global variable, which stays set as long as the router stays up. In my case, I load the current wan IP from DNS if the global variable isn't set:
#Check for valid wanip environment variable. Use DNS to initialize it if not a valid IP.
:global wanip
:if ([:typeof $wanip] != "ip") do={
  :log debug "ddns - wanip environment variable ($wanip) is invalid - resolving $host.$zone to learn currently-published address"
  :set $wanip [:resolve "$host.$zone" ]
  #If not connected to internet, script will fail here and retry on next execution.
  #$wanip will still be invalid
} 
If they (Mikrotik) were to provide the ability to launch a script on event where dhcp-client receives a new lease, then launch script, I would do it that way instead of a scheduled job that checks the wan IP for changes.
 
User avatar
LincolnG
newbie
Topic Author
Posts: 26
Joined: Mon Dec 21, 2015 11:02 pm
Location: Catalunya

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Wed Jan 27, 2016 10:04 pm

That's great.

However, my public IP is not my router IP so I needed a way to find out what my actual public IP is - plus I wanted to experiment with scripts. I find playing is the best way to learn. :D

I put the question on the beginners forum after, because I thought it was a better place, where a suggestion was made to put delays in between the script lines to slow it down and give time for the file system to refresh. This worked like a charm.

Forgive the untidyness, my first goal was to get it working - tomorrow I'll make it a bit more professional. But, this is what I got

/file remove "public-ip.txt"
:delay 2s
/file print file="public-ip.txt"
:delay 2s
/file set "public-ip.txt" contents=""
:delay 2s
/tool fetch url="http://api.ipify.org/\3Fformat=text" dst-path="/public-ip.txt" mode=http
:delay 2s
:global "publicIP" [/file get [/file find name="public-ip.txt"] contents];
:delay 2s
/ip firewall nat set [ find where comment="hairpin" ] dst-address=$publicIP;

I did find another solution which was to resolve my Mikrotik cloud client and then apply that to the nat rule. Perhaps I'll have a go that way next week.
 
User avatar
ZeroByte
Forum Guru
Forum Guru
Posts: 4047
Joined: Wed May 11, 2011 6:08 pm

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Wed Jan 27, 2016 10:31 pm

Your router is behind another NAT router - this was an important detail. :D

Since you're trying to affect the firewall's behavior with your script, you could just store the result as an address in /ip firewall address-list and use the address-list in your rules. The same rule will work for both hairpin and inbound connections if you use an address list.

e.g.
# wan IP has changed - clear the list except for the IP of the WAN interface and insert new address
/ip firewall address-list
remove [ find where address!=192.168.1.2 and list=wanip ]
add list=wanip address=192.0.2.12
This code snippet will clear the address list but leave the actual private wan IP and then add the current public wanip. Address list will be preserved across reboot also, which is helpful.

Then your port translation NAT rule would look like this:
/ip firewall nat
add chain=dstnat dst-address-list=wanip protocol=tcp dst-port=80,443 action=dst-nat to-address=192.168.100.12
The hairpin rule doesn't care what your wan IP is anyway so use what I posted earlier:
/ip firewall nat
add chain=srcnat out-interface=LAN src-address=192.168.0.0/16 action=masquerade
 
User avatar
ZeroByte
Forum Guru
Forum Guru
Posts: 4047
Joined: Wed May 11, 2011 6:08 pm

Re: Script to change hairpin NAT rule DST.Address when public IP changes.

Wed Jan 27, 2016 10:35 pm

Of course, an even easier thing to do would be to use DNS proxy on the Mikrotik (/ip dns set allow-remote-requests=yes) and then assign the Mikrotik as your LAN's DNS server in the DHCP settings.

Then you can create a static entry in DNS:
/ip dns static add address=192.168.1.12 name=myhost.dyndns.example.com

If the name you use is the same as the real dyndns hostname on the Internet, then the Mikrotik will just give the client the private IP address and you won't even need hairpin nat at all.