ESP32-C6 Wi-Fi中继NAPT源IP转换异常排查求助
在ESP-IDF 5.4.0环境下为ESP32-C6配置AP/STA模式,当前状态:
- STA成功连接上级网络,获取192.168.1.127,可被同网段设备Ping通;
- 其他设备可连接ESP32的AP网络,获取192.168.4.X段IP,AP网段内设备可互相Ping通或建立TCP连接传输数据;
核心问题:AP侧设备无法访问互联网。执行esp_netif_napt_enable(sta_netif)返回ESP_OK,但AP侧设备Ping STA网段设备时,ICMP包源IP仍为AP网段的192.168.4.2,未被NAT转换为ESP32的STA接口IP(192.168.1.127)。
已完成的配置:
- 菜单配置中启用WPA3;
- 启用LWIP -> Enable NAT & NAT Port Mapping;
相关代码
File main.c
#include <stdio.h> // tmp NVS #include "nvs_flash.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_event.h" #include "esp_log.h" #include "net_tools.c" void init_nvs() { // Initialize NVS esp_err_t ret = nvs_flash_init(); if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } ESP_ERROR_CHECK(ret); } int app_main(int argc, char **argv) { vTaskDelay(1000); init_nvs(); esp_err_t crel_err = esp_event_loop_create_default(); if (crel_err != ESP_OK) { printf("Failed to create event loop"); } printf("Start Wi-Fi :\n"); esp_log_level_set("esp_netif_lwip", ESP_LOG_VERBOSE); esp_log_level_set("lwip", ESP_LOG_DEBUG); esp_log_level_set(0x00U, ESP_LOG_DEBUG); // Be a AP_STA with IP address forwarding init_AP_STA(); // net_tools.c return 0; }
File net_tools.c
#include "esp_log.h" #include "esp_wifi.h" #include <string.h> #include "keys.c" // My Wi-Fi passwords #define DEFAULT_SCAN_LIST_SIZE 10 #define DHCPS_OFFER_DNS 0x02 ////////// DEBUG TAGS /////////// static const char *STA_WIFI = "Wi-Fi STA"; static const char *AP_WIFI = "Wi-Fi AP"; static const char *NAPT = "Wi-Fi NAPT"; esp_netif_t *ap_netif; esp_netif_t *sta_netif; void softap_set_dns_addr() { esp_netif_dns_info_t dns; esp_netif_get_dns_info(sta_netif,ESP_NETIF_DNS_MAIN,&dns); // uint8_t dhcps_offer_option = DHCPS_OFFER_DNS; uint8_t dhcps_offer_option = 0; ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(ap_netif)); ESP_ERROR_CHECK(esp_netif_dhcps_option(ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_offer_option, sizeof(dhcps_offer_option))); ESP_ERROR_CHECK(esp_netif_set_dns_info(ap_netif, ESP_NETIF_DNS_MAIN, &dns)); ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(ap_netif)); } void enable_nat(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { #ifdef NAPT_DEBUG ESP_LOGI(NAPT, "NAPT_DEBUG DEFINED !!!"); #endif ESP_LOGI(NAPT, "START ENABLE NAT FOR STA"); esp_netif_ip_info_t ip_info; esp_netif_get_ip_info(sta_netif, &ip_info); ESP_LOGI(NAPT, "STA IP address: " IPSTR, IP2STR(&ip_info.ip)); if (ip_info.ip.addr != 0) { // esp_netif_attach(sta_netif, esp_netif_get_io_driver(sta_netif)); // Enable NAPT on the STA interface esp_err_t err = esp_netif_napt_enable(sta_netif); if (err != ESP_OK) { if(err != 0x106) { ESP_LOGE(NAPT, "esp_netif_napt_enable error -> ESP_ERR_NOT_SUPPORTED"); ESP_LOGW(NAPT, "you probably didn't enable napt in Menuconfig."); } ESP_LOGE(NAPT, "Failed to enable NAPT: %s", esp_err_to_name(err)); return; } ESP_LOGI(NAPT, "Added route for AP subnet via STA interface"); } else { ESP_LOGW(NAPT, "No IP address assigned to STA interface. Cannot enable NAPT."); } ESP_LOGI(NAPT, "Set up DNS configuration"); softap_set_dns_addr(); esp_netif_ip_info_t sta_ip_info, ap_ip_info; esp_netif_get_ip_info(sta_netif, &sta_ip_info); esp_netif_get_ip_info(ap_netif, &ap_ip_info); ESP_LOGI(NAPT, "Routes - STA: " IPSTR "/24 via " IPSTR, IP2STR(&sta_ip_info.ip), IP2STR(&sta_ip_info.gw)); ESP_LOGI(NAPT, "Routes - AP: " IPSTR "/24 via " IPSTR, IP2STR(&ap_ip_info.ip), IP2STR(&ap_ip_info.gw)); } } void init_AP_STA() { // Init esp_netif_init(); sta_netif = esp_netif_create_default_wifi_sta(); ap_netif = esp_netif_create_default_wifi_ap(); // Set Wi-Fi mode esp_wifi_set_mode(WIFI_MODE_APSTA); // Set configuration wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(&cfg); esp_netif_set_hostname(sta_netif, "STA_HANDLE"); wifi_config_t wifi_config_sta = { .sta = { .ssid = AP_NAME, .password = PSWD, }, }; esp_wifi_set_config(WIFI_IF_STA, &wifi_config_sta); wifi_config_t wifi_config_ap = { .ap = { .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID), .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS, .channel = EXAMPLE_ESP_WIFI_CHANNEL, .max_connection = EXAMPLE_MAX_STA_CONN, // .authmode = WIFI_AUTH_WPA2_PSK .authmode = WIFI_AUTH_WPA2_WPA3_PSK }, }; esp_wifi_set_config(WIFI_IF_AP, &wifi_config_ap); // Start Wi-Fi interfaces esp_err_t ap_result = esp_wifi_start(); if (ap_result != ESP_OK) { ESP_LOGE(AP_WIFI, "Wi-Fi AP start failed: %s", esp_err_to_name(ap_result)); }else{ ESP_LOGI(AP_WIFI, "Wi-Fi AP started: %s", esp_err_to_name(ap_result)); } // Event handlers esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, enable_nat, NULL); // Connect to source esp-sta to source AP esp_err_t sta_connect = esp_wifi_connect(); if(sta_connect == ESP_OK) { ESP_LOGI(STA_WIFI, "Wi-Fi STA connected successfully\n"); }else{ ESP_LOGI(STA_WIFI, "Wi-Fi STA failed to connect\n"); } }
1. NAPT启用对象错误
ESP-IDF中,NAPT需要启用在AP侧网络接口,而非STA侧。NAPT的作用是将AP子网的私有地址转换为STA接口的公网(上级网络)地址,必须在入口接口(AP)上启用,指定STA为出口转发接口。
解决方法:
修改enable_nat函数中的NAPT启用代码:
// 替换原有的esp_netif_napt_enable(sta_netif); esp_err_t err = esp_netif_napt_enable(ap_netif, 1); // 第二个参数1表示启用NAPT
2. 路由表配置缺失
即使启用NAPT,若没有正确的路由规则,AP侧流量无法被转发到STA接口。需要确保ESP32的路由表中存在AP子网到STA网关的路由。
解决方法:
在enable_nat函数的NAPT启用成功后,添加静态路由配置:
ip4_addr_t gw; esp_netif_get_ip_info(sta_netif, &sta_ip_info); gw.addr = sta_ip_info.gw.addr; // 添加AP子网路由,指向STA网关 ip4_addr_t ap_subnet; IP4_ADDR(&ap_subnet, 192, 168, 4, 0); err = esp_netif_add_route(ap_netif, &ap_subnet, 24, &gw, NULL); if (err != ESP_OK) { ESP_LOGE(NAPT, "Failed to add route: %s", esp_err_to_name(err)); }
3. DHCP DNS配置错误
当前softap_set_dns_addr函数中,dhcps_offer_option被设置为0,导致AP侧设备无法获取正确的DNS服务器地址,无法解析域名。
解决方法:
恢复dhcps_offer_option为DHCPS_OFFER_DNS,确保DHCP服务器向AP侧设备推送DNS信息:
uint8_t dhcps_offer_option = DHCPS_OFFER_DNS; // 替换原有的0 ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(ap_netif)); ESP_ERROR_CHECK(esp_netif_dhcps_option(ap_netif, ESP_NETIF_OP_SET, ESP_NETIF_DOMAIN_NAME_SERVER, &dhcps_offer_option, sizeof(dhcps_offer_option))); ESP_ERROR_CHECK(esp_netif_set_dns_info(ap_netif, ESP_NETIF_DNS_MAIN, &dns)); ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(ap_netif));
4. 冗余的接口挂载操作
代码中esp_netif_attach(sta_netif, esp_netif_get_io_driver(sta_netif));属于冗余操作,esp_netif_create_default_wifi_sta已经完成了接口与驱动的绑定,重复挂载可能导致网络栈异常。
解决方法:删除该行代码。
5. LWIP IP转发未启用
仅启用NAPT不足以完成流量转发,还需要开启LWIP的IPv4转发功能。
解决方法:
在idf.py menuconfig中:
- 进入
Component config -> LWIP -> IPv4,勾选Enable IPv4 forwarding; - 确认
Component config -> LWIP -> NAT下的Enable NAT和Enable NAPT均已勾选;
- ESP32的路由表输出:通过
esp_netif_dump_all()或LWIP的netif_list打印完整路由表; - AP侧设备的网络配置:包括IP、子网掩码、网关、DNS服务器地址;
- 上级路由器的ARP表:查看是否存在ESP32 STA接口IP对应的ARP条目;
- LWIP的NAT日志:开启
Component config -> LWIP -> Debug -> Enable debug prints for NAT,查看NAT转换的详细日志;
内容的提问来源于stack exchange,提问作者v42

