本代码是从ch579m中提炼出来的,可用于堆栈都比较小的单片机程序。代码如下:
dns.h
#ifndef __DNS_H__ #define __DNS_H__ #include <stdint.h> void InitDnsBuff (char *buff); // 需要先初始化buffer,buffer要大于等于512 // op选项如下: // 0 QUERY,标准查询 // 1 IQUERY,反向查询 // 2 STATUS,DNS状态请求 // 5 UPDATE, DNS域更新请求 uint16_t MakeDnsQueryMsg (uint16_t op, char *name, uint8_t *buf, uint16_t len); uint8_t ParseMsg (uint8_t *pbuf, uint8_t *pSip); #endif
dns.c
#include <string.h> #include "dns.h" #define MAX_DNS_BUF_SIZE 512 /*DNS缓冲区最大长度 */ char *dnsbuff; uint16_t MSG_ID = 0x1100; /* 标识 */ #define TYPE_A 1 /* Host address */ #define TYPE_NS 2 /* Name server */ #define TYPE_MD 3 /* Mail destination (obsolete) */ #define TYPE_MF 4 /* Mail forwarder (obsolete) */ #define TYPE_CNAME 5 /* Canonical name */ #define TYPE_SOA 6 /* Start of Authority */ #define TYPE_MB 7 /* Mailbox name (experimental) */ #define TYPE_MG 8 /* Mail group member (experimental) */ #define TYPE_MR 9 /* Mail rename name (experimental) */ #define TYPE_NULL 10 /* Null (experimental) */ #define TYPE_WKS 11 /* Well-known sockets */ #define TYPE_PTR 12 /* Pointer record */ #define TYPE_HINFO 13 /* Host information */ #define TYPE_MINFO 14 /* Mailbox information (experimental)*/ #define TYPE_MX 15 /* Mail exchanger */ #define TYPE_TXT 16 /* Text strings */ #define TYPE_ANY 255 /* Matches any type */ struct dhdr { uint16_t id; /* 标识 */ uint8_t qr; /* 查询或应答标志*/ uint8_t opcode; uint8_t aa; /* 授权回答 */ uint8_t tc; /* 可截断的 */ uint8_t rd; /* 期望递归*/ uint8_t ra; /* 可以递归 */ uint8_t rcode; /* 应答码 */ uint16_t qdcount; /* 问题数 */ uint16_t ancount; /* 应答数 */ uint16_t nscount; /* 授权数 */ uint16_t arcount; /* 额外记录数 */ }; /******************************************************************************* * Function Name : get16 * Description : 将缓冲区UINT8数据转为UINT16格式数据 * Input : s -UINT8类型数据 * Output : None * Return : 转化后的UINT16类型数据 *******************************************************************************/ uint16_t get16 (uint8_t * s) { uint16_t i; i = *s++ << 8; i = i + *s; return i; } /******************************************************************************* * Function Name : ParseName * Description : 分析完整的域名 * Input : msg -指向报文的指针 compressed -指向报文中主域名的指针 buf -缓冲区指针,用于存放转化后域名 * Output : None * Return : 压缩报文的长度 *******************************************************************************/ int ParseName (uint8_t *msg, uint8_t *compressed, char *buf) { uint16_t slen; /* 当前片段长度*/ uint8_t *cp; int clen = 0; /* 压缩域名长度 */ int indirect = 0; int nseg = 0; /* 域名被分割的片段总数 */ cp = compressed; while (1) { 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_t* DnsQuestion(uint8_t *msg, uint8_t *cp) { int len; char *name = dnsbuff; 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_t *DnsAnswer (uint8_t *msg, uint8_t *cp, uint8_t *pSip) { int len, type; char *name = dnsbuff; 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_t ParseMsg (uint8_t *pbuf, uint8_t *pSip) { struct dhdr dhdr; uint16_t tmp; uint16_t i; uint8_t *msg; uint8_t *cp; msg = pbuf; memset(&dhdr, 0, sizeof(dhdr)); dhdr.id = get16(&msg[0]); tmp = get16(&msg[2]); if (tmp & 0x8000) { dhdr.qr = 1; } dhdr.opcode = (tmp >> 11) & 0xf; if (tmp & 0x0400) { dhdr.aa = 1; } if (tmp & 0x0200) { dhdr.tc = 1; } if (tmp & 0x0100) { dhdr.rd = 1; } if (tmp & 0x0080) { dhdr.ra = 1; } dhdr.rcode = tmp & 0xf; dhdr.qdcount = get16(&msg[4]); dhdr.ancount = get16(&msg[6]); dhdr.nscount = get16(&msg[8]); dhdr.arcount = get16(&msg[10]); /* 分析可变数据长度部分*/ cp = &msg[12]; /* 查询问题 */ for (i = 0; i < dhdr.qdcount; i++) { cp = DnsQuestion(msg, cp); } /* 回答 */ for (i = 0; i < dhdr.ancount; i++) { cp = DnsAnswer(msg, cp, pSip); } /* 授权 */ for (i = 0; i < dhdr.nscount; i++) { /*待解析*/ ; } /* 附加信息 */ for (i = 0; i < dhdr.arcount; i++) { /*待解析*/ ; } if (dhdr.rcode == 0) { return 1; /* rcode = 0:成功 */ } else { return 0; } } /******************************************************************************* * Function Name : put16 * Description :UINT16 格式数据按UINT8格式存到缓冲区 * Input : s -缓冲区首地址 i -UINT16数据 * Output : None * Return : 偏移指针 *******************************************************************************/ uint8_t* put16 (uint8_t * s, uint16_t i) { *s++ = i >> 8; *s++ = i; return s; } /******************************************************************************* * Function Name : MakeDnsQuery * Description : 制作DNS查询报文 input : op - 递归 * name - 指向待查域名指针 * buf - DNS缓冲区. * len - 缓冲区最大长度. * Output : None * Return : 指向DNS报文指针 *******************************************************************************/ uint16_t MakeDnsQueryMsg (uint16_t op, char *name, uint8_t *buf, uint16_t len) { uint8_t *cp; char *cp1; char *dname = dnsbuff; uint16_t p; uint16_t dlen; 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(dname, name); dlen = strlen(dname); while (1) { /* 按照DNS请求报文域名格式,把URI写入到buf里面去 */ cp1 = strchr(dname, '.'); if (cp1 != NULL) { len = cp1 - dname; } else { len = dlen; } *cp++ = len; if (len == 0) { break; } strncpy(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_t)(cp - buf)); } void InitDnsBuff (char *buff) { dnsbuff = buff; }
文章作者:沃航科技