DNS课程设计报告.docx

上传人:b****5 文档编号:8870059 上传时间:2023-05-15 格式:DOCX 页数:23 大小:397.62KB
下载 相关 举报
DNS课程设计报告.docx_第1页
第1页 / 共23页
DNS课程设计报告.docx_第2页
第2页 / 共23页
DNS课程设计报告.docx_第3页
第3页 / 共23页
DNS课程设计报告.docx_第4页
第4页 / 共23页
DNS课程设计报告.docx_第5页
第5页 / 共23页
DNS课程设计报告.docx_第6页
第6页 / 共23页
DNS课程设计报告.docx_第7页
第7页 / 共23页
DNS课程设计报告.docx_第8页
第8页 / 共23页
DNS课程设计报告.docx_第9页
第9页 / 共23页
DNS课程设计报告.docx_第10页
第10页 / 共23页
DNS课程设计报告.docx_第11页
第11页 / 共23页
DNS课程设计报告.docx_第12页
第12页 / 共23页
DNS课程设计报告.docx_第13页
第13页 / 共23页
DNS课程设计报告.docx_第14页
第14页 / 共23页
DNS课程设计报告.docx_第15页
第15页 / 共23页
DNS课程设计报告.docx_第16页
第16页 / 共23页
DNS课程设计报告.docx_第17页
第17页 / 共23页
DNS课程设计报告.docx_第18页
第18页 / 共23页
DNS课程设计报告.docx_第19页
第19页 / 共23页
DNS课程设计报告.docx_第20页
第20页 / 共23页
亲,该文档总共23页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

DNS课程设计报告.docx

《DNS课程设计报告.docx》由会员分享,可在线阅读,更多相关《DNS课程设计报告.docx(23页珍藏版)》请在冰点文库上搜索。

DNS课程设计报告.docx

DNS课程设计报告

DNS服务器程序

实验报告

班级:

2011211301

小组成员:

曹晓欢2011211139

杨静怡2011211140

系统功能设计

⏹设计一个DNS服务器程序,读入“IP地址-域名”对照表,当客户端查询域名对应的IP地址时,用域名检索该对照表,有三种可能检索结果:

◆检索结果:

ip地址0.0.0.0,则向客户端返回“域名不存在”的报错消息(不良网站拦截功能)

◆检索结果:

普通IP地址,则向客户端返回该地址(服务器功能)

◆表中未检到该域名,则向因特网DNS服务器发出查询,并将结果返给客户端(中继功能)

Ø考虑多个计算机上的客户端会同时查询,需要进行消息ID的转换

系统和运行环境描述

Windows7操作系统平台,VS2010编程环境。

使用C/C++编写dns中继服务器。

主要数据结构

SOCKETsockfd;

Socket套接字

SOCKADDR_INser_addr,nser_addr;

表达地址结构信息,等价于sockaddr结构

typedefstructreq_inform

{//DNS请求包信息

SOCKADDR_INcli_addr;

unsignedshortid;//id和cli_addr唯一标识一个DNS请求

}req_inform;

该结构唯一标示了一个来自客户端的dns请求。

mapurl_ip_table;//本地域名解析表

用来构建本地存储的dnsrelay.txt中域名和IP的映射。

mapreq_cache[cache_num];//id转换表

这一个map映射,把客户端dns请求映射到一个unsignedshort上面,用它来存储id转换信息。

Unsignedshort类型的key值为新的id号,用于标识转发给外部服务器,而客户端的信息和旧id作为value存在map中,与key形成映射。

待服务器发回应答包,根据包中id号,即可找到原id与客户端信息。

#definecache_num2//转换表数目

#definecache_size500//每个转换表容量

intidThen_max=cache_num*cache_size;//总条目数

intcur_cache=0;

intidThen=0;

cache_num指定了id转换表的个数,cache_size是每个id转换表的大小,

cur_cache指向是当前正在装入的id转换表,idThen是一个从0到1000一直循环的被映射到的id号。

