mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
dd3d27a03c
Feature note: Sets up a simple DNS server that answers all questions with the ESP softAP's IP as well as a HTTP server which redirects all requests to a captive portal welcoming page. Triggers captive portal detection (log-in screen popup) for iOS, Android and Windows. Includes example test for testing DNS redirect and HTTP redirect. Closes https://github.com/espressif/esp-idf/issues/7099 Closes https://github.com/espressif/esp-idf/issues/4075
164 lines
5.1 KiB
C
164 lines
5.1 KiB
C
/* Captive Portal Example
|
|
|
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
|
|
Unless required by applicable law or agreed to in writing, this
|
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include "esp_event.h"
|
|
#include "esp_log.h"
|
|
#include "esp_system.h"
|
|
|
|
#include "nvs_flash.h"
|
|
#include "esp_wifi.h"
|
|
#include "esp_netif.h"
|
|
#include "lwip/inet.h"
|
|
|
|
#include "esp_http_server.h"
|
|
#include "dns_server.h"
|
|
|
|
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
|
|
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
|
|
#define EXAMPLE_MAX_STA_CONN CONFIG_ESP_MAX_STA_CONN
|
|
|
|
extern const char root_start[] asm("_binary_root_html_start");
|
|
extern const char root_end[] asm("_binary_root_html_end");
|
|
|
|
static const char *TAG = "example";
|
|
|
|
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
|
int32_t event_id, void *event_data)
|
|
{
|
|
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
|
|
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
|
|
ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",
|
|
MAC2STR(event->mac), event->aid);
|
|
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
|
|
wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
|
|
ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d",
|
|
MAC2STR(event->mac), event->aid);
|
|
}
|
|
}
|
|
|
|
static void wifi_init_softap(void)
|
|
{
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
|
|
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
|
|
|
|
wifi_config_t wifi_config = {
|
|
.ap = {
|
|
.ssid = EXAMPLE_ESP_WIFI_SSID,
|
|
.ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID),
|
|
.password = EXAMPLE_ESP_WIFI_PASS,
|
|
.max_connection = EXAMPLE_MAX_STA_CONN,
|
|
.authmode = WIFI_AUTH_WPA_WPA2_PSK
|
|
},
|
|
};
|
|
if (strlen(EXAMPLE_ESP_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(ESP_IF_WIFI_AP, &wifi_config));
|
|
ESP_ERROR_CHECK(esp_wifi_start());
|
|
|
|
esp_netif_ip_info_t ip_info;
|
|
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info);
|
|
|
|
char ip_addr[16];
|
|
inet_ntoa_r(ip_info.ip.addr, ip_addr, 16);
|
|
ESP_LOGI(TAG, "Set up softAP with IP: %s", ip_addr);
|
|
|
|
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:'%s' password:'%s'",
|
|
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
|
|
}
|
|
|
|
// HTTP GET Handler
|
|
static esp_err_t root_get_handler(httpd_req_t *req)
|
|
{
|
|
const uint32_t root_len = root_end - root_start;
|
|
|
|
ESP_LOGI(TAG, "Serve root");
|
|
httpd_resp_set_type(req, "text/html");
|
|
httpd_resp_send(req, root_start, root_len);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static const httpd_uri_t root = {
|
|
.uri = "/",
|
|
.method = HTTP_GET,
|
|
.handler = root_get_handler
|
|
};
|
|
|
|
// HTTP Error (404) Handler - Redirects all requests to the root page
|
|
esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
|
|
{
|
|
// Set status
|
|
httpd_resp_set_status(req, "302 Temporary Redirect");
|
|
// Redirect to the "/" root directory
|
|
httpd_resp_set_hdr(req, "Location", "/");
|
|
// iOS requires content in the response to detect a captive portal, simply redirecting is not sufficient.
|
|
httpd_resp_send(req, "Redirect to the captive portal", HTTPD_RESP_USE_STRLEN);
|
|
|
|
ESP_LOGI(TAG, "Redirecting to root");
|
|
return ESP_OK;
|
|
}
|
|
|
|
static httpd_handle_t start_webserver(void)
|
|
{
|
|
httpd_handle_t server = NULL;
|
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
|
config.max_open_sockets = 13;
|
|
config.lru_purge_enable = true;
|
|
|
|
// Start the httpd server
|
|
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
|
|
if (httpd_start(&server, &config) == ESP_OK) {
|
|
// Set URI handlers
|
|
ESP_LOGI(TAG, "Registering URI handlers");
|
|
httpd_register_uri_handler(server, &root);
|
|
httpd_register_err_handler(server, HTTPD_404_NOT_FOUND, http_404_error_handler);
|
|
}
|
|
return server;
|
|
}
|
|
|
|
void app_main(void)
|
|
{
|
|
/*
|
|
Turn of warnings from HTTP server as redirecting traffic will yield
|
|
lots of invalid requests
|
|
*/
|
|
esp_log_level_set("httpd_uri", ESP_LOG_ERROR);
|
|
esp_log_level_set("httpd_txrx", ESP_LOG_ERROR);
|
|
esp_log_level_set("httpd_parse", ESP_LOG_ERROR);
|
|
|
|
|
|
// Initialize networking stack
|
|
ESP_ERROR_CHECK(esp_netif_init());
|
|
|
|
// Create default event loop needed by the main app
|
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
|
|
|
// Initialize NVS needed by Wi-Fi
|
|
ESP_ERROR_CHECK(nvs_flash_init());
|
|
|
|
// Initialize Wi-Fi including netif with default config
|
|
esp_netif_create_default_wifi_ap();
|
|
|
|
// Initialise ESP32 in SoftAP mode
|
|
wifi_init_softap();
|
|
|
|
// Start the server for the first time
|
|
start_webserver();
|
|
|
|
// Start the DNS server that will redirect all queries to the softAP IP
|
|
start_dns_server();
|
|
}
|