SylixOS DNS浅析

来源:互联网 发布:知乎回答被删除 编辑:程序博客网 时间:2024/06/04 18:28

1. DNS 概述

       网络通讯大部分是基于TCP/IP,而TCP/IP又基于IP地址。故计算机在网络上进行通讯时只能识别如“192.168.2.1”之类的IP地址,而无法识别域名。在访问网站时,更多的是在浏览器地址栏中输入域名,就能看到所需的页面,这是因为有一个叫“DNS服务器”的计算机自动把域名“翻译”成了相应的IP地址。

       DNS(Domain Name System)是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于TCP/IP网络,它所提供的服务是用来将主机名和域名转换为IP地址的工作。DNS就是这样的一位“翻译官”,它的基本工作原理如图 1‑1所示。
 

图1-1 DNS工作原理

       域名系统作为一个层次结构和分布式数据库,包含各种类型的数据,包括主机名和域名。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。在解析域名时,可以首先采用静态域名解析的方法,如果静态域名解析不成功,再采用动态域名解析的方法。可以将一些常用的域名放入静态域名解析表中,这样可以大大提高域名解析效率。

2. SylixOS DNS 技术实现

       SylixOS实现了一个DNS主机名的IP解析器。

       RealEvo-IDE中新建一个base工程,在该工程/libsylixos/SylixOS/net/lwip/src/core目录下有一个dns.c文件,dns.c文件具体实现了SylixOS  DNS功能。

2.1 实现DNS的初始化函数

       dns.c文件中的初始化工作主要由dns_init函数和dns_setserver函数完成。
       1、 dns_init函数初始化解析器:建立UDP进程控制块和配置默认的服务器,函数具体实现如程序清单 2 1所示。
程序清单 2 1  dns_init函数
void dns_init(void){#ifdef DNS_SERVER_ADDRESS                                                                        /* 初始化默认DNS服务器地址 */  ip_addr_t dnsserver;  DNS_SERVER_ADDRESS(&dnsserver);  dns_setserver(0, &dnsserver);#endif                                                                  /* DNS_SERVER_ADDRESS     */  LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY",    sizeof(struct dns_query) == SIZEOF_DNS_QUERY);  LWIP_ASSERT("sanity check SIZEOF_DNS_ANSWER",    sizeof(struct dns_answer) <= SIZEOF_DNS_ANSWER_ASSERT);  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));                                                                        /* 如果dns客户尚未初始化  */#if ((LWIP_DNS_SECURE & LWIP_DNS_SECURE_RAND_SRC_PORT) == 0)  if (dns_pcbs[0] == NULL) {    dns_pcbs[0] = udp_new_ip_type(IPADDR_TYPE_ANY);    LWIP_ASSERT("dns_pcbs[0] != NULL", dns_pcbs[0] != NULL);    LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",      DNS_STATE_UNUSED == 0);    udp_bind(dns_pcbs[0], IP_ANY_TYPE, 0);                              /* 初始化DNS客户         */    udp_recv(dns_pcbs[0], dns_recv, NULL);  }#endif#if DNS_LOCAL_HOSTLIST  dns_init_local();#endif}
       2、dns_setserver函数初始化一个DNS服务器,函数具体实现如程序清单 2 2所示。

 程序清单 dns_setserver函数

void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver){if (numdns < DNS_MAX_SERVERS) { if (dnsserver != NULL) {      dns_servers[numdns] = (*dnsserver);    } else {      dns_servers[numdns] = *IP_ADDR_ANY;   } }}

2.2 实现DNS的报文格式

       SylixOS DNS定义了一个用于查询和响应的报文格式。这个报文格式由12字节长的首部和4个长度可变的字段组成,如图 2‑1所示。

       

图 2-1 DNS报文格式

       标识字段:由客户程序设置并由服务器返回结果,客户程序通过它来确定响应与查询是否匹配;

       标志字段:16bit的标字段被划分为若干子段,如图 2‑2所示。


图 2-2 标志字段


3. SylixOS mDNS移植评估

        mDNS即多播dns(Multicast DNS),在局域网中,设备和设备之前相互通信需要知道对方的IP地址,大多数情况下,设备的IP不是静态IP地址,而是通过dhcp协议动态分配的IP地址,如何发现设备呢,就需要mDNS大显身手。

       以乐鑫mDNS为例,_mdns_server_init函数初始化mdns服务器,具体实现如程序清单 3‑1所示。

程序清单 3 1 _mdns_server_init函数


esp_err_t _mdns_server_init(mdns_server_t * server){    esp_err_t err = ESP_OK;    tcpip_adapter_ip_info_t if_ip_info;    err = tcpip_adapter_get_ip_info(server->tcpip_if, &if_ip_info);    if (err) {        return err;    }    ip_addr_t laddr;IP_ADDR4(&laddr, 224, 0, 0, 251);    ip_addr_t multicast_if_addr = IPADDR4_INIT(if_ip_info.ip.addr);    if (igmp_joingroup((const struct ip4_addr *)&multicast_if_addr.u_addr.ip4, (const struct ip4_addr *)&laddr.u_addr.ip4)) {        return ESP_ERR_INVALID_STATE;    }    struct udp_pcb * pcb = udp_new();    if (!pcb) {        return ESP_ERR_NO_MEM;    }    pcb->remote_port = MDNS_SERVICE_PORT;    if (udp_bind(pcb, &multicast_if_addr, pcb->remote_port) != 0) {        udp_remove(pcb);        return ESP_ERR_INVALID_STATE;    }    pcb->mcast_ttl = 1;    ip_addr_copy(pcb->multicast_ip, multicast_if_addr);    ip_addr_copy(pcb->remote_ip, laddr);    server->pcb = pcb;    udp_recv(pcb, &_mdns_server_recv, server);    return err;}
       mDNS主要实现了在没有SylixOS DNS服务器的情况下使用局域网内的主机实现相互发现和通信,使用的端口为5353,遵从DNS协议,使用现有DNS信息结构、名语法和资源记录类型,并且没有指定新的操作代码或相应代码。
       故SylixOS完全可以移植mDNS功能。




0 0