[嵌入式开发模块]DNS客户端模块(基于wizW5500官方io库)

mac2022-06-30  23

文章目录

前言代码DNSClient.hDNSClient.c 使用示例更新历史

前言

出于同样的项目需要的原因,我把我的DNS模块也进一步进行了封装。基于W5500官方IO库,提供完成一次域名解析IPv4的整个过程的接口。

先复制黏贴好DNS模块的代码: https://blog.csdn.net/lin_strong/article/details/101915670

代码中遇到的依赖之类的问题都可以在NTPClient模块中找到: https://blog.csdn.net/lin_strong/article/details/100807679

接下来直接上源码:

代码

DNSClient.h

/* ****************************************************************************************** * * DNS CLIENT MODULE * * File : DNSClient.h * By : Lin Shijun(http://blog.csdn.net/lin_strong) * Date: 2019/10/15 * Version: V1.1 * History: 2019/09/16 V1.0 * 2019/10/15 V1.1 add bufSize parameter to DnsClient_QueryIPv4 interface * fix serverPort parameter from uint8_t to uint16_t * NOTE(s): the module is to provide DNS client function based on wiznet io-library. ****************************************************************************************** */ #ifndef _DNSCLIENT_H #define _DNSCLIENT_H /* ******************************************************************************************* * INCLUDE ******************************************************************************************* */ #include "DNS.h" /* ******************************************************************************************* * CONFIGURATION ******************************************************************************************* */ // to enable debug message //#define DNSC_DEBUG // set the wait time of a request #ifndef DNSC_TIMEOUT_TIME_MS #define DNSC_TIMEOUT_TIME_MS 1000 #endif /* ******************************************************************************************* * PUBLIC INTERFACES ******************************************************************************************* */ // description: launch a dns ipv4 standard query(A record) on given socketNum and return the respond if any. // parameter : socketNum the socket number for dns client // buf the buffer for dns client. // bufSize the size of buffer. Should be bigger enough to hold the request // and respond message, or it will fail. // serverIp ip of the dns server. // serverPort udp port of the dns server. 0 if default port(i.e. DNSS_PORT) // DName domain name to query // ret to return the result if success, uint8_t[4] // return : TRUE if success // FALSE if fail // note : BOOL DnsClient_QueryIPv4(uint8_t socketNum, uint8_t *buf, uint16_t bufSize, uint8_t serverIp[4], uint16_t serverPort, const char *DName,uint8_t *ret); #endif

DNSClient.c

