Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

ESP32-C3 Captive Portal with DNS Redirection and Auto Popup Implementation #11558

Jayden1Joe started this conversation in Question - Community Help
Discussion options

When I connect to the Wi-Fi Soft AP, it prints the received DNS requests as expected as you can see below. However, the webpage does not automatically pop up on my smartphone.
I believe it should work because the code sends a DNS response with the predefined IP address "192.168.4.1" using sendto(sock, response, pos, 0, (struct sockaddr *)&client_addr, addr_len);. The DNS request is caught and answered correctly, but the browser does not open the page automatically.
BTW, the web server and HTTP handlers seem to be functioning properly because when I manually enter "192.168.4.1" in the browser, the HTML page defined in the code is displayed.
I would really appreciate your help with this.

I (23669) dns_redirect: Received DNS request for: connectivitycheckgstaticcom
Response size: 512
Response position: 63
I (23679) dns_redirect: Received DNS request for: wwwgooglecom
Response size: 512
Response position: 48
I (23749) dns_redirect: Received DNS request for: mtalkgooglecom
Response size: 512
Response position: 50

#include <string.h>
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_http_server.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lwip/sockets.h"
#include "lwip/inet.h"
#define EXAMPLE_WIFI_SSID "MyDevice_AP"
#define EXAMPLE_WIFI_PASS "12345678"
static const char *TAG = "dns_redirect";
#define DNS_PORT 53
#define DNS_IP_ADDR "192.168.4.1"
#define DNS_BUF_SIZE 512
static const char *TAG_HTTP = "captive_portal";
typedef struct {
 uint16_t id;
 uint16_t flags;
 uint16_t qdcount;
 uint16_t ancount;
 uint16_t nscount;
 uint16_t arcount;
} dns_header_t;
static void dns_server_task(void *pvParameters)
{
 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if (sock < 0) {
 ESP_LOGE(TAG, "Failed to create socket");
 vTaskDelete(NULL);
 return;
 }
 struct sockaddr_in server_addr = {
 .sin_family = AF_INET,
 .sin_port = htons(DNS_PORT),
 .sin_addr.s_addr = INADDR_ANY,
 };
 if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
 ESP_LOGE(TAG, "Socket bind failed");
 close(sock);
 vTaskDelete(NULL);
 return;
 }
 ESP_LOGI(TAG, "DNS server started on port %d", DNS_PORT);
 uint8_t buf[DNS_BUF_SIZE];
 struct sockaddr_in client_addr;
 socklen_t addr_len = sizeof(client_addr);
 while (1) {
 int len = recvfrom(sock, buf, DNS_BUF_SIZE, 0, (struct sockaddr *)&client_addr, &addr_len);
 if (len < 0) continue;
 ESP_LOGI(TAG, "Received DNS request for: %s", &buf[12]);
 if (len < 12) continue;
 uint8_t response[DNS_BUF_SIZE];
 memcpy(response, buf, len);
 response[2] = 0x81; // QR=1, Opcode=0, AA=0, TC=0, RD=1
 response[3] = 0x80; // RA=1, Z=0, RCODE=0
 // Answer count = 1
 response[7] = 0x01;
 int pos = len;
 response[pos++] = 0xC0;
 response[pos++] = 0x0C;
 // Type A, Class IN
 response[pos++] = 0x00; response[pos++] = 0x01;
 response[pos++] = 0x00; response[pos++] = 0x01;
 // TTL
 response[pos++] = 0x00; response[pos++] = 0x00;
 response[pos++] = 0x00; response[pos++] = 0x3C;
 // Data length = 4
 response[pos++] = 0x00; response[pos++] = 0x04;
 // IP Address
 struct in_addr ip_resp;
 inet_aton(DNS_IP_ADDR, &ip_resp);
 memcpy(&response[pos], &ip_resp.s_addr, 4);
 pos += 4;
 printf("Response size: %zu\n", sizeof(response));
 printf("Response position: %d\n", pos);
 sendto(sock, response, pos, 0, (struct sockaddr *)&client_addr, addr_len);
 //sendto(sock, buff_snd, strlen( buff_snd)+1, 0, ( struct sockaddr*)&client_addr, sizeof( client_addr));
 }
}
// Basic HTML Page
static const char *html_page =
"<!DOCTYPE html><html><head><title>Device Control</title></head>"
"<body><h1>Hello, Captive Portal!</h1><p>Control interface coming soon.</p></body></html>";
// Root Handler
esp_err_t root_get_handler(httpd_req_t *req) {
 ESP_LOGI(TAG_HTTP, "Request URI: %s", req->uri);
 httpd_resp_send(req, html_page, HTTPD_RESP_USE_STRLEN);
 return ESP_OK;
}
// Redirection Handler
esp_err_t redirect_handler(httpd_req_t *req) {
 ESP_LOGI(TAG_HTTP, "Redirecting request");
 httpd_resp_set_status(req, "302 Found");
 httpd_resp_set_hdr(req, "Location", "http://192.168.4.1/");
 httpd_resp_send(req, NULL, 0);
 return ESP_OK;
}
esp_err_t android_handler(httpd_req_t *req) {
 httpd_resp_set_status(req, "204 No Content");
 httpd_resp_send(req, NULL, 0);
 return ESP_OK;
}
// URI Definitions
httpd_uri_t root = {
 .uri = "/",
 .method = HTTP_GET,
 .handler = root_get_handler,
};
httpd_uri_t redirect_android = {
 .uri = "/generate_204",
 .method = HTTP_GET,
 .handler = android_handler,
};
httpd_uri_t redirect_apple = {
 .uri = "/hotspot-detect.html",
 .method = HTTP_GET,
 .handler = redirect_handler,
};
httpd_uri_t redirect_msft = {
 .uri = "/ncsi.txt",
 .method = HTTP_GET,
 .handler = redirect_handler,
};
httpd_uri_t uri_android_2 = {
 .uri = "/redirect",
 .method = HTTP_GET,
 .handler = android_handler,
};
httpd_uri_t uri_android_3 = {
 .uri = "/mobile/status.php",
 .method = HTTP_GET,
 .handler = android_handler,
};
httpd_uri_t catch_all = {
 .uri = "/*",
 .method = HTTP_GET,
 .handler = redirect_handler
};
httpd_handle_t start_webserver(void) {
 httpd_config_t config = HTTPD_DEFAULT_CONFIG();
 config.max_uri_handlers = 20;
 httpd_handle_t server = NULL;
 config.uri_match_fn = httpd_uri_match_wildcard;
 if (httpd_start(&server, &config) == ESP_OK) {
 httpd_register_uri_handler(server, &root);
 httpd_register_uri_handler(server, &redirect_android);
 httpd_register_uri_handler(server, &redirect_apple);
 httpd_register_uri_handler(server, &redirect_msft);
 httpd_register_uri_handler(server, &uri_android_2);
 httpd_register_uri_handler(server, &uri_android_3);
 // httpd_register_uri_handler(server, &catch_all);
 }
 return server;
}
void wifi_init_softap(void) {
 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
 ESP_ERROR_CHECK(esp_wifi_init(&cfg));
 wifi_config_t wifi_config = {
 .ap = {
 .ssid = EXAMPLE_WIFI_SSID,
 .ssid_len = strlen(EXAMPLE_WIFI_SSID),
 .password = EXAMPLE_WIFI_PASS,
 .channel = 1,
 .authmode = WIFI_AUTH_WPA_WPA2_PSK,
 .max_connection = 4,
 .beacon_interval = 100,
 },
 };
 if (strlen(EXAMPLE_WIFI_PASS) == 0) {
 wifi_config.ap.authmode = WIFI_AUTH_OPEN;
 }
 ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
 ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
 ESP_ERROR_CHECK(esp_wifi_start());
 ESP_LOGI(TAG_HTTP, "SoftAP started with SSID: %s", EXAMPLE_WIFI_SSID);
}
void app_main(void) {
 ESP_ERROR_CHECK(nvs_flash_init());
 ESP_ERROR_CHECK(esp_netif_init());
 ESP_ERROR_CHECK(esp_event_loop_create_default());
 esp_netif_create_default_wifi_ap();
 wifi_init_softap();
 start_webserver();
 ESP_LOGI(TAG_HTTP, "Captive portal ready.");
 xTaskCreate(dns_server_task, "dns_server", 4096, NULL, 5, NULL);
}
You must be logged in to vote

Replies: 1 comment 1 reply

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
1 participant

AltStyle によって変換されたページ (->オリジナル) /