When is connection-nat-state applied (default firewall rule)?

I was going through the mikrotik default firewall rules trying to make sure I had a fundamental understanding of all of them, as well as trying to figure out how they map to iptables rules. I got to the forward WAN drop rule, and realized there was one part I didn’t understand. This is the rule I’m referring to:

/ip firewall filter add chain=forward action=drop connection-state=new connection-nat-state=!dstnat in-interface-list=WAN comment="defconf: drop all from WAN not DSTNATed"

My understanding is that this rule is meant to prevent any external/incoming FORWARD requests from initiating NEW connections; the intended flow should be an internal/outgoing FORWARD request sets the connection-state to NEW, and then the external/incoming FORWARD responses should set the connection-state to ESTABLISHED in PREROUTING. Couldn’t that be accomplished with just this?

/ip firewall filter add chain=forward action=drop connection-state=new in-interface-list=WAN comment="defconf: drop all from WAN not DSTNATed"

Isn’t the

connection-nat-state=!dstnat

redundant here (based on my understanding of what the rule is trying to accomplish)?

My understanding is that for a packet to be put in the FORWARD chain in the first place (instead of the INPUT chain), the packet’s src-ip, src-port, dst-ip (the routers public ip) and dst-port all needed match an existing connection in the connection-list and point to the client that made the request, and if no connection was matched, it would be sent to the INPUT chain instead. Therefore if the packet was placed on the forward chain, wouldn’t that mean a connection in the connection-list was found and dstnat was applied, making the connection-nat-state=!dstnat part of the rule redundant?

I think I have a fundamental misunderstanding of when connection-nat-state=dstnat gets applied. This also seems to make the rule less secure, because it narrows down the DROP scope, and mikrotik has a default ALLOW policy after this. There also seems to be very little information about exactly what scenarios connection-nat-state gets applied: the places I cant find these topics mentioned are, dstnat, connection-nat-forwarding and general NAT.

I was hoping someone might help me understand what

connection-nat-state=!dstnat

is trying to accomplish in the default rule, as well as when the

connection-nat-state

gets updated (I have already read through the RouterOS packet flow page but that didn’t really clear up my confusion).

The idea is to drop all packets, which represent a new connection, in chain=forward, surviving rules so far, except for packets which are subject to DST NAT. Note the “!” character in front of “dstnat” property … which is a negation. So rule will drop packets which are not DST-NATed (see below).

Bearing in mind that there’s implicit ultimate rule in every chain (action=accept), the above rule can be re-written into pair of rules:

/ip/firewall/filter
add chain=forward action=accept connection-state=new connection-nat-state=dstnat in-interface-list=WAN comment="accept DSTNATed connection from WAN"
add chain=forward action=drop # connection-state=new

(the comment part of the second rule is there to show literal rewrite of the single rule … however due to the default filter rules above it, packets with none of other connection states survive this far so it’s not necessary. And omitting it actually makes firewal filter ruleset more secure)

The translation is only correct for default firewall filter ruleset, if there are other rules added, then the translation might not be correct.

Regarding the connection-nat-state: as per packet flow of routed packets, DST NAT function comes after connection tracking and before firewall fiter. Which means that by the moment of evaluation of filters DST NAT state will already be determined … and that’s true also for the initial packet of a new connection (because it matches DST NAT rules). For the rest of packets (both forward and return), they will be handled by rule(s), handling “established,related” packets (plural because by default there will be at least two of such rules, the “accept established,related,untracked” rule and similar fasttrack rule … but if necessary there can be even more similar - perhaps more selective - rules).
Also mind that packets, eligible for DST NAT, are most often (but not necessarily) originally “targeting” router’s own WAN IP address. Which means that default firewall chain would be chain=input. So if packet is not marked as DST-NATed, then it will be handled by firewall filter rules governing chain=input (and they better are very restrictive).
So in reality, only initial packets of new connections will be matched by the rule(s) we’re discussing here.

It’s not quite correct, the second rule should be:


/ip/firewall/filter
add chain=forward action=drop in-interface-list=WAN

to produce something similar to the original rule.

This thing comes up often........

