#include "DNS.h" #include "CH57xNET.H" #include "DBG.h" #define CH57xNET_DBG 1 /* 变量定义 */ UINT8 DNS_SERVER_IP[4]={223,5,5,5}; /* DNS服务器1 */ UINT8 DNS_SERVER_IP2[4]={114,114,114,114}; /* DNS服务器2 */ #define IPPORT_DOMAIN 53 /* DNS默认端口 */ UINT16 MSG_ID = 0x1100; /* 标识 */ //UINT32 count = 0; //UINT8 dns_buf[MAX_DNS_BUF_SIZE]; UINT8* dns_buf = NULL; //UINT8 url_dn4[] = "www.boonlive-rcu.com"; /******************************************************************************* * Function Name : get16 * Description : 将缓冲区UINT8数据转为UINT16格式数据 * Input : s -UINT8类型数据 * Output : None * Return : 转化后的UINT16类型数据 *******************************************************************************/ UINT16 get16(UINT8 * s) { UINT16 i; i = *s++ << 8; i = i + *s; return i; } /******************************************************************************* * Function Name : ParseName * Description : 分析完整的域名 * Input : msg -指向报文的指针 compressed -指向报文中主域名的指针 buf -缓冲区指针,用于存放转化后域名 * Output : None * Return : 压缩报文的长度 *******************************************************************************/ int ParseName(UINT8 * msg, UINT8 * compressed, char * buf) { UINT16 slen; /* 当前片段长度*/ UINT8 * cp; int clen = 0; /* 压缩域名长度 */ int indirect = 0; int nseg = 0; /* 域名被分割的片段总数 */ cp = compressed; for (;;){ slen = *cp++; /* 首字节的计数值*/ if (!indirect) clen++; if ((slen & 0xc0) == 0xc0){ /* 计数字节高两比特为1,用于压缩格式 */ if (!indirect) clen++; indirect = 1; cp = &msg[((slen & 0x3f)<<8) + *cp]; /* 按计数字节数值指针偏移到指定位置 */ slen = *cp++; } if (slen == 0) break; /* 计数为0,结束 */ if (!indirect) clen += slen; while (slen-- != 0) *buf++ = (char)*cp++; *buf++ = '.'; nseg++; } if (nseg == 0){ /* 根域名; */ *buf++ = '.'; } *buf++ = '\0'; return clen; /* 压缩报文长度 */ } /******************************************************************************* * Function Name : DnsQuestion * Description : 分析响应报文中的问题记录部分 * Input : msg -指向响应报文的指针 cp -指向问题记录的指针 * Output : None * Return : 指向下一记录的指针 *******************************************************************************/ UINT8 * DnsQuestion(UINT8 * msg, UINT8 * cp) { int len; char name[MAX_DNS_BUF_SIZE]; len = ParseName(msg, cp, name); cp += len; cp += 2; /* 类型 */ cp += 2; /* 类 */ return cp; } /******************************************************************************* * Function Name : DnsAnswer * Description : 分析响应报文中的回答记录部分 * Input : msg -指向响应报文的指针 cp -指向回答记录的指针 psip * Output : None * Return :指向下一记录的指针 *******************************************************************************/ UINT8 * DnsAnswer(UINT8 * msg, UINT8 * cp, UINT8 * pSip) { int len, type; char name[MAX_DNS_BUF_SIZE]; len = ParseName(msg, cp, name); cp += len; type = get16(cp); cp += 2; /* 类型 */ cp += 2; /* 类 */ cp += 4; /* 生存时间 */ cp += 2; /* 资源数据长度 */ switch ( type ){ case TYPE_A: pSip[0] = *cp++; pSip[1] = *cp++; pSip[2] = *cp++; pSip[3] = *cp++; break; case TYPE_CNAME: case TYPE_MB: case TYPE_MG: case TYPE_MR: case TYPE_NS: case TYPE_PTR: len = ParseName(msg, cp, name); cp += len; break; case TYPE_HINFO: case TYPE_MX: case TYPE_SOA: case TYPE_TXT: break; default: break; } return cp; } /******************************************************************************* * Function Name : parseMSG * Description : 分析响应报文中的资源记录部分 * Input : msg -指向DNS报文头部的指针 cp -指向响应报文的指针 * Output : None * Return :成功返回1,否则返回0 *******************************************************************************/ UINT8 parseMSG(struct dhdr * pdhdr, UINT8 * pbuf, UINT8 * pSip) { UINT16 tmp; UINT16 i; UINT8 * msg; UINT8 * cp; msg = pbuf; memset(pdhdr, 0, sizeof(*pdhdr)); pdhdr->id = get16(&msg[0]); tmp = get16(&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 = get16(&msg[4]); pdhdr->ancount = get16(&msg[6]); pdhdr->nscount = get16(&msg[8]); pdhdr->arcount = get16(&msg[10]); /* 分析可变数据长度部分*/ cp = &msg[12]; /* 查询问题 */ for (i = 0; i < pdhdr->qdcount; i++) { cp = DnsQuestion(msg, cp); } /* 回答 */ for (i = 0; i < pdhdr->ancount; i++) { cp = DnsAnswer(msg, cp, pSip); } /*授权 */ for (i = 0; i < pdhdr->nscount; i++) { /*待解析*/ ; } /* 附加信息 */ for (i = 0; i < pdhdr->arcount; i++) { /*待解析*/ ; } if(pdhdr->rcode == 0) return 1; /* rcode = 0:成功 */ else return 0; } /******************************************************************************* * Function Name : put16 * Description :UINT16 格式数据按UINT8格式存到缓冲区 * Input : s -缓冲区首地址 i -UINT16数据 * Output : None * Return : 偏移指针 *******************************************************************************/ UINT8 * put16(UINT8 * s, UINT16 i) { *s++ = i >> 8; *s++ = i; return s; } /******************************************************************************* * Function Name : MakeDnsQuery * Description : 制作DNS查询报文 input : op - 递归 * name - 指向待查域名指针 * buf - DNS缓冲区. * len - 缓冲区最大长度. * Output : None * Return : 指向DNS报文指针 *******************************************************************************/ UINT16 MakeDnsQueryMsg(UINT16 op, char * name, UINT8 * buf, UINT16 len) { UINT8 *cp; char *cp1; char tmpname[MAX_DNS_BUF_SIZE]; char *dname; UINT16 p; UINT16 dlen; //printf("Domain name:%s \n",name); cp = buf; MSG_ID++; cp = put16(cp, MSG_ID); /* 标识 */ p = (op << 11) | 0x0100; cp = put16(cp, p); /* 0x0100:Recursion desired */ cp = put16(cp, 1); /* 问题数:1 */ cp = put16(cp, 0); /* 资源记录数:0 */ cp = put16(cp, 0); /* 资源记录数:0 */ cp = put16(cp, 0); /* 额外资源记录数:0 */ strcpy(tmpname, name); dname = tmpname; dlen = strlen(dname); for (;;){ /* 按照DNS请求报文域名格式,把URI写入到buf里面去 */ cp1 = strchr(dname, '.'); if (cp1 != NULL) len = cp1 - dname; else len = dlen; *cp++ = len; if (len == 0) break; strncpy((char *)cp, dname, len); cp += len; if (cp1 == NULL) { *cp++ = 0; break; } dname += len+1; /* dname首地址后移 */ dlen -= len+1; /* dname长度减小 */ } cp = put16(cp, 0x0001); /* type :1------ip地址 */ cp = put16(cp, 0x0001); /* class:1-------互联网地址 */ return ((UINT16)(cp - buf)); } /******************************************************************************* * Function Name : DnsQuery * Description : 进行DNS查询 input : s -socket索引 * name - 指向待查域名指针 pSip -查询结果 * Output : None * Return : 查询结果。成功返回1,失败返回2 *******************************************************************************/ //UINT8 DnsQuery2(UINT8* s, UINT8 * name, UINT8 * pSip) //{ // struct dhdr dhp; // UINT8 ret; // UINT32 len; // if(Status >1 ){ // count++; // DelayMs(10); // if( count>20000 ){ //#if CH57xNET_DBG // printf("DNS Fail!!!!!\n"); //#endif // count=0; // Status = 0; // return 2; // } // } // if(Status == 1) // { // DNS_SocketParamInit(s, DNS_SERVER_IP, 4000, IPPORT_DOMAIN); // //UDPSocketParamInit(*s,DNS_SERVER_IP,4000,IPPORT_DOMAIN); // Status = 2; //#if CH57xNET_DBG // printf(" 2 status = %d!\n",Status); //#endif // } // if(Status ==2) // { // len = MakeDnsQueryMsg(0,(char *)name, dns_buf, MAX_DNS_BUF_SIZE); // ret = CH57xNET_SocketSend(*s,dns_buf,&len); // if ( ret ) return(0); // else{ // Status = 3; //#if CH57xNET_DBG // printf("status = 3!\n"); //#endif // } // } // if(Status ==4) // { // //CH57xNET_SocketClose(*s,TCP_CLOSE_NORMAL ); // return(parseMSG(&dhp, dns_buf, pSip)); /*解析响应报文并返回结果*/ // // } // return 0; //} /******************************************************************************* * Function Name : DnsQuery_Task * Description : 进行DNS查询 input : s -socket索引 * name - 指向待查域名指针 pSip -查询结果 * Output : None * Return : 查询结果。成功返回1,失败返回2 *用 法 : 循环调用 *******************************************************************************/ UINT8 DnsQuery_Task(UINT8* s, UINT8 * name, UINT8 * pSip) { static uint32_t dnschange_wait_tick1 = 0; switch(server_info.dns_sta) { case DNS_INIT: { if(dns_buf == NULL) dns_buf = (UINT8*)malloc(MAX_DNS_BUF_SIZE/2); //为DNS分配空间 UINT8 ret = DNS_SocketParamInit(s, DNS_SERVER_IP, 4000, IPPORT_DOMAIN); //创建DNS用的套接字 if(ret == CH57xNET_ERR_SUCCESS) { server_info.dns_sta = DNS_DATA_SEND; Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS socket创建成功,DNS Server IP:%d.%d.%d.%d",\ DNS_SERVER_IP[0],DNS_SERVER_IP[1],DNS_SERVER_IP[2],DNS_SERVER_IP[3]); } else { Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS socket重新创建,DNS Server IP:%d.%d.%d.%d",\ DNS_SERVER_IP[0],DNS_SERVER_IP[1],DNS_SERVER_IP[2],DNS_SERVER_IP[3]); server_info.dns_sta = DNS_ClOSE; //2023-03-06 server_info.dns_fail++; //2023-03-06 } } break; case DNS_INIT1: { if(dns_buf == NULL) dns_buf = (UINT8*)malloc(MAX_DNS_BUF_SIZE/2); //为DNS分配空间 UINT8 ret = DNS_SocketParamInit(s, DNS_SERVER_IP2, 4000, IPPORT_DOMAIN); //创建DNS用的套接字 if(ret == CH57xNET_ERR_SUCCESS) { server_info.dns_sta = DNS_DATA_SEND; Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS socket创建成功,DNS Server IP:%d.%d.%d.%d",\ DNS_SERVER_IP2[0],DNS_SERVER_IP2[1],DNS_SERVER_IP2[2],DNS_SERVER_IP2[3]); } else { Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS socket重新创建,DNS Server IP:%d.%d.%d.%d",\ DNS_SERVER_IP2[0],DNS_SERVER_IP2[1],DNS_SERVER_IP2[2],DNS_SERVER_IP2[3]); server_info.dns_sta = DNS_ClOSE; //2023-03-06 server_info.dns_fail++; //2023-03-06 } } break; case DNS_DATA_SEND: { UINT32 len = MakeDnsQueryMsg(0,(char *)name, dns_buf, MAX_DNS_BUF_SIZE); //数据组包 UINT8 ret = CH57xNET_SocketSend(*s, dns_buf, &len); //发送到DNS服务器 if(ret == CH57xNET_ERR_SUCCESS) { Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS等待接收"); } else Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS发送失败"); server_info.wait_cot = SysTick_10ms; server_info.dns_sta = DNS_WAIT_RECV; server_info.dns_flg = 0x00; } break; case DNS_WAIT_RECV: //如果DNS成功,会在接收数据后关闭套接字 if(server_info.dns_flg == 1) //如果成功获取到服务器ip { struct dhdr dhp; UINT8 rev = 0; //将该套接字索引清零 Dbg_Println(DBG_BIT_NET_STATUS_bit,"DNS 耗时:%d0ms", SysTick_10ms - server_info.wait_cot); rev = parseMSG(&dhp, dns_buf, pSip); /*这个函数的返回值是0x01:成功,0x00:失败*/ CH57xNET_SocketClose(*s,SOCK_STAT_CLOSED ); Dbg_Println(DBG_BIT_NET_STATUS_bit,"释放DNS套接字"); if(rev == 0x01) /*parseMSG 解析响应报文并返回结果 2022-06-08*/ { return 0x01; //解析成功 }else { server_info.dns_fail++; server_info.dns_sta = DNS_ClOSE; dnschange_wait_tick1 = SysTick_10ms; } } else if(SysTick_10ms - server_info.wait_cot > 200) //等待接收超时 { server_info.wait_cot = SysTick_10ms; server_info.dns_sta = DNS_ClOSE; server_info.dns_fail++; } break; case DNS_ClOSE: free(dns_buf); //释放DNS空间 dns_buf = NULL; CH57xNET_SocketClose(*s,SOCK_STAT_CLOSED ); //将该套接字索引清零 if(server_info.dns_fail == 0x01) { if(SysTick_10ms - dnschange_wait_tick1 > 50) { Dbg_Println(DBG_BIT_NET_STATUS_bit,"切换DNS域名解析服务器"); dnschange_wait_tick1 = SysTick_10ms; server_info.dns_sta = DNS_INIT1; } } else if(server_info.dns_fail >= 0x02) { *s = 0; server_info.dns_fail = 0x00; return 0x02; //解析失败 } break; } return 0; }