第 1 章 - Azure RTOS NetX Duo DNS 客户端简介

DNS 提供了一个分布式数据库,其中包含域名与物理 IP 地址之间的映射。 此数据库之所以被称为分布式数据库是因为,Internet 上没有一个单独的实体包含完整的映射。 维护部分映射的实体被称为“DNS 服务器”。 Internet 是由许多 DNS 服务器组成的,每个服务器都包含此数据库的一个子集。 DNS 服务器也会响应 DNS 客户端对域名映射信息的请求,但前提是服务器有所请求的映射信息。

NetX Duo 的 DNS 客户端协议为应用程序提供了从一个或多个 DNS 服务器请求获取映射信息的服务。

DNS 客户端设置

为了能够正常运行,DNS 客户端包要求已经创建了 NetX Duo IP 实例。

在创建 DNS 客户端后,应用程序必须将一个或多个 DNS 服务器添加到 DNS 客户端维护的服务器列表中。 应用程序使用 nxd_dns_server_add 服务来添加 DNS 服务器。 NetX Duo DNS 客户端服务 nx_dns_server_add 也可用于添加服务器。 但它只接受 IPv4 地址,建议开发人员改用 nxd_dns_server_add 服务。

如果已启用 NX_DNS_IP_GATEWAY_SERVER 选项,并且 IP 实例网关地址不为零,则会将 IP 实例网关自动添加为主 DNS 服务器。 如果 DNS 服务器信息不是静态已知的,它也可以通过 NetX Duo 的动态主机配置协议 (DHCP) 获得。 有关详细信息,请参阅 NetX Duo DHCP 用户指南。

DNS 客户端需要一个数据包池来传输 DNS 消息。 默认情况下,在调用 nx_dns_create 服务时,此数据包池由 DNS 客户端创建。 使用配置选项 NX_DNS_PACKET_PAYLOAD_UNALIGNED 和 NX_DNS_PACKET_POOL_SIZE,应用程序可以分别确定此数据包池的数据包有效负载和数据包池大小(例如数据包数量)。 第 2 章中的“配置选项”部分介绍了这些选项。

除了由 DNS 客户端创建自己的数据包池之外,还可以让应用程序创建数据包池,并使用 nx_dns_packet_pool_set 服务将它设置为 DNS 客户端的数据包池。 为此,必须定义 NX_DNS_CLIENT_USER_CREATE_PACKET_POOL 选项。 此选项还需要将之前使用 nx_packet_pool_create 创建的数据包池用作 nx_dns_packet_pool_set 的数据包池指针输入。 当删除 DNS 客户端实例时,如果启用了 NX_DNS_CLIENT_USER_CREATE_PACKET_POOL,则由应用程序负责删除不再需要的 DNS 客户端数据包池。

注意

对于选择使用 NX_DNS_CLIENT_USER_CREATE_PACKET_POOL 选项提供自己的数据包池的应用程序,数据包大小需要能够容纳 DNS 最大消息大小(512 字节)以及 UDP 头、IPv4 或 IPv6 头和 MAC 头。

DNS 消息

DNS 有一种非常简单的机制来获取主机名和 IP 地址之间的映射。 DNS 客户端为了获取映射会准备一条 DNS 查询消息,其中包含需要解析的域名或 IP 地址。 然后,此消息会被发送到服务器列表中的第一个 DNS 服务器。 如果服务器有这样的映射,则会使用包含所请求的映射信息的 DNS 响应消息来答复 DNS 客户端。 如果服务器没有响应,那么 DNS 客户端会查询其列表上的下一个服务器,直到查询完其所有 DNS 服务器。 如果所有 DNS 服务器都没有响应,则 DNS 客户端会利用重试逻辑来重新传输 DNS 消息。 在重新发送 DNS 查询后,重新传输超时时间会加倍。 此过程会一直持续,直到达到最大传输超时(在 nxd_dns.h 中定义为 NX_DNS_MAX_RETRANS_TIMEOUT),或直到收到来自相应服务器的成功响应。

NetX Duo DNS 客户端通过在 nxd_dns_host_by_name_get 调用中指定 IP 地址版本,可以同时执行 IPv6 地址查找(类型为 AAAA)和 IPv4 地址查找(类型为 A)。 DNS 客户端可以使用 nxd_dns_host_by_address_get 来执行 IP 地址的反向查找(类型为 PTR 查询),从而获取 Web 主机名。 NetX Duo DNS 客户端仍支持 nx_dns_host_by_name_get 和 nx_dns_host_by_address_get 这些等效服务,但它们仅限于 IPv4 网络通信。 不过,建议开发人员将现有的 DNS 客户端应用程序移植到 nxd_dns_host_by_name_get 和 nxd_dns_host_by_address_get 服务中。