/ip firewall filter
add chain=forward action=fasttrack-connection connection-state=established                      comment="defconf: fasttrack estabilished"
add chain=forward action=fasttrack-connection connection-state=related                          comment="defconf: fasttrack related"
add chain=forward action=accept               connection-state=established                      comment="defconf: accept established"
add chain=forward action=accept               connection-state=related                          comment="defconf: accept related"
add chain=forward action=accept               connection-state=untracked                        comment="defconf: accept untracked"
add chain=forward action=drop                 connection-state=invalid                          comment="defconf: drop invalid"
add chain=forward action=accept               in-interface-list=WAN connection-nat-state=dstnat comment="defconf: accept all connection from WAN DSTNATed"
add chain=forward action=drop                 in-interface-list=WAN out-interface-list=LAN      comment="defconf: drop unsolicited connections from WAN to LAN"
add chain=forward action=drop                 in-interface-list=WAN out-interface-list=WAN      comment="defconf: drop all coming from WAN to WAN"
add chain=forward action=accept               in-interface-list=LAN out-interface-list=LAN      comment="defconf: accept all connection from LAN to LAN"
add chain=forward action=accept               in-interface-list=LAN out-interface-list=WAN      comment="defconf: accept all connection from LAN to WAN"

# this rule not exist, but if exist, at this point what block?
add chain=forward action=drop                                                                   comment="defconf: drop all not coming from LAN or WAN"

One rule to rule them all...

add chain=forward action=drop   in-interface-list=WAN connection-nat-state=!dstnat connection-state=new comment="defconf: drop all from WAN not DSTNATed"
# useless implicit
# WARNING: "anything" mean all other interfaces not in WAN and not in LAN lists
add chain=forward action=accept in-interface-list=WAN connection-nat-state=dstnat comment="defconf: accept all connection from WAN DSTNATed"
add chain=forward action=drop   in-interface-list=WAN out-interface-list=WAN      comment="defconf: drop unsolicited connections from WAN to WAN"
add chain=forward action=drop   in-interface-list=WAN out-interface-list=LAN      comment="defconf: drop unsolicited connections from WAN to LAN"
add chain=forward action=drop   in-interface-list=WAN                             comment="defconf: drop unsolicited connections from WAN to anything"
add chain=forward action=accept in-interface-list=LAN out-interface-list=WAN      comment="defconf: accept all connection from LAN to WAN"
add chain=forward action=accept in-interface-list=LAN out-interface-list=LAN      comment="defconf: accept all connection from LAN to LAN"
add chain=forward action=accept in-interface-list=LAN                             comment="defconf: accept all connection from LAN to anything"
add chain=forward action=accept                       out-interface-list=WAN      comment="defconf: accept all connection from anything to WAN"
add chain=forward action=accept                       out-interface-list=LAN      comment="defconf: accept all connection from anything to LAN"
add chain=forward action=accept                                                   comment="defconf: accept all connection from anything to anything"

In short, if one rule is enough, why should I write more than one unnecessarily?
If the problem is that the user does not understand the rule, then it also means that the user is better off not touching anything...
And then, even if the user does understand it, it is not a given that he will then modify it correctly.

Right. Thanks for correcting me.

I recognize that the default rules explanation comes up pretty frequently but I was hoping that I could more specifically target information on when the dstnat attribute is applied. I think my question might better be phrased as “When does the connection attribute dstnat become ‘yes’?”. I recognize that DST-NAT occurs at the end of the PREROUTING chain, but is the dstnat attribute set for both explicit static DNAT rules, as well as implicit ones set up by SNAT? Or is dstnat only set when matching explicit DNAT rules for something like port forwarding?

In the case that the dstnat attribute is set on every connection that has either an explicit DNAT rule, or an implicit rules from SNAT masquerading, wouldn’t the packet simply being on the forward chain be enough to say it was dstnat’ed (assuming a standard home network)? Is there any instance in which a packet coming in the WAN interface on the forward chain (assuming a standard home router setup with a single public WAN IP) would not have the dstnat attribute=yes?

edit: hmm, after thinking about it some more, I guess theoretically my ISP could send me any random packet that isn’t addressed to my routers public IP, no DNAT would be applied, and my router would send it to the forward chain. That would put me in a situation where:

  1. the packet is coming from the WAN interface
  2. the packet is on the forward chain
  3. the connection is marked as dstnat=no
    and I would want the extra protection of action=drop connection-nat-state=!dstnat. Is this the specific case being guarded against when adding connection-nat-state=!dstnat in the default rule?

