应用调用 getaddrinfo 之后,到底发生了什么?操作系统里的“存根解析器”按什么规则选名字服务器、要不要加搜索域、先查 /etc/hosts 还是先发 DNS、.local 为什么走多播?这篇用抓包把一次次 getaddrinfo 在线路上的真实动作逐个看清,并且只保留本机自己发出的包。
默认(非作用域)解析器共 7 个:
resolver #1 | search domain[0] : lan | nameserver[0] : 114.114.114.114 | nameserver[1] : 223.5.5.5 | flags : Request A records
resolver #2 | domain : local | options : mdns | timeout : 5 | flags : Request A records | order : 300000
resolver #3 | domain : 254.169.in-addr.arpa | options : mdns | timeout : 5 | flags : Request A records | order : 300200
resolver #4 | domain : 8.e.f.ip6.arpa | options : mdns | timeout : 5 | flags : Request A records | order : 300400
resolver #5 | domain : 9.e.f.ip6.arpa | options : mdns | timeout : 5 | flags : Request A records | order : 300600
resolver #6 | domain : a.e.f.ip6.arpa | options : mdns | timeout : 5 | flags : Request A records | order : 300800
resolver #7 | domain : b.e.f.ip6.arpa | options : mdns | timeout : 5 | flags : Request A records | order : 301000
/etc/hosts 的文件头说明它在 macOS 上“不被大多数进程用于 DNS 主机名解析”——但里面的 localhost / broadcasthost 仍有效(第四节验证)macOS 按系统配置里的 7 个解析器按后缀选择:1 个负责普通名字,其余 6 个是 mDNS(local 与链路本地反向域)。
AF_UNSPEC:耗时 291 ms,失败 gaierror;抓到 2 个包
+ 0.0 ms → 114.114.114.114 查询 [('w73-rzavjmvt.example.com.', 'A')]
+ 285.2 ms ← 114.114.114.114 响应 [('w73-rzavjmvt.example.com.', 'A')] RCODE 3,回答 0
只要 IPv4(AF_INET):耗时 259 ms;抓到 2 个包
+ 0.0 ms → 114.114.114.114 查询 [('w73-ngvtezst.example.com.', 'A')]
+ 256.1 ms ← 114.114.114.114 响应 [('w73-ngvtezst.example.com.', 'A')] RCODE 3,回答 0
AF_INET 时发出的查询类型:['A']没有可用的 IPv6,配置标志是 Request A records:即使要求 IPv4+IPv6,线上也只有 A 查询。
耗时 55 ms,失败:gaierror [Errno 8] nodename nor servname provided, or not known;抓到 4 个包
+ 0.0 ms → 114.114.114.114 查询 [('w73hostbdgchl.lan.', 'A')]
+ 27.7 ms ← 114.114.114.114 响应 [('w73hostbdgchl.lan.', 'A')] RCODE 3,回答 0
+ 31.0 ms → 114.114.114.114 查询 [('w73hostbdgchl.', 'A')]
+ 46.7 ms ← 114.114.114.114 响应 [('w73hostbdgchl.', 'A')] RCODE 3,回答 0
出现过的查询名字:['w73hostbdgchl.', 'w73hostbdgchl.lan.'](带不带搜索域后缀、是否有裸名字)
这次查询发往的服务器:['114.114.114.114']单标签名字先加搜索域 lan 问一次,NXDOMAIN 后再问不带后缀的裸名字。
localhost:耗时 0.8 ms,结果 ['127.0.0.1', '::1'];抓到的 DNS / mDNS 包 0 个 broadcasthost:耗时 2.8 ms,结果 ['255.255.255.255'];抓到的 DNS / mDNS 包 1 个
localhost 等条目不发 DNS 包;自定义条目是否生效没有测。
getaddrinfo("w73-rskhta.local"):耗时 5002 ms,失败:gaierror;抓到 4 个包:
+ 0.0 ms mDNS 本机→224.0.0.251 查询 [('w73-rskhta.local.', 'A')]
+ 1004.6 ms mDNS 本机→224.0.0.251 查询 [('w73-rskhta.local.', 'A')]
+ 3723.7 ms mDNS 本机→224.0.0.251 查询 [('_adb-tls-connect._tcp.local.', <RdataType.ANY: 255>), ('_adb-tls-pairing._tcp.local.', <RdataType.ANY: 255>), ('_adb._tcp.local.', <RdataType.ANY: 255>)]
+ 4012.0 ms mDNS 本机→224.0.0.251 查询 [('w73-rskhta.local.', 'A')]
按(类型, 目的地址)计数:{('mdns', '224.0.0.251'): 4}.local 名字向 224.0.0.251 发多播查询,查不到要等 5 秒超时。