mDNS

mDNS(Multicast DNS,组播 DNS)是一种在本地局域网内、无需专用 DNS 服务器就能做主机名解析与服务发现的协议。

功能

  • 主机名解析:把 my-printer.local 解析成 IP,适用于临时/家庭/小型网络,无需搭建 DNS。

  • 服务发现(配合 DNS-SD):发现“有哪些 AirPlay、打印、HTTP 服务”等,而不仅仅是主机名。例如浏览 _airplay._tcp.local、_http._tcp.local。

关键点一览

  • 端口与地址:UDP/5353;IPv4 组播 224.0.0.251,IPv6 组播 ff02::fb(链路本地,路由器不会转发)。

    • 正确的 mDNS 查询(多播)需要满足

      • IP Header 中目标IP地址属于多播地址 224.0.0.251 或 ff02::fb

      • Ethernet Header中目标 MAC 属于多播 MAC(由多播IP编码而成)

        1. IPv4 mDNS(224.0.0.251)→ 01:00:5e:00:00:fb

          规则:01:00:5e + IPv4 多播地址的低 23 位(RFC 1112)。对 224.0.0.251(0xE0.00.00.FB)映射即 00:00:fb。

        2. IPv6 mDNS(ff02::fb)→ 33:33:00:00:00:fb

          规则:33:33 + IPv6 组播地址的低 32 位(RFC 2464/5342)。

      • UDP、端口 5353

  • 域名后缀:通常是 .local.(RFC 6762 规定为 mDNS 专用后缀)。

  • 相关标准:RFC 6762(mDNS)、RFC 6763(DNS-SD)。

  • 常见实现/名称:Apple Bonjour(macOS/iOS),Linux 上的 Avahi,Windows 10+ 也支持 mDNS。

使用

主动查询

  1. 你要访问 host.local,系统把 DNS 查询改为发组播到 224.0.0.251:5353。

  2. 网段里拥有该名字的设备直接单播/组播回复 A/AAAA 记录(还可能带 SRV/TXT 等)。

  3. DNS-SD:要找服务时,先查询 _<service>._<proto>.local(比如 _http._tcp.local)得到服务实例名,再查 SRV/TXT 获取主机名+端口+元数据,最后查主机名的 A/AAAA。

  4. 冲突处理:设备上电会探测(probe)名字是否被占用;如冲突会改名(如 X (2).local)并宣布(announce/defend)。

被动缓存

mDNS/ DNS-SD 守护进程(macOS 的 mDNSResponder、Linux 的 avahi-daemon)会旁听所有 5353 流量,把看到的应答(含开机 announce、后续更新、goodbye=TTL 0)放进本地缓存。


主机名解析与服务发现

  • 主机名解析:只用 A/AAAA 查询 host.local

  • 服务发现(DNS-SD):查 _service._tcp.local

目标

查询名

主要 RR 类型

结果里有什么

适用场景

主机名解析

host.local.

A/AAAA(可能带附加记录)

只给你 IP(v4/v6)

你已经知道主机名,只想拿到 IP

服务发现(DNS-SD)

_<service>._<proto>.local.(例如 _http._tcp.local.)或先查 _services._dns-sd._udp.local.

PTR → SRV + TXT → A/AAAA

发现有哪些“服务实例”(名字、端口、元信息),再解析它背后的主机 IP

你不知道谁提供服务、端口是多少、或需要按类型列出

简化流程对比:

  • 主机名解析

    你发 A/AAAA host.local → 返回 A/AAAA(IP)。到此结束

  • 服务发现

    你发 PTR _http._tcp.local → 得到若干实例名(比如 "Home Assistant._http._tcp.local")

    → 对某个实例发 SRV/TXT → 得到目标主机名 + 端口 + 元数据(如路径、特性)

    → 再对目标主机名发 A/AAAA 拿到 IP。链路更长,但信息更全

_services._dns-sd._udp.local

DNS-SD 的“服务类型枚举 (Service Type Enumeration)”入口。

_services._dns-sd._udp.local 发 PTR 查询,网络里的设备会用 PTR 记录告诉你“我正在发布哪些服务类型”。返回的不是具体设备或 IP,而是一串类型名,比如:

_http._tcp.local. _airplay._tcp.local. _raop._tcp.local. _googlecast._tcp.local. _hap._tcp.local. # HomeKit / HAP _home-assistant._tcp.local. _ipp._tcp.local. # IPP 打印

这一步就像“先看看这个网段都有什么品类的服务”。

说明:设备/栈(Bonjour/Avahi)通常会自动把自己声明的服务类型通过这个入口再“指一遍”。不是强制标准动作,但主流实现都支持,所以 Browser / Scan 类工具常用它来“列清单”。

工具

# 列出全部服务 avahi-browse -at # 列出全部服务及其解析结果 avahi-browse -art # 列出网段里“有哪些服务类型” avahi-browse -rt _services._dns-sd._udp # 浏览某个服务类型(列出实例名) avahi-browse -rt _http._tcp # 针对具体实例查看 SRV/TXT/IP(avahi 会自动跟进解析) avahi-browse -rt _hap._tcp # 或 Apple 工具分步: dns-sd -B _http._tcp # 浏览类型 dns-sd -L "Home Assistant" _http._tcp local # 解析某个实例 → SRV/TXT/A/AAAA