简单的DNS请求报文实现

本文介绍了DNS请求报文的结构,重点讲解了DNS协议头的12字节固定部分,并提供了一段测试代码作为实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DNS数据包包括DNS协议头+DNS正文段。协议头为固定的12字节,结构如下:

typedef struct
{   
u16 id;
  u16 flags;
  u16 nques;
  u16 nanswer;
  u16 nauth;
  u16 naddi;
}dns_header;

查询ip的正文包括域名值和请求类型标识字段。结构如下:

typedef struct
{
    u16 type;
    u16 class;
}dns_query;

我们的DNS数据包格式就是:dns_header+域名+dns_header

值得一提的是"域名"需要经过简单的编码,如 microsoft.com,在问题名称字段中的域名称被编码为一系列的长度-值格式。 例如,域 microsoft.com 表示为0x09microsoft0x03com0x00,其中十六进制数字表示每个标签的长度、 ASCII 字符表示单个标签,并最终 0 指示名称的结尾。

测试代码如下:

#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h> 
#include <string.h>
#include <error.h>
#include <errno.h>

#define BUF_SIZE 1024
#define SRV_PORT 53
#define SRV_IP	"8.8.8.8"

typedef unsigned short u16;

typedef struct
{   
	u16 id;
  	u16 flags;
  	u16 nques;
  	u16 nanswer;
  	u16 nauth;
  	u16 naddi;
}dns_header;

typedef struct
{
   	u16 type;
   	u16 class;
}dns_query;

int isOline(char *argv)
{
    	int	connfd, len = 0;
    	struct  sockaddr_in servaddr;
    	char    buf[BUF_SIZE];
    	char    *p;
	int 	i=0;
	struct timeval tv;

	tv.tv_sec = 5;
	tv.tv_usec = 0;
    	dns_header  *dnshdr = (dns_header *)buf;
    	dns_query   *dnsqer;
    
    	if ((connfd  =  socket(AF_INET, SOCK_DGRAM, 0 ))  <   0 ){
         	perror( "socket error!\n " );
         	return -1;
    	} 
    
    	bzero(&servaddr, sizeof(servaddr));
    	servaddr.sin_family = AF_INET;
    	servaddr.sin_port = htons(SRV_PORT);
	if(inet_pton(AF_INET,SRV_IP,&servaddr.sin_addr) < 0){
		perror("inet_pton error.\n");
		return -1;
	}

   	memset(buf, 0, BUF_SIZE); 
    	dnshdr->id = (u16)1;
    	dnshdr->flags = htons(0x0100);
    	dnshdr->nques = htons(1);
    	dnshdr->nanswer = htons(0);
    	dnshdr->nauth = htons(0);
    	dnshdr->naddi = htons(0);
    	strcpy(buf + sizeof(dns_header) + 1, argv);
    	p = buf + sizeof(dns_header) + 1; 
    	while (p < (buf + sizeof(dns_header) + 1 + strlen(argv))){
        	if ( *p == '.'){
            		*(p - i - 1) = i;
            		i = 0;
        	} else{
            		i++;
        	}

        	p++;
    	}

    	*(p - i - 1) = i;
    	dnsqer = (dns_query *)(buf + sizeof(dns_header) + 2 + strlen(argv));
    	dnsqer->class = htons(1);
    	dnsqer->type = htons(1);
	setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    	if(sendto(connfd, buf, sizeof(dns_header) + sizeof(dns_query) + strlen(argv) + 2, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
		perror("sendto error.\n");
		return -1;
	}

    	i = sizeof(struct sockaddr_in);
    	if((len = recvfrom(connfd, buf, BUF_SIZE, 0, (struct sockaddr *)&servaddr, &i)) < 0){
		if(errno == EWOULDBLOCK){
			printf("timeout\n");
			return -1;
		}else{	
          		perror("recvfrom error\n");
          		return -1;
    		}
	}
 
    	if (dnshdr->nanswer == 0){
        	printf("ack error\n");
          	return -1;
    	}

    	p = buf + len -4;
    	printf("%s ==> %u.%u.%u.%u\n", argv, (unsigned char)*p, (unsigned char)*(p + 1), (unsigned char)*(p + 2), (unsigned char)*(p + 3));
    	close(connfd);
    	return 0;
}

int main()
{
	if(isOline("www.google.com") ==0)
		printf("ok");
	else
		printf("error");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值