DNS课程设计报告.docx
- 文档编号:23288532
- 上传时间:2023-05-16
- 格式:DOCX
- 页数:23
- 大小:397.62KB
DNS课程设计报告.docx
《DNS课程设计报告.docx》由会员分享,可在线阅读,更多相关《DNS课程设计报告.docx(23页珍藏版)》请在冰豆网上搜索。
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请求。
map
用来构建本地存储的dnsrelay.txt中域名和IP的映射。
map
这一个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
从文件中读入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;
map
map
/*
structdns_ans_add
{//构造响应包所要添加的信息除了请求包外,包括指针、类型、生存时间、类、资源大小、资源等等
unsignedshorturl_pointer;
unsignedshorttype;
unsignedshortclas_s;
unsignedlongttl;
unsignedshortsourse_size;
unsignedlongsourse;
};
*/
intget_url_ip_table(map
{
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 } 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 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映射: map 把客户端dns请求映射到一个unsignedshort上面,用它来
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- DNS 课程设计 报告