显示标签为“dns用戶端”的博文。显示所有博文
显示标签为“dns用戶端”的博文。显示所有博文

2012年9月19日星期三

【Final】如何用W7100A單晶片,實現DNS用戶端(二)


這篇文檔將會介紹DNS以及如何用iMCU7100EVB來實現DNS用戶端,並且通過實際例子演示該功能。

在昨天的博文“如何用W7100A單晶片,實現DNS用戶端(一)”我們給大家介紹了第二章網域名稱系統以及第三章DNS演示的部分,今天繼續與大家分享第四章實現代碼的內容。本文中所有的示例代碼全部基於Keil編譯環境。

這是本篇文檔的最後一部分,希望對大家有所幫助。




4 实现代码

本章将会介绍相关的示例代码,这些代码被下载到iMCU7100EVB开发板后,开发板利用UDP协议实现DNS客户端的功能。更多关于UDP协议的详细信息,请参考文档‘如何使用W7100A实现UDP通信’。


4.1 dns_query()函数
该DNS客户端的示例代码是用dns_query()函数完成的。其它的低级函数被dns_query()函数调用执行。代码4.1为dns_query()函数的代码。

所有的变量都定义于dns_query()函数内,结构变量dhdr位于dns.c的头文件中。DNS_IP保存DNS服务器的IP地址,必须正确输入。
首先,打开UDP socket。在代码4.2中,将端口号设置为5000(端口号可以根据用户的需求进行修改),然后利用dns_makequery()函数(后面将会详细介绍该函数)创建一个查询信息。在查询信息创建后,调用sento()函数将该信息作为一个UDP数据包发送到服务器。
在发送完查询信息后,iMCU7100EVB等待DNS服务器的响应。通过getSn_RX_RSR()函数来确认DNS服务器是否接收到响应信息;如果在一段时间后没有收到响应,就会认为是超时。一旦有响应,通过recvfrom()函数接收响应,并且调用parseMSG()函数来解析该响应信息。parseMSG()函数可以检测来自DNS服务器应答的rcode(DNS信息报文头段);并且返回1或者0。若返回值为1(rcode=0), 表示域名搜索成功。除了0之外的其它值都表示发生错误,但是在示例代码中,对于其它错误parseMSG()函数的返回值都将为0。

4.2 dns_makequery()函数
dns_makequery()函数由dns_query()函数调用来创建DNS查询信息。更多的详细信息,请参考第2章DNS查询信息的配置。该函数的返回值为DNS缓存器的信息指针。



查询信息是由dns_makequery()函数创建的,具体格式在第2章已经介绍。在缓存器中输入DNS信息时要用到Put16()函数,该函数将16位的输入保存到8位的缓存器中。


4.3 parseMSG()函数
parseMSG()由dns_query()函数调用,用来分析接收到的DNS信息。首先分析报文头段,然后调用dns_question()函数来分析问题段,之后再次调用dns_answer()函数分析应答段。最后将已经分析完成的应答信息、与域名相对应的IP地址保存到一个变量中通过printf()函数进行输出。




4.4 dns_question()函数
dns_question()函数由parseMSG()函数调用,用来分析问题段(如:Qname、Qtype、
Qclass)。更多的详细信息,请参考RFC1034和RFC1035文档中问题段的值。


4.5 dns_answer()函数
dns_answer()函数由parseMSG()函数调用,用来对资源记录(RRs)段(Name、Type、
Class、TTL、Rdlength、Rddata)进行分析。在对所有的信息类型解析完成之后,如果信息的类型为TypeA、TypePTR、TypeHINFO、TypeMX、TypeSOA或者TypeTXT时,需要对其进行再次解析。
更多的详细信息,请参考RFC1034和RFC1035文档中对各信息类型的介绍。




4.6 parse_name()函数
parse_name()函数只分析来自DNS应答信息的name段。parse_name()函数也可以改变
DNS信息格式从而使用户更容易进行操作,在分析完成之后返回Name段的长度。




技術支援: wiznetbj@wiznettechnology.com
銷售和代理: winzethk@wiznettechnology.com

