pull/13250/merge
Sly Gryphon 2024-05-02 13:33:54 +02:00 zatwierdzone przez GitHub
commit 11605a2a5f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
11 zmienionych plików z 373 dodań i 91 usunięć

Wyświetl plik

@ -230,7 +230,11 @@ netif_related_data_t * esp_netif_new_ppp(esp_netif_t *esp_netif, const esp_netif
#if PPP_NOTIFY_PHASE
ppp_set_notify_phase_callback(ppp_obj->ppp, on_ppp_notify_phase);
#endif
#if PPP_IPV4_SUPPORT
#if LWIP_DNS
ppp_set_usepeerdns(ppp_obj->ppp, 1);
#endif /* LWIP_DNS */
#endif /* PPP_IPV4_SUPPORT */
return (netif_related_data_t *)ppp_obj;
}

Wyświetl plik

@ -384,16 +384,29 @@ menu "Example Connection Configuration"
select LWIP_IPV6
select LWIP_PPP_ENABLE_IPV6 if EXAMPLE_CONNECT_PPP
help
By default, examples will wait until IPv4 and IPv6 local link addresses are obtained.
Disable this option if the network does not support IPv6.
Choose the preferred IPv6 address type if the connection code should wait until other than
the local link address gets assigned.
Consider enabling IPv6 stateless address autoconfiguration (SLAAC) in the LWIP component.
By default, examples will wait until any IP preferred (usually global) address is obtained,
allowing flexible deployment to IPv4-only, IPv6-only, or dual-stack networks.
Enables SLAAC (State-Less Address Auto-Configuration) to get IPv6
address prefixes from Router Advertisement (RA) messages, and both
RA RDNSS (Recursive DNS Server) and DHCPv6 Stateless mode to get IPv6 DNS
server details from whichever is available on the network.
if EXAMPLE_CONNECT_IPV6
config EXAMPLE_CONNECT_PREF_ANY
bool "Obtain any preferred address"
default y
help
By default, examples will wait until any IP preferred address is obtained, either an IPv4 or
IPv6 global scope addresses.
This enables flexible deployment into any network type.
Disable this option to wait for both address types, although this will break single-stack networks.
Choose the preferred IPv6 address type if the connection code should wait until other than
an IPv6 global address.
choice EXAMPLE_CONNECT_PREFERRED_IPV6
prompt "Preferred IPv6 Type"
default EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK
default EXAMPLE_CONNECT_IPV6_PREF_GLOBAL
help
Select which kind of IPv6 address the connect logic waits for.
@ -421,5 +434,4 @@ menu "Example Connection Configuration"
endif
endmenu

Wyświetl plik

@ -18,6 +18,7 @@
#include "freertos/event_groups.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
static const char *TAG = "example_common";
@ -136,3 +137,46 @@ esp_err_t example_disconnect(void)
#endif
return ESP_OK;
}
esp_err_t example_getaddrinfo(const char *nodename, const char *servname, struct addrinfo **res)
{
#if CONFIG_EXAMPLE_CONNECT_IPV6
// Iterate over active interfaces, and find if we have any global scope IPv6
bool has_global_scope_ipv6 = false;
esp_netif_t *netif = NULL;
while ((netif = esp_netif_next_unsafe(netif)) != NULL) {
esp_ip6_addr_t ip6[MAX_IP6_ADDRS_PER_NETIF];
int ip6_addrs = esp_netif_get_all_ip6(netif, ip6);
for (int j = 0; j < ip6_addrs; ++j) {
// Both global and unique local addresses have global scope.
// ULA assumes either private DNS or NAT66 (same assumpation as IPv4 private address ranges).
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j]));
if (ipv6_type == ESP_IP6_ADDR_IS_GLOBAL || ipv6_type == ESP_IP6_ADDR_IS_UNIQUE_LOCAL) {
has_global_scope_ipv6 = true;
break;
}
}
if (has_global_scope_ipv6) break;
}
if (has_global_scope_ipv6) {
const struct addrinfo hints6 = {
.ai_family = AF_INET6,
.ai_socktype = SOCK_STREAM,
};
ESP_LOGI(TAG, "IPv6 DNS lookup");
int err6 = getaddrinfo(nodename, servname, &hints6, res);
if(err6 == 0) return err6;
ESP_LOGI(TAG, "- IPv6 DNS lookup failed, trying IPv4 lookup");
}
#endif
const struct addrinfo hints4 = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
ESP_LOGI(TAG, "IPv4 DNS lookup");
int err4 = getaddrinfo(nodename, servname, &hints4, res);
return err4;
}

