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;
}