更多資訊,請登錄我們的官方網站:http://www.iwiznet.cn


有關產品W7100A的更多應用博文,請參考下列文章:
如何用W7100A實現DNS用戶端
如何用W7100A實現HTTP用戶端(一)

2012年9月18日星期二

如何用W7100A單晶片,實現DNS用戶端(一)


這篇文檔將會介紹DNS以及如何用iMCU7100EVB來實現DNS用戶端,並且通過實際例子演示該功能。

在第二章我們簡單地介紹一下網域名稱系統,第三章是DNS演示的部分,第四章將涉及到代碼的分析。本文中所有的示例代碼全部基於Keil編譯環境。

這裡我們先分享前面部分,希望對大家有所幫助。

 

1 简介

这篇文档将会介绍DNS以及如何用iMCU7100EVB来实现DNS客户端,并且通过实际例子演示该功能。本文中所有的示例代码全部基于Keil编译环境。

2 域名系统(Domain Name System)

域名系统可以实现互联网域名(ex:www.wiznet.co.kr)和互联网IP地址(ex:202.131.29.70)之间的互相转换。DNS由DNS服务器组成,不同域名间的映射表被保存在服务器中;DNS解析程序(DNS客户端)能够查询并且接收来自DNS服务器的映射结果。DNS解析程序请求域名服务器把域名转换成对应的IP地址,域名服务器在接收到请求后开始搜索数据库。如果搜索到客户端请求的相关信息,映射的结果就会被发送到客户端。相反,如果没有搜索到相关信息,域名服务器就会查询根名服务器(root Name Server),等待查询结果并将结果发送到客户端。
下面的图2.2显示了DNS客户端和DNS服务器之间的通信方式。这些查询/应答的信息可以分成五段:报文头(Header)、问题(Question)、应答(Answer)、授权应答(Authority)、附加信息(Additional)。报文头段大小固定为12字节,而其它4段的长度不固定。应答、授权应答以及附加信息这三段可以看做一组,称为资源记录(Resource Records,简称RRs)。而每个报文头﹑问题和资源记录分别有自己的特殊格式。
想了解更多关于DNS的信息,请参阅RFC1034和RFC1035相关文档。
在本文中,iMCU7100EVB实现了DNS客户端的功能;它从DNS服务器上查询域名所对应的IP地址。该例程用UDP协议实现了与DNS服务器之间的发送/接收/分析应答通讯。

3 DNS演示

本章将会对iMCU7100EVB实现DNS客户端的过程进行演示。iMCU7100EVB可以利用UDP协议实现DNS客户端功能。要进行DNS演示,还需要用到超级终端机程序。
在进行演示之前,有一些重要的注意事项需要说明。必须根据用户的设置来设定相应的DNS程序中main.c文件的IP地址、网关IP地址、子网掩码等等信息。想了解更多关于这些值的信息,可以询问ISP(互联网服务提供商)或者是网络管理员。示例代码中的值都是随机设定的,如果不修改这些值,DNS代码可能无法正常工作。同时dns.c文件的DNS服务器的IP地址也需要根据用户的网络环境进行修改。通常DNS服务都是由ISP提供的,如果发生任何问题,请向ISP寻求解决方法。
开始进行演示时,将所有的电源线、网线以及串口线连接到iMCU7100EVB。关于开发板(EVB)的更多细节,可以参考‘iMCU7100EVB用户指南’。在正确修改DNS客户端和DNS服务器的IP地址后,编译附录中的源程序并生成HEX文件,然后利用串口线或者是调试器线将编译生成的HEX文件下载到iMCU7100EVB开发板。用户需要使用WizISP程序或者W7100A Debugger程序。详细信息请参考文档‘W7100A Debugger指南’和‘W7100A的WizISP程序用户指南’。这两个程序都在附带的CD内,也可以从WIZnet主页下载。
在成功下载HEX文件后,运行超级终端机程序。如果使用WizISP下载,需要关闭BOOTSEL 引脚,同时复位开发板。而如果使用W7100A Debugger,按下’run’按钮停止Debugger并且复位开发板。
在DNS演示中要用到超级终端机程序,原因是用户需要通过串口来输入要解析的域名。如图3.3所示,超级终端机的设置也需要根据用户的串行端口进行相应设定。尽管COM2口在图3.3中作为串行端口使用,但是它可以根据用户PC机上的实际设置进行更改。
同时,将波特率设置为115200,用户可以通过手动修改DNSC代码的串口设置来改变波特率。运行开发板和超级终端机程序,然后在超级终端机窗口中输入正确的域名。如图3.4所示,将会显示如下的结果。
当解析成功时,将会出现图3.4中的Part(a)中的结果,如果域名输入错误或者是DNS服务器解析失败,则出现Part(b)中的结果。除了这两种情况,如果在一段时间之后DNS服务器仍然没有响应,iMCU7100EVB将会提示超时信息。


