I'm testing something with IP masquerade on locally generated traffic but it seems to be breaking DNS lookups. Everything else works fine--all IP traffic without DNS queries work.

$ iptables -t mangle -A OUTPUT -j MARK --set-mark 2
$ iptables -t nat -A POSTROUTING -m mark --mark 0x2 -j MASQUERADE

Why does this work with all IP traffic except DNS queries?

Results of requested commands below:

# ip address

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: enp2s0f1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 54:21:c6:28:99:1f brd ff:ff:ff:ff:ff:ff
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether c1:b2:a1:55:34:d2 brd ff:ff:ff:ff:ff:ff
    inet brd scope global dynamic noprefixroute wlp3s0
       valid_lft 242078sec preferred_lft 242078sec
    inet6 fe80::1dd6:f094:be8d:ef51/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

# ip route

default via dev wlp3s0 proto dhcp metric 600 dev wlp3s0 scope link metric 1000 dev wlp3s0 proto kernel scope link src metric 600

In a surprise twist, systemd is acting as a DNS server on

systemctl status systemd-resolved is reporting "systemd-resolved[3315]: Got packet on unexpected IP range, refusing." after enabling the two commands.

I believe this issue may be related.

The relevant portions of those two links are:

all queries to goes not from, but from interface with default route due to masquerading, and systemd-resolved rejects all of these requests with

systemd-resolved[21366]: Got packet on unexpected IP range, refusing.

systemd-resolved goes to the extra effort of validating the stub resolver source/dest addresses, and thus MASQUERADE rule breaks those assumptions:

if (in_addr_is_localhost(p->family, &p->sender) <= 0 ||
            in_addr_is_localhost(p->family, &p->destination) <= 0) {
                log_error("Got packet on unexpected IP range, refusing.");
                dns_stub_send_failure(m, s, p, DNS_RCODE_SERVFAIL, false);
                goto fail;
  • 1
    Bill. I tried i just can' t emulate, maybe because you have more than this two rules? Please explain. Is this a router? Is the tests of DNS being doing inside the router or in machines using this as a router? Where in your network this machine is, what do you expect to occur with this two rules. You marked the packet right! Will this affect routing tables? Aug 31, 2018 at 20:28
  • 1
    So let me see if i understand you have a desktop machine and add this rules, and dns just stop im right? You don't have any route rules, like route tables and others? Aug 31, 2018 at 20:47
  • 1
    Right i do the two commands, and ping is working and also www.gooogle.com is resolving including with nslookup... Maybe you have a strange interface or route configuration can you post the outputs of ip address and ip route on your question? And if you have a route table the results of it. Thanks. I added a ip route table 2 with fwmark 2 using this and seems to still work ok Aug 31, 2018 at 20:51
  • 1
    If a local DNS server is listening on any or eg and superseding the dhcp's dns setting in /etc/resolv.conf, then doing a query to (anything else than can go wrong, eg (conntrack -E): [NEW] udp 17 30 src= dst= sport=38781 dport=53 [UNREPLIED] src= dst= sport=53 dport=38781. Answer fails (EINVAL) if answering with sendto(). I have some theories, but first there are a lot of ifs that OP should confirm. doesn't involve mark. btw avoiding it is simple: state the interface in iptables to filter out lo.
    – A.B
    Aug 31, 2018 at 23:41
  • 1
    So you do have a local dns server (anyway, a query done on 127.x.x.x-which-isn't- ok. i'll do an answer but sorry that won't be before the next day (anybody else feel free to do so). I'm not sure it will give a real root cause, but at least how to reproduce, what is happening and how to avoid. Meanwhile you should edit your question and add the piece of information from your comment
    – A.B
    Sep 1, 2018 at 5:27

3 Answers 3


This worked fine to me. Just exclude the local interface and nslookup works fine.

sudo iptables ! -o lo -t nat -A POSTROUTING -j MASQUERADE

The solution for me based on systemd-resolved behavior was to implement the rules like this:

$ iptables -t mangle -A OUTPUT ! -s -j MARK --set-mark 2
$ iptables -t nat -A POSTROUTING -m mark --mark 0x2 -j MASQUERADE

I turned off systemd-resolved, but still have a dns resolver problem which I fix by using your mangle solution.

Posing an alt Answer, because maybe we just want iptables and not systemd-resolved to be our firewall:

StubListener to no in /etc/systemd/resolved.conf.d/00-hostname.conf

For an uncomfortable while, we just had systemd-resolved and no way to stop it from running and taking firewall domain away from iptables.

For a while we have had an option to stop that, and either go back to just deferring to google resolver, or opennic resolvers. Check namebench, for picking locally fastest.

Or, we can have dnsmasq, or good old djbdns dnscache. We can improve on google and/or opennic or whatever, either by dnsmasq or dnscache or a combination. I am using dnsmasq with namebench-ed opennic plus dnscache, so www.bigtube.com SERVFAIL is not taking three minutes! I have dnsmasq in /etc/resolvconf and NetworkManager. Erwin Hoffmann's djbns dnscache does have ipv6, not that I care personally.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .