跳至正文
老丹的足迹 —— 代码写给机器,游记写给自己,感悟写给时间
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面

Ubuntu 上 mDNS 解析异常排查实录:从 Docker 劫持到 firewalld 放行

背景

两台 Ubuntu 主机:

主机名局域网 IP网卡防火墙
ubuphy001192.168.1.104enp1s0firewalld
ubuvm001192.168.1.103ens33UFW

ubuphy001 上运行了 Docker,创建了多个网桥接口。目标:让 ping ubuphy001.local 解析到本机真实的局域网 IP。

问题现象

最初在 ubuphy001 上执行:

ping ubuphy001.local
PING ubuphy001.local (172.21.0.1) 56(84) bytes of data.

返回的竟然是 Docker 网桥地址,而不是 192.168.1.104。

而 ping ubuphy001(不带 .local)返回 127.0.1.1,这是 /etc/hosts 里的回环别名,与 mDNS 无关,属于正常现象。

第一层问题:Avahi 把 Docker 网桥 IP 也广播了出去

原因

avahi-daemon 默认会在所有处于 UP 状态的网络接口上注册本机地址。Docker 创建的 docker0、br-xxxx 网桥也是接口,它们上面的 IP(如 172.20.0.1、172.21.0.1)就被 Avahi 一并当作”本机可用地址”发布出去了。

当有设备查询 ubuphy001.local 时,Avahi 返回了包含 Docker IP 的地址列表,系统优先选中了 Docker 网桥地址。

解决:限制 Avahi 的广播接口

编辑 /etc/avahi/avahi-daemon.conf,在 [server] 段落中指定只允许物理网卡:

[server]
allow-interfaces=enp1s0

这里有一个关键认知:deny-interfaces 不支持 br-* 这类通配符。Avahi 官方只接受逗号分隔的接口名列表,社区里流传的 br-* 写法属于”碰巧能用”的副作用,并不可靠。更稳妥的做法是用 allow-interfaces 白名单,只放行物理网卡,Docker 接口自动被排除。

改完后重启 Avahi:

sudo systemctl restart avahi-daemon.service

改完 allow-interfaces 后,ping 自己反而失败了

重启 Avahi 后出现了一个新现象:

ping ubuphy001.local
ping: ubuphy001.local: Name or service not known

这跟防火墙没有关系。

ping xxx.local 的解析路径是:

ping → NSS → nss-mdns → 本机 Avahi 守护进程(D-Bus / 本地 socket)→ 返回结果

这是一条纯本机进程间通信的路径,不经过网络层,也不经过防火墙。

真正的原因是:allow-interfaces 改动后,Avahi 需要重新枚举接口并重新注册本机主机名。在某些时序下,Avahi 重启后没有正确发布 ubuphy001.local 这个主机名记录,导致本机 NSS 查询返回 Name or service not known。

再重启一次 Avahi,让它重新走一遍注册流程,主机名就恢复了:

sudo systemctl restart avahi-daemon.service

第二层问题:局域网内其他设备无法解析本机

现象

在 ubuvm001 上执行 avahi-browse -alr,看不到 ubuphy001 的任何服务。同时,从 ubuvm001 ping ubuphy001.local 也可能失败。

原因

mDNS 使用多播地址 224.0.0.251:5353(IPv4)。如果 ubuphy001 的防火墙拦截了 mDNS 多播包,它的广播就传不出去,局域网内其他设备收不到它的公告,自然无法解析 ubuphy001.local。

注意:这影响的是”别人能否解析你”,不影响”你自己 ping 自己”。

解决:放行防火墙的 mDNS 服务

ubuphy001 使用 firewalld:

sudo firewall-cmd --permanent --add-service=mdns
sudo firewall-cmd --reload
sudo firewall-cmd --list-services

输出中应包含 mdns:

dhcpv6-client http https mdns ssh

ubuvm001 使用 UFW:

sudo ufw allow 5353/udp

最终结果

在 ubuphy001 上:

ping ubuphy001.local
PING ubuphy001.local (192.168.1.104) 56(84) bytes of data.
64 bytes from ubuphy001 (192.168.1.104): icmp_seq=1 ttl=64 time=0.077 ms
...

在 ubuvm001 上:

ping ubuphy001.local
PING ubuphy001.local (192.168.1.104) 56(84) bytes of data.
64 bytes from 192.168.1.104 (192.168.1.104): icmp_seq=1 ttl=64 time=0.524 ms
...