Wyświetl plik

@ -22,8 +22,11 @@
static const char *TAG = "ethernet_connect";
static SemaphoreHandle_t s_semph_get_ip_addrs = NULL;
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
static SemaphoreHandle_t s_semph_get_ip6_addrs = NULL;
#endif
#endif
static esp_netif_t *eth_start(void);
static void eth_stop(void);
@ -55,7 +58,11 @@ static void eth_on_got_ipv6(void *arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "Got IPv6 event: Interface \"%s\" address: " IPV6STR ", type: %s", esp_netif_get_desc(event->esp_netif),
IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) {
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
xSemaphoreGive(s_semph_get_ip_addrs);
#else
xSemaphoreGive(s_semph_get_ip6_addrs);
#endif
}
}
@ -206,14 +213,23 @@ void example_ethernet_shutdown(void)
vSemaphoreDelete(s_semph_get_ip_addrs);
s_semph_get_ip_addrs = NULL;
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
vSemaphoreDelete(s_semph_get_ip6_addrs);
s_semph_get_ip6_addrs = NULL;
#endif
#endif
eth_stop();
}
esp_err_t example_ethernet_connect(void)
{
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
if (s_semph_get_ip_addrs == NULL) {
return ESP_ERR_NO_MEM;
}
#else
#if CONFIG_EXAMPLE_CONNECT_IPV4
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
if (s_semph_get_ip_addrs == NULL) {
@ -226,14 +242,19 @@ esp_err_t example_ethernet_connect(void)
vSemaphoreDelete(s_semph_get_ip_addrs);
return ESP_ERR_NO_MEM;
}
#endif
#endif
eth_start();
ESP_LOGI(TAG, "Waiting for IP(s).");
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#else
#if CONFIG_EXAMPLE_CONNECT_IPV4
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#endif
#if CONFIG_EXAMPLE_CONNECT_IPV6
xSemaphoreTake(s_semph_get_ip6_addrs, portMAX_DELAY);
#endif
#endif
return ESP_OK;
}

Wyświetl plik

