为什么`dig`会成功,但`host`、`nslookup`、`curl`、`ping`都失败了?

bal*_*ton 3 networking linux dns iptables docker

从今天起,每当我使用带有bridge网络接口的任何 docker 容器时,某些实用程序的 DNS 解析似乎都失败了。

例如,如果我运行:

sudo docker run --rm \
    --cap-add=NET_ADMIN \
    --log-driver json-file \
    --log-opt max-size=10m \
    --net=bridge --dns 9.9.9.9 \
    alpine \
    sh -c 'apk add curl bind-tools; printf "\nDATE:\n"; date; printf "\nRESOLV.conf\n"; cat /etc/resolv.conf; printf "\nDIG:\n"; dig api.nordvpn.com; printf "\nTRACE:\n"; dig +trace api.nordvpn.com; printf "\nHOST:\n"; host -va api.nordvpn.com; printf "\nNSLOOKUP:\n"; nslookup api.nordvpn.com; printf "\nCURL:\n"; curl api.nordvpn.com; printf "\nPING:\n"; ping -c 5 api.nordvpn.com; printf "\nWHOIS:\n"; whois api.nordvpn.com; printf "\nRESOLVE:\n"; systemd-resolve --status'
Run Code Online (Sandbox Code Playgroud)

我回来了:

DATE:
Sun Jul  4 05:58:26 UTC 2021

RESOLV.conf
nameserver 9.9.9.9

DIG:

; <<>> DiG 9.16.16 <<>> api.nordvpn.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 60558
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;api.nordvpn.com.       IN  A

;; ANSWER SECTION:
api.nordvpn.com.    30  IN  A   104.17.50.74
api.nordvpn.com.    30  IN  A   104.17.49.74

;; Query time: 43 msec
;; SERVER: 9.9.9.9#53(9.9.9.9)
;; WHEN: Sun Jul 04 05:58:26 UTC 2021
;; MSG SIZE  rcvd: 106


TRACE:

; <<>> DiG 9.16.16 <<>> +trace api.nordvpn.com
;; global options: +cmd
.           39329   IN  NS  m.root-servers.net.
.           39329   IN  NS  b.root-servers.net.
.           39329   IN  NS  a.root-servers.net.
.           39329   IN  NS  e.root-servers.net.
.           39329   IN  NS  d.root-servers.net.
.           39329   IN  NS  c.root-servers.net.
.           39329   IN  NS  j.root-servers.net.
.           39329   IN  NS  k.root-servers.net.
.           39329   IN  NS  h.root-servers.net.
.           39329   IN  NS  i.root-servers.net.
.           39329   IN  NS  f.root-servers.net.
.           39329   IN  NS  g.root-servers.net.
.           39329   IN  NS  l.root-servers.net.
.           39329   IN  RRSIG   NS 8 0 518400 20210716050000 20210703040000 26838 . EB6qz8ilTb/5LvUg+xcuMuPL5KeZCcJNJxwD7kFGX/UiWdLuhk11/MZ3 R11asqSV7dC0pmttG+1h8kJG+IR022UaPBH7C/mV5vfvk5s0Vcp+DA7Y j3Rya2qm7UdTRPX3VEaL1C2ji/hnX2VIL1bU68t7OPNmhx/g0M9uwgXx hjL5jhPmRYTDInUHJThFn894VE0/HtkoIFZrWSDZjzMLf+j/CqWluRDI HH0JoOQVO5fSj7Vjtr9T67x6QG7C9qyMQ0xfTTkURkMQN4A1TEW5YGGB Ti6ypbLUmJQvHMKgFhoAc4Be/4dAm/spIlD4srIHMzECAayRXn2IXDsq xCCjaQ==
;; Received 717 bytes from 9.9.9.9#53(9.9.9.9) in 43 ms

api.nordvpn.com.    299 IN  A   104.17.50.74
api.nordvpn.com.    299 IN  A   104.17.49.74
;; Received 106 bytes from 199.7.83.42#53(l.root-servers.net) in 43 ms


HOST:
Trying "api.nordvpn.com"
Host api.nordvpn.com not found: 2(SERVFAIL)
Received 33 bytes from 9.9.9.9#53 in 43 ms

NSLOOKUP:
Server:     9.9.9.9
Address:    9.9.9.9#53

Non-authoritative answer:
Name:   api.nordvpn.com
Address: 104.17.49.74
Name:   api.nordvpn.com
Address: 104.17.50.74
** server can't find api.nordvpn.com: SERVFAIL


CURL:
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0curl: (6) Could not resolve host: api.nordvpn.com

PING:
ping: bad address 'api.nordvpn.com'

WHOIS:
[Querying whois.iana.org:43 'api.nordvpn.com']
[Redirected to whois.verisign-grs.com]
[Querying whois.verisign-grs.com:43 'api.nordvpn.com']
[Querying whois.verisign-grs.com:43 'domain api.nordvpn.com']
[whois.verisign-grs.com]
No match for domain "API.NORDVPN.COM".
>>> Last update of whois database: 2021-07-04T05:58:26Z <<<

NOTICE: The expiration date displayed in this record is the date the
registrar's sponsorship of the domain name registration in the registry is
currently set to expire. This date does not necessarily reflect the expiration
date of the domain name registrant's agreement with the sponsoring
registrar.  Users may consult the sponsoring registrar's Whois database to
view the registrar's reported date of expiration for this registration.

