• Springs

    Uggg… JIM!!!!


    You don’t need to masquerade each rule.

    This is where address lists are also useful.

    Lets start with the first part…
    /ip firewall address-list
    (Some of you guys who already use my firewall should know this but here we go.)
    Enter this
    /ip firewall address-list
    add address= disabled=no list=RLCNet

    What this will do is make a GROUP that rules can be applied to.
    So it is spelling out: anything with IP address is part of the RLCNet address list or group.

    How is this useful??? Look at the next line.

    /ip firewall nat
    add action=masquerade chain=srcnat disabled=no dst-address-list=RLCNet \
    out-interface=ether2 src-address-list=RLCNet

    What that states: should something from the LAN ask for something on LAN DESPITE THAT I ASKED FOR IT FROM THE WAN. Make it appear to come from the WAN.

    Hence… only one masquerade rule to handle all your internal redirects.

    Put that under your DEFAULT RULE that looks like…
    /ip firewall nat
    add action=masquerade chain=srcnat comment=”default configuration” disabled=\
    no out-interface=ether1-WAN src-address-list=RLCNnet

    The router will only maqurade traffic from your LAN… because of the address list.
    The router will maqurade traffic that is on the LAN but EXPECTED from the WAN.

  • Ryan

    Chris, I think it was you who posted this at IP. However the way outlined above is much more clean, and you don’t need to keep the rules on the correct lines as it shows below. Did you discover a new way to do it since posting this? Or was it not you who posted it?

    First Make an Address List
    /ip firewall address-list
    add address= disabled=no list=RLCLocalNet

    This lets you apply rules to lots of addresses without typing in each IP.

    Next Masquerade your own network back on interface 2 (Where most of you have your LANs.)
    /ip firewall nat
    add action=masquerade chain=srcnat comment=”Masquerade Local BACK IN” disabled=no out-interface=ether2-master-local src-address-list=\

    Now using the DNS updater from this thread.
    Go to the bottom of the script and add this line.

    /ip firewall nat set 2 dst-address=”$previousIP”

    This will plug the WAN IP ADDRESS into NAT Rule 2
    Whats that… you have 30 Nat Rules…

    /ip firewall nat set 2,3,4,5,6,7,8,9,10,11 dst-address=”$previousIP”
    This line will plug it into rules 2-11

    Last Step…
    Those dst-nat rules in NAT.

    What all this will break down to in Mikrotik world.

    My Home DYNDNS address is: http://jmssu.areyouserious.com
    If a outside device needs to reach a webcam at http://jmssu.areyouserious.com:8081
    When the request hits the router from the outside world… or the local network
    The router sees you want to talk to the device on dt-nat rule that forwards too 8081
    The router then makes that forward.
    The Masqurade rule allows the return information to APPEAR to come from the outside IP.

  • Springs

    I do improve as I go along.

    The processing the firewall rules in the dyndns updater was something I came up with a few months back. I posted it at the forum. Then Jim called one night and I was working on a router with him. I told him about it. Then he wrote an article.

    He never warns me when he does this… so the first post is usually me yelling… YOU FORGOT TO HOOK UP THE DOLL!!!

    But Jim and I have a running joke about working together. When I think its JIM PROOF, then its ready.

  • Springs


    Don’t use resolvedIP. At the point in the script where it occurs… IT GETS THE ADDRESS THAT DYNDNS THINKS IS YOUR IP. You want to use the one in previousIP.

    $previousIP is set when acutual != resolved.

    Granted… it does not fill in the blanks when the unit first starts. But it also does not try to update with an IP that is about to be changed.

    example in plain english… (or Springs Speak)
    DYNDNS updater is running.
    Set variables
    get some info
    Now… query dns server to what it has the DNS record as. (resolvedIP)
    Now… Get the actual WAN IP. Parse it. result. (currentIP)
    Then the If / Then
    If resolvedIP = currentIP Print info “NO UPDATE NEEDED”
    If resolvedIP ! = currentIP Then
    Set previous IP to currentIP
    Update DYNDNS with result.
    Result = Good Log Info “Thanks Springs”

    See the glitch?
    resolved IP is what we are checking to see if its out of date. No point in setting your rules to an out of date IP.


  • Thanks for the info! I knew this was possible with Mikrotik and have needed this for a while.

  • Springs

    Forgot to update this…

    If you are behind another NAT device like a FiOS router. You will need to enter each rule 2 times.

    Once with the dst-address updating comment.
    Once with the interface of your WAN.

    This because a packet coming from the WAN does not have a dst-address of the WAN interface any longer. It is Nat’d when it comes back from the other router. So the rule that matches dst-address needs to be duplicated for EXTERNAL ACCESS.

  • Jason

    I copied the two scripts exactly and the DNS works, but can’t seem to get second one to work, it won’t update the firewall rule with WAN ip,

    • admin

      The script inside your dyndns updater doesn’t work?

    • Rich

      I have the same issue. The dyndns script does not run the hairpin_updater

      • admin

        Well, there’s no trick to that part of it. That line should have four spaces, then /system script run [name of your hairpin updater script].

        Try running that line from a Terminal window and see if it works.

  • Pingback: [Quick Steps] – Hairpin NAT | Networking For Integrators()

  • Matthew M

    This is fantastic!

    I’ve been trying to set up hairpin NAT for some time now, and it seems that everything I tried either didn’t work or had some negative affect.

    This, however, has worked without any issues. Previously, I had relied entirely on in-interface rather than dst-address since I have a dynamic WAN address and every other guide I found assumed a static WAN address.

    The only additional thing I had to do was add my domain to an address list (add domain to list’s comment and the IP address is updated by another script) that prevents certain hosts going through a VPN that some clients are using.

    Thank you very much!

    • Matthew M

      Apologies for another post, however just to point out, the address list for your LAN is not required. You can put your CIDR in “src/dst address” of the masquerade rule.

  • Andy Ng


    :resolve $hostname in terminal
    failure: bad name

    can’t seem to get this working.

    Andy Ng

    • admin

      In Winbox, go to System/Scripts then click on the Environment tab. Is there a “hostname” variable with what you think it is?

  • Andy Ng


    Found the problem, in dyndns script, the variable hostname was declare as local. Changing this to global solve the issue. Works wonderfully.

    Andy Ng

  • jack torres

    Awesome! finally a comprehensive explanation about hairpin NAT!!

  • John Deaton

    I went to the page link for the DynDNS script but page is corrupt. Can’t click link to download. Have tried multiple browsers. Can I get a direct download link?

    • admin

      It was a bad cache setting on my end. For some reason it was only affecting that page, but should be good to go now (and for a while now)

  • rich

    I cannot get this to work – I have tried it a dozen times but no traffic ever passes through the masquerade rule.

    the script is running
    The ip is updating

    it doesn’t look all that hard – what could I be missing?

    • admin

      Are you doing double-NAT? (e.g. is the Mikrotik plugged into another router?)

  • rich

    I reset the router completely and re-did everything. It works now.

    The only thing I still cannot get to work on multiple routers is the dyndns script running the hairpin updater. I have to use a separate scheduler to run it.

    I placed it exactly where you state to, I also tried it at the end of the script but the dyndns script never runs the hairpin updater script.

    • admin

      If you put it at the very end of the script and it doesn’t run, there must be some kind of syntax error (I would think). You can go in Terminal and it’ll give you some clues as to if there’s a syntax error in the script somewhere. Go to /system scripts and do “print brief”. It’ll give you a list of all your scripts with a number next to it. Let’s say that it’s #3. Type “print from=3” and it’ll print out the whole script (it’s long, so it won’t fit on one screen and you can scroll up/down, quit, etc).

      If there’s a syntax error in the script, the character where the error is should be “highlighted” and show you what part the system doesn’t understand.

      You can also try running the script from Terminal and it might output an error to give you some ideas as well.

      Also, you can add some “debugging” stuff into the script to track where it’s failing. Like:

      :put message=”about to run hairpin_updater”
      /system script run hairpin_updater
      :put message=”hairpin_updater should have just run”

      Then run the script from Terminal