什么是ZeroConf?
零配置网络协议规范,是一种自动生成可用ip地址的网络技术、自动化配置管理网络的一种规范。即计算机或一些网络设备可以无需任何配置可以自动互连并可发现各自相关的服务。多应用于局域网,如自动发现可用打印机、MacBook可以自动发现连入同一局域网内iphone设备并使用相关服务等。
如何实现?
从技术层面上讲,ZeroConf是三种技术的组合:
- Link-Local Address: 无需利用DHCP Server 取得设备地址和IP的相关资料 【RFC3927】
- Multicast Dns: 不需要DNS Server 就可以解决domain 和ip的绑定关系 【RFC6762】
- DNS-SD(dns-based service discovery): 不需要目录服务器,就可以自动发现设备服务 【RFC6763】
接下来我们逐一介绍,这三种技术的大致原理及简单过程:
Link-Local Address
Link-Local Address
(链接本地地址): 网络设备无需通过DHCP或者配置,设备自己负责获取一个可以的IP地址。
主要原理:Link-Local Address 首选有一个固定的可选地址范围:169.254.0.0 ~ 169.254.255.255,在此范围内随机选择一个IP后,通过借助ARP协议,完成IP的选择和通告。
ARP简单介绍:
ARP 协议(Address Resolution Protocol): 地址解析协议, 用于实现IP到MAC地址的映射, 即询问目标IP对应的MAC地址
小栗子:
如下图: A, B, C 同属一个局域网,若A要获取B的MAC地址时,会先广播一个ARP包,包的内容:会带上自己的mac-A,IPA, 目的端IPB,当B收到后,发现目的IP是自己的,就会填上自己的mac地址发回到A,C发现不是自己的IP则会丢弃掉。
简单讲就是: 广播问,单播答。询问时带自己的信息,非IP本身者丢掉广播包
自获取IP的大致的过程:
首先必须先在 169.254.0.0 ~ 169.254.255.255范围内随机选择一个IP(如果某设备以前使用过某个ip,优先使用之前使用过的ip)
进入
探测阶段,假设选择的ip为 169.254.187.245
发送地址解析协议(ARP)请求,请求与169.254.187.245 匹配的MAC地址,发送的ARP包为:
发送端的MAC:0 发送端ip为:0.0.0.0
目的方MAC为:0 目的IP:169.254.187.245
发送3次,间隔大致1到2秒, 如果此时有设备已经占用了169.254.187.245,那么重新回到1,重新开始探测
4. 当探测结束后,需要进行宣告,进入宣告阶段,告诉其他设备自己选用的ip地址,宣告包发送2次, 间隔2秒
宣告包的格式:
发送方ip为:169.254.187.245 发送方的MAC地址:自己设备的MAC地址
目的IP地址为:169.254.187.245 目的MAC地址为:0
Multicast Dns
Multicast Dns(组播DNS):可理解为局域网内的DNS系统,主要用于hostname和ip的绑定. 组播DNS的单播DNS的包格式基本相同.
顶级域为“.local”
默认端口: 5353, 目的ip(可理解为”DNS服务器”):224.0.0.251
简单讲:设备A通过发送组播DNS包(hostA和ipA对应关系)到224.0.0.251,这样局域网中其他设备都会收到这个包,会将hostA和ipA对应关系缓存到各自内存中。
大致过程:
- 设置设备的hostName,假设为:hostA.local,ip为:1.2.3.4
- 发送组播DNS查询, 发送3次后,没有响应,进入宣告阶段, DNS查询包内容:
hostA.local IN ANY
4.3.2.1.in-addr.arpa IN ANY
- 将hostName和ip的A记录等信息,放到dns查询包的answer区域, 宣告包的内容:
hostA.local IN A 1.2.3.4
4.3.2.1.in-addr.arpa IN PTR hostA.local
hostA.local IN HIFO cpu x86_64 os linux
- 有冲突的话,重新选择hostName,重新开始。
DNS-SD(dns-based service discovery)
DNS-SD: 基于DNS的服务发现,需明确发现的服务,而不是某个设备(一个设备可能会包含很多服务)
简单讲:分为发布服务和浏览服务,发布服务即告知局域网其他网络设备,自己有哪些服务,浏览服务即发现局域网内拥有某个服务的设备具体的ip地址和端口,借助以下的3种DNS记录完成(请看大致过程),同样将DNS的查询或者响应包发送到224.0.0.251上,这样网内的其他设备就能将相关的信息保存自己本地或者响应相关的信息。
主要作用:
1.枚举给定类型网络上的服务名称的列表 (比如:局域网中拥有打印机服务的设备有:打印机A,打印机B)
2.将上述礼拜的名称转换为连接和使用该列表的ip,即找到打印机A的ip地址
通过DNS的三个记录实现:
1) PTR: 用来将服务类型映射到被命名的实例上
2) SRV: 用于服务实例的位置(IP地址)和端口号
3) TXT: 用于提供服务类型的附加数据
DNS-SD使用PTR记录的样例格式:
serverType.Domain IN PTR InstanceA.ServiceType.Domain
serverType.Domain IN PTR InstanceB.ServiceType.Domain
这样,在查询serverType类型时, 会找到具体的服务名称实例列表:InstanceA、InstanceB
DNS-SD使用SRV记录的样例格式:
InstanceA.ServiceType.Domain IN SRV 0 0 80 A.target.local
A.target.local IN A 1.1.1.1
SRV记录说明:
_Service.Proto.Name TTL Class SRV Priority Weight Port Target
Service: 服务名称,前缀“”是为防止与DNS Label(普通域名)冲突。
Proto: 服务使用的通信协议,_TCP、_UDP、其它标准协议或者自定义的协议。
Name: 提供服务的域名。
TTL: 缓存有效时间。
CLASS: 类别
Priority: 该记录的优先级,数值越小表示优先级越高,范围0-65535。
Weight: 该记录的权重,数值越高权重越高,范围0-65535。
Port: 服务端口号,0-65535。
Target: host地址。
DNS-SD使用TXT记录的样例格式:
InstanceA.ServiceType.Domain IN TXT "path=/abc/"
接下来我们看,DNS-SD是如何借助以上3个DNS记录来发布和浏览服务的。
发布服务的主要过程
假设需发布的服务类型为”_http._tcp”,实例名称为:”JustinWeb2._http._tcp”
- 发送Dns组播查询,查询内容为:
JustinWeb2._http._tcp IN ANY
- 没有同名实例名称的情况下,发送Dns组播响应包:
_http.tcp.local IN PTR JustinWeb2. _http._tcp
JustinWeb2. _http._tcp IN SRV 0 0 80 A.target.local
JustinWeb2. _http._tcp IN TXT
“path=/”
A.target.local IN A 1.1.1.1
_services._dns-sd._udp.local IN PTR _http._tcp.local
- 如果有冲突,就更换实例名称重新到1
浏览服务器的主要过程
假设需发现的服务类型为”_http._tcp”
1.发送Dns组播查询,查询内容为:
_http._tcp.local IN PTR
- 同局域网内中其他拥有”_http._tcp”服务类型的设备,会响应组播DNS包:
_http.tcp.local IN PTR A._http._tcp.local
A._http._tcp.local IN SRV 0 0 80 A.target.local
A.target.local IN A 1.1.1.1
A._http._tcp.local IN TXT
“path=/”
- 接受到所有设备的响应后,第二次发送组播查询,此时会在answer区域带上,所有设备的服务类型
- 发送三次后,之后所有查询在其他设备服务未变化的情况下,不再响应内容
开源实现软件
- 开源的zeroconf协议技术实现 – Avahi (仅支持linux平台)
- Apple的zeroconf协议技术实现 – Bonjour (os,linux,windows都可以支持。)
抓包分析过程
环境:
使用公司的虚拟机,【同一个路由下可能多个虚拟机】
10.16.77.232 (hostname为:justinfoo) :主要用于发布服务
10.16.77.235 :主要用于发现服务
软件:
因在linux平台,故使用开源软件Avahi
可源码编译或通过yum安装
yum install avahi
yum install avahi-devel
yum install avahi-tools.x86_64
安装后,还需启动
1. dbus-daemon --system
【因avahi-daemon,需依赖dbus进行进程间通信,故需启动】
2. avahi-daemon -D
注:如果在mac或者iphone上测试,可使用系统的mDNSResponder服务和dns-sd命令测试
Link-Local Address
因测试机均已经配置了相关的ip地址,未进行环境模拟进行抓包分析,有兴趣的同学可以自己试试。
Multicast Dns
ip与hostname的绑定过程分析:
- 在10.16.77.232测试机上,启动 avahi-daemon -D时
- 同时在10.16.77.235上,进行“tcpdump -i eth0 port 5353 -w mdns.pcap”抓包
- 用Wireshark打开上述mdns.pcap文件:
从图中可以看出(结合第二节相关过程),10.16.77.232首先进行了3次查询(每次间隔250毫秒),从DNS包中的query部分可以看出查询的内容:
232.77.16.10.in-addr.arpa: type ANY, class IN, "QM" question
justinfoo.local: type ANY, class IN, "QM" question
也就是询问同一局域网中,有没有其他机器正在使用10.16.77.232和justinfoo.local的。
如果没有其他机器响应,10.16.77.232会接着发送宣告包:
从图中可看出,宣告包即为DNS的响应包,在dns包的answer区域内,会把justinfoo.local和10.16.77.232信息告知同一局域网中的所有机器.
DNS-SD
接下来我们分析,在10.16.77.235上,如何发现本局域网中相关类型的服务的,使用Avahi的工具 avahi-browse
1. 假设我们需要在10.16.77.235机器上查看同局域网中是否有其他机器存在打印机服务
[root@de01v examples]# avahi-browse "_printer._tcp" -r
注:”_printer._tcp“ 为“_服务类型名 . _协议类型”, 详细可看参考链接
假设此时局域网中没有相关服务,抓包截图:
图中可看出,在定期的查询”_printer._tcp.local”的DNS ptr记录
2.在10.16.77.232发布一个服务,服务名为”justin-test”的打印机服务。
[root@de02v examples]# avahi-publish -s "justin-test" "_printer._tcp" 123
当3次探测包发送后,局域网中其他机器没有同名的服务,那么进入宣告阶段,会发送DNS响应包,在answer区域中带上以下相关信息:
从图中可以看出,10.16.77.232向局域网中发布的内容为,服务名”justin-test”的打印机服务在justinfoo.local的机器上,此机器的IP为10.16.77.232
3.此时在10.16.77.235机器上我们就能发现刚发布的”justin-test”的相关信息:
从抓包截图中也可看出:
总结
以上仅对ZeroConf的基本流程进行了大致的介绍,ZeroConf是自治服务发现的一种将对简单而出色的解决方案,目前在苹果的设备中已经广泛使用,当下IOT的迅猛发展,以及各种设备层出不穷,我们也初步尝试将ZeroConf移植到了一些android和ios平台的设备中,用于服务发现及设备自动化互联。