do
{
int sub_name_len = *label;
// (len + 1),因为我们要添加一个'.'
name_len += (sub_name_len + 1);
if (name_len > parsed_name_max_len)
{
return NULL;
}
// 复制标签后面的子名称
memcpy(name_itr, label + 1, sub_name_len);
name_itr[sub_name_len] = '.';
name_itr += (sub_name_len + 1);
label += sub_name_len + 1;
} while (*label != 0);
// 终止最后一个字符串,替换掉最后一个'.'
parsed_name[name_len - 1] = '\0';
// 返回指向名称后第一个字符的指针
return label + 1;
}
/**
* @description: 解析DNS请求并准备一个带有软AP的IP的DNS响应。
* @param {char} *req
* @param {size_t} req_len
* @param {char} *dns_reply
* @param {size_t} dns_reply_max_len
* @return {*}
*/
static int parse_dns_request(char *req, size_t req_len, char *dns_reply, size_t dns_reply_max_len)
{
if (req_len > dns_reply_max_len)
{
return -1;
}
// 准备好答复
memset(dns_reply, 0, dns_reply_max_len);
memcpy(dns_reply, req, req_len);
// NW数据包的端点与芯片不同
dns_header_t *header = (dns_header_t *)dns_reply;
ESP_LOGD(TAG, "DNS query with header id: 0x%X, flags: 0x%X, qd_count: %d",
ntohs(header->id), ntohs(header->flags), ntohs(header->qd_count));
// 不是一个标准的查询
if ((header->flags & OPCODE_MASK) != 0)
{
return 0;
}
// 设置问题响应标志
header->flags |= QR_FLAG;
uint16_t qd_count = ntohs(header->qd_count);
header->an_count = htons(qd_count);
int reply_len = qd_count * sizeof(dns_answer_t) + req_len;
if (reply_len > dns_reply_max_len)
{
return -1;
}
// 指向当前答案和问题的指针
char *cur_ans_ptr = dns_reply + req_len;
char *cur_qd_ptr = dns_reply + sizeof(dns_header_t);
char name[128];
// 用ESP32的IP地址回答所有问题
for (int i = 0; i < qd_count; i++)
{
char *name_end_ptr = parse_dns_name(cur_qd_ptr, name, sizeof(name));
if (name_end_ptr == NULL)
{
ESP_LOGE(TAG, "Failed to parse DNS question: %s", cur_qd_ptr);
return -1;
}
dns_question_t *question = (dns_question_t *)(name_end_ptr);
uint16_t qd_type = ntohs(question->type);
uint16_t qd_class = ntohs(question->class);
ESP_LOGD(TAG, "Received type: %d | Class: %d | Question for: %s", qd_type, qd_class, name);
if (qd_type == QD_TYPE_A)
{
dns_answer_t *answer = (dns_answer_t *)cur_ans_ptr;
answer->ptr_offset = htons(0xC000 | (cur_qd_ptr - dns_reply));
answer->type = htons(qd_type);
answer->class = htons(qd_class);
answer->ttl = htonl(ANS_TTL_SEC);
esp_netif_ip_info_t ip_info;
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info);
ESP_LOGD(TAG, "Answer with PTR offset: 0x%X and IP 0x%X", ntohs(answer->ptr_offset), ip_info.ip.addr);
answer->addr_len = htons(sizeof(ip_info.ip.addr));
answer->ip_addr = ip_info.ip.addr;
}
}
return reply_len;
}
/**
* @description: 设置一个套接字并监听 DNS 查询。 用软AP的IP回复所有A类查询。
* @param {void} *pvParameters
* @return {*}
*/
void dns_server_task(void *pvParameters)
{
char rx_buffer[128];
char addr_str[128];
int addr_family;
int ip_protocol;
//uint32_t result = 0;
while (1)
{
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(DNS_PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
if (sock < 0)
{
ESP_LOGE(TAG, "Unable to create socket: errno |