DNS中继服务器实验报告07415林珅(13)07140107415刘磊(18)07140607415李鸿(19)071407一、系统概述1)运行环境:windowsXP2)编译:MicrosoftvisualC++6.03)使用方法:a)使用ipconfig/all,记下当前DNS服务器,例如为211.68.71.4b)使用下页的配置界面,将DNS设置为127.0.0.1(本地主机)c)运行你的dnsrelay程序(在你的程序中把外部dns服务器设为前面记下的211.68.71.4)d)正常使用ping,ftp,IE等,名字解析工作正常二、系统的功能设计设计一个DNS服务器程序,读入“域名-IP地址”对照表,当客户端查询域名对应的IP地址时,用域名检索该对照表,三种检索结果:1)检索结果为ip地址0.0.0.0,则向客户端返回“域名不存在”的报错消息(不良网站拦截功能)2)检索结果为普通IP地址,则向客户返回这个地址(服务器功能)3)表中未检到该域名,则向因特网DNS服务器发出查询,并将结果返给客户端(中继功能)考虑多个计算机上的客户端会同时查询,需要进行消息ID的转换三、模块划分DNS服务器主模块包含三个子模块,分别如下:1)命令行参数处理模块:该模块用来处理通过命令行提示符来启动这个DNS服务器时所输入的命令行参数,管理员通过设置不同的参数可以使DNS服务器显示不同程度的提示和调试信息。所以这模块主要是依照输入的参数设置标志数据,以控制最后的各种信息的输出。2)本地解析模块:本模块是在本DNS服务器本地保存的曾经解析过的或者需要屏蔽额域名和其对应IP信息文件中查找从应用程序来的请求解析的域名,在这个文件中查到需要的域名后取出对应的IP地址,并构造DNS应答数据包返回给发送此DNS域名解析请求的应用程序。3)外部DNS服务器解析模块:当本地解析失败时,本DNS服务器会调用外部DNS服务器解析模块。此模块将应用程序发送的DNS请求报文转发给外部DNS服务器,然后接收外部服务器返回的应答信息,并根据这个信息给予应用程序相应的DNS应答。三个模块与主模块的关系图如下,主模块调用这三个并列的模块,而本地解析模块调用文件查找子模块:DNS服务器主模块命令行参数处理模块本地解析模块外部DNS服务器解析模块文件查找子模块调用调用半调用四、软件流程图开始创建套接字初始化接收缓冲命令行参数处理初始化设置UDP连接和套接字信息套接字绑定是否退出程序否接收UDP\DNS数据包获取DNS包头参数DNS包类型域名格式转换找到对应IP?本地文件解析设置DNS包头设置应答结果发送DNS应答结果设置外部DNS请求数据包向指定外部DNS转发请求转换DNS数据包头ID设置外部DNS应答数据包向应用程序发送DNS响应数据包还原DNS数据包头ID清除socket关闭套接字结束请求包应答包是否是五、主要数据结构unsignedlongupDNSaddr=inet_addr(DNS_SVR);//外部DNS地址unsignedshortoID,nID,ID=0,TYPE,CLASS,RDLENGTH,RDATA,flag,qdcount,ancount;//oID,nID,ID为数据报ID//TYPE,CLASS,RDLENGTH,RDATA,flag,qdcount,ancount为报文的相应标志位charinitxt[100]=C:\\dns.txt,name[50];//initxt[100]为配置文件路径,name[50]为保存文件域名或IPintopt=0,isfind=0,TTL,len=0,leng,strlen=512;//opt为用户选项,isfind标志是否在本地文件找到记录的布尔变量//TTL为生存周期,len接收的数据报长度,leng发送的数据报长度//strlen为保存接收到的sockaddr的长度WSADatawsaData;//套接口WORDwVersionRequested;//使用的套接口版本structsockaddr_inserver,from,to,temp;//server用于本地监听DNS数据报,from用于接收外部数据报//to用于发送数据报,temp是保存发送请求的浏览器信息charsendbuf[256],recvbuf[256];//发送缓存和接收缓存char*ptr=recvbuf//以ptr的增减来达到在数组中指针移动的效果六、测试用例以及运行结果a)测试本地解析功能请求一个本地DNS对照表中已有的某一记录,如2qq.cn:在本地DNS对照表中找到记录,将相应的IP地址返回给用户:调试信息级别0:dnsrelay调试信息级别1:dnsrelay–d调试信息级别2:dnsrelay–ddb)测试中继功能:请求一个本地DNS对照表中没有的记录,如。本地DNS没有找到相应记录,向外部web服务器转发请求,并接收相应的应答报文并转发给用户:调试信息级别0:dnsrelay调试信息级别1:dnsrelay–d调试信息级别2:dnsrelay–ddc)测试拦截功能:请求一个不良网站,如向用户返回IP地址0.0.0.0,告知用户“域名不存在”的报错信息:调试信息级别0:dnsrelay调试信息级别1:dnsrelay–d调试信息级别2:dnsrelay–ddd)请求一个不存在的域名,如。当外部web服务器找不到相应的域名时返回超时信息,本地DNS服务器将此信息返回给用户。调试信息级别0:dnsrelay调试信息级别1:dnsrelay–d调试信息级别2:dnsrelay–dde)请求一个不合法的域名,如123:本地DNS服务器返回给用户“找不到该域名”的报错信息。七、调试中遇到并解决的问题1)使用socket连接的时候,刚开始只用了一个socket作为所有发送和接收的接口。在实际调试的过程中发现一个不能满足软件需求的实现,所以用一个socket负责发送数据报,另一个socket负责接收数据报。2)回应报文中域名是使用偏移指针的方式实现的,这是由于在域名段写入需要请求的域名时会与问题报文中的域名字段重复从而造成不必要的浪费,用偏移指针的方式既可以防止重复,也可以节省空间。3)使用sendto函数时,一开始使用的是sizeof(sendbuf)来确定发送的数据报大小,但是实际操作中发现发送消息时只需要发送有用的部分,如果使用原来的方法会造成发送数据的冗余,需要精确确定发送数据的有效位数。4)在编程过程中,对于指针的掌握不当造成了多次错误,例如在对于不同的标志位要转换成不同长度的指针进行赋值。5)对于请求包的域名还原问题,需要注意数组下标与实际位数的区别。6)当请求的域名为不带开头的域名时,本机会自动在其尾部追加“.localdomain”来形成新的域名,导致在本地解析工作中无法找到该域名对应的记录,从而转发给外部web服务器,这与本地解析工作是相违背的。所以后来每当在接收到写有“.localdomain”域名的时候,强行进行字符匹配并将其删除,从而完成本地解析工作。八、心得体会本次大作业为实现一个DNS中继服务器。通过完成本地域名解析、中继功能以及不良网站拦截等基本的三个功能,来实现用户访问外部服务器的需求。这次大作业的完成,需要我们阅读并了解RFC1035文档。一开始的时候对RFC完全没有一个清晰地概念,只知道这是一个规格说明,而且初读其中的内容也觉得一头雾水。但后来在老师的提点下抓住了重点,然后一遍一遍反复的阅读,不懂的地方借助网络和图书资料,渐渐发现对DNS的原理和实现方法有了更加全面和深刻的理解,这对后期的程序编写起到了非常大的帮助作用。通过本次网络实验,对小型网络应用程序的实现有了一定程度的理解,同时更加熟悉了winsock函数库。通过抓包分析UDP数据报文、DNS数据报文,对传输层和应用层的数据包发送和接收等工作原理也有了更深的理解。在本次大作业中,让我感触最深的就是这三年来编程实力的反映。在编程的过程中就不断的被一些低级错误影响了软件实现的进度,而且对在大一大二学到的知识点,例如文件的读取,不同进制数的转换等掌握不牢,导致需要花额外的时间去弥补以前遗忘的知识。在最终验收的阶段,通过比较其他组同学的程序就可以很明显的看出,自己程序的功能上比较单一,实现的方法也没有他们来的精妙。继而通过老师质疑的几个问题,也可以发现我们的程序还存在许多不足,例如思考的方面不够全面,思考的角度不够多向。细节反应一个程序的健壮性,而我们没有尽可能的考虑每一个可能的情况,导致仍存在许多漏洞。所以这次的大作业告诉了我们,在以后的学习与实践中,要时刻注意“细节”的重要性。这个不仅要在软件分析的时候要注意,在编程的时候要注意,在调试测试的时候要注意,在最后维护阶段也不能放松。这次的收获想必对未来从事的网络工作很有益处。无论程序好还是坏,最重要就是亲手实践。借鉴别人的好代码永远只是模范,只有自己动手才会实现突破与创新。我们会在以后的学习与实践中不断提高自己的编程能力,日臻完善。