這就是我們今天的內容,後續部分我們將在明天發佈,謝謝關注。

產品W7100A的相關文章,請參考:

單片機乙太網控制晶片--- iMCU W7100A

如何實現W7100A程式燒錄

2012年8月30日星期四

W5100E01-AVR是什麼?怎麼用?(七)(用戶手冊V1.0版)

W5100E01-AVR是为AVR开发者提供的W5100评估板。本文是W5100E01-AVR用户手册的第七部份,因为这个用户手册内容比较多,所以就分了很多部分,一一给大家讲,不要没有耐性噢~ 我的帖子还是希望对大家有帮助。今天我们接着昨天的内容继续介绍:


第六部分在这里W5100E01-AVR是什么?怎么用?(六)(用户手册V1.0版)



3.2.6.6.6 DNS客户端

在介绍DNS客户端设置之前,让我们简要的看一下DNS(域名系统)。
 
DNS系统用于将因特网域名转换成因特网IP地址,反之亦然。DNS由域名服务器和域名解析模块组成,域名服务器包含IP地址与域名之间的映射图,域名解析模块通过给域名服务器传输查询接收查询结果。
 
域名解析模块查询转换成本地域名服务器的IP地址或域名。本地域名服务器通过搜索DB(数据库)接收查询,并响应解析模块。如果域名解析模块找不到需要的信息,本地域名服务器就将接收到的查询发送给上一级域名服务器,接收到的响应就可以发送给域名解析模块。
如<图3.33>所示,DNS查询与DNS响应信息在域名解析系统和域名服务器之间的传送包括5部分,如<图3.34>所示。
Header部分包含固定12字节长度,其他4部分的长度是可变的。除了Header和Question部分,Answer、Authority和Additional部分被称为资源记录(RRs)。每一个Header、Question和RRs都有不同的格式。
DNS信息的Header部分保存信息类型、DNS查询类型和可变长度部分的统计信息。
 
在<图3.35:Header部分格式>中,当DNS信息是域名解析器到域名服务器的请求,QR字段值为0;反之,QR字段得值为1。当DNS信息为查询域名IP地址时,Opcode字段值为0;当它查询域名服务器状态时,Opcode字段值为2。
 
QDCOUNT、ANCOUNT、NSCOUNT与ARCOUNT字段统计可变长度的信息、由Question部分组成的代表区块数、Answer、Authority以及additional部分。组成Question部分的块如<图3.36:Question部分格式>所示,组成Answer、Authority和Additional部分的块如<图3.37>所示。
 
举例来说,如果QDCOUNT是1,ANCOUNT是0,NSCOUNT是10,ARCOUNT是10,那么组成Question部分的块如<图3.36:Question部分格式>所示。Answer、Authority和Additional部分由10块组成,如<图3.37>所示。
 
<图3.37>的NAME字段、<图3.36>的QNAME字段与RDDATA字段也可以得到可变长度。QNAME与NAME字段是可变长度字段,组成的格式和他们处理的每一个字段如<图3.36>所示。RDDATA可变长度字段和进程使用RDLENGTH字段的数据长度。
想了解更多,参见RFC1034和RFC1035。
 
