13397158231   jevian_ma@worldflying.cn

可以用于单片机的dns解析代码

2021-04-14 22:44:36

本代码是从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;
}

文章作者:沃航科技

优秀产品推荐:可编程网络IO控制器

上一篇:智慧安全节能系统——智慧家居(书房)

下一篇:Qt5.6.3的windows版本最精简静态编译的方法

联系我们

  • 地址:武汉市东湖高新开发区光谷总部国际1栋2412室
  • QQ:932773931
  • 电话:027-59761089-806
  • 手机:13397158231
  • 邮箱:jevian_ma@worldflying.cn

关注公众号

扫码添加微信

沃航(武汉)科技有限公司版权所有

备案号:鄂ICP备16014230号-1

本网站由提供CDN加速/云存储服务