# DNS ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- # 功能概述 DNS(Domain Name System,域名系统)是一种基于UDP协议的域名解析工具,用于将域名转换为IP地址。其原理是:发送 DNS 查询请求,等待服务器返回 IP 地址信息。 在嵌入式/物联网场景中,DNS常见用途: - 网络连接初始化 - 域名解析以访问远程服务器 - 故障定位(检查DNS服务器可用性) 模块支持异步和同步解析模式,支持IPv4/IPv6双栈,适用于资源受限的嵌入式设备。遵循RFC 1035标准,确保兼容性。 ## 基本要素 1. **工作原理**:客户端发送UDP查询包到DNS服务器,服务器返回包含IP地址的响应包。支持递归/迭代查询。 2. **网络协议支持**:基于UDP(端口53),可选TCP用于大响应。 3. **输入信息**: - 域名(hostname):如"www.example.com",最大256字符。 - 地址类型(hints):指定IPv4 (AF_INET) 或 IPv6 (AF_INET6)。 4. **输出信息**: - IP地址链表:*qosa_addrinfo_s* 结构体,包含 *ip_addr* 和 *ai_family*。 5. **常见结果**: - 成功:返回IP地址链表。 - 失败:如域名不存在、超时或内存不足。 6. **故障排查步骤**: - 检查网络连接(Ping DNS服务器,如8.8.8.8)。 - 验证域名格式。 - 测试IPv4/IPv6分别解析。 ## 流程概述 DNS操作流程主要包括以下步骤: 1. 初始化参数:设置SIM/PDP ID、域名、hints(地址类型)。 2. 等待网络就绪(PDP激活)。 3. 发送查询:异步(*qosa_dns_asyn_getaddrinfo()*)或同步(*qosa_dns_syn_getaddrinfo()*)。 4. 处理响应:解析IP地址链表。 5. 释放资源:调用 *qosa_dns_result_free()*。 ## 消息结构 DNS消息基于UDP,使用端口53。标准DNS消息包括头部(12字节)、问题区、回答区、授权区和附加区。根据RFC 1035,消息格式如下。 以下是DNS消息结构图: ```{figure} images/board_EzhwwlawDhk6fTbBojHceVCtnGd.jpg :align: center :alt: image ``` - **偏移量细节**(字节为单位): - 0~1:ID - 2~3:Flags (QR、Opcode、AA、TC、RD、RA、Z、RCODE) - 4~5:QDCOUNT - 6~7:ANCOUNT - 8~9:NSCOUNT - 10~11:ARCOUNT - 12+:Question/Answer等(可变)。 ```{note} 域名使用压缩指针避免重复;QTYPE:1 = A (IPv4), 28 = AAAA (IPv6)。 ``` # API说明 ## 头文件 *qosa_asyn_dns.h* ## 函数概览 | **函数** | **描述** | | --- | --- | | *qosa_dns_asyn_getaddrinfo()* | 异步DNS解析域名 | | *qosa_dns_syn_getaddrinfo()* | 同步DNS解析域名 | | *qosa_dns_result_free()* | 释放DNS解析结果 | ### qosa_dns_asyn_getaddrinfo - **功能描述** 异步DNS解析接口,用于解析域名到IP地址,支持IPv4或IPv6,并通过回调函数通知结果。该函数适用于需要非阻塞操作的场景,如多任务环境,避免阻塞主线程。 - **函数原型** ```c qosa_dns_error_e qosa_dns_asyn_getaddrinfo(qosa_uint8_t simcid, qosa_uint8_t pdpcid, const char *hostname, struct qosa_addrinfo_s *hints, dns_result_callback cb, void *user_argv); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *simcid* | 输入 | qosa_uint8_t | SIM ID | | *pdpcid* | 输入 | qosa_uint8_t | PDP ID | | *hostname* | 输入 | const char* | 要解析的域名信息,长度不超过 *QOSA_DNS_REQUEST_MAX_LEN* (256 字符) | | *hints* | 输入 | *struct qosa_addrinfo_s\** | 主要用于指定解析的地址类型(如IPv4或IPv6);详见 [*qosa_addrinfo_s*](#qosaaddrinfos) | | *cb* | 输入 | *dns_result_callback* | 用户注册的异步通知回调函数,在回调函数中禁止进行自己的数据业务,可能导致数据临界问题 | | *user_argv* | 输入 | void* | 用户自定义参数指针 | - **返回值说明** *QOSA_DNS_RESULT_OK*:函数执行成功 其他值:函数执行失败;详见 [*qosa_dns_error_e*](#qosadnserror_e) ```{note} 1. 如果DNS请求成功,调用者需要在回调函数中调用 *qosa_dns_result_free()* 函数释放地址指针。 2. 回调函数中禁止进行阻塞操作或复杂业务逻辑,以避免影响系统性能。 3. *hostname* 长度超过256字符将导致解析失败,返回 *QOSA_DNS_RESULT_ERROR*。 4. *hints* 参数用于指定 *ai_family*(如AF_INET for IPv4, AF_INET6 for IPv6),其他成员可设为0。 5. 该函数异步执行,不会阻塞调用线程,结果通过 *cb* 回调返回。 6. 如果内存分配失败,返回 *QOSA_DNS_MEMORY_ERROR*。 ``` ### qosa_dns_syn_getaddrinfo - **功能描述** 同步DNS解析接口,用于解析域名到IP地址,支持IPv4或IPv6,直接返回结果。该函数适用于简单场景,需要阻塞等待解析完成。 - **函数原型** ```c qosa_dns_error_e qosa_dns_syn_getaddrinfo(qosa_uint8_t simcid, qosa_uint8_t pdpcid, const char *hostname, struct qosa_addrinfo_s *hints, struct qosa_addrinfo_s **res); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *simcid* | 输入 | qosa_uint8_t | SIM ID | | *pdpcid* | 输入 | qosa_uint8_t | PDP ID | | *hostname* | 输入 | const char* | 要解析的域名信息,长度不超过 *QOSA_DNS_REQUEST_MAX_LEN* (256 字符) | | *hints* | 输入 | *struct qosa_addrinfo_s\** | 主要用于指定解析的地址类型(如IPv4或IPv6);详见 [*qosa_addrinfo_s*](#qosaaddrinfos) | | *res* | 输入 | *struct qosa_addrinfo_s\*\** | 解析结果输出,如果失败则 **res* = NULL;详见 [*qosa_addrinfo_s*](#qosaaddrinfos) | - **返回值说明** *QOSA_DNS_RESULT_OK*:函数执行成功 其他值:函数执行失败;详见 [*qosa_dns_error_e*](#qosadnserror_e) ```{note} 1. 如果DNS请求成功,调用者需要调用 *qosa_dns_result_free()* 函数释放 *res* 指向的内存。 2. 该函数是同步的,会阻塞调用线程直到解析完成或超时,可能影响实时性。 3. *hostname* 长度超过256字符将导致解析失败,返回 *QOSA_DNS_RESULT_ERROR*。 4. *hints* 参数用于指定 *ai_family*(如AF_INET for IPv4, AF_INET6 for IPv6),其他成员可设为0。 5. 如果内存分配失败,返回 *QOSA_DNS_MEMORY_ERROR*。 ``` ### qosa_dns_result_free - **功能描述** 释放DNS返回结果内存,适用于异步或同步解析成功后的结果释放。 - **函数原型** ```c void qosa_dns_result_free(struct qosa_addrinfo_s *info); ``` - **参数说明** | **参数名** | **输入/输出** | **类型** | **说明** | | --- | --- | --- | --- | | *info* | 输入 | *struct qosa_addrinfo_s\** | 要释放的 *qosa_addrinfo_s* 结构体;详见 [*qosa_addrinfo_s*](#qosaaddrinfos) | - **返回值说明** 无 ```{note} 1. 必须在DNS解析成功后调用此函数释放内存,以避免内存泄漏。 2. 如果 *info* 为NULL,则无操作,不引发错误。 3. 链表结构中会递归释放所有 *ai_next* 节点。 ``` ## 结构体定义 ### qosa_addrinfo_s ```c struct qosa_addrinfo_s { int ai_family; char ip_addr[CONFIG_QOSA_INET6_ADDRSTRLEN]; struct qosa_addrinfo_s *ai_next; }; ``` | **参数** | **类型** | **说明** | | --- | --- | --- | | *ai_family* | int | IP地址类型(如AF_INET或AF_INET6) | | *ip_addr* | char | 字符类型IP地址,如"127.0.0.1"或IPv6地址,最大48字符 | | *ai_next* | *struct qosa_addrinfo_s* | 存储地址的下一个节点(链表结构);详见 [*qosa_addrinfo_s*](#qosaaddrinfos) | ## 枚举定义 ### qosa_dns_error_e ```c typedef enum { QOSA_DNS_RESULT_OK = 0, QOSA_DNS_RESULT_ERROR = 1 | QOSA_ERRCODE_DNS_BASE, QOSA_DNS_MEMORY_ERROR = 2, QOSA_DNS_RESULT_MAX } qosa_dns_error_e; ``` | **成员** | **说明** | | --- | --- | | *QOSA_DNS_RESULT_OK* | DNS请求成功 | | *QOSA_DNS_RESULT_ERROR* | DNS请求失败 | | *QOSA_DNS_MEMORY_ERROR* | DNS内部内存分配失败 | | *QOSA_DNS_RESULT_MAX* | 最大枚举值 | # 应用逻辑流程图 ```{figure} images/board_FqlPw5J3HhzZW9bJQWCcnSLvntf.jpg :align: center :alt: image ``` # 示例代码 完整示例代码请查看 https://github.com/UniRTOS/UniRTOS-Doc-Examples/blob/main/network/network_protocol/dns/dns_demo.c 。 # 功能配置建议 DNS配置主要通过hints结构体指定解析类型。以下是详细建议,适用于嵌入式场景。 1. **simcid(SIM卡ID)** - 推荐:0(主SIM)。 - 解释:选择稳定SIM;在双SIM设备中动态检测信号。 2. **pdpcid(PDP ID)** - 推荐:1(默认上下文)。 - 解释:确保PDP激活前调用。 3. **hostname(域名)** - 推荐:有效域名,如"www.baidu.com",< 256字符。 - 解释:避免无效域名导致 `QOSA_DNS_RESULT_ERROR`。 4. **hints.ai_family(地址类型)** - 推荐:AF_INET (IPv4) 或 AF_INET6 (IPv6)。 - 解释:默认IPv4;IPv6需网络支持。其他成员设为0。 **通用指南**:异步模式优先(非阻塞);释放内存避免泄漏。示例中 `hints.ai_family` = AF_INET。 # 常见问题排查指南 | **问题现象(错误码)** | **可能原因** | **建议解决方案** | | --- | --- | --- | | *QOSA_DNS_RESULT_ERROR* | 域名无效、超时或网络问题 | 检查 *hostname*;测试网络(Ping DNS服务器);增大超时。 | | *QOSA_DNS_MEMORY_ERROR* | 内存不足 | 优化代码;增加栈大小;检查系统负载。 | | 回调未触发(异步) | 任务/队列初始化失败 | 检查异步回调是否已正确注册;确认网络已就绪且调用线程未阻塞结果处理流程;如使用异步解析,请确保应用层事件循环能够正常接收并处理回调通知。 | | *res* = NULL(同步) | 解析失败 | 验证 *hints*;使用IP代替域名测试。 | | 内存泄漏 | 未调用 *qosa_dns_result_free()* | 在成功后释放 *info*。 | # 附录 ## 术语缩写表 | **缩写** | **全称** | **说明** | | --- | --- | --- | | DNS | Domain Name System | 域名系统,用于地址解析 | | UDP | User Datagram Protocol | 用户数据报协议,DNS传输层 | | IP | Internet Protocol | 互联网协议 | | IPv4 | Internet Protocol version 4 | 互联网协议第4版 | | IPv6 | Internet Protocol version 6 | 互联网协议第6版 | | PDP | Packet Data Protocol | 分组数据协议,用于移动网络 | | SIM | Subscriber Identity Module | 用户身份模块(SIM卡) |