DNS信息由<表3-38>所定义的数据类型操作,参见“inet/dns.h”。
如<图3.33>所示,DNS查询与DNS响应信息在域名解析系统和域名服务器之间的传送包括5部分,如<图3.34>所示。
 
域名解析模块基于gethostbyaddr()函数和gethostbyname()函数运作。gethostbyaddr()函数负责将因特网IP地址转换成因特网域名,gethostbyname()的功能正好相反。gethostbyaddr()函数和gethostbyname()函数测试域名服务器IP地址的设置和搜索W5100连接域名服务器所需信道。如果W5100的闲置信道存在,gethostbyaddr()函数和gethostbyname()函数用‘BYNAME’或‘BYIP’元素调用dns_query()。
 
更多gethostbyaddr() 函数和gethostbyname()函数的例子,参见3.2.5.3.章——Ping请求程序。
 
实际与域名服务器的连接是通过dns_query()函数执行的,gethostbyaddr()函数和gethostbyname()函数只负责报告dns_query()函数的结果。
 
dns_query()函数用于初始化域名服务器间的工作缓存区并基于‘BYNAME’和‘BYIP’查询类型创建Question部分的QNAME。如果查询类型是‘BYNAME’,那么当使用IP地址查询域名时,域名可以当成QNAME使用而不需要转换。
 
当查询类型是‘BYIP’时,那么当使用IP地址查询域名时,需要将IP地址转换成IP地址字符串,并在改变的IP地址字符串添加“in-addr.arpa”后使用QNAME。创建完QNAME后,需要为域名服务器间的工作创建UDP Socket,并通过调用dns_make_query()函数创建DNS请求信息。如果DNS请求信息被成功创建,就通过UDP Socket发送给域名服务器。发送完DNS请求信息后,它就接收DNS响应信息或等待,直到等待时间结束。
 
如果在等待期间从域名服务器接收到DNS响应信息,就使用dns_parse_response()函数分析接收到的DNS响应信息,dns_query()函数会基于查询类型返回IP地址或域名。
 
<图3.39>是dns_query()函数的流程图。
 
<图3‑39: dns_query()函数>
<图3‑40: dns_makequery()函数>
 
dns_makequery()函数创建需要发送给域名服务器的DNS请求信息。因为DNS请求信息只能通过Header和Question部分查询,dns_makequery()函数不需要创建RRs部分。如果你在dns_makequery()函数中查看Header部分,首先它将ID字段值与在域名服务期间工作的信息设置相同,这里ID设置成0x1122。为进一步实现域名服务器间的工作,ID值加1。QR、Opcode、AA、TC和RD字段通过MAKE_FLAG0()函数分别设置成QR_QUERY、OP_QUERY/OP_IQUERY、0、0、1,RA、Z和RCODE字段通过MAKE_FLAG1()函数分别设置成0、0、0。
因为count字段中,QDCOUNT、ANCOUNT、NSCOUNT和ARCOUNT都只有一个question,因此分别设置成1、0、0、0。
让我们来看一下Question部分,QNAME字段用于设置IP地址字符串。域名和IP地址字符串由1 byte的标签和最大可达63 byte的标签组成。为了识别QNAME的可变长度,QNAME字段通常以0作为结尾。<图3.41>所示是QNAME字段中,域名为www.wiznet.co.kr的实际传输例子。
因为count字段中,QDCOUNT、ANCOUNT、NSCOUNT和ARCOUNT都只有一个question,因此分别设置成1、0、0、0。
让我们来看一下Question部分,QNAME字段用于设置IP地址字符串。域名和IP地址字符串由1 byte的标签和最大可达63 byte的标签组成。为了识别QNAME的可变长度,QNAME字段通常以0作为结尾。<图3.41>所示是QNAME字段中,域名为www.wiznet.co.kr的实际传输例子。
 
Question部分的QTYPE字段需要设置成‘TYPE_PTR’,当它保存的域名认为是QNAME时,它的IP地址设置成‘TYPE_A’时,因为它包含在网络中,因此QCLASS字段需要设置成‘CLASS_IN’。
 
