基于LWIP协议栈实现DNS服务

前言

TCP/IP协议是网络通讯的基础,平常在对TCP/IP协议设置时会涉及到IP地址,子网掩码,默认网关和DNS这几个参数。这里我们主要谈下IP地址和DNS这两个参数之间的关系。

首先计算机在网络中进行通讯时只能识别“101.86.134.121”之类的IP地址,那么为什么我们平时在访问网站时只在浏览器地址栏中输入“www.baidu.com”之类的域名就能看到所需要的页面呢?这是因为DNS服务器在起到一个翻译的作用。这么做的原因其实很容易理解,因为IP地址没有规律,很难记,但是访问网站必须要事先知道对方服务器的IP地址,那么就选择了像www.baidu.com,www.163.com这些有意义的字符串(域名)代替了IP地址,同时发明了DNS服务器对这些域名进行解析,DNS服务器知道所有域名对应的IP地址,当我们访问www.baidu.com的时候,计算机会去向DNS服务器查询这个域名对应的IP地址,当计算机拿到IP地址后就可以访问该网站了。


DNS查询

DNS 查询的过程如下:

  • 在浏览器中输入http://www.baidu.com域名,计算机会先检查自己本地的hosts文件、本地DNS解析器缓存是否有这个网址映射关系,如果有则直接返回,完成域名解析。
  • 如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,会通过TCP/IP参数中设置的首选DNS服务器进行查询,如果该服务器具有网址映射关系,则调用这个IP地址映射,完成域名解析。
  • 当以上的DNS服务器和缓存解析都失效了,则会将请求转发至上一级DNS服务器或根DNS进行解析,以此循环。该过程属于DNS服务器之间的交互查询。

使用浏览器请求网站,通过Wireshark抓包分析DNS数据包如下所示:DNS为应用层协议,在传输层UDP协议基础上实现,DNS目的端口(Dst Port)是53,域名为www.baidu.com,DNS服务器的IP地址是(172.20.1.2 在网络连接中配置)。作为DNS服务器,可以通过监听网卡53端口号的数据来获得DNS数据包,对应DNS协议格式进行解析。

基于LWIP协议栈实现DNS服务


LWIP实现

接下来讲述下LwIP协议栈对DNS服务的支持。LwIP是应用于嵌入式领域的轻量级开源以太网协议栈, 它使用C语言实现非常方便移植,而且支持socket接口,因此使用十分广泛。LwIP协议栈中涉及到DNS服务的代码为dns.c文件,主要功能是完成ipv4的客户端域名解析,不涉及复杂的服务器端的处理过程。客户端调用API接口可以实现DNS查询请求,解析DNS响应,建立本地缓存。

  • 宏定义开启DNS模块

基于LWIP协议栈实现DNS服务

  • 配置DNS服务器地址,类似在网络连接中配置DNS服务器地址,也可以通过DHCP方式自动分配

基于LWIP协议栈实现DNS服务

  • DNS初始化,其中包括创建UDP pcb,配置默认DNS服务器,如果有本地缓存则初始化缓存列表(该函数在初始化时执行)。

基于LWIP协议栈实现DNS服务

  • 通过域名字符串解析出IP地址。客户端需要根据域名获取对应的IP地址时,如果不久前已经查询过该域名对应的IP地址,那么直接从本地DNS解析器缓存中获取(dns_lookup函数)。否则,客户端就以DNS客户的身份,向DNS服务器发出查询请求报文(dns_enqueue函数,此时返回状态ERR_INPROGRESS正在处理,后续dns_tmr函数会周期处理请求队列的内容)。

基于LWIP协议栈实现DNS服务

  • 该函数需要周期处理,主要作用是处理向DNS服务器请求的队列

基于LWIP协议栈实现DNS服务

  • 该函数向队列中加入一条向DNS服务器查询的请求,并且根据每条请求的状态进行对应的处理

基于LWIP协议栈实现DNS服务

  • 接收函数在初始化时注册到UDP pcb中,用于处理接收到的DNS响应包。在接收函数中会将获取的IP地址保存至对应的dns_table[DNS_TABLE_SIZE]中

基于LWIP协议栈实现DNS服务

基于LWIP协议栈实现DNS服务