1

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 127.0.0.1/8 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 192.168.1.108/24 brd 192.168.1.255 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 192.168.1.1 dev wlp3s0 proto dhcp metric 600 
169.254.0.0/16 dev wlp3s0 scope link metric 1000 
192.168.1.0/24 dev wlp3s0 proto kernel scope link src 192.168.1.108 metric 600

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


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 127.0.0.53:53 goes not from 127.0.0.0/8, 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? – Luciano Andress Martini Aug 31 '18 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? – Luciano Andress Martini Aug 31 '18 at 20:47
  • 1
    Right i do the two commands, and ping 8.8.8.8 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 – Luciano Andress Martini Aug 31 '18 at 20:51
  • 1
    If a local DNS server is listening on any or eg 127.0.1.1 and superseding the dhcp's dns setting in /etc/resolv.conf, then doing a query to 127.0.1.1 (anything else than 127.0.0.1) can go wrong, eg (conntrack -E): [NEW] udp 17 30 src=127.0.0.1 dst=127.0.1.1 sport=38781 dport=53 [UNREPLIED] src=127.0.1.1 dst=10.0.3.66 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 '18 at 23:41
  • 1
    So you do have a local dns server (anyway, a query done on 127.x.x.x-which-isn't-127.0.0.1)... 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 '18 at 5:27
1

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

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

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 127.0.0.53 dnscache, so www.bigtube.com SERVFAIL is not taking three minutes! I have dnsmasq 127.0.0.1 in /etc/resolvconf and NetworkManager. Erwin Hoffmann's djbns dnscache does have ipv6, not that I care personally.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.