I guess another way of looking at it is, “If its coming from WAN and it wasn’t dstnat’ed, we werent expecting it”. Either because LAN didn’t initiate the connection, or we didn’t have a static DNAT rule setup.

You can simply open the IP → Firewall → Connections tab in WinBox and see that the dstnat flag is not automatically turned on for connections being srcnat’ed.

Even in the theoretical case where srcnat implicitly enables dstnat (which is not the reality) nothing will change with this rule, because this rule in the filter table only applies to packets with connection state new. At this point the packet has not yet reached postrouting where all the srcnat rules are located.


Yes, the rule is for this case, and also for the case where the ISP puts multiple customers in the same layer 2 without proper isolation and some rogue neighbors might send packets with any destination IP address to your router, using it as relay gateway to your LAN or to the Internet. If the ISP is not incompetent, then normally you should never see the counter on this rule increases above 0.

because this rule in the filter table only applies to packets with connection state new

Youre absolutely right, I had completely forgotten about this, but that removes any importance of whether or not SNAT masquerading potentially sets up connections with returning traffic as dstnat or not (apparently it doesn’t, though). If the connection was initiated coming from my LAN first, the connection-state=NEW would already exist on the forward chain in my connection-list, and the returning response would turn that NEW into an ESTABLISHED connection. Since connection tracking occurs well before filter rules, packets returning to SNAT connections would only ever be ESTABLISHED, never NEW. Thank you for reminding me of that!

Also I do wish I could have verified this by just looking at the connection list on my mikrotik but I don’t have access to it at the moment which is why I was asking so many clarifying questions :confused:

As you can see here “expanded default rules on forward code”:
http://forum.mikrotik.com/t/when-is-connection-nat-state-applied-default-firewall-rule/182830/1
you need to have an overall vision, you can’t consider ONLY that rule to understand it.
Some things are implied.
For example, it considers only new connection attempts from the WAN
because the previous rules have already admitted estabilished,related,untracked and blocked invalid ones,
so it is “obvious” that the connections that remain are only “new”, so there is no point in checking whether they are new or not “again
By default, everything forwarded from LAN is allowed, but nothing can arrive from the WAN,
except (!) if ports are opened in the NAT that need to reach devices of the internal LAN.
And of course LAN->LAN traffic is allowed.

I agree with almost everything said in this thread.

The default firewall rules as written are totally correct, and match what most (not really configurable) off-the-shelf routers provide. However I also think that it would be easier to understand and modify them if they were split up to be more explicit.

Now onto connection-nat-state. First of all, this is a property of the conntrack entry. It is set by dstnat (and similar) and srcnat (and similar as in masquerade) rules respectively.

Both srcnat and dstnat assume a mapping both of the direct and the reply traffic. In case of a typical srcnat rule for example, the source address (and port) of the packet are modified, however the destination address (and port) of the reply packets are as well. Similarly, for a typical dstnat rule, the destination address (and port) of the direct packets are modified, but the source address (and port) of the reply packets are also.

Assuming that connection tracking is active, all this translation happens in the “connection tracking” step of the firewall. In fact the entire NAT firewall table is only consulted for new connections.

That both directions of traffic are modified does not imply that there would be any sort of “implicit” dstnat rule constructed for srcnat, or vice versa.

In fact a connection can be both src- and dstnatted. A quite common example is exposing a service to the internet (via a dstnat rule), and making it possible to access this through the external IP of the router (probably via DNS) from inside the same network the server resides in. It is well known that in this case a possible solution is hairpin nat. These connections are both dst- and srcnatted.

As for the forward rule that allows dstnat traffic. For external traffic that is dstnatted to an internal service, both a dstnat rule is necessary and a rule that allows it to pass forward as well. It is quite useful to allow dstnatted traffic to pass forward, because dstnat rules don’t just come out of thin air - the administrator must have configured it. It is a viable strategy to simply allow them through forward._It would also be completely valid to have to add a forward rule specifically for this traffic.

Thank you very much, I think that last statement really got through to the heart of what I was trying to understand.

dstnat rules don’t just come out of thin air - the administrator must have configured it

