前言
出于同样的项目需要的原因,我把我的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参数以避免超出缓冲区;