dnsmasq 无法绑定 53 端口:找出占用该套接字的进程
53 端口上的 bind 失败是套接字归属问题。先读监听者,再看通配地址的范围,然后决定由哪个守护进程应答 VPN 客户端。
dnsmasq 退出并提示地址已被占用,而日志只点出端口,不点出元凶。在同时运行 VPN 的机器上,第一反应是怀疑被推送的路由,但 bind 失败发生在任何客户端发出查询之前。已经有东西占着这个套接字,任务就是把它找出来。改路由并不能释放端口。
按这个顺序走五步:复现错误、列出监听者、理解通配地址、分派职责,最后验证。
第 1 步:复现并读取错误
用服务所用的同一份配置在前台启动 dnsmasq,错误就会出现在你的终端里,而不是需要猜测的日志里。留意消息中的地址族和本地地址。绑定到具体地址与绑定到通配地址是两种不同的失败,归属者也不同。
保留原文。地址被占用、权限失败和接口不存在都会表现为启动失败,而它们指向三种不同的修复。
第 2 步:列出占用者
先列套接字。以源端口 53 过滤,在有权限查看时会同时显示两种传输协议和占用进程:
ss -lntup 'sport = :53'按列读输出:传输协议、本地地址、端口、进程。TCP 监听者和 UDP 监听者是两个独立的套接字,停掉一个并不会释放另一个。通配地址覆盖所有接口,也就是说 VPN 地址其实已被占用,哪怕没有任何一行点名。进程名还能告诉你,这是发行版托管的解析器、容器,还是上一次实验留下的东西。
第 3 步:通配地址的陷阱
bind-interfaces 选项决定 dnsmasq 是绑定一个通配套接字,还是每个已配置接口各绑一个,正如 dnsmasq 参考手册 所述。不启用它时,dnsmasq 可能绑定通配地址、改为按接口过滤请求,一旦别的守护进程占着通配地址就会立刻失败。Linux 增加了 bind-dynamic,用于处理启动之后才创建的接口;VPN 接口只在连接时才出现,这就是实打实的问题。
这就是为什么两个看起来分别配置给不同接口的守护进程仍然会撞车。冲突在套接字,而不在意图。请有意识地选择绑定方式,改动之前先读你所装版本文档写明的行为。
第 4 步:分派职责
决定由哪个守护进程应答 VPN 客户端、哪个应答主机。一个在隧道地址上监听并向上游转发的解析器是常见做法;两个解析器各自以为独占 53 端口,那根本不成其为做法。
然后把这一决定写进每个服务自己的配置:监听地址、接口过滤和转发。改动要经由服务的归属方完成,无论是发行版的单元、网络管理器还是容器运行时,这样改动才能挺过重启。
第 5 步:先验证套接字,再验证路径
重启之后,先确认预期的套接字确实存在,再去测客户端。从未绑定成功的守护进程救不回来,路由也救不了;而在绑定正确的套接字上客户端失败,是另一个问题、另一种修法。然后再从隧道里的客户端检查可达性。只有做完这些,才值得去问所需的名字能否解析。
三个结果要分开看:套接字存在、客户端能到达、答案正确。
不要做的事
不要在不知道谁依赖它的情况下,为了腾出端口而停掉一个陌生的解析器,因为主机自身的查询通常就依赖它。不要照搬把第二个守护进程挪到公网监听地址的旧配方,那会顺带决定谁能来查询你。失败本来就是本地问题时,也不要加转发。
如果机器是受管环境,把归属决定记在下一任管理员能找到的地方。每次重建镜像,端口冲突都会回来。