TERMS OF USE: You are not authorized to access or query our Whois
database through the use of electronic processes that are high-volume and
automated except as reasonably necessary to register domain names or
modify existing registrations; the Data in VeriSign Global Registry
Services' ("VeriSign") Whois database is provided by VeriSign for
information purposes only, and to assist persons in obtaining information
about or related to a domain name registration record. VeriSign does not
guarantee its accuracy. By submitting a Whois query, you agree to abide
by the following terms of use: You agree that you may use this Data only
for lawful purposes and that under no circumstances will you use this Data
to: (1) allow, enable, or otherwise support the transmission of mass
unsolicited, commercial advertising or solicitations via e-mail, telephone,
or facsimile; or (2) enable high volume, automated, electronic processes
that apply to VeriSign (or its computer systems). The compilation,
repackaging, dissemination or other use of this Data is expressly
prohibited without the prior written consent of VeriSign. You agree not to
use electronic processes that are automated and high-volume to access or
query the Whois database except as reasonably necessary to register
domain names or modify existing registrations. VeriSign reserves the right
to restrict your access to the Whois database in its sole discretion to ensure
operational stability.  VeriSign may restrict or terminate your access to the
Whois database for failure to abide by these terms of use. VeriSign
reserves the right to modify these terms at any time.

The Registry database contains ONLY .COM, .NET, .EDU domains and
Registrars.

RESOLVE:
sh: systemd-resolve: not found
Run Code Online (Sandbox Code Playgroud)

我已经试过了:

  1. 擦拭泊坞窗并重新开始
  2. 刷新 dns 并尝试不同的名称服务器
  3. 重新启动机器、docker 服务等。
  4. 清除防火墙规则

为了清除防火墙,这是我在运行 Ubuntu Server arm64 的 Raspberry Pi 4 主机上使用的

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -t nat -F
sudo iptables -t mangle -F
sudo iptables -F
sudo iptables -X
sudo ip6tables -P INPUT ACCEPT
sudo ip6tables -P FORWARD ACCEPT
sudo ip6tables -P OUTPUT ACCEPT
sudo ip6tables -t nat -F
sudo ip6tables -t mangle -F
sudo ip6tables -F
sudo ip6tables -X
sudo iptables -nvL

sudo ufw disable
sudo ufw status verbose

sudo systemctl restart docker
Run Code Online (Sandbox Code Playgroud)

所有命令在主机上都可以正常工作。

主机上的 Docker 网络接口符合预期:

> docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
73b916cb9b14   bridge    bridge    local
ea4702692896   host      host      local
03d46009da3e   none      null      local

> docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "73b916cb9b14ce7d31b091279f2763cba5e2856430ad10883ce93a2cefbf8eee",
        "Created": "2021-07-04T05:58:18.735577898Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
Run Code Online (Sandbox Code Playgroud)

use*_*686 7

hostnslookup进行多个单独的 DNS 查询——每个记录类型一个。他们想要向您显示 IPv4 和 IPv6 地址,因此他们需要进行 A 查询和 AAAA 查询。

如果您运行host -v api.nordvpn.com(使用 'verbose' 选项以类似 dig 的格式显示响应),您将看到它实际上等同于连续执行以下 3 个命令:

dig api.nordvpn.com A
dig api.nordvpn.com AAAA
dig api.nordvpn.com MX
Run Code Online (Sandbox Code Playgroud)

运行nslookup -debug api.nordvpn.com将类似地显示它同时查询 A 和 AAAA 记录(尽管不是 MX)。

如果您仔细查看 Docker 输出,您会注意到 A 查询实际上成功了,它是 AAAA 查询返回 SERVFAIL。因此,在“挖掘”中永远不会看到失败,因为您从未要求它进行 AAAA 查询。

部分失败的查询可能有几种解释:

  • 您的解析器与权威服务器存在一些连接问题,但它恰好具有从早期缓存的 A 的结果,并且仍然能够返回这些结果。

  • nordvpn.com 的权威服务器对 A 查询返回响应,但对 AAAA 查询根本没有响应。

  • 您的 DNS 请求被拦截并重定向到不同的解析器,该解析器以“不支持 IPv6”或“避免 IPv6 VPN 泄漏”或类似的借口阻止所有 AAAA 查询。

实际上,您的dig +trace输出已经表明这是第 3 种情况:

api.nordvpn.com.    299 IN  A   104.17.50.74
api.nordvpn.com.    299 IN  A   104.17.49.74
;; Received 106 bytes from 199.7.83.42#53(l.root-servers.net) in 43 ms
Run Code Online (Sandbox Code Playgroud)

在跟踪模式下,dig 首先联系根服务器,它应该在那里接收推荐响应(指向“.com”服务器的响应)并跟踪链。

但是在您的情况下, dig 以某种方式立即收到带有请求的 A 记录的直接答案。这是不是根服务器是如何工作的-他们不能够提供这样的答案。您会看到此结果的唯一时间是,如果您在端口 53 上的数据包被重定向到本地解析器,而您实际上并未与您认为正在与之通信的 DNS 服务器通信。


尝试在 192.0.2.1 或 203.0.113.1 进行 DNS 查询——如果您收到来自该地址的响应,您就会知道它是不合法的,因为该地址在 Internet 上的任何地方都不存在。)

dig @192.0.2.1 google.com
Run Code Online (Sandbox Code Playgroud)

尝试进行这些查询以找出您实际与之交谈的 DNS 服务器的名称:

dig @9.9.9.9 hostname.bind chaos txt
dig @9.9.9.9 id.server chaos txt
Run Code Online (Sandbox Code Playgroud)

(如果与真正的9.9.9.9 交谈,您应该看到类似“res600.fra.rrdns.pch.net”的内容作为 id.server 响应。)

可能值得一试traceroute --udp --port=53 9.9.9.9;它将显示正常结果,直到到达数据包被重定向的点,然后是无意义的结果。