文章目录
前言代码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
#ifndef _DNSCLIENT_H
#define _DNSCLIENT_H
#include "DNS.h"
#ifndef DNSC_TIMEOUT_TIME_MS
#define DNSC_TIMEOUT_TIME_MS 1000
#endif
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
#include <string.h>
#include "DNSClient.h"
#include "socket.h"
#include "MyOS.h"
#ifndef DNSC_DEBUG
#undef _DEBUG
#endif
#include "DebugMsg.h"
#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
#define socketNum_valid(socketNum) ((socketNum) < _WIZCHIP_SOCK_NUM_)
static uint16_t _id
= ANYNUM
;
static const char *_str_DNSCErrFormat
= "DNSC Err: %s.\r\n";
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
;
}
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;
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
;
}
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);
_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参数以避免超出缓冲区;