<表3-41 >是在QTYPE & QCLASS字段使用的常量定义。
<图3‑42: dns_parse_response()函数>
 
<图3.42> 所示的dns_parse_response()函数分析了通过域名服务器接收的响应信息。dns_parse_response()函数检查发送给域名服务器的ID与响应信息的ID是否相同,它也检测接收到的响应信息是否为通过检查Header部分的QR字段的响应信息。如果接收到的信息是域名服务器的响应,改变的成功与否决定于检查Header部分的RCODE字段。
<表3-42>所示为RCODE字段使用的常量定义。
 
如果RCODE是RC_NO_ERROR,可变长度部分,例如Question、Answer、Authority和Additional部分被解析,因为在Answer部分设置了必要信息被分析和处理,而其他部分没有。如果你需要Authority和Additional部分的信息,你可以通过自己很轻松的获取。
 
Question部分通过调用dns_parse_question()函数处理Header部分的次数与QDCOUNT一样。Answer部分通过调用dns_parse_question()函数处理部分的次数与ANCOUNT一样多。
 
<图3‑43: dns_parse_question()函数和dns_answer()函数>
 
dns_parse_question()函数分析和处理Question部分。在DNS请求信息的Question部分并没有实际的信息,但是它必须被处理以获取Answer部分的开始位置。因为Question 部分的QNAME字段得到可变长度,parse_name()函数跳过了处理QNAME字段可变长度的过程、QTYPE和QCLASS字段。
 
dns_answer()函数分析和处理Answer部分。Answer部分在转换确实产生作用时,在Answer部分的TYPE字段执行适当的程序。
 
Answer部分的TYPE字段只有一种值,而不是来自TYPE_A 或TYPE_PTR,如<表3-41 : QTYPE & QCLASS字段的常量定义>所示。如果域名变成IP地址,它可以从TYPE中得到改变的IP地址,域名可以从TYPE_PTR中获取,改变的域名或IP地址也可以通过parse_name()函数加工和提取。
 
<图3‑44: parse_name()函数>
 
parse_name()函数处理Question部分的QNAME字段或RRs部分的NAME、RDDATA字段。QNAME、NAME、RDDATA字段大多数的组成如<图3.41:Question 部分的QNAME 字段传输实例>所示,但是,它可以被压缩从而减少DNS信息的大小。压缩方法为2字节压缩,如果第1个字节——高字节的2位是‘11’,这就描述标签被压缩了。它包含第1个字节的偏移量,除了高字节的2位和第2个字节。
 
这个偏移量是DNS信息的偏移量,表示从DNS信息的起点到标签存放位置的实际偏移量。如果压缩方案尝试重新使用已经在DNS信息中使用过的域名,就需要间接设置在DNS信息中的相关域名偏移量。<图3.45>所示为DNS信息压缩方案和应用实例。
 
<图3.45>的压缩方案实例是为了防止“F.ISI.ARPA”、“FOO.F.ISI.ARPA”、“ARPA”和ROOT. “F.ISI.ARPA” 没有压缩的情况下,在<图3.41:Question部分的QNAME字段传输实例>的格式中产生20的偏移量。
 
在“FOO.F.ISI.ARPA,”中,因为剩下的除了“FOO”,都和先前处理的Name字段一样。“FOO”在没有压缩的情况下的处理流程如<图3.41:Question部分的QNAME字段传输实例>所示格式,剩下的名称做位移26处理。ROOT是最高级的域名,它使用0的Label Length字段处理。
 
parse_name()函数在分析Name字段之前,检测Label Length Byte的高字节2位是否为11。如果是‘11’,相关Label就分析DNS信息中Lable所在的偏移量;如果不存在,Label的分析和处理过程如<图3.41:Question部分的QNAME字段传输实例>所示。
 
 
这是本文的第七部分内容,后面还剩下一些部分,我将会在下次帖子中发布,敬请期待噢!希望我的内容对大家有所帮助。
更多有關W5100的帖子請進入我們的官方網站www.iwiznet.cn 或官方部落http://blog.iwiznet.cn/ 查看更多。