/* ****************************************************************************************** * * DNS CLIENT MODULE * * File : DNSClient.c * By : Lin Shijun(http://blog.csdn.net/lin_strong) * Date: 2019/10/15 * Version: V1.1 * History: * NOTE(s): ****************************************************************************************** */ /* ******************************************************************************************* * INCLUDES ******************************************************************************************* */ #include <string.h> #include "DNSClient.h" #include "socket.h" #include "MyOS.h" #ifndef DNSC_DEBUG #undef _DEBUG #endif #include "DebugMsg.h" /* ******************************************************************************************* * CONFIGURATION ******************************************************************************************* */ #ifndef DNSC_POLL_INTERVAL_MS #define DNSC_POLL_INTERVAL_MS 10 #endif #define DNSC_POLL_CNT ((DNSC_TIMEOUT_TIME_MS) / (DNSC_POLL_INTERVAL_MS)) #define ANYNUM 0x3453 /* ******************************************************************************************* * LOCAL FUNCTION DECLARATION ******************************************************************************************* */ #define socketNum_valid(socketNum) ((socketNum) < _WIZCHIP_SOCK_NUM_) /* ******************************************************************************************* * LOCAL VARIABLE DECLARATION ******************************************************************************************* */ static uint16_t _id = ANYNUM; /* ******************************************************************************************* * DEBUG STRINGS ******************************************************************************************* */ static const char *_str_DNSCErrFormat = "DNSC Err: %s.\r\n"; /* ******************************************************************************************* * PUBLIC INTERFACE IMPLEMENTATIONS ******************************************************************************************* */ BOOL DnsClient_QueryIPv4(uint8_t socketNum, uint8_t *buf, uint16_t bufSize, uint8_t serverIp[4], uint16_t serverPort, const char *DName,uint8_t *ret){ int32_t len; uint8_t dip[4]; uint16_t dport; uint16_t id; DNSHdr hdr; DNSRR QueOrRR; const uint8_t *p; int i; BOOL rst = FALSE; int remainPollCnt = DNSC_POLL_CNT; id = ++_id; if(serverIp == NULL || ret == NULL || buf == NULL || DName == NULL || !socketNum_valid(socketNum)){ _dbg_printf1(_str_DNSCErrFormat, "bad param"); return FALSE; } serverPort = (serverPort != 0)? serverPort: DNSS_PORT; if(getSn_SR(socketNum) != SOCK_UDP) if(socketNum != socket(socketNum, Sn_MR_UDP, 0, 0x00)){ _dbg_printf1(_str_DNSCErrFormat, "Open socket"); goto bail; }; len = (int32_t)DnsMsg_printStandardQueryIPv4Message(buf, bufSize, id, DName); if(len <= 0){ _dbg_printf1(_str_DNSCErrFormat, "printf query"); goto bail; } len = sendto(socketNum, buf, (uint16_t)len, serverIp, serverPort); if(len < 0){ _dbg_printf1(_str_DNSCErrFormat, "sendto"); goto bail; } _dbg_printf0("DNSC :wating for respond\r\n"); do{ MyOS_DlyHMSM(0,0,0,DNSC_POLL_INTERVAL_MS); if(getSn_RX_RSR(socketNum) <= 0) continue; len = recvfrom(socketNum, buf, bufSize, dip, &dport); if(len <= 0){ _dbg_printf1(_str_DNSCErrFormat, "socket mode"); goto bail; } // intentionly only check server ip. considering the situation that respond with another port; if(*(uint32_t *)dip != *(uint32_t *)serverIp) continue; p = DNSMsg_scanHeader(buf, (uint16_t)len, &hdr); if(p == NULL || hdr.QR != 1 || id != hdr.TransID) continue; // we have confirm that this message is the response, so stop loop in this time. // jumpoff query section for(i = 0; i < hdr.Questions; i++){ if((p = DNSMsg_scanQuery(buf, (uint16_t)len, p, (DNSQue *)&QueOrRR)) == NULL){ _dbg_printf1(_str_DNSCErrFormat, "resolve query"); goto bail; } DNSMsg_freeQueReturnByScan((DNSQue *)&QueOrRR); } for(i = 0; i < hdr.AnswerRRs; i++){ if((p = DNSMsg_scanRR(buf, (uint16_t)len, p, (DNSRR *)&QueOrRR)) == NULL){ _dbg_printf1(_str_DNSCErrFormat, "resolve RR"); goto bail; } // id对上了就默认回答的A记录一定是那个域名的了。就不浪费时间核对域名了。因为有的时候有别名就特麻烦。 if(QueOrRR.Type == DNSQT_A){ rst = TRUE; (void)memcpy(ret, QueOrRR.RData.A.addr, 4); DNSMsg_freeRRReturnByScan((DNSRR *)&QueOrRR); _dbg_printf4("DNSC :got IPv4 addr %u.%u.%u.%u\r\n", ret[0], ret[1], ret[2], ret[3]); goto bail; } DNSMsg_freeRRReturnByScan((DNSRR *)&QueOrRR); } _dbg_printf1(_str_DNSCErrFormat, "no answer"); goto bail; }while(remainPollCnt-- > 0); // timeout _dbg_printf1(_str_DNSCErrFormat, "timeout"); bail: close(socketNum); return rst; }

使用示例

如下就可以从192.168.1.1处的DNS服务器处要到www.baidu.com的IP地址:

static uint8_t dnsBuf[200]; static uint8_t dnsServerIP[] = {192,168,1,1}; static const char * dnameForQuery = "www.baidu.com"; void DnsTask(void *p_arg){ uint8_t ip[4]; // 已省去不重要的代码 ... printf("launch dns query for %s to %u.%u.%u.%u on socket %u\r\n", dnameForQuery, dnsServerIP[0], dnsServerIP[1], dnsServerIP[2], dnsServerIP[3],DNS_SOCKET); if(DnsClient_QueryIPv4(DNS_SOCKET, dnsBuf, sizeof(dnsBuf), (uint8_t *)dnsServerIP, 0, dnameForQuery,ip) == TRUE){ printf("%s's ip is %u.%u.%u.%u\r\n", dnameForQuery, ip[0], ip[1], ip[2], ip[3]); }else{ printf("query dns fail\r\n"); } ... }

更新历史

2020/06/04 更新到V1.1 修复V1.0中端口号使用uint8_t的问题,应该使用uint16_t;为接口添加bufSize参数以避免超出缓冲区;

最新回复(0)