【无OS】基于STM32移植LWIP 1.4.1之DNS
1.前言
DNS(Domain Name System)域名系统,主要实现的功能是将域名转换成ip地址的一个服务。它是由一个分层的DNS服务器实现的分布式数据库。同时,他也是一个使得主机能够查询分布式数据库的应用层协议。DNS服务器通常是一个运行BIND(Berkeley Internet Name Domain)软件的UNIX机器。DNS协议运行在UDP之上,使用53号端口。
由于有之前实现DHCP功能的基础《【无OS】基于STM32移植LWIP 1.4.1之DHCP》,所以DNS的移植很简单,下面将主要介绍LwIP DNS的流程分析。
2.LwIP如何实现DNS功能
LwIP基本上已经实现了DNS功能,我只需要打开相关的宏就可以,操作如下:
- 在lwipopts.h定义
LWIP_DNS
,打开DNS功能; - 在netconf.c的
LwIP_Init
函数中调用dns_init
,来初始化DNS客户端; - DHCP动态获取IP地址后,再调用DNS API
dns_gethostbyname
进行DNS域名解析。(参考代码如下:LwIP_DNS_Test
)
--- a/stm32f429_lwip_pro_list/2.stm32f429_lwip_basic_dhcp/User/LAN8742A/netconf.c
+++ b/stm32f429_lwip_pro_list/2.stm32f429_lwip_basic_dhcp/User/LAN8742A/netconf.c
@@ -31,6 +31,7 @@
#include "lwip/tcp.h"
#include "lwip/tcp_impl.h"
#include "lwip/udp.h"
+#include "lwip/dns.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "ethernetif.h"
@@ -137,6 +138,11 @@ void LwIP_Init(void)
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ETH_link_callback);
+
+#if LWIP_DNS
+ dns_init();
+#endif /* LWIP_DNS */
+
}
+#ifdef LWIP_DNS
+void LwIP_DNS_Callback_handler(const char *name, struct ip_addr *ipaddr, void *arg)
+{
+ uint8_t ip[4];
+
+ ip[0] = ipaddr->addr>>24;
+ ip[1] = ipaddr->addr>>16;
+ ip[2] = ipaddr->addr>>8;
+ ip[3] = ipaddr->addr;
+
+ printf("[%s]域名解析的IP:%d.%d.%d.%d\n",name,ip[3], ip[2], ip[1], ip[0]);
+}
+void LwIP_DNS_Test(void)
+{
+ struct ip_addr DNS_IP;
+ char hostname[] = "www.qq.com";
+
+ printf("\r\n开始DNS解析:%s\r\n", hostname);
+ dns_gethostbyname(hostname, &DNS_IP, LwIP_DNS_Callback_handler, NULL);
+}
+
+#endif
+
#ifdef USE_DHCP
@@ -265,6 +294,10 @@ void LwIP_DHCP_Process_Handle()
sprintf((char*)mactxt, " %02x-%02x-%02x-%02x-%02x-%02x", gnetif.hwaddr[0], gnetif.hwaddr[1], gnetif.hwaddr[2], gnetif.hwaddr[3], gnetif.hwaddr[4], gnetif.hwaddr[5]);
printf("MAC addr: %s\r\n", mactxt);
+#ifdef LWIP_DNS
+ LwIP_DNS_Test();
+#endif
+
LED1(ON);
}
else
--- a/stm32f429_lwip_pro_list/2.stm32f429_lwip_basic_dhcp/User/lwipopts.h
+++ b/stm32f429_lwip_pro_list/2.stm32f429_lwip_basic_dhcp/User/lwipopts.h
@@ -121,6 +121,9 @@ a lot of data that needs to be copied, this should be set high. */
turning this on does currently not work. */
#define LWIP_DHCP 1
+/* ---------- DNS options ---------- */
+#define LWIP_DNS 1
+
编译成功后,验证结果截图如下:
3.dns_init主要流程
dns_init其实主要初始化了UDP,设置的默认DNS Server地址后面会被覆盖。
4.如何获取DNS Server地址
通过前一篇文章DHCP的学习,DNS Server的地址和本机IP地址会通过DHCP Server一起下发。在dhcp.c
代码 中看到dhcp_handle_ack
解析DHCP Server的ACK报文时,会设置DNS Server IP地址,代码如下:
static void
dhcp_handle_ack(struct netif *netif)
{
...
#if LWIP_DNS
/* DNS servers */
n = 0;
while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) {
ip_addr_t dns_addr;
ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
dns_setserver(n, &dns_addr);
n++;
}
#endif /* LWIP_DNS */
}
使用的Wireshark抓取的DHCP报文可以再次确认,如下:
在设备运行的Log中,我们也可以看到DNS Server IP地址就是DHCP ACK报文所提供的地址:(114.114.114.114, 53)
[19:33:07.252]ip_output_if: st0
[19:33:07.253]IP header:
[19:33:07.253]+-------------------------------+
[19:33:07.254]| 4 | 5 | 0x00 | 56 | (v, hl, tos, len)
[19:33:07.268]+-------------------------------+
[19:33:07.268]| 2 |000| 0 | (id, flags, offset)
[19:33:07.269]+-------------------------------+
[19:33:07.280]| 255 | 17 | 0x0000 | (ttl, proto, chksum)
[19:33:07.281]+-------------------------------+
[19:33:07.281]| 192 | 168 | 1 | 102 | (src)
[19:33:07.295]+-------------------------------+
[19:33:07.295]| 114 | 114 | 114 | 114 | (dest)
[19:33:07.296]+-------------------------------+
5. DNS域名解析流程
我们调用DNS API域名解析函数dns_gethostbyname
后,解析流程大致如下:
6. DNS分析的设备Log
[19:33:07.232]开始DNS解析:www.qq.com
[19:33:07.234]dns_enqueue: "www.qq.com": use DNS entry 0
[19:33:07.248]dns_send: dns_servers[0] "www.qq.com": request
[19:33:07.249]udp_connect: connected to 0.0.0.0,port 49153
[19:33:07.250]udp_send
[19:33:07.250]udp_send: added header in given pbuf 200045ec
[19:33:07.250]udp_send: sending datagram of length 36
[19:33:07.250]udp_send: UDP packet length 36
[19:33:07.250]udp_send: UDP checksum 0x0000
[19:33:07.252]udp_send: ip_output_if (,,,,IP_PROTO_UDP,)
[19:33:07.252]ip_output_if: st0
[19:33:07.253]IP header:
[19:33:07.253]+-------------------------------+
[19:33:07.254]| 4 | 5 | 0x00 | 56 | (v, hl, tos, len)
[19:33:07.268]+-------------------------------+
[19:33:07.268]| 2 |000| 0 | (id, flags, offset)
[19:33:07.269]+-------------------------------+
[19:33:07.280]| 255 | 17 | 0x0000 | (ttl, proto, chksum)
[19:33:07.281]+-------------------------------+
[19:33:07.281]| 192 | 168 | 1 | 102 | (src)
[19:33:07.295]+-------------------------------+
[19:33:07.295]| 114 | 114 | 114 | 114 | (dest)
[19:33:07.296]+-------------------------------+
[19:33:07.297]netif->output()ip_input: iphdr->dest 0x6601a8c0 netif->ip_addr 0x6601a8c0 (0x1a8c0, 0x1a8c0, 0x66000000)
[19:33:07.309]ip_input: packet accepted on interface st
[19:33:07.310]ip_input:
[19:33:07.310]IP header:
[19:33:07.310]+-------------------------------+
[19:33:07.323]| 4 | 5 | 0x00 | 92 | (v, hl, tos, len)
[19:33:07.323]+-------------------------------+
[19:33:07.323]| 2 |000| 0 | (id, flags, offset)
[19:33:07.339]+-------------------------------+
[19:33:07.340]| 125 | 17 | 0x969c | (ttl, proto, chksum)
[19:33:07.340]+-------------------------------+
[19:33:07.340]| 114 | 114 | 114 | 114 | (src)
[19:33:07.342]+-------------------------------+
[19:33:07.343]| 192 | 168 | 1 | 102 | (dest)
[19:33:07.343]+-------------------------------+
[19:33:07.358]ip_input: p->len 92 p->tot_len 92
[19:33:07.358]udp_input: received datagram of length 72
[19:33:07.358]UDP header:
[19:33:07.358]+-------------------------------+
[19:33:07.372]| 53 | 49153 | (src port, dest port)
[19:33:07.372]+-------------------------------+
[19:33:07.374]| 72 | 0x65fe | (len, chksum)
[19:33:07.374]+-------------------------------+
[19:33:07.389]udp (192.168.1.102, 49153) <-- (114.114.114.114, 53)
[19:33:07.390]pcb (0.0.0.0, 49153) --- (114.114.114.114, 53)
[19:33:07.390]udp_input: calculating checksum
[19:33:07.405]dns_recv: "www.qq.com": response = 58.250.137.36
[19:33:07.419][www.qq.com]域名解析的IP:58.250.137.36
7.资料下载地址
移植成功的完整代码下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/13033555
本文地址:https://blog.csdn.net/ZHONGCAI0901/article/details/109254481