组播DNS
在计算机网络中,多播DNS(mDNS)协议将主机名解析为不包含本地名称服务器的小型网络中的IP地址。它是一种零配置服务,使用与单播域名系统(DNS)基本相同的编程接口,数据包格式和操作语义。虽然Stuart Cheshire将mDNS设计为独立协议,但它可以与标准DNS服务器协同工作。
mDNS协议作为RFC 6762发布,使用IP多播用户数据报协议(UDP)数据包,由Apple Bonjour和开源Avahi软件包实现。Android包含mDNS实现。 mDNS也已在Windows 10中实现,但其在那里的使用仅限于发现网络打印机。
mDNS可以与DNS服务发现(DNS-SD)结合使用,DNS服务发现是RFC 6763中单独指定的配套零配置技术。
协议概述
当mDNS客户端需要解析主机名时,它会发送IP多播查询消息,要求具有该名称的主机标识自己。然后该目标机器多播包含其IP地址的消息。然后,该子网中的所有计算机都可以使用该信息来更新其mDNS高速缓存。
任何主机都可以通过发送生存时间(TTL)等于零的响应数据包来放弃对域名的声明。
默认情况下,mDNS仅限并且专门解析以.local顶级域(TLD)结尾的主机名。如果该域包括未实现mDNS但可以通过传统单播DNS服务器找到的主机,则会导致问题。解决此类冲突需要违反零配置目标的网络配置更改。
包结构
mDNS消息是发送到以下位置的多播UDP数据包:
- 使用以太网帧时,标准组播 MAC地址 01:00:5E:00:00:FB(对于IPv4)或33:33:00:00:00:FB(对于IPv6)。
- IPv4地址 224.0.0.251或IPv6地址 ff02 :: fb。
- UDP 端口 5353。
有效载荷结构基于单播DNS数据包格式,由两部分组成 - 标头和数据。
标题与单播DNS中的标题相同,数据部分中的子节也是如此:查询,答案,权威名称服务器和其他记录。
每个子节中的记录数与标题中相应的* COUNT字段的值相匹配。
示例代码
package main
import (
"context"
"github.com/grandcat/zeroconf"
"log"
"time"
)
func main() {
for {
// Discover all services on the network (e.g. _workstation._tcp)
resolver, err := zeroconf.NewResolver(nil)
if err != nil {
log.Fatalln("Failed to initialize resolver:", err.Error())
}
entries := make(chan *zeroconf.ServiceEntry)
go func(results <-chan *zeroconf.ServiceEntry) {
for entry := range results {
log.Println(entry)
}
log.Println("No more entries.")
}(entries)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel()
err = resolver.Browse(ctx, "_workstation._tcp", "local.", entries)
if err != nil {
log.Fatalln("Failed to browse:", err.Error())
}
<-ctx.Done()
}
}