@ -17,6 +17,7 @@
#include "esp_eth.h"
#endif
#endif // !CONFIG_IDF_TARGET_LINUX
#include "lwip/netdb.h"
#ifdef __cplusplus
extern "C" {
@ -77,6 +78,14 @@ esp_err_t example_disconnect(void);
*/
esp_err_t example_configure_stdin_stdout(void);
/**
* @brief Resolve best destination address based on available source addresses
*
* If a global IPv6 address is available, this tries to get an IPv6 address,
* otherwise it falls back to IPv4.
*/
esp_err_t example_getaddrinfo(const char *nodename, const char *servname, struct addrinfo **res);
/**
* @brief Returns esp-netif pointer created by example_connect() described by
* the supplied desc field

Wyświetl plik

@ -230,6 +230,7 @@ esp_err_t example_ppp_connect(void)
#endif // CONNECT_PPP_DEVICE
ESP_LOGI(TAG, "Waiting for IP address");
// Note: CONFIG_EXAMPLE_CONNECT_PREF_ANY is ignored; PPP always waits for ANY (does not wait for all)
EventBits_t bits = xEventGroupWaitBits(s_event_group, CONNECT_BITS, pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & CONNECTION_FAILED) {
ESP_LOGE(TAG, "Connection failed!");

Wyświetl plik

@ -23,8 +23,11 @@ static const char *TAG = "example_connect";
static esp_netif_t *s_example_sta_netif = NULL;
static SemaphoreHandle_t s_semph_get_ip_addrs = NULL;
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
static SemaphoreHandle_t s_semph_get_ip6_addrs = NULL;
#endif
#endif
#if CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST
#define EXAMPLE_WIFI_SCAN_METHOD WIFI_FAST_SCAN
@ -71,9 +74,12 @@ static void example_handler_on_wifi_disconnect(void *arg, esp_event_base_t event
xSemaphoreGive(s_semph_get_ip_addrs);
}
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
if (s_semph_get_ip6_addrs) {
xSemaphoreGive(s_semph_get_ip6_addrs);
}
#endif
#endif
return;
}
@ -102,6 +108,7 @@ static void example_handler_on_sta_got_ip(void *arg, esp_event_base_t event_base
return;
}
ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));
if (s_semph_get_ip_addrs) {
xSemaphoreGive(s_semph_get_ip_addrs);
} else {
@ -122,10 +129,15 @@ static void example_handler_on_sta_got_ipv6(void *arg, esp_event_base_t event_ba
IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) {
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
if (s_semph_get_ip_addrs) {
xSemaphoreGive(s_semph_get_ip_addrs);
#else
if (s_semph_get_ip6_addrs) {
xSemaphoreGive(s_semph_get_ip6_addrs);
#endif
} else {
ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
}
}
}
@ -172,11 +184,14 @@ esp_err_t example_wifi_sta_do_connect(wifi_config_t wifi_config, bool wait)
return ESP_ERR_NO_MEM;
}
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
s_semph_get_ip6_addrs = xSemaphoreCreateBinary();
if (s_semph_get_ip6_addrs == NULL) {
vSemaphoreDelete(s_semph_get_ip_addrs);
return ESP_ERR_NO_MEM;
}
#endif
#endif
}
s_retry_num = 0;
@ -196,11 +211,15 @@ esp_err_t example_wifi_sta_do_connect(wifi_config_t wifi_config, bool wait)
}
if (wait) {
ESP_LOGI(TAG, "Waiting for IP(s)");
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#else
#if CONFIG_EXAMPLE_CONNECT_IPV4
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#endif
#if CONFIG_EXAMPLE_CONNECT_IPV6
xSemaphoreTake(s_semph_get_ip6_addrs, portMAX_DELAY);
#endif
#endif
if (s_retry_num > CONFIG_EXAMPLE_WIFI_CONN_MAX_RETRY) {
return ESP_FAIL;
@ -221,9 +240,12 @@ esp_err_t example_wifi_sta_do_disconnect(void)
vSemaphoreDelete(s_semph_get_ip_addrs);
}
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
if (s_semph_get_ip6_addrs) {
vSemaphoreDelete(s_semph_get_ip6_addrs);
}
#endif
#endif
return esp_wifi_disconnect();
}

Wyświetl plik

@ -20,6 +20,26 @@ When connecting using Wi-Fi, enter SSID and password of your Wi-Fi access point
When connecting using Ethernet, set up PHY type and configuration in the provided fields. If using Ethernet for the first time, it is recommended to start with the [Ethernet example readme](../ethernet/basic/README.md), which contains instructions for connecting and configuring the PHY. Once Ethernet example obtains IP address successfully, proceed to the protocols example and set the same configuration options.
### Disabling IPv6
### IP protocol handling
By default, `example_connect()` function waits until Wi-Fi or Ethernet connection is established, and IPv4 address and IPv6 link-local address are obtained. In network environments where IPv6 link-local address cannot be obtained, disable "Obtain IPv6 link-local address" option found in "Example Connection Configuration" menu.
By default the examples support any network configuration: IPv4 only, IPv6 only, and dual stack.
The `example_connect()` function waits until Wi-Fi or Ethernet connection is established, and either an IPv4 address or an IPv6 global scope address is obtained. By waiting for the first (of either), this allows it to work in any network.
The behaviour is based on the available network:
| Network | Addresses | DNS | IPv4 destination | IPv6 destination | Dual-stack destination
| -- | -- | -- | -- | -- | --
| IPv4 only | IPv4, IPv6 link-local | IPv4 | Yes | Not possible | Uses IPv4
| IPv6 only | IPv6 global, IPv6 link-local | IPv6 | NAT64 if available | Yes | Uses IPv6
| Dual-stack | IPv6 global (*1), IPv4, IPv6 link-local | IPv6, then IPv4 | Yes | Yes | Uses IPv6
(*1) There may be a delay waiting for an IPv6 global address, in which case IPv4 may be used for the first test request (with IPv4 DNS)
#### Disabling protocol versions
Where the target network is unknown, such as this sample, using an adaptable configuration that supports all networks (whatever is available) is best.
However in some cases you may want to restrict network configuration.
For example the Matter standard requires IPv6, so you can reduce application size and simplify development and testing complexity by completely disabling IPv4 (`LWIP_IPV4`), as it is never needed for a Matter device.

Wyświetl plik

@ -22,6 +22,10 @@ idf.py menuconfig
```
Open the project configuration menu (`idf.py menuconfig`) to configure Wi-Fi or Ethernet. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
The default configuration (`sdkconfig.defaults`) fully enables both IPv6 and IPv4: it enables SLAAC (State-Less Address Auto-Configuration) to get IPv6 address prefixes from Router Advertisement (RA) messages, and both IPv6 RA RDNSS (Recursive DNS Server) and DHCPv6 Stateless mode to get IPv6 DNS server details from whichever is available on the network.
The application is written to work on whatever network is available: dual-stack, IPv4-only, and IPv6-only networks.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
@ -38,77 +42,207 @@ See the Getting Started Guide for full steps to configure and use ESP-IDF to bui
## Example Output
### Dual-stack network connecting to dual-stack server
Default configuration on a dual-stack network (Astral) connecting to a dual-stack server (`v4v6.ipv6-test.com`), starts the connection test as soon as any address, e.g. an IPv4 address (`192.168.1.146`, private range) is received. So the first connection does an IPv4 DNS lookup (`51.75.78.103`) and uses that address.
Note that the server responds with the NAT44 public address it sees for the client (`220.240.255.134`).
When an IPv6 prefix (`2407:8800:bc61:1340::`) is then receive via RA (router advertisement) a global IPv6 address is configured, so the second connection test does a DNS lookup for IPv6 first, and uses that address (`2001:41D0:701:1100::29C8`).
The server then responds with the IPv6 address seen: `2407:8800:bc61:1340:0a3a:f2ff:fe65:db28`
```
I (10557) example_connect: - IPv4 address: 192.168.194.219
I (10557) example_connect: - IPv6 address: fe80:0000:0000:0000:266f:28ff:fe80:2c74, type: ESP_IP6_ADDR_IS_LINK_LOCAL
W (10577) wifi:<ba-add>idx:0 (ifx:0, ee:6d:19:60:f6:0e), tid:0, ssn:3, winSize:64
I (10587) example: DNS lookup succeeded. IP=93.184.216.34
I (10587) example: ... allocated socket
I (10917) example: ... connected
I (10917) example: ... socket send success
I (10927) example: ... set socket receiving timeout success
HTTP/1.0 200 OK
Age: 317271
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Mon, 06 Sep 2021 08:09:49 GMT
Etag: "3147526947+ident"
Expires: Mon, 13 Sep 2021 08:09:49 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (nyb/1D2B)
I (764) example_connect: Connecting to Astral...
I (764) example_connect: Waiting for IP(s)
I (3174) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
I (3424) wifi:state: init -> auth (b0)
I (3434) wifi:state: auth -> assoc (0)
I (3444) wifi:state: assoc -> run (10)
I (3464) wifi:connected with Astral, aid = 8, channel 11, BW20, bssid = f4:92:bf:a8:db:d1
I (3464) wifi:security: WPA2-PSK, phy: bgn, rssi: -70
I (3464) wifi:pm start, type: 1
I (3464) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3494) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (3514) wifi:<ba-add>idx:0 (ifx:0, f4:92:bf:a8:db:d1), tid:6, ssn:1, winSize:64
I (4474) esp_netif_handlers: example_netif_sta ip: 192.168.1.146, mask: 255.255.255.0, gw: 192.168.1.1
I (4474) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.1.146
I (4484) example_common: Connected to example_netif_sta
I (4484) example_common: - IPv4 address: 192.168.1.146,
I (4494) example_common: - IPv6 address: fe80:0000:0000:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (4504) example: DNS lookup v4v6.ipv6-test.com (port 80)
I (4514) example_common: IPv4 DNS lookup
I (4514) main_task: Returned from app_main()
I (4544) wifi:<ba-add>idx:1 (ifx:0, f4:92:bf:a8:db:d1), tid:0, ssn:1, winSize:64
I (4554) example: DNS lookup succeeded. (2) IP=51.75.78.103
I (4554) example: ... allocated socket
I (4564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5044) example: ... connected
I (5044) example: ... socket send success
I (5054) example: ... set socket receiving timeout success
HTTP/1.1 200 OK
Date: Sat, 24 Feb 2024 05:33:08 GMT
Server: Apache/2.4.25 (Debian)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256
Connection: close
Content-Type: text/html; charset=UTF-8
<!doctype html>
<html>
<head>
<title>Example Domain</title>
220.240.255.134
I (5464) example: ... done reading from socket. Last read return=0 errno=128.
I (5474) example: 10...
I (6474) example: 9...
I (7474) example: 8...
I (7564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: 2407:8800:bc61:1340:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_GLOBAL
I (7564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fd7c:e25e:67e8:0040:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_UNIQUE_LOCAL
I (8474) example: 7...
I (9474) example: 6...
I (10474) example: 5...
I (11474) example: 4...
I (12474) example: 3...
I (13474) example: 2...
I (14474) example: 1...
I (15474) example: 0...
I (16474) example: Starting again!
I (16474) example: DNS lookup v4v6.ipv6-test.com (port 80)
I (16474) example_common: IPv6 DNS lookup
I (16514) example: DNS lookup succeeded. (10) IP=2001:41D0:701:1100::29C8
I (16514) example: ... allocated socket
I (16924) example: ... connected
I (16924) example: ... socket send success
I (16924) example: ... set socket receiving timeout success
HTTP/1.1 200 OK
Date: Sat, 24 Feb 2024 05:33:19 GMT
Server: Apache/2.4.25 (Debian)
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
I (11467) example: ... done reading from socket. Last read return=0 errno=128.
I (11477) example: 10...
I (12477) example: 9...
I (13477) example: 8...
2407:8800:bc61:1340:a3a:f2ff:fe65:db28
I (17334) example: ... done reading from socket. Last read return=0 errno=128.
I (17344) example: 10...
```
On a dual-stack network when connecting to an IPv4-only server, then (with an IPv6 global address) an IPv6 lookup is still attempted first. If DNS64/NAT64 is not available, then the IPv6 DNS lookup will fail, and the code will fall back to an IPv4 DNS lookup.
```
I (17034) example: DNS lookup v4.ipv6-test.com (port 80)
I (17034) example_common: IPv6 DNS lookup
I (17074) example_common: - IPv6 DNS lookup failed, trying IPv4 lookup
I (17074) example_common: IPv4 DNS lookup
I (17074) example: DNS lookup succeeded. (2) IP=51.75.78.103
I (17084) example: ... allocated socket
I (17694) example: ... connected
I (17694) example: ... socket send success
I (17694) example: ... set socket receiving timeout success
HTTP/1.1 200 OK
Date: Sat, 24 Feb 2024 06:10:00 GMT
Server: Apache/2.4.25 (Debian)
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
220.240.255.134
I (18314) example: ... done reading from socket. Last read return=0 errno=128.
I (18314) example: 10...
```
### IPv4-only network connecting to dual-stack server
This shows an IPv4 only network (Shadow) connecting to a dual-stack server (`v4v6.ipv6-test.com`).
The connection attempt starts as soon as the IPv4 address is received, and as the device has no global IPv6 address, the DNS lookup and connection will only be IPv4 (`51.75.78.103`).
Note that, although the device has an IPv6 link-local address, it is ignored because it cannot be used to connect to a public address returned from DNS.
Although we only get a private IPv4 address, the assumption is that IPv4 DNS lookups are still usable, either for private DNS or via NAT44, e.g. we see the server responds with the NAT44 address `220.240.255.134`. (A similar assumption is made for IPv6 Unique Local Addresses)
```
I (764) example_connect: Connecting to Shadow...
I (764) example_connect: Waiting for IP(s)
I (3174) wifi:new:<1,0>, old:<1,0>, ap:<255,255>, sta:<1,0>, prof:1
I (3424) wifi:state: init -> auth (b0)
I (3524) wifi:state: auth -> assoc (0)
I (3554) wifi:state: assoc -> run (10)
I (3584) wifi:connected with Shadow, aid = 1, channel 1, BW20, bssid = 06:25:9c:13:92:ab
I (3584) wifi:security: WPA2-PSK, phy: bgn, rssi: -56
I (3584) wifi:pm start, type: 1
I (3594) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3634) wifi:dp: 2, bi: 102400, li: 4, scale listen interval from 307200 us to 409600 us
I (3634) wifi:AP's beacon interval = 102400 us, DTIM period = 2
I (5104) esp_netif_handlers: example_netif_sta ip: 192.168.5.146, mask: 255.255.255.0, gw: 192.168.5.1
I (5104) example_connect: Got IPv4 event: Interface "example_netif_sta" address: 192.168.5.146
I (5114) example_common: Connected to example_netif_sta
I (5114) example_common: - IPv4 address: 192.168.5.146,
I (5124) example_common: - IPv6 address: fe80:0000:0000:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5134) example: DNS lookup v4v6.ipv6-test.com (port 80)
I (5144) example_common: IPv4 DNS lookup
I (5144) main_task: Returned from app_main()
I (5564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5584) example: DNS lookup succeeded. (2) IP=51.75.78.103
I (5584) example: ... allocated socket
I (5914) example: ... connected
I (5914) example: ... socket send success
I (5914) example: ... set socket receiving timeout success
HTTP/1.1 200 OK
Date: Sat, 24 Feb 2024 05:54:34 GMT
Server: Apache/2.4.25 (Debian)
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
220.240.255.134
I (6414) example: ... done reading from socket. Last read return=0 errno=128.
I (6424) example: 10...
```
### IPv6-only network, with NAT64, connecting to an IPv4 server
This connects to an IPv6-only network (Wildspace), and waits to receive an IPv6 global scope address before starting the connection test. The default configurations waits for the first public usable address, either IPv4 or IPv6, so works in any network.
The DNS lookup for an IPv4-only server (`v4.ipv6-test.com`) returns a DNS64 address (`64:FF9B::334B:4E67`), which is then used for the HTTP connection.
Note that the server responds with the NAT64 public IPv4 address it sees for the client (`220.240.255.134`).
```
I (764) example_connect: Connecting to Wildspace...
I (764) example_connect: Waiting for IP(s)
I (3174) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
I (3424) wifi:state: init -> auth (b0)
I (3444) wifi:state: auth -> assoc (0)
I (3464) wifi:state: assoc -> run (10)
I (3504) wifi:connected with Wildspace, aid = 1, channel 11, BW20, bssid = ea:63:da:bd:5a:09
I (3514) wifi:security: WPA2-PSK, phy: bgn, rssi: -80
I (3514) wifi:pm start, type: 1
I (3514) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us
I (3634) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fe80:0000:0000:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5584) wifi:<ba-add>idx:0 (ifx:0, ea:63:da:bd:5a:09), tid:0, ssn:0, winSize:64
I (7564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: 2407:8800:bc61:1300:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_GLOBAL
I (7564) example_connect: Got IPv6 event: Interface "example_netif_sta" address: fd7c:e25e:67e8:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_UNIQUE_LOCAL
I (7574) example_common: Connected to example_netif_sta
I (7584) example_common: - IPv4 address: 0.0.0.0,
I (7594) example_common: - IPv6 address: fe80:0000:0000:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (7604) example_common: - IPv6 address: 2407:8800:bc61:1300:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_GLOBAL
I (7614) example_common: - IPv6 address: fd7c:e25e:67e8:0000:0a3a:f2ff:fe65:db28, type: ESP_IP6_ADDR_IS_UNIQUE_LOCAL
I (7624) example: DNS lookup v4.ipv6-test.com (port 80)
I (7624) example_common: IPv6 DNS lookup
I (7634) main_task: Returned from app_main()
I (8584) example: DNS lookup succeeded. (10) IP=64:FF9B::334B:4E67
I (8584) example: ... allocated socket
I (9064) example: ... connected
I (9064) example: ... socket send success
I (9064) example: ... set socket receiving timeout success
HTTP/1.1 200 OK
Date: Sat, 24 Feb 2024 05:45:33 GMT
Server: Apache/2.4.25 (Debian)
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
220.240.255.134
I (9474) example: ... done reading from socket. Last read return=0 errno=128.
I (9484) example: 10...
```

Wyświetl plik

@ -24,9 +24,14 @@
#include "sdkconfig.h"
/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "example.com"
// Default example will work on all networks: IPv4 only, IPv6 only, and dual stack
#define WEB_SERVER "v4v6.ipv6-test.com"
// Alternative tests for IPv4 only and IPv6 only destinations
//#define WEB_SERVER "v4.ipv6-test.com"
//#define WEB_SERVER "v6.ipv6-test.com"
#define WEB_PORT "80"
#define WEB_PATH "/"
// This will reflect the IP address the server sees, e.g. NAT64 will return the public IPv4
#define WEB_PATH "/api/myip.php"
static const char *TAG = "example";
@ -37,29 +42,35 @@ static const char *REQUEST = "GET " WEB_PATH " HTTP/1.0\r\n"
static void http_get_task(void *pvParameters)
{
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
struct in_addr *addr;
void *addr;
int s, r;
char recv_buf[64];
while(1) {
int err = getaddrinfo(WEB_SERVER, WEB_PORT, &hints, &res);
ESP_LOGI(TAG, "DNS lookup %s (port %s)", WEB_SERVER, WEB_PORT);
int err = example_getaddrinfo(WEB_SERVER, WEB_PORT, &res);
if(err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
/* Code to print the resolved IP. */
#if LWIP_IPV4 && LWIP_IPV6
if (res->ai_family == AF_INET6) {
addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
} else {
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
}
#elif LWIP_IPV6
addr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
#elif LWIP_IPV4
addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*addr));
#endif
char ipStr[128];
inet_ntop(res->ai_family, addr, ipStr, sizeof(ipStr));
ESP_LOGI(TAG, "DNS lookup succeeded. (%i) IP=%s", res->ai_family, ipStr);
s = socket(res->ai_family, res->ai_socktype, 0);
if(s < 0) {
@ -109,6 +120,7 @@ static void http_get_task(void *pvParameters)
putchar(recv_buf[i]);
}
} while(r > 0);
putchar('\n');
ESP_LOGI(TAG, "... done reading from socket. Last read return=%d errno=%d.", r, errno);
close(s);

Wyświetl plik

@ -0,0 +1,3 @@
CONFIG_LWIP_IPV6_AUTOCONFIG=y
CONFIG_LWIP_IPV6_DHCP6=y
CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=2