/*******************************************************************************
Copyright (c) [scl]。保留所有权利。
******************************************************************************/#ifndefF1XX_TEMPLATE_W5500_DNS_H#defineF1XX_TEMPLATE_W5500_DNS_H#include"socket.h"#defineTYPE_A1/* Host address */#defineTYPE_NS2/* Name server */#defineTYPE_MD3/* Mail destination (obsolete) */#defineTYPE_MF4/* Mail forwarder (obsolete) */#defineTYPE_CNAME5/* Canonical name */#defineTYPE_SOA6/* Start of Authority */#defineTYPE_MB7/* Mailbox name (experimental) */#defineTYPE_MG8/* Mail group member (experimental) */#defineTYPE_MR9/* Mail rename name (experimental) */#defineTYPE_NULL10/* Null (experimental) */#defineTYPE_WKS11/* Well-known sockets */#defineTYPE_PTR12/* Pointer record */#defineTYPE_HINFO13/* Host information */#defineTYPE_MINFO14/* Mailbox information (experimental)*/#defineTYPE_MX15/* Mail exchanger */#defineTYPE_TXT16/* Text strings */#defineTYPE_ANY255/* Matches any type */#defineMAX_DNS_BUF_SIZE256/* maximum size of DNS buffer. *//**
* @memberof delay_ms_cb 毫秒延迟回调
* @memberof dns_server_ip: dns 服务ip
* @memberof dns_port: dns 端口,默认53
*/structdns_conf{void(*delay_ms_cb)(uint32_t ms);uint8_t dns_server_ip[4];uint16_t dns_port;};voiddns_config_set(structdns_conf*cnf);/**
*
* @param s socket num
* @param domain_name 服务域名
* @param dst_ip [out] 保存解析的数据
* @param wait_ms [in] 发送请求后等待时间
* @return
*/
bool do_dns(SOCKET s,uint8_t*domain_name,uint8_t*dst_ip,uint32_t wait_ms);#endif//F1XX_TEMPLATE_W5500_DNS_H
源文件
/*******************************************************************************
Copyright (c) [scl]。保留所有权利。
******************************************************************************/#include"w5500_dns.h"#defineDBG_ENABLE#defineDBG_SECTION_NAME"dns"#defineDBG_LEVELDBG_INFO // DBG_LOG DBG_INFO DBG_WARNING DBG_ERROR#include"sys_dbg.h"/* Header for all domain messages */structdhdr{uint16_t id;/* Identification */uint8_t qr;/* Query/Response */uint8_t opcode;uint8_t aa;/* Authoratative answer */uint8_t tc;/* Truncation */uint8_t rd;/* Recursion desired */uint8_t ra;/* Recursion available */uint8_t rcode;/* Response code */uint16_t qdcount;/* Question count */uint16_t ancount;/* Answer count */uint16_t nscount;/* Authority (name server) count */uint16_t arcount;/* Additional record count */};staticuint8_t DNS_BUF[MAX_DNS_BUF_SIZE]={0};staticstructdhdr dhp ={0};/*定义一个结构体用来包含报文头信息*/staticuint16_t MSG_ID =0x1122;structdns_conf*cnf_ptr =NULL;staticintdns_packet_build(uint16_t op,uint8_t*name,uint8_t*buf,uint16_t len);static bool parse_DNS_Response(structdhdr*pdhdr,uint8_t*pbuf,uint8_t*dst_result_ip);staticuint8_t*dns_question(uint8_t*msg,uint8_t*cp);staticuint8_t*dns_answer(uint8_t*msg,uint8_t*cp,uint8_t*dst_result_ip);staticint16_tparse_name(uint8_t*msg,uint8_t*compressed,uint16_t len);voiddns_config_set(structdns_conf*cnf){
cnf_ptr = cnf;}/**
* dns 解析
* @param s
* @param domain_name 域名
* @return
*/
bool do_dns(SOCKET s,uint8_t*domain_name,uint8_t*dst_ip,uint32_t wait_ms){if(cnf_ptr ==NULL){LOG_E("dns_config_set not set");goto _exit_false;}if(udp_client_init(s, cnf_ptr->dns_port)){uint16_t len =dns_packet_build(0, domain_name, DNS_BUF, MAX_DNS_BUF_SIZE);sendto(s, DNS_BUF, len, cnf_ptr->dns_server_ip, cnf_ptr->dns_port);/*发送DNS请求报文给DNS服务器*/for(int i =0; i < wait_ms /2;++i){
len =w5500_socket_rx_size_read(s);if(len >0)break;
cnf_ptr->delay_ms_cb(2);}if(len >0){if(len > MAX_DNS_BUF_SIZE) len = MAX_DNS_BUF_SIZE;recvfrom_simple(s, DNS_BUF, len);if(parse_DNS_Response(&dhp, DNS_BUF, dst_ip)){close(s);/*关闭socket*/return true;/*返回DNS解析成功域名信息*/}else{LOG_W("parse_DNS_Response err");}}else{LOG_D("w5500_socket_rx_size_read not rec data");}}else{LOG_W("udp_client_init error");}
_exit_false:return false;}staticintdns_packet_build(uint16_t op,uint8_t*name,uint8_t*buf,uint16_t len){uint8_t*cp = buf;uint8_t*cp1;uint8_t*dname;uint16_t p;uint16_t dlen;
MSG_ID++;*(uint16_t*)&cp[0]=htons(MSG_ID);
p =(op <<11)|0x0100;*(uint16_t*)&cp[2]=htons(p);*(uint16_t*)&cp[4]=htons(1);*(uint16_t*)&cp[6]=htons(0);*(uint16_t*)&cp[8]=htons(0);*(uint16_t*)&cp[10]=htons(0);
cp +=sizeof(uint16_t)*6;
dname = name;
dlen =strlen((char*) dname);for(;;){/* Look for next dot */
cp1 =(unsignedchar*)strchr((char*) dname,'.');if(cp1){/* More to come */
len = cp1 - dname;}else{
len = dlen;/* Last component */}*cp++= len;/* Write length of component */if(len ==0)break;strncpy((char*) cp,(char*) dname, len);/* Copy component up to (but not including) dot */
cp += len;if(!cp1){*cp++=0;/* Last one; write null and finish */break;}
dname += len +1;
dlen -= len +1;}*(uint16_t*)&cp[0]=htons(0x0001);/* type */*(uint16_t*)&cp[2]=htons(0x0001);/* class */
cp +=sizeof(uint16_t)*2;return((int)((uint32_t)(cp)-(uint32_t)(buf)));}static bool parse_DNS_Response(structdhdr*pdhdr,uint8_t*pbuf,uint8_t*dst_result_ip){uint16_t tmp =0, i =0;uint8_t*msg =NULL,*cp =NULL;
msg = pbuf;memset(pdhdr,0,sizeof(structdhdr));
pdhdr->id =ntohs(*((uint16_t*)&msg[0]));
tmp =ntohs(*((uint16_t*)&msg[2]));if(tmp &0x8000)
pdhdr->qr =1;
pdhdr->opcode =(tmp >>11)&0xf;if(tmp &0x0400)
pdhdr->aa =1;if(tmp &0x0200)
pdhdr->tc =1;if(tmp &0x0100)
pdhdr->rd =1;if(tmp &0x0080)
pdhdr->ra =1;
pdhdr->rcode = tmp &0xf;
pdhdr->qdcount =ntohs(*((uint16_t*)&msg[4]));
pdhdr->ancount =ntohs(*((uint16_t*)&msg[6]));
pdhdr->nscount =ntohs(*((uint16_t*)&msg[8]));
pdhdr->arcount =ntohs(*((uint16_t*)&msg[10]));/* Now parse the variable length sections */
cp =&msg[12];/* Question section */for(i =0; i < pdhdr->qdcount; i++){
cp =dns_question(msg, cp);}/* Answer section */for(i =0; i < pdhdr->ancount; i++){
cp =dns_answer(msg, cp, dst_result_ip);}/* Name server (authority) section */for(i =0; i < pdhdr->nscount; i++){;}/* Additional section */for(i =0; i < pdhdr->arcount; i++){;}if(pdhdr->rcode ==0)return1;elsereturn0;}/**
*@brief 解析回复消息的问询记录
*@param msg - 指向回复信息的指针
cp - 指向问询记录的指针
*@return 返回下一个记录指针
*/uint8_t*dns_question(uint8_t*msg,uint8_t*cp){int16_t len =parse_name(msg, cp, MAX_DNS_BUF_SIZE);if(len ==-1)return0;
cp += len;
cp +=2;/* type */
cp +=2;/* class */return cp;}staticuint8_t*dns_answer(uint8_t*msg,uint8_t*cp,uint8_t*dst_result_ip){int16_t len, type;
len =parse_name(msg, cp,/*name,*/ MAX_DNS_BUF_SIZE);if(len ==-1)return0;
cp += len;
type =ntohs(*((uint16_t*)&cp[0]));
cp +=2;/* type */
cp +=2;/* class */
cp +=4;/* ttl */
cp +=2;/* len */switch(type){case TYPE_A:
dst_result_ip[0]=*cp++;
dst_result_ip[1]=*cp++;
dst_result_ip[2]=*cp++;
dst_result_ip[3]=*cp++;break;case TYPE_CNAME:case TYPE_MB:case TYPE_MG:case TYPE_MR:case TYPE_NS:case TYPE_PTR:/* These types all consist of a single domain name *//* convert it to ascii format */
len =parse_name(msg, cp, MAX_DNS_BUF_SIZE);if(len ==-1)return0;
cp += len;break;case TYPE_HINFO:
len =*cp++;
cp += len;
len =*cp++;
cp += len;break;case TYPE_MX:
cp +=2;/* Get domain name of exchanger */
len =parse_name(msg, cp, MAX_DNS_BUF_SIZE);if(len ==-1)return0;
cp += len;break;case TYPE_SOA:/* Get domain name of name server */
len =parse_name(msg, cp, MAX_DNS_BUF_SIZE);if(len ==-1)return0;
cp += len;/* Get domain name of responsible person */
len =parse_name(msg, cp, MAX_DNS_BUF_SIZE);if(len ==-1)return0;
cp += len;
cp +=4;
cp +=4;
cp +=4;
cp +=4;
cp +=4;break;case TYPE_TXT:/* Just stash */break;default:/* Ignore */break;}return cp;}staticint16_tparse_name(uint8_t*msg,uint8_t*compressed,uint16_t len){staticint8_t name[MAX_DNS_BUF_SIZE];uint16_t slen =0;/* Length of current segment */uint8_t*cp =NULL;int16_t clen =0;/* Total length of compressed name */int16_t indirect =0;/* Set if indirection encountered */int16_t nseg =0;/* Total number of segments in name */int8_t*buf =NULL;
buf = name;
cp = compressed;for(;;){
slen =*cp++;/* Length of this segment */if(!indirect)
clen++;if((slen &0xc0)==0xc0){if(!indirect)
clen++;
indirect =1;/* Follow indirection */
cp =&msg[((slen &0x3f)<<8)+*cp];
slen =*cp++;}if(slen ==0)/* zero length == all done */break;
len -= slen +1;if(len <=0)return-1;if(!indirect)
clen += slen;while(slen--!=0)*buf++=(int8_t)*cp++;*buf++='.';
nseg++;}if(nseg ==0)/* Root name; represent as single dot */{*buf++='.';
len--;}*buf++='\0';
len--;return clen;/* Length of compressed message */}
文章目录 概念1. 先行发生 编译器重排同步机制init函数协程的创建channelsync 包1. sync.mutex2. sync.rwmutex3. sync.once atomic 参考文献 概念
1. 先行发生 The happens before relation is defined as the transitive closure of the union of the sequenced before and …