这样的设计可循环利用id转换表,并及时清除旧记录。

具体流程是:

生成id转换的item(idThen,structreq_inform的一个变量)

把id转换的item加入到req_cache[cur_cache]中

如果req_cache[cur_cache]已经达到cache_size

{

cur_cache指向下一个id转换表,并将其清空

}

idThen加1

函数划分(模块划分)

intget_url_ip_table(map&iptable)//失败返回-1

从文件中读入url和ip的映射表。

intinit();

用来初始化ser_addr、nser_addr、sockfd,以及对sockfd绑定到本地的ser_addr的

地址上。

intis_req(char*buffer);

用来判断收到的包是上级服务器的回答包,还是来自客户端的请求包。

voidget_url(char*buf,string&url);

从请求包中提取URL。

voidask_next_server(char*buffer,structsockaddr_inreq_addr,intbuffer_size);

询问上级dns服务器。

voidcreate_respose(char*buffer,structsockaddr_inreq_addr,int

buffer_size,stringip);

根据url-ip表中找到的结果自己构造响应。

voiddeal_req(char*buffer,structsockaddr_inreq_addr,intbuffer_size);

客户端请求包的处理

voiddeal_res(char*buffer,intbuffer_size);

上级服务器回答包的处理。

intmain();

主函数

软件流程图

失败

成功

失败

成功

请求包应答包

NO

YES

源代码

#include

#include

#include

#include

#include

#include

#include

#include"WinSock2.h"//socket头文件

#pragmacomment(lib,"ws2_32.lib")//链接Ws2_32.lib库,不必再setting里设置

usingnamespacestd;

//id转换表参数定义

#definecache_num2//转换表数目

#definecache_size500//每个转换表容量

intidThen_max=cache_num*cache_size;//总条目数

intcur_cache=0;

intidThen=0;

SOCKETsockfd;

SOCKADDR_INser_addr,nser_addr;/*使用sockaddr_in表达地址结构

信息,等价于sockaddr结构*/

constchar*nx_ip="211.68.71.4";

constchar*file_name="dnsrelay.txt";

typedefstructreq_inform

{//DNS请求包信息

SOCKADDR_INcli_addr;

unsignedshortid;//id和cli_addr唯一标识一个DNS请求

}req_inform;

mapurl_ip_table;//本地域名解析表

mapreq_cache[cache_num];//id转换表

/*

structdns_ans_add

{//构造响应包所要添加的信息除了请求包外,包括指针、类型、生存时间、类、资源大小、资源等等

unsignedshorturl_pointer;

unsignedshorttype;

unsignedshortclas_s;

unsignedlongttl;

unsignedshortsourse_size;

unsignedlongsourse;

};

*/

intget_url_ip_table(map&iptable)//失败返回-1

{

stringtmpip,tmpurl;

fstreamfs;

fs.open("dnsrelay.txt");

if(!

fs.is_open())

{

cout<<"txtcan'topen."<

return-1;

}

else

{

iptable.clear();

while(!

fs.eof())

{

fs>>tmpip;

fs>>tmpurl;

iptable.insert(pair(tmpurl,tmpip));

}

fs.close();

return0;

}

}

intinit()//失败返回-1

