mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feat/netif_dhcps_captive_portal' into 'master'
feat(esp_netif): add support for DHCP Option 114 captive portal URI Closes IDFGH-11885 See merge request espressif/esp-idf!30267
This commit is contained in:
commit
e42f1c53e0
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -594,6 +594,23 @@ esp_err_t esp_netif_napt_disable(esp_netif_t *esp_netif);
|
||||
/**
|
||||
* @brief Set or Get DHCP server option
|
||||
*
|
||||
* @note Please note that not all combinations of identifiers and options are supported.
|
||||
* Get operations:
|
||||
* * IP_ADDRESS_LEASE_TIME
|
||||
* * ESP_NETIF_SUBNET_MASK/REQUESTED_IP_ADDRESS (both options do the same, they reflect dhcps_lease_t)
|
||||
* * ROUTER_SOLICITATION_ADDRESS
|
||||
* * DOMAIN_NAME_SERVER
|
||||
* Set operations:
|
||||
* * IP_ADDRESS_LEASE_TIME
|
||||
* * ESP_NETIF_SUBNET_MASK -- set operation is allowed only if the configured mask corresponds to the settings,
|
||||
* if not, please use esp_netif_set_ip_info() to prevent misconfiguration of DHCPS.
|
||||
* * REQUESTED_IP_ADDRESS -- if the address pool is enabled, a sanity check for start/end addresses is performed
|
||||
* before setting.
|
||||
* * ROUTER_SOLICITATION_ADDRESS
|
||||
* * DOMAIN_NAME_SERVER
|
||||
* * ESP_NETIF_CAPTIVEPORTAL_URI -- set operation copies the pointer to the URI, so it is owned by the application
|
||||
* and needs to be maintained valid throughout the entire DHCP Server lifetime.
|
||||
*
|
||||
* @param[in] esp_netif Handle to esp-netif instance
|
||||
* @param[in] opt_op ESP_NETIF_OP_SET to set an option, ESP_NETIF_OP_GET to get an option.
|
||||
* @param[in] opt_id Option index to get or set, must be one of the supported enum values.
|
||||
@ -613,6 +630,16 @@ esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_
|
||||
/**
|
||||
* @brief Set or Get DHCP client option
|
||||
*
|
||||
* @note Please note that not all combinations of identifiers and options are supported.
|
||||
* Get operations:
|
||||
* * ESP_NETIF_IP_REQUEST_RETRY_TIME
|
||||
* * ESP_NETIF_VENDOR_SPECIFIC_INFO -- only available if ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER=n
|
||||
* Set operations:
|
||||
* * ESP_NETIF_IP_REQUEST_RETRY_TIME
|
||||
* * ESP_NETIF_VENDOR_SPECIFIC_INFO -- only available if ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER=n
|
||||
* lwip layer creates its own copy of the supplied identifier.
|
||||
* (the internal copy could be feed by calling dhcp_free_vendor_class_identifier())
|
||||
*
|
||||
* @param[in] esp_netif Handle to esp-netif instance
|
||||
* @param[in] opt_op ESP_NETIF_OP_SET to set an option, ESP_NETIF_OP_GET to get an option.
|
||||
* @param[in] opt_id Option index to get or set, must be one of the supported enum values.
|
||||
|
@ -89,6 +89,7 @@ typedef enum{
|
||||
ESP_NETIF_IP_REQUEST_RETRY_TIME = 52, /**< Request IP address retry counter */
|
||||
ESP_NETIF_VENDOR_CLASS_IDENTIFIER = 60, /**< Vendor Class Identifier of a DHCP client */
|
||||
ESP_NETIF_VENDOR_SPECIFIC_INFO = 43, /**< Vendor Specific Information of a DHCP server */
|
||||
ESP_NETIF_CAPTIVEPORTAL_URI = 114, /**< Captive Portal Identification */
|
||||
} esp_netif_dhcp_option_id_t;
|
||||
|
||||
/** IP event declarations */
|
||||
|
@ -2398,6 +2398,10 @@ esp_err_t esp_netif_dhcps_option_api(esp_netif_api_msg_t *msg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_NETIF_CAPTIVEPORTAL_URI: {
|
||||
opt_info = (char *)opt->val;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -60,6 +60,7 @@
|
||||
#define DHCP_OPTION_PERFORM_ROUTER_DISCOVERY 31
|
||||
#define DHCP_OPTION_BROADCAST_ADDRESS 28
|
||||
#define DHCP_OPTION_REQ_LIST 55
|
||||
#define DHCP_OPTION_CAPTIVEPORTAL_URI 114
|
||||
#define DHCP_OPTION_END 255
|
||||
|
||||
//#define USE_CLASS_B_NET 1
|
||||
@ -135,6 +136,7 @@ struct dhcps_t {
|
||||
dhcps_time_t dhcps_lease_time;
|
||||
dhcps_offer_t dhcps_offer;
|
||||
dhcps_offer_t dhcps_dns;
|
||||
char *dhcps_captiveportal_uri;
|
||||
dhcps_cb_t dhcps_cb;
|
||||
void* dhcps_cb_arg;
|
||||
struct udp_pcb *dhcps_pcb;
|
||||
@ -164,6 +166,7 @@ dhcps_t *dhcps_new(void)
|
||||
dhcps->dhcps_lease_time = DHCPS_LEASE_TIME_DEF;
|
||||
dhcps->dhcps_offer = 0xFF;
|
||||
dhcps->dhcps_dns = 0x00;
|
||||
dhcps->dhcps_captiveportal_uri = NULL;
|
||||
dhcps->dhcps_pcb = NULL;
|
||||
dhcps->state = DHCPS_HANDLE_CREATED;
|
||||
return dhcps;
|
||||
@ -238,6 +241,10 @@ void *dhcps_option_info(dhcps_t *dhcps, u8_t op_id, u32_t opt_len)
|
||||
option_arg = &dhcps->dhcps_mask;
|
||||
}
|
||||
|
||||
break;
|
||||
case CAPTIVEPORTAL_URI:
|
||||
option_arg = &dhcps->dhcps_captiveportal_uri;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -292,6 +299,11 @@ err_t dhcps_set_option_info(dhcps_t *dhcps, u8_t op_id, void *opt_info, u32_t op
|
||||
dhcps->dhcps_mask = *(ip4_addr_t *)opt_info;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CAPTIVEPORTAL_URI:
|
||||
dhcps->dhcps_captiveportal_uri = (char *)opt_info;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -400,6 +412,7 @@ static u8_t *add_msg_type(u8_t *optptr, u8_t type)
|
||||
*******************************************************************************/
|
||||
static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr)
|
||||
{
|
||||
u32_t i;
|
||||
ip4_addr_t ipadd;
|
||||
|
||||
ipadd.addr = *((u32_t *) &dhcps->server_address);
|
||||
@ -468,6 +481,17 @@ static u8_t *add_offer_options(dhcps_t *dhcps, u8_t *optptr)
|
||||
*optptr++ = 0x05;
|
||||
*optptr++ = 0xdc;
|
||||
|
||||
if (dhcps->dhcps_captiveportal_uri) {
|
||||
size_t length = strlen(dhcps->dhcps_captiveportal_uri);
|
||||
|
||||
*optptr++ = DHCP_OPTION_CAPTIVEPORTAL_URI;
|
||||
*optptr++ = length;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
*optptr++ = dhcps->dhcps_captiveportal_uri[i];
|
||||
}
|
||||
}
|
||||
|
||||
*optptr++ = DHCP_OPTION_PERFORM_ROUTER_DISCOVERY;
|
||||
*optptr++ = 1;
|
||||
*optptr++ = 0x00;
|
||||
@ -1006,7 +1030,7 @@ static s16_t parse_msg(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
|
||||
dhcps->client_address.addr = dhcps->client_address_plus.addr;
|
||||
}
|
||||
|
||||
if (flag == false) { // search the fisrt unused ip
|
||||
if (flag == false) { // search the first unused ip
|
||||
if (first_address.addr < pdhcps_pool->ip.addr) {
|
||||
flag = true;
|
||||
} else {
|
||||
|
@ -1,16 +1,8 @@
|
||||
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -129,6 +121,7 @@ typedef enum
|
||||
CLIENT_LAST_TRANSACTION_TIME = 91,
|
||||
ASSOCIATED_IP = 92,
|
||||
USER_AUTHENTICATION_PROTOCOL = 98,
|
||||
CAPTIVEPORTAL_URI = 114,
|
||||
AUTO_CONFIGURE = 116,
|
||||
NAME_SERVICE_SEARCH = 117,
|
||||
SUBNET_SELECTION = 118,
|
||||
|
@ -5,7 +5,11 @@
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example demonstrates a simple captive portal that will redirect all DNS IP questions to point to the softAP and redirect all HTTP requests to the captive portal root page. Triggers captive portal (sign in) pop up on Android, iOS and Windows. Note that the example will not redirect HTTPS requests.
|
||||
This example demonstrates two methods of a captive portal, used to direct users to an authentication page or other necessary starting point before browsing.
|
||||
|
||||
One approach response to all DNS queries with the address of the softAP, and redirects all HTTP requests to the captive portal root page. This "funnelling" of DNS and traffic triggers the captive portal (sign in) to appear on Android, iOS, and Windows. Note that the example will not redirect HTTPS requests.
|
||||
|
||||
The other approach is a more modern method which includes a field in the DHCP offer (AKA DHCP Option 114), provided when the client is assigned an IP address, which specifies to the client where the captive portal is. This is advantageous because it doesn't require the overhead of DNS redirects and can work more reliably around HTTPS, HTST, and other security systems, as well as being more standards compliant. This feature is toggleable in the `Example Configuration`, but does not conflict with the DNS methodology -- these two methods work towards the same goal and can complement each other.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
@ -27,6 +31,7 @@ In the `Example Configuration` menu:
|
||||
* Set `SoftAP SSID`
|
||||
* Set `SoftAP Password`
|
||||
* Set `Maximal STA connections`
|
||||
* Set `DHCP Captive portal` to enable or disable DHCP Option 114
|
||||
|
||||
### Build and Flash
|
||||
|
||||
@ -42,6 +47,9 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
|
||||
|
||||
## Example Output
|
||||
|
||||
|
||||
### ESP32 Output for DNS Redirect
|
||||
|
||||
```
|
||||
I (733) example: Set up softAP with IP: 192.168.4.1
|
||||
I (743) example: wifi_init_softap finished. SSID:'esp32_ssid' password:'esp32_pwd'
|
||||
@ -95,3 +103,27 @@ I (23473) example: Serve root
|
||||
I (23503) example_dns_redirect_server: Received 48 bytes from 192.168.4.2 | DNS reply with len: 64
|
||||
I (23513) example_dns_redirect_server: Waiting for data
|
||||
```
|
||||
|
||||
### `tcpdump` Output for DHCP Option 114
|
||||
|
||||
Note `URL (114)` with the AP address.
|
||||
|
||||
```
|
||||
19:14:20.522698 c8:yy:yy:yy:yy:yy > 74:xx:xx:xx:xx:xx, ethertype IPv4 (0x0800), length 590: (tos 0x0, ttl 64, id 243, offset 0, flags [none], proto UDP (17), length 576)
|
||||
192.168.4.1.67 > 192.168.4.2.68: [udp sum ok] BOOTP/DHCP, Reply, length 548, xid 0x76a26648, Flags [none] (0x0000)
|
||||
Your-IP 192.168.4.2
|
||||
Client-Ethernet-Address 74:xx:xx:xx:xx:xx
|
||||
Vendor-rfc1048 Extensions
|
||||
Magic Cookie 0x63825363
|
||||
DHCP-Message (53), length 1: Offer
|
||||
Subnet-Mask (1), length 4: 255.255.255.0
|
||||
Lease-Time (51), length 4: 7200
|
||||
Server-ID (54), length 4: 192.168.4.1
|
||||
Default-Gateway (3), length 4: 192.168.4.1
|
||||
Domain-Name-Server (6), length 4: 192.168.4.1
|
||||
BR (28), length 4: 192.168.4.255
|
||||
MTU (26), length 2: 1500
|
||||
URL (114), length 18: "http://192.168.4.1"
|
||||
Router-Discovery (31), length 1: N
|
||||
Vendor-Option (43), length 6: 1.4.0.0.0.2
|
||||
```
|
||||
|
@ -17,4 +17,10 @@ menu "Example Configuration"
|
||||
default 4
|
||||
help
|
||||
Max number of the STA connects to AP.
|
||||
|
||||
config ESP_ENABLE_DHCP_CAPTIVEPORTAL
|
||||
bool "DHCP Captive portal"
|
||||
default y
|
||||
help
|
||||
Enables more modern DHCP-based Option 114 to provide clients with the captive portal URI
|
||||
endmenu
|
||||
|
@ -79,6 +79,32 @@ static void wifi_init_softap(void)
|
||||
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL
|
||||
static void dhcp_set_captiveportal_url(void) {
|
||||
// get the IP of the access point to redirect to
|
||||
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);
|
||||
|
||||
// turn the IP into a URI
|
||||
char* captiveportal_uri = (char*) malloc(32 * sizeof(char));
|
||||
assert(captiveportal_uri && "Failed to allocate captiveportal_uri");
|
||||
strcpy(captiveportal_uri, "http://");
|
||||
strcat(captiveportal_uri, ip_addr);
|
||||
|
||||
// get a handle to configure DHCP with
|
||||
esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_AP_DEF");
|
||||
|
||||
// set the DHCP option 114
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_stop(netif));
|
||||
ESP_ERROR_CHECK(esp_netif_dhcps_option(netif, ESP_NETIF_OP_SET, ESP_NETIF_CAPTIVEPORTAL_URI, captiveportal_uri, strlen(captiveportal_uri)));
|
||||
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_netif_dhcps_start(netif));
|
||||
}
|
||||
#endif // CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL
|
||||
|
||||
// HTTP GET Handler
|
||||
static esp_err_t root_get_handler(httpd_req_t *req)
|
||||
{
|
||||
@ -155,6 +181,11 @@ void app_main(void)
|
||||
// Initialise ESP32 in SoftAP mode
|
||||
wifi_init_softap();
|
||||
|
||||
// Configure DNS-based captive portal, if configured
|
||||
#ifdef CONFIG_ESP_ENABLE_DHCP_CAPTIVEPORTAL
|
||||
dhcp_set_captiveportal_url();
|
||||
#endif
|
||||
|
||||
// Start the server for the first time
|
||||
start_webserver();
|
||||
|
||||
|
@ -498,7 +498,6 @@ components/hal/spi_slave_hal_iram.c
|
||||
components/idf_test/include/idf_performance.h
|
||||
components/log/host_test/log_test/main/log_test.cpp
|
||||
components/lwip/apps/ping/ping.c
|
||||
components/lwip/include/apps/dhcpserver/dhcpserver_options.h
|
||||
components/lwip/include/apps/esp_ping.h
|
||||
components/lwip/include/apps/ping/ping.h
|
||||
components/mbedtls/esp_crt_bundle/test_gen_crt_bundle/test_gen_crt_bundle.py
|
||||
|
Loading…
Reference in New Issue
Block a user