DNS c语言实现 可ping验证

DNS服务器功能实现:
程序创建UDP套接字,端口设置为53(dns服务器指定端口)接收DNS报文,程序通过DNS报文协议定位到报文请求的请求响应报文字段,通过analysis函数解析请求域名实现域名获取,将获取到的域名与服务器本地内存中的域名进行对比,当域名与本地域名相互匹配时,程序将通过package函数实现DNS响应报文的封装,根据本地域名匹配的IP地址进行响应报文的封装和发送,此时请求端将收到相对于的DNS响应报文并获取到请求域名的IP,当请求域名与本地域名不匹配时程序返回0,拒绝DNS响应。

设计概要:
1.流程图

在这里插入图片描述

1.analysis函数模块介绍
解析DNS报文,根据DNS报文中的域名请求部分获取请求域名并与本地域名进行对比, 匹配成功则调用package模块,匹配失败返回0.
接口:int analysis(unsigned char *buf,int rec)
输入:DNS请求报文,报文字长
返回:1 0
2.package函数模块介绍
根据请求报文域名实现DNS响应报文封装。
接口:int package(int i,int len_dns)
输入:响应域名IP,客户端socket字长。
返回:1 0
DNS服务器操作流程:
1.关掉原始DNS服务器:
ps查看原始dns 进程
Pservice tools stop 关闭原始dns进程
2.运行程序 dns_test
3.使用ping 或 nslookup进行测试

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<errno.h>
#include<sys/types.h>
#include<fcntl.h>
#include<unistd.h> 
#define LEN_DNS_HEADER sizeof(struct DNS_HEADER)
#define LEN_DNS_QUESTION sizeof(struct DNS_QUESTION)
#define LEN_DNS_ANSWER sizeof(struct DNS_ANSWER)
#define TYPE 				0x0100
#define CLASS 				0x0100
#define ANSWER_TTL 			0x5f000000
#define ANSWER_NAME 		0x0cc0
#define ANSWER_DL 			0x0400
#define QUESTION_COUNT	    0x0100
#define ANSWER_COUNT 		0x0100
#define AUTH_COUNT          0x0
#define ADD_COUNT 			0x0
#define IP_PORT 			53
#define IP_ADDR 			"192.168.0.1"
struct DNS_HEADER {
    unsigned char id1; //会话id
    unsigned char id2; //会话id
    unsigned char rd :1; // 递归
    unsigned char tc :1; // 截断
    unsigned char aa :1; // 授权回答
    unsigned char op :4; // 标准查询
    unsigned char qr :1; //  查询响应标志
    unsigned char rc :4; // 应答
    unsigned char cd :1; // 
    unsigned char ad :1; //
    unsigned char zero :1; //保留值
    unsigned char ra :1; // 可递归
    unsigned short q_count; // 查询数
    unsigned short ans_count; //回答数量
    unsigned short auth_count; // 授权区数量
    unsigned short add_count; //附加区数量
};
	//查询字段									
struct DNS_QUESTION{
	unsigned short qtype;
	unsigned short qclass;
};
	//回答字段
#pragma pack(push, 1)
struct DNS_ANSWER{
	unsigned short answer_name;
	unsigned short answer_type;
	unsigned short answer_class;
	unsigned int time_live;
	unsigned short DL;
};
#pragma pack(pop)
struct my_dns{
	char name[20];
	char ip[20];
};
	//本地DNS数据