双向解析均恢复正常。

关于 avahi-browse 的补充说明

排查过程中容易产生一个误解:以为 avahi-browse 能列出所有主机。

实际上,avahi-browse 的工作是发现网络上广播的服务(Service Discovery),不是列出所有主机名。它显示的是”某台机器通过 mDNS 宣告了某个服务”。

  • ubuvm001 之所以出现在 ubuphy001 的 avahi-browse 输出中,是因为它注册了 Device Info 和 Microsoft Windows Network(SMB)服务。
  • 如果一台机器只跑了 Avahi 的基础主机名广播,没有注册任何服务,那么 avahi-browse 就看不到它——这跟 -l 参数无关。

验证主机名解析,应该用 avahi-resolve -n xxx.local,而不是 avahi-browse。

关键认知总结

层面配置作用影响范围
Avahi 广播层allow-interfaces=enp1s0决定 Avahi 在哪个网卡上说话,排除 Docker 接口影响本机 mDNS 广播内容
Avahi 重启systemctl restart avahi-daemon重新注册主机名记录影响本机 .local 解析是否正常
防火墙层firewall-cmd --add-service=mdns 或 ufw allow 5353/udp决定 mDNS 多播包能否通过防火墙影响其他设备能否解析本机

三个容易混淆的点:

  1. ping xxx.local 走本机进程间通信,不经过防火墙。 本机解析失败,查 Avahi 状态和 NSS 配置,不要查防火墙。
  2. 防火墙只影响”别人能否解析你”。 放行 5353/udp 解决的是局域网内其他设备的解析问题。
  3. deny-interfaces 不支持通配符。 用 allow-interfaces 白名单更稳妥。

附:完整操作清单

ubuphy001(firewalld):

# 1. 限制 Avahi 只在物理网卡上广播
sudo vi /etc/avahi/avahi-daemon.conf
# 在 [server] 段落添加:
# allow-interfaces=enp1s0

# 2. 重启 Avahi
sudo systemctl restart avahi-daemon.service

# 3. 放行 firewalld 的 mDNS 服务
sudo firewall-cmd --permanent --add-service=mdns
sudo firewall-cmd --reload

# 4. 验证
ping ubuphy001.local
avahi-resolve -n ubuphy001.local

ubuvm001(UFW):

sudo ufw allow 5353/udp
ping ubuphy001.local
作者

老丹

关注我
其他文章
上一个

为什么 SSH 里的 Vim 复制粘贴这么难用?

下一个

WebDAV 详解:让远程文件像本地硬盘一样好用

关于博主

    老丹是一名C/C++后台开发工程师,信奉“无抽象不设计,无性能不生产”。

  • 技术栈:Modern C++、Linux环境编程、多线程/并发、网络编程等。
  • 信条:能用constexpr解决的问题绝不拖到运行时,能靠RAII避免的泄漏绝不写析构。
  • 正在填坑:从解封装到渲染的C++全链路实现,正在驯服FFmpeg与H.264/H.265。
  • 输出原则:这里的每一段代码都经过-Wall -Wextra -Werror -O2的洗礼。

近期文章

  • 在 Windows 里养一只 Linux:WSL 完整指南 2026年10月24日
  • Paho MQTT C 与 C++ 客户端库完全指南:从概念到 Ubuntu 26.04 下的编译、安装与使用 2026年10月23日
  • Mosquitto $SYS 主题详解:Broker 自监控指南 2026年10月23日
  • 应用级 MQTT 服务搭建完全指南:Mosquitto + 宿主机 Nginx 2026年10月22日
  • OpenWrt 固件签名三剑客:usign、ucert 与 fwtool 深度解析 2026年10月21日

文章分类

  • C/C++开发 (22)
  • Docker容器 (5)
  • Linux工具包 (21)
  • Linux服务配置 (53)
  • Linux系统 (16)
  • MQTT技术 (6)
  • OpenWrt路由 (5)
  • Shell脚本 (3)
  • 代码管理 (1)
  • 安防技术 (4)
  • 数据安全 (36)
  • 网络协议 (25)
  • 计算机理论 (23)
  • 问题解决 (3)
  • 防火墙 (6)
  • 音视频技术 (6)
联系我们:📍 地址:中国·广东省深圳市   |   ✉️ 邮箱:support@tanglinux.com   |   💬 QQ:870866607
版权所有:老丹的足迹粤ICP备2026061170号-1       公安备案图标 粤公网安备44030002013274号