| 第二十二章 DNS22.1 DNS例程概述        W7500EVB的DNS例程,主要实现用W7500EVB通过DNS协议解析域名,获取该域名的IP地址信息。使用前先了解下DNS协议。22.2 DNS协议简介         DNS是计算机域名系统或域名解析服务器(Domain Name System 或Domain Name Service) 的缩写,它是由解析器以及域名服务器组成的。它保存了一张域名(domain name)和与之相对应的IP地址的表,并为Internet上的主机分配域名地址和IP地址,域名和IP地址之间是一一对应的。         DNS域名解析是把域名指向网站空间IP,让人们通过域名可以方便地访问到网站。IP地址是网络上标识站点的数字地址,为了方便记忆,所以采用域名来代替IP地址标识站点地址22.3 Internet域名结构        通常Internet主机域名的一般结构为:主机名、三级域名、二级域名、顶级域名。        ICANN定义了域名的命名采用层次结构的方法。包括:顶级域名,二级域名。每个域都有不同的组织来管理,而这些组织又可将其子域分给下级组织来管理。 顶级域名TLD(Top Level Domain)分为三大类: 1. 国家顶级域名nTLD(cn - 中国、uk - 英国、us - 美国等) 2. 国际顶级域名iTLD(.int,国际性组织可在.int下注册) 3. 通用顶级域名gTLD(.com - 商业组织、.edu - 教育机构、.org - 非赢利性组织、.gov -政府部门、.biz - 公司或企业等) 更多通用顶级域名如下表所示: | 通用顶级域名 | 描述 | 通用顶级域名 | 描述 |  | aero | 航空机构 | int | 国际机构 |  | biz | 公司或企业 | mil | 军事机构 |  | com | 商业机构 | museum | 博物馆 |  | coop | 合作机构 | name | 个人网站 |  | edu | 教育机构 | net | 网络服务机构 |  | gov | 政府部门 | org | 非赢利性组织 |  | info | 信息提供 | pro | 专业机构 | 
 二级域名:        我国将二级域名划分为“ 类别域名”和“行政域名”两大类。         类别域名(ac--科研机构、com--商业组织、edu--教育机构、gov--政府部门、net--网络服务机构、org--各种非赢利组织)        行政域名(bj--北京、sh--上海、nm--内蒙等)  组织内域名:        当一个组织拥有一个域的管理权后,它可以决定是否需要进一步划分层次。例如:CERNET网络中心将“.edu”域划分为多个三级域,将三级域名分配给各个大学与教育机构。同时某大学也可以决定是否将自己得到的三级域划分为多个四级域,将四级域分配给下属部门或主机。 图22.3.1 DNS域名结构图22.4 DNS协议解析过程        1、在浏览器中输入www.baidu.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。         2、如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。         3、如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找首选的DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。         4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。        5、如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找www.baidu.com域服务器,重复上面的动作,进行查询,直至找到www.baidu.com主机。        6、如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把转请求转至上上级,以此循环。不管如何,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。  图22.4.1 DNS查询过程22.5 DNS协议例程解析        DNS例程初始化部分与Network install例程一致,不了解的可以参照Network install例程解析章节。        了解了DNS的工作原理,下面我们来看一下在W7500EVB中的程序是如何处理DNS消息,获取一个域名的IP地址的过程。在本示例中,DNS的报文处理主要由dns.c中定义的函数来处理。一般来讲,为了提高通信的效率,DNS采用UDP协议进行通信,DNS服务器默认的UDP端口是53。这些内容在我们的dns.c实际代码中都体现了出来。        和以前章节的代码一样,main函数在初始化完成后,在主循环里面做DNS消息处理。当一个域名被成功解析后,通过对dns_ok这个变量的判断,主循环将不再和DNS服务器通信。当出现DNS解析失败时,主循环将会不断重试。下面主要讲解DNS执行函数DNS_run();。 [mw_shl_code=applescript,true]1.      int8_t DNS_run(uint8_t * dns_ip, uint8_t * name, uint8_t * ip_from_dns)2.      {
 3.        int8_t ret;
 4.        struct dhdr dhp;
 5.        uint8_t ip[4];
 6.        uint16_t len, port;
 7.        int8_t ret_check_timeout;
 8.        socket(DNS_SOCKET, Sn_MR_UDP, 0, 0);   // 打开DNS的Socket端口
 9.        #ifdef _DNS_DEBUG_
 10.       printf("> DNS Query to DNS Server: %d.%d.%d.%d\r\n",dns_ip[0],dns_ip[1],dns_ip[2],dns_ip[3]);
 11.       #endif
 12.       len = dns_makequery(0, (char *)name, pDNSMSG, MAX_DNS_BUF_SIZE);
 13.       sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);//给DNS服务器发送解析信息
 14.       while (1)
 15.       {
 16.         if ((len = getSn_RX_RSR(DNS_SOCKET)) > 0)
 17.         {
 18.           if (len > MAX_DNS_BUF_SIZE) len = MAX_DNS_BUF_SIZE;
 19.           len = recvfrom(DNS_SOCKET, pDNSMSG, len, ip, &port);//接收服务器应答信息
 20.           #ifdef _DNS_DEBUG_
 21.           printf("> Receive DNS message from %d.%d.%d.%d(%d). len = %d\r\n", ip[0], ip[1], ip[2], ip[3],port,len);
 22.           #endif
 23.           ret = parseDNSMSG(&dhp, pDNSMSG, ip_from_dns);
 24.           break;
 25.         }
 26.       // Check Timeout
 27.       ret_check_timeout = check_DNS_timeout();
 28.       if (ret_check_timeout < 0)
 29.       {
 30.         #ifdef _DNS_DEBUG_
 31.         printf("> DNS Server is not responding : %d.%d.%d.%d\r\n", dns_ip[0], dns_ip[1], dns_ip[2], dns_ip[3]);
 32.         #endif
 33.         return 0; // timeout occurred
 34.       }
 35.       else if (ret_check_timeout == 0)
 36.       {
 37.         #ifdef _DNS_DEBUG_
 38.         printf("> DNS Timeout\r\n");
 39.         #endif
 40.         sendto(DNS_SOCKET, pDNSMSG, len, dns_ip, IPPORT_DOMAIN);
 41.       }
 42.     }
 43.     close(DNS_SOCKET);//关闭Socket
 44.     return ret;
 45.   }[/mw_shl_code]
 第8行是初始化DNS的Socket端口,第12行是用来解析来自DNS服务器的回复,第13行是给DNS服务器发送解析信息,第18~19是判断是否有接收到DNS服务器发送的应答,第23行是解析来自DNS服务器的回复信息然后跳出while并关闭Socket,回到主函数将解析完的IP地址打印出来。 至此,DNS例程代码解析就结束了。将DNS例程编译烧录后打印串口信息结果如图22.5.1。 图22.5.1 DNS例程打印结果 
 |