struct my_dns my_dns_server[]={
 {	
	.name = "www.baidu.com.cn",
	.ip = "192.168.0.111"
 },
 {	
	.name = "www.baidu.org",
	.ip = "192.168.0.101"
 },
 {	
	.name = "www.baidu.net",
	.ip = "192.168.0.1"
 },
 {	
	.name = "www.baidu.jk",
	.ip = "192.168.0.111"
 },
 {
	.name = "www.baidu.com",
	.ip = "172.16.20.20"
 },
};
unsigned char BUF[128] = {0};
unsigned char ID[2] = {0};
unsigned char * qname = NULL;
int socketfd = 0;
struct sockaddr_in ser,cli;
//讲相对应域名写入BUF中
int add_qname(int i)
{
	int j = 0;
	int len = strlen(my_dns_server[i].name);
	for(j=1;j <= len ;j++)
	{
		qname[j] = my_dns_server[i].name[j-1];
		printf("qname is %c\n",qname[j]);
	}
	return len;
}
//将BUF域名中的‘.’改为对应数字
int chang_dns(int i)
{
	int j = 0,k = 0;
	int len = strlen(my_dns_server[i].name);
	for(j = 1;j <= len+1;j++)
	{	
		k++;
		if(qname[j] == '.' || qname[j] == '\0')
		{
			//k-=1;
			printf("j = %d k = %d\n",j,k);
			qname[j-k] = k-1;
			k = 0;		
		}	
	}
	for(k = 0;k <= len+2 ;k++)
	{
	printf("  %c\n",qname[k]);
	}
}
//解析ip字符转数字
int IPtoI(char *ip )
{
	int a =0, b = 0 ,c = 0, d = 0;//网段
	int IP = 0;
	char IPADDR[20] = {0};
	strcpy(IPADDR,ip);
	char *A  = strtok(IPADDR,".");
	char *B  = strtok(NULL,".");
	char *C  = strtok(NULL,".");
	char *D  = strtok(NULL,".");
	printf("%s ",A);
	 a = atoi(A);
	 b = atoi(B);
	 c = atoi(C);
	 d = atoi(D);
	 printf("\n\n%d %d %d %d \n\n",a,b,c,d);
	 IP = d*256*256*256 + c*256*256 + b*256 + a;
	return IP;
}
//数据包封装
int  package(int i,int len_dns)
{
	bzero(BUF,sizeof(BUF));	
	struct DNS_HEADER *my_header = NULL;
	struct DNS_ANSWER *my_answer = NULL;
	struct DNS_QUESTION *my_question = NULL;
	int IP = 0;
	int j = 0;
	//头部
	my_header = (struct DNS_HEADER *)&BUF;
	my_header->id1 =  ID[0];
	my_header->id2 =  ID[1];			
	my_header->qr =		 1;    //1
	my_header->op = 	 0;    //4
	my_header->aa = 	 0;    //1
	my_header->tc =		 0;    //1
	my_header->rd = 	 1;    //1
	my_header->ra =		 1;    //1
	my_header->zero = 	 0;  //3
	my_header->rc = 	 0;    //4
	my_header->q_count = QUESTION_COUNT;  
	my_header->ans_count = ANSWER_COUNT; 
	my_header->auth_count =AUTH_COUNT;
	my_header->add_count = ADD_COUNT;
	qname = &BUF[sizeof(struct DNS_HEADER)];
	int len = add_qname(i)+1;	
	//询问字段
	my_question = (struct DNS_QUESTION *)&BUF[LEN_DNS_HEADER+len+1];
	my_question->qtype = TYPE;
	my_question->qclass = CLASS;
	chang_dns(i);
	//回答字段
	my_answer = (struct DNS_ANSWER *)&BUF[LEN_DNS_HEADER+len+1+LEN_DNS_QUESTION];
	my_answer->answer_name = ANSWER_NAME;
	my_answer->answer_type = TYPE;
	my_answer->answer_class = CLASS;
	my_answer->time_live = ANSWER_TTL;
	my_answer->DL = ANSWER_DL;
	unsigned int*qip  = (int *)&BUF[LEN_DNS_HEADER+len+1+LEN_DNS_QUESTION+LEN_DNS_ANSWER];
	IP = IPtoI(my_dns_server[i].ip);	
	*qip = IP;
	sendto(socketfd,BUF,128,0,(struct sockaddr*)&cli,len_dns);
	//以下为打印 BUF内容.......................
		printf(".............\n");
	while(1)
	{
		if(j >= 256)
		{
			break;
		}
		printf("%0x ",BUF[j]);
		j++;
	}
	printf("\n");
	 j = 0;
		printf(".............\n");	
	while(1)
	{
		if(j >= 256)
		{
			break;
		}	
		printf("%2c",BUF[j]);
		j++;
	}
	printf("                    %x",'.');	
	//..........................................
	return 1;	
}
//recv  解析buf报文中的域名与本地DNS做对比 对比成功发送报文,失败返回0
int analysis(unsigned char *buf,int rec,int len_dns)
{
	unsigned char *pname = buf + LEN_DNS_HEADER + 1;;
	unsigned char dns_name[20] = {0};
	int i = 0,j = 0;
	bzero(ID,sizeof(ID));
	for(;i < 2;i++)
	{
		ID[i] = buf[i];	
		printf("ID  %x \n",ID[i]);
	}
	printf("UDP is coming : byte %d\n",rec);
	for(i = 0;i < 20;i++)
	{
		dns_name[i] = pname[i];
	}
	int len = strlen(dns_name);
	printf("\n\n%s    %d\n\n",dns_name,len);
	for(i = 0;i < 5;i++)
	{
		char frist[5] = {0};
		char second[10] = {0};
		char thrid[10] = {0};
		char four[5] = {0};
		char *token = NULL;
		char my_dns[20] = {0};
		strcpy(my_dns,my_dns_server[i].name);
		token = strtok(my_dns,".");
		strcpy(frist,token);       //  www
		printf("1:%s\n",frist);
		token = strtok(NULL,".");
		strcpy(second,token);      //   baidu
		printf("2:%s\n",second);
	 	token = strtok(NULL,".");
		strcpy(thrid,token);       //   com
		printf("3:%s\n",thrid);
	 	token = strtok(NULL,".");
		if(strlen(my_dns_server[i].name) == len)
	{			
		if(0 == strncmp(frist,dns_name,strlen(frist)))
		{
			printf("frist word success!!!!\n");
			if(0 == strncmp(second,dns_name+4,strlen(second)))
			{
				printf("second word success !!!\n");
				if(0 ==  strncmp(thrid,dns_name+4+strlen(second)+1,strlen(thrid))) 
				{
					printf("%s\n",dns_name+4+strlen(second));
					printf("thrid word success !!!\n");
					if(token != NULL)
					{
						strcpy(four,token);
						if(0 == strncmp(four,dns_name+4+strlen(second)+1+strlen(thrid)+1,strlen(four)))						
						{								
								printf("4:%s\n",four);
								printf("four word success !!!\n");
								package(i,len_dns);
								return 1;
						}
						return 0;
					}
					package(i,len_dns);
					return 1;
				}
			}
		}
	}
	}
return 0;
}
int main()
{
	socketfd = socket(AF_INET,SOCK_DGRAM,0);
	{
		if(-1 == socketfd)
		{
			perror("fail to socket");
			exit(1);
		}
	}
	
	bzero(&ser,sizeof(ser));
	bzero(&cli,sizeof(cli));
	ser.sin_family = AF_INET;
	ser.sin_port = htons(IP_PORT);
	ser.sin_addr.s_addr = inet_addr(IP_ADDR);
	int ret = bind(socketfd,(struct sockaddr*)&ser,sizeof(ser));
	if(-1 == ret)
	{
		perror("faile to bind");
		exit(1);
	}
	while(1)
	{
	unsigned char buf[128] = {0};		
		int len = sizeof(cli);
		int rec = recvfrom(socketfd,buf,128,0,(struct sockaddr*)&cli,&len);
		if(0 > rec)
		{
			perror("fail to recv");
			exit(1);
		}		
	    ret = analysis(buf,rec,len);
	    printf("\n\n   %d\n",ret);			
	}
		close(socketfd);
	return 0;	
}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值