本代码是从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;
}文章作者:沃航科技