ie. in the event that dstnat has been tagged on a connection, it was as a result of an deliberate action the admin made. connection-nat-state=!dstnat may not be applicable now but it might be later in the event that you setup port forwarding, in which case this rule is already configured to allow it.

I also looked back through the docs and realized that I was misunderstanding the definition of connection-nat-state; It is flagged with srcnat/dstnat based on direction of the first packet, so even in my “implicit dstnat via masquerading” scenario, it would have been tagged with srcnat first and maintained that flag for the rest of the connection, regardless of how the packets are routed back to the client.

To summarize then, the only time the dstnat flag is set is when routing for explicit dstnat rules. It is convenient to have in this default rule because in the event that dstnat rules are setup (for port forwarding for example), the rule already accepts the connection. The added benefit is that in the event that rogue traffic is sent to the routers WAN IP which is not destined for the router itself, it will be dropped after being routed to the forward chain.

Thank you everyone who had feedback and clarification!

What you probably realized somewhere through the long winded explanations of my colleagues ;-P, is that
the rule actually provides three functions.
a. allows traffic from the wan that is for port forwarding ( obtainable understanding )
b. drops any other traffic from the wan ( kinda obscure )
c. allows all LAN to WAN traffic ( very obscure )

MTs efficient use of firewall rules however as you have eloquently described and experienced are way too confusing for the new person and their attempt to be ‘cute’ with their use of negation “!” makes me puke.

Instead they should have simply gone with a straightforward approach that anybody who changes the config ( from default rule and single user on ether2 - aka probably 99.9 percent of people end up doing more - being the type that didnt buy a plugNpray router !!! ) will quickly need to gravitate towards anyway…

add chain=forward action=accept in-interface-list=LAN out-interface-list=WAN comment=“internet traffic, disable or remove if not required”
add chain=forward action=accept connection-nat-state=dsntnat comment=“port forwarding, disable or remove if not required”
add chain=forward action=drop in-interface-list=WAN comment=“drop all traffic coming from the WAN”

Now, you should note that the rules are somewhat less vague and clearer.
The connection-nat rule recognized or is adaptive to the fact that folks may be port forwarding from the WAN side or LAN side.
You should also note what is not there, we do not block traffic LAN to LAN

To that end, most admins ( especially due to multiple subnets ) move to a simple rule of block everything not allowed above So the last rule morphs somewhat too:

add chain=forward action=accept in-interface-list=LAN out-interface-list=WAN comment=“internet traffic, disable or remove if not required”
add chain=forward action=accept connection-nat-state=dsntnat comment=“port forwarding, disable or remove if not required”
++++++++++++++++++++++++++++++++++++++++++++
add chain=forward action=drop comment=“drop all else”

The simplicity of this approach is that we dont worry about figuring out what to block, if its traffic we need/want we include it above the last rule!!

@anav Thank you :), that was a great summary. I think your callout about the rule also allowing all LAN to WAN, and LAN to LAN forward traffic was something I didn’t touch on but definitely worth mentioning in the event anyone else stumbles across this thread.

I honestly will likely migrate to a slightly more verbose set of firewall rules as expanded upon here and in some of the linked forum threads, in addition to the default drop rule at the end. I was kind of surprised that mikrotik doesn’t have the option to change the default policy as expended upon in many other threads, especially considering how straight-forward it is to do in iptables; maybe there is some other technical issue, maybe its just not worth their time since a drop all rule at the end of the chain accomplishes the same thing, or maybe its because its routerOS, for routers where a default allow makes sense, and not targeting firewalls, whose to say.

I do feel like I have a much more fundamental understanding now, though. Thank you all!

I think it’s mostly done for consistency and to have one less “hidden” option that influences everything. In addition, all of the paths to accelerate packet processing (fast path, bridge fast path - this obviously involves ebtables, etc) all have the condition of no firewall/bridge fw rules for being active which would become much more difficult to implement if the default policy could be changed. When the default policy is deny, the rules would actually have to be formally analyzed for whether they are equivalent to “accept all”. (Also, if you have a policy deny, you probably have other rules as well, so no real harm in adding one more.)

For me the whole “default policy” thing looked like an unnecessary flair even before I ever encountered a Mikrotik device. I think that having no rules being equivalent to not using or even removing the necessary hook/callback is a sane behavior.