{

WSADatawsa;//socket初始化

if(WSAStartup(MAKEWORD(2,2),&wsa)!

=0)//Winsock服务的初始化

{

WSACleanup();

cout<<"winsock初始失败"<

return0;

}

for(inti=0;i

req_cache[i].clear();

sockfd=socket(AF_INET,SOCK_DGRAM,0);//创建socket套接字

ser_addr.sin_family=AF_INET;//sin_family指代协议族

ser_addr.sin_port=htons(53);//使用53端口即DNS服务器端口

ser_addr.sin_addr.s_addr=INADDR_ANY;//0.0.0.0,sin_addr存储IP地址

nser_addr.sin_family=AF_INET;

nser_addr.sin_port=htons(53);

nser_addr.sin_addr.s_addr=inet_addr(nx_ip);//返回值作Internet地址

if(bind(sockfd,(SOCKADDR*)&ser_addr,sizeof(ser_addr))==-1){

cout<<"绑定端口失败"<

return-1;

}

else

cout<<"绑定端口成功"<

return0;

}

intis_req(char*buffer)

{

unsignedshortflags=0;

memcpy(&flags,buffer+2,2);//取标志位信息

if(flags==0x0001)//3号位002号位01请求包(0001为网络顺序)本地:

0100

return1;

else

return0;

}

voidget_url(char*buf,string&url)

{//从请求包中提取URL

intindex=0;

unsignedcharnum,i;

url.clear();

num=buf[index++];//第一节字段长度

while(num)//当num=0为结尾跳出

{

for(i=0;i

url.push_back(buf[index++]);//push_back字符串之后插入一个字符

num=buf[index++];

if(num!

=0)//说明没结束

url.push_back('.');

}

}

voidask_next_server(char*buffer,sockaddr_inreq_addr,intbuffer_size)

{

structreq_informtem;

cout<<"本地域名解析表未找到,询问外部服务器..."<

tem.cli_addr=req_addr;//请求端地址

memcpy(&(tem.id),buffer,2);//原请求端id

memcpy(buffer,&idThen,2);//赋予新的id号idThen

if(sendto(sockfd,buffer,buffer_size,0,(structsockaddr*)&nser_addr,sizeof(structsockaddr))==-1)

{

cout<<"未成功发送请求至外部服务器"<

return;

}

req_cache[cur_cache].insert(pair(idThen,tem));//增加本id转换项,至映射表项

if(req_cache[cur_cache].size()>=cache_size)//当前本映射表已满,跳到另一张表

{

cur_cache=(cur_cache+1)%cache_num;//指向新的一张表

req_cache[cur_cache].clear();//新表的历史记录清空

}

idThen=(idThen+1)%idThen_max;//下一个转发请求的id号

}

voidcreate_respose(char*buffer,sockaddr_inreq_addr,intbuffer_size,stringip)

{

charans[1000];//响应包

unsignedshortflags=0x8081;//响应包标志位8180(8180为x86顺序)

unsignedshortans_num=0x0100;//正常的响应数设置响应个数1

cout<<"在本地域名解析表缓存中找到。

"<

memcpy(ans,buffer,buffer_size);//拷贝请求包

memcpy(ans+2,&flags,2);//改标志位

if(pare("0.0.0.0")==0)

{//若是屏蔽,则直接返回

ans_num=0x0000;//重置回复数为0,屏蔽

memcpy(&ans[6],&ans_num,sizeof(unsignedshort));

if(sendto(sockfd,ans,buffer_size,0,(structsockaddr*)&req_addr,sizeof(structsockaddr))==-1)

{

cout<<"发送至客户端失败!

"<

return;

}

printf("url已屏蔽...\n");

return;

}

else

{//构造响应包

charc_ip[50];

ip.copy(c_ip,ip.length());

c_ip[ip.length()]='\0';

printf("该请求包所要找的的ip是%s...\n",c_ip);

memcpy(ans+6,&ans_num,sizeof(unsignedshort));//修改、添加信息,包括响应数、多出的响应字段等等

//构造DNS响应部分

intcurLen=0;

charanswer[16];

unsignedshortName=htons(0xc00c);

memcpy(answer,&Name,sizeof(unsignedshort));

curLen+=sizeof(unsignedshort);

unsignedshortTypeA=htons(0x0001);

memcpy(answer+curLen,&TypeA,sizeof(unsignedshort));

curLen+=sizeof(unsignedshort);

unsignedshortClassA=htons(0x0001);

memcpy(answer+curLen,&ClassA,sizeof(unsignedshort));

curLen+=sizeof(unsignedshort);

unsignedlongtimeLive=htonl(0x7b);

memcpy(answer+curLen,&timeLive,sizeof(unsignedlong));

curLen+=sizeof(unsignedlong);

unsignedshortIPLen=htons(0x0004);

memcpy(answer+curLen,&IPLen,sizeof(unsignedshort));

curLen+=sizeof(unsignedshort);

unsignedlongIP=(unsignedlong)inet_addr(c_ip);

memcpy(answer+curLen,&IP,sizeof(unsignedlong));

curLen+=sizeof(unsignedlong);

curLen+=buffer_size;

//请求报文和响应部分共同组成DNS响应报文存入sendbuf

memcpy(ans+buffer_size,answer,curLen);

if(sendto(sockfd,ans,curLen,0,(structsockaddr*)&req_addr,sizeof(structsockaddr))==-1)

{

cout<<"发送客户端失败!

"<

return;

}

}

}

voiddeal_req(char*buffer,structsockaddr_inreq_addr,intbuffer_size)

{

stringurl;

map:

:

iteratoruit_iter;

printf("收到请求包,正在处理...\n");

get_url(buffer+12,url);//包头12个字节

printf("请求解析的url是:

");

cout<

uit_iter=url_ip_table.find(url);//找ip

if(uit_iter==url_ip_table.end())

{

ask_next_server(buffer,req_addr,buffer_size);//未找到,向上级服务器询问

}

else//自己构造响应

{

cout<<"在本地缓存找到ip:

"+uit_iter->second<

create_respose(buffer,req_addr,buffer_size,uit_iter->second);

}

}

voiddeal_res(char*buffer,intbuffer_size)

{

unsignedshortcur_id,i;

map:

:

iteratormiter;

structreq_informcur_inform;

printf("从外部服务器得到响应包...");

memcpy(&cur_id,buffer,2);

for(i=0;i

{//检索映射表找到相匹配的id信息,从而正确返回dns请求回复

miter=req_cache[i].find(cur_id);

if(miter!

=req_cache[i].end())

{

cur_inform=miter->second;//获得之前dns请求信息

memcpy(buffer,&(cur_inform.id),2);//得到旧id复制到buffer,修改id

if(sendto(sockfd,buffer,buffer_size,0,(structsockaddr*)&(cur_inform.cli_addr),sizeof(structsockaddr))==-1)

printf("发送至客户端失败!

\n");

else

printf("成功发送至客户端!

\n");

return;

}

}

printf("couldnotbefoundinthecache...\n");

}

intmain()

{

charrecv_buffer[512];

SOCKADDR_INrecv_addr;

intrecv_size;

printf("读入url-ip表...");

if(get_url_ip_table(url_ip_table)==-1)

{

perror("读入url-ip表错误!

\n");

return0;

}

printf("缓存一共有%d条记录\n",url_ip_table.size());//TXT中表项

//初始化socket和sockaddr_in,bind端口

printf("初始化socket...");

if(init()==-1)

return0;

printf("初始化成功...\n");

printf("dns服务器启动...\n");

while

(1)

{

intrecv_len=sizeof(sockaddr);

if((recv_size=recvfrom(sockfd,recv_buffer,sizeof(recv_buffer),0,(sockaddr*)&recv_addr,&recv_len))==-1)

{

perror("接收错误包!

\n");

continue;

}

elseif(is_req(recv_buffer))

{//处理请求包

deal_req(recv_buffer,recv_addr,recv_size);

}

else

{//处理响应包

deal_res(recv_buffer,recv_size);

}

printf("\n\n");

}

return0;

}

测试用例以及运行结果

(1)首先先把本地连接中的DNS服务器地址改成本地的127.0.0.1

此时无法正常使用网页:

(2)开启本实验设计的DNS服务器:

正常浏览网页:

能正常ping通网址:

服务器显示信息:

能正常使用nslookup命令查ip地址:

a.本地解析表存在的记录:

服务器信息:

b.查询本地解析表中,被屏蔽的记录

服务器信息:

C.本地没有记录,转发出去:

服务端信息:

遇到并解决的问题

1.Id转换问题

构造一个map映射:

mapreq_cache[cache_num];

把客户端dns请求映射到一个unsignedshort上面,用它来

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2