如何允许 systemd-resolved 监听环回以外的接口?

如何允许 systemd-resolved 监听环回以外的接口?

systemd-resolved 是一个守护进程,除其他外,它通过侦听本地环回接口上的 IP 地址 127.0.0.53 充当 DNS 服务器。

我想让守护进程监听另一个接口。我的用例是将其公开给 docker 容器,以便 docker 容器共享 systemd-resolved 提供的 DNS 缓存。我知道如何将主机配置为 docker 容器的 DNS 服务器,但至少在默认情况下,systemd-resolved 会拒绝这些 DNS 查询,因为它们不是来自环回接口,而是来自 docker 桥接接口。

使用 dnsmasq (类似于 systemd-resolved 的工具),我通过以下方式做到了这一点添加listen-address=172.17.0.1到配置文件中。不幸的是,我找不到系统解析的等效项。

由于 systemd-resolved 至少在 Ubuntu 18.04 上是默认的,我想要一个适用于此配置的解决方案。

有没有办法配置 systemd-resolved 监听哪个接口?

答案1

你不能。正如 cristian-rodríguez 上面提到的,它被严格设计为仅向环回提供服务。

甚至没有使用 + iptables NAT 的替代解决方案net.ipv4.conf.all.route_localnet=1(例如https://serverfault.com/questions/211536/iptables-port-redirect-not-working-for-localhost),https://superuser.com/questions/594163/how-do-i-route-a-port-range-in-a-linux-host-to-a-guest-vm), 和https://stackoverflow.com/questions/18580637/iptables-redirect-from-external-interface-to-loopbacks-port)将起作用,因为 systemd-resolve 显式检查目的地是否位于环回网络之外。请参阅下面的代码static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p)

    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;
    }

解决方法是使用socat侦听 docker 接口并将其转发到 systemd-resolved。下面的行就可以解决这个问题。如果需要,将其更改为侦听 TCP:

socat UDP-LISTEN:53,fork,reuseaddr,bind=172.17.0.1 UDP:127.0.0.53:53

答案2

Resolved 并不是为了您的用例而设计的,而是为了在本地环回中提供服务,因此监听地址是硬编码的。

答案3

由于 systemd-resolved,监听地址的所需配置是可以自由实现的247版(犯罪1f05101f和后续)通过设置DNSStubListenerExtra.

地址、端口和协议(tcp/udp)可多次配置。甚至可以通过设置DNSStubListener为 false 来禁用 (tcp/udp) 127.0.0.53:53 处的默认侦听器。

systemd 解析的配置文件/etc/systemd/resolved.conf在其注释中显示了这一点 - 例如在 ubuntu impish (21.10) 中。

# systemd --version
systemd 248 (248.3-1ubuntu8)
...

# man resolved.conf
...
DNSStubListener=
       Takes a boolean argument or one of "udp" and "tcp". If "udp", a DNS stub resolver will listen for UDP requests on address 127.0.0.53 port 53. If "tcp",
       the stub will listen for TCP requests on the same address and port. If "yes" (the default), the stub listens for both UDP and TCP requests. If "no", the
       stub listener is disabled.

       Note that the DNS stub listener is turned off implicitly when its listening address and port are already in use.

DNSStubListenerExtra=
   Takes an IPv4 or IPv6 address to listen on. The address may be optionally prefixed with a protocol name ("udp" or "tcp") separated with ":". If the
   protocol is not specified, the service will listen on both UDP and TCP. It may be also optionally suffixed by a numeric port number with separator ":".
   When an IPv6 address is specified with a port number, then the address must be in the square brackets. If the port is not specified, then the service
   uses port 53. Note that this is independent of the primary DNS stub configured with DNSStubListener=, and only configures additional sockets to listen
   on. This option can be specified multiple times. If an empty string is assigned, then the all previous assignments are cleared. Defaults to unset.

   Examples:

       DNSStubListenerExtra=192.168.10.10
       DNSStubListenerExtra=2001:db8:0:f102::10
       DNSStubListenerExtra=192.168.10.11:9953
       DNSStubListenerExtra=[2001:db8:0:f102::11]:9953
       DNSStubListenerExtra=tcp:192.168.10.12
       DNSStubListenerExtra=udp:2001:db8:0:f102::12
       DNSStubListenerExtra=tcp:192.168.10.13:9953
       DNSStubListenerExtra=udp:[2001:db8:0:f102::13]:9953
...

这是一个明确的答案,方便参考。@TCB13已经将其声明为评论。

相关内容