DNS 消息传递利用 UDP 协议来发送请求和处理响应。 DNS 服务器侦听端口号 53,以确定是否有来自客户端的查询。 因此,在 NetX Duo 中,必须在之前创建的 IP 实例 (nx_ip_create) 上使用 nx_udp_enable 服务来启用 UDP 服务。

此时,DNS 客户端已就绪,可以接受来自应用程序的请求,并发出 DNS 查询。

扩展的 DNS 资源记录类型

如果启用了 NX_DNS_ENABLE_EXTENDED_RR_TYPES,那么 NetX Duo DNS 客户端还支持以下记录类型查询:

  • CNAME:包含别名的规范名称
  • TXT:包含文本字符串
  • NS:包含授权名称服务器
  • SOA:包含授权区域的起始部分
  • MX:用于邮件交换
  • SRV:包含域提供的服务的相关信息

应用程序必须提供 4 字节对齐的缓冲区来接收 DNS 数据记录(CNAME 和 TXT 记录类型除外)。

在 NetX Duo DNS 客户端中,记录数据以这种方式存储是为了最高效地利用缓冲区空间。

下面展示了长度固定的记录缓冲区(类型为 AAAA 记录)示例:

Record buffer of fixed length

对于记录类型的数据长度可变的查询(如主机名长度可变的 NS 记录),NetX Duo DNS 客户端的数据保存方式如下: DNS 客户端查询中提供的缓冲区被组织成一个固定长度数据区域和一个非结构化内存区域。 内存缓冲区的顶部被组织成 4 字节对齐的记录条目。 每个记录条目都包含 IP 地址,以及指向此 IP 地址的可变长度数据的指针。 每个 IP 地址的可变长度数据存储在从内存缓冲区末尾开始的非结构化区域内存中。 每个后续记录条目的可变长度数据保存在与上一个记录条目变量数据相邻的下一个区域内存中。 因此,变量数据向包含记录条目的结构化区域内存“增长”,直到没有足够的内存来存储另一个记录条目和变量数据。

如下图所示:

Figure 2

上面展示了 DNS 域名 (NS) 数据存储的示例。

使用记录存储格式的 NetX Duo DNS 客户端查询返回保存到记录缓冲区中的记录数量。 根据此信息,应用程序可以从记录缓冲区中提取 NS 记录。

下面展示了使用此记录存储格式来存储可变长度 DNS 数据的 DNS 客户端查询示例:

UINT  _nx_dns_domain_name_server_get(NX_DNS *dns_ptr, 
                    UCHAR *host_name, VOID *record_buffer, 
                    UINT buffer_size, UINT *record_count, 
                    ULONG wait_option);

有关更多详情,请参阅第 3 章“DNS 客户端服务说明”。

DNS 缓存

如果启用了 NX_DNS_CACHE_ENABLE,则 NetX Duo DNS 客户端支持 DNS 缓存功能。 在创建 DNS 客户端后,应用程序可以调用 API nx_dns_cache_initialize() 来设置特殊的 DNS 缓存。 如果启用了 DNS 缓存功能,那么 DNS 客户端在开始发送 DNS 查询之前会从 DNS 缓存中查找可用应答;如果找到可用应答,就会直接将应答返回给应用程序,否则 DNS 客户端会向 DNS 服务器发送查询消息并等待答复。 当 DNS 客户端获得响应消息并且有可用缓存时,DNS 客户端会将应答返回给应用程序,并将应答作为资源记录添加到 DNS 缓存中。

每个应答在缓存中都有一个数据结构 NX_DNS_RR(资源记录)。 记录中的字符串(资源记录名称和数据)是可变长度的,因此不会存储在 NX_DNS_RR 结构中。 记录包含指向存储字符串的实际内存位置的指针。 字符串表和记录共享缓存。 记录从缓存的开头开始存储,然后向缓存的末尾增长。 字符串表从缓存的末尾开始存储,然后向缓存的开头增长。 字符串表中的每个字符串都有一个长度字段和一个计数器字段。 当向字符串表添加字符串时,如果表中已有相同的字符串,则计数器值会递增,但不会为此字符串分配内存。 如果无法向缓存添加更多资源记录或新字符串,则认为缓存已满。

DNS 客户端限制

DNS 客户端一次只支持一个 DNS 请求。 尝试发出另一个 DNS 请求的线程会被暂时阻止,直到上一个 DNS 请求完成。

NetX Duo DNS 客户端不使用授权应答中的数据来将额外 DNS 查询转发给其他 DNS 服务器。

DNS RFC

NetX Duo DNS 符合以下 RFC:

  • RFC1034 域名 - 概念和设施
  • RFC1035 域名 - 实现和规范
  • RFC1480 美国域
  • RFC 2782 指定服务位置的 DNS RR (DNS SRV)
  • RFC 3596 支持 IP 版本 6 的 DNS 扩展