Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Network refactoring - fix some IPv6 DNS issues #9439

Merged

Conversation

sgryphon
Copy link
Contributor

@sgryphon sgryphon commented Mar 31, 2024

By completing this PR sufficiently, you help us to review this Pull Request quicker and also help improve the quality of Release Notes

Checklist

  1. Please provide specific title of the PR describing the change, including the component name (eg. „Update of Documentation link on Readme.md“)
  2. Please provide related links (eg. Issue which will be closed by this Pull Request)
  3. Please update relevant Documentation if applicable
  4. Please check Contributing guide
  5. Please confirm option to "Allow edits and access to secrets by maintainers" when opening a Pull Request

This entire section above can be deleted if all items are checked.


Description of Change

Allows dual-stack networks to connect to IPv6-only destinations.

Replace hostbyname with getaddrinfo for better IPv6 support. The API is also simpler, as it has no callbacks (they are handled internally).

Note: Still does not work for IPv6-only networks, as IPv6 DNS is not enabled in the pre-built ESP-IDF libraries.

Also includes an update to dnsIP() to correctly return IPv6 addresses (they do work internally, when enabled, just weren't being returned correctly).

Tests scenarios

Tested on M5Stack Core2 (ESP32), on dual-stack, IPv4-only, and IPv6-only networks (with DNS64/NAT64), for dual-stack. IPv4-only, and IPv6-only destination servers.

The IPv4-only and dual-stack networks work for all destination servers, although due to a limitation in LWIP the dual-stack to dual-stack scenario uses the IPv4 address (instead of IPv6).

I have a patch submitted for ESP-LWIP to fix this issue, and in the meanwhile also have a workaround I can implement for Arduino-ESP32.

Network Dual-Stack IPv6 IPv4 TLS Dual-Stack
IPv4 (Shadow) Yes Not Possible Yes Yes
Dual-stack+NAT64 (Astral) IPv4 Yes Yes Yes
IPv6+NAT64 (Wildspace) No DNS No DNS No DNS No DNS

Note that IPv6-only networks do not work yet. They are reporting no-DNS, probably because the underlying ESP-IDF libraries do not have IPv6 DNS enabled.

Example outputs:

(These are from my own test app, at https://github.com/sgryphon/iot-demo-build/tree/feature/arduino-esp32-v3-update/m5stack/m5unified_wifi_https -- I will look at making sure a simpler test example in Arduino-ESP32 also works.)

Dual-stack network, to IPv6-only destination:

[ 38329][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 3, scenario 2, v0.1.0-156-gaf345f5
[ 38342][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1340:a3a:f2ff:fe65:db28
[ 38357][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 192.168.1.159
[ 38365][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Link-Local IPv6 fe80::a3a:f2ff:fe65:db28%st1
sta: <UP>
      ether 08:3A:F2:65:DB:28
      inet 192.168.1.159 netmask 255.255.255.0 broadcast 192.168.1.255
      gateway 192.168.1.1 dns 192.168.1.1
      inet6 fe80::a3a:f2ff:fe65:db28%st1 type LINK_LOCAL
      inet6 2407:8800:bc61:1340:a3a:f2ff:fe65:db28 type GLOBAL
      inet6 fd7c:e25e:67e8:40:a3a:f2ff:fe65:db28 type UNIQUE_LOCAL
[ 38402][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 192.168.1.1
[ 38417][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 38424][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: URL: http://v4.ipv6-test.com/api/myip.php
[ 38465][D][HTTPClient.cpp:303] beginInternal(): protocol: http, host: v4.ipv6-test.com port: 80 url: /api/myip.php
[ 38476][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0

[ 38505][D][NetworkManager.cpp:88] hostByName(): DNS found IPv4 51.75.78.103
[ 38917][D][HTTPClient.cpp:1170] connect():  connected to v4.ipv6-test.com:80
[ 39330][D][HTTPClient.cpp:1321] handleHeaderResponse(): code: 200
[ 39336][D][HTTPClient.cpp:1328] handleHeaderResponse(): Transfer-Encoding: chunked
[ 39344][D][HTTPClient.cpp:642] sendRequest(): sendRequest code=200

[ 39350][D][HTTPClient.cpp:388] disconnect(): still data in buffer (2), clean up.

[ 39358][D][HTTPClient.cpp:393] disconnect(): tcp keep open for reuse
[ 39364][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: response=<220.240.255.134>
[ 39375][I][Core2Logger.cpp:176] success(): [Core2Logger] Success

Failure - IPv6 only network, to dual-stack host. No IPv6 DNS available. (LWIP does support IPv6 DNS, but not enabled in library build)

[ 18184][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 1, scenario 0, v0.1.0-156-gaf345f5
[ 18196][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28
[ 18211][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 0.0.0.0
[ 18218][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Link-Local IPv6 fe80::a3a:f2ff:fe65:db28%st1
sta: <UP>
      ether 08:3A:F2:65:DB:28
      inet 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255
      gateway 0.0.0.0 dns 0.0.0.0
      inet6 fe80::a3a:f2ff:fe65:db28%st1 type LINK_LOCAL
      inet6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28 type GLOBAL
      inet6 fd7c:e25e:67e8:0:a3a:f2ff:fe65:db28 type UNIQUE_LOCAL
[ 18256][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 0.0.0.0
[ 18268][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 18275][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: URL: http://v4v6.ipv6-test.com/api/myip.php
[ 18289][D][HTTPClient.cpp:303] beginInternal(): protocol: http, host: v4v6.ipv6-test.com port: 80 url: /api/myip.php
[ 18299][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0

[ 18307][E][NetworkManager.cpp:101] hostByName(): DNS Failed for 'v4v6.ipv6-test.com' with error '-54'
[ 18317][E][NetworkClient.cpp:258] connect(): connect on fd 48, errno: 118, "Host is unreachable"
[ 18326][D][HTTPClient.cpp:1163] connect(): failed connect to v4v6.ipv6-test.com:80
[ 18333][W][HTTPClient.cpp:1486] returnError(): error(-1): connection refused
[ 18340][E][Core2Logger.cpp:192] log(): [Core2Logger] CORE2: HTTP GET error -1: connection refused

Related links

Partially addresses the issues in #9143, and in the IPv6 discussion.

Copy link
Contributor

github-actions bot commented Mar 31, 2024

Messages
📖 🎉 Good Job! All checks are passing!

👋 Hello sgryphon, we appreciate your contribution to this project!


Click to see more instructions ...


This automated output is generated by the PR linter DangerJS, which checks if your Pull Request meets the project's requirements and helps you fix potential issues.

DangerJS is triggered with each push event to a Pull Request and modify the contents of this comment.

Please consider the following:
- Danger mainly focuses on the PR structure and formatting and can't understand the meaning behind your code or changes.
- Danger is not a substitute for human code reviews; it's still important to request a code review from your colleagues.
- To manually retry these Danger checks, please navigate to the Actions tab and re-run last Danger workflow.

Review and merge process you can expect ...


We do welcome contributions in the form of bug reports, feature requests and pull requests.

1. An internal issue has been created for the PR, we assign it to the relevant engineer.
2. They review the PR and either approve it or ask you for changes or clarifications.
3. Once the GitHub PR is approved we do the final review, collect approvals from core owners and make sure all the automated tests are passing.
- At this point we may do some adjustments to the proposed change, or extend it by adding tests or documentation.
4. If the change is approved and passes the tests it is merged into the default branch.

Generated by 🚫 dangerJS against 5634137

@sgryphon sgryphon force-pushed the sgryphon/refactor-dns-getaddrinfo-ipv6 branch from fd77166 to 44940e4 Compare March 31, 2024 00:31
@me-no-dev
Copy link
Member

Note: Still does not work for IPv6-only networks, as IPv6 DNS is not enabled in the pre-built ESP-IDF libraries.

Can you open a PR for this in the lib-builder? Options need to be added to this file. Then in the PR, the CI will generate new libs that you can use to test the feature

@sgryphon
Copy link
Contributor Author

Note: Still does not work for IPv6-only networks, as IPv6 DNS is not enabled in the pre-built ESP-IDF libraries.
Can you open a PR for this in the lib-builder? Options need to be added to this file.

Thanks. I have built the libs locally with the needed config, but need to test it out.

Also, there may be some corresponding changes in Arduino-ESP32, e.g. not sure if it reports DNS servers correctly.

@sgryphon
Copy link
Contributor Author

Note: Still does not work for IPv6-only networks, as IPv6 DNS is not enabled in the pre-built ESP-IDF libraries.
Can you open a PR for this in the lib-builder? Options need to be added to this file.

Thanks. I have built the libs locally with the needed config, but need to test it out.

Also, there may be some corresponding changes in Arduino-ESP32, e.g. not sure if it reports DNS servers correctly.

So, it had finished building the libs overnight, and it worked. Well, internally LWIP is using the IPv6 DNS servers, and the IPv6-only to IPv6-only scenario works, but I need to updates to Arduino-ESP32 as well:

  1. DNS server addresses are not being displayed correctly, i.e. does not support IPv6. Internally in LWIP they are IPv6 (because they are working), just not displayed correctly. Should be a relatively easy fix, I will work on.
  2. Dual-stack and NAT64 scenarios do not work, as LWIP DNS has fixed preference for IPv4, which an IPv6-only network can't reach (as mentioned originally).

To properly fix this second issue requires my patch to LWIP, espressif/esp-lwip#66

In the meanwhile, I can add a workaround in Arduino-ESP32, based on the code in my ESP-IDF examples updates: espressif/esp-idf#13250

Here is IPv6 - IPv6 working:

[ 32097][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 2, scenario 1, v0.1.0-156-gaf345f5
[ 32110][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28
[ 32125][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 0.0.0.0
[ 32132][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Link-Local IPv6 fe80::a3a:f2ff:fe65:db28%st1
sta: <UP>
      ether 08:3A:F2:65:DB:28
      inet 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255
      gateway 0.0.0.0 dns 253.124.226.94
      inet6 fe80::a3a:f2ff:fe65:db28%st1 type LINK_LOCAL
      inet6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28 type GLOBAL
      inet6 fd7c:e25e:67e8:0:a3a:f2ff:fe65:db28 type UNIQUE_LOCAL
[ 32169][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 253.124.226.94
[ 32184][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 32191][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: URL: http://v6.ipv6-test.com/api/myip.php
[ 32204][D][HTTPClient.cpp:303] beginInternal(): protocol: http, host: v6.ipv6-test.com port: 80 url: /api/myip.php
[ 32214][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0

[ 32258][D][NetworkManager.cpp:81] hostByName(): DNS found IPv6 2001:41d0:701:1100::29c8
[ 32711][D][HTTPClient.cpp:1170] connect():  connected to v6.ipv6-test.com:80
[ 33334][D][HTTPClient.cpp:1321] handleHeaderResponse(): code: 200
[ 33340][D][HTTPClient.cpp:1328] handleHeaderResponse(): Transfer-Encoding: chunked
[ 33348][D][HTTPClient.cpp:642] sendRequest(): sendRequest code=200

[ 33354][D][HTTPClient.cpp:388] disconnect(): still data in buffer (2), clean up.

[ 33362][D][HTTPClient.cpp:393] disconnect(): tcp keep open for reuse
[ 33368][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: response=<2407:8800:bc61:1300:a3a:f2ff:fe65:db28>
[ 33383][I][Core2Logger.cpp:176] success(): [Core2Logger] Success

@sgryphon
Copy link
Contributor Author

Note: Still does not work for IPv6-only networks, as IPv6 DNS is not enabled in the pre-built ESP-IDF libraries.
Can you open a PR for this in the lib-builder? Options need to be added to this file.

Thanks. I have built the libs locally with the needed config, but need to test it out.
Also, there may be some corresponding changes in Arduino-ESP32, e.g. not sure if it reports DNS servers correctly.

So, it had finished building the libs overnight, and it worked. Well, internally LWIP is using the IPv6 DNS servers, and the IPv6-only to IPv6-only scenario works, but I need to updates to Arduino-ESP32 as well:

The related PR for libs is here: espressif/esp32-arduino-lib-builder#166

Note that the changes are independent, i.e. even with the old DNS the libs update will help IPv6-only scenarios.

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 1, 2024

I have added a work around for IPv6-only networks, by, if you have a public IPv6 address, then check IPv6 first.

Most scenarios now work, with only failing on TLS from an IPv6-only network to a dual-stack host:

Network Dual-Stack IPv6 IPv4 TLS Dual-Stack
IPv4 (Shadow) Yes Not Possible Yes Yes
Dual-stack+NAT64 (Astral) IPv4 Yes Yes Yes
IPv6+NAT64 (Wildspace) IPv6 Yes NAT64 fail

The third commit implements the work around, and is independent of fixing libs, but not much use if the libs don't have IPv6 DNS enabled (it will change the preference in dual-stack).

I am not sure if you want the first commit as part of this pull request, or separate. Separate might make it easy to review (and back out once LWIP is patched).

Some examples:

IPv6-only to dual-stack, that fails without the workaround:

[  1524][W][STA.cpp:544] disconnect(): STA already disconnected.
[  1629][D][WiFiNetworkService.cpp:94] loop(): [Network] WiFi begin status 254
[  1759][D][STA.cpp:133] _onStaArduinoEvent(): Arduino STA Event: 13 - STA_CONNECTED
[  1766][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: WF STA connected
[  3530][D][STA.cpp:133] _onStaArduinoEvent(): Arduino STA Event: 17 - STA_GOT_IP6
[  3538][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: WF STA IPv6 fe80:0000:0000:0000:0a3a:f2ff:fe65:db28
[  3552][D][WiFiNetworkService.cpp:47] wifiOnEvent(): [Network] IPv6 address type 2
[  4530][D][STA.cpp:133] _onStaArduinoEvent(): Arduino STA Event: 17 - STA_GOT_IP6
[  4538][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: WF STA IPv6 2407:8800:bc61:1300:0a3a:f2ff:fe65:db28
[  4552][I][Core2Logger.cpp:176] success(): [Core2Logger] Success
[  4558][D][WiFiNetworkService.cpp:47] wifiOnEvent(): [Network] IPv6 address type 1
[  4566][D][STA.cpp:133] _onStaArduinoEvent(): Arduino STA Event: 17 - STA_GOT_IP6
[  4573][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: WF STA IPv6 fd7c:e25e:67e8:0000:0a3a:f2ff:fe65:db28
[  4587][I][Core2Logger.cpp:176] success(): [Core2Logger] Success
[  4593][D][WiFiNetworkService.cpp:47] wifiOnEvent(): [Network] IPv6 address type 4
[ 10488][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 1, scenario 0, v0.1.0-156-gaf345f5
[ 10501][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28
[ 10515][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 0.0.0.0
[ 10523][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Link-Local IPv6 fe80::a3a:f2ff:fe65:db28%st1
sta: <UP>
      ether 08:3A:F2:65:DB:28
      inet 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255
      gateway 0.0.0.0 dns [ 10537][D][NetworkInterface.cpp:611] dnsIP(): DNS got IPv6: fd7c:e25e:67e8:0000:0000:0000:0000:0001
fd7c:e25e:67e8::1
      inet6 fe80::a3a:f2ff:fe65:db28%st1 type LINK_LOCAL
      inet6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28 type GLOBAL
      inet6 fd7c:e25e:67e8:0:a3a:f2ff:fe65:db28 type UNIQUE_LOCAL
[ 10568][D][NetworkInterface.cpp:611] dnsIP(): DNS got IPv6: fd7c:e25e:67e8:0000:0000:0000:0000:0001
[ 10583][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 fd7c:e25e:67e8::1
[ 10592][D][NetworkInterface.cpp:637] dnsIP(): DNS IPv4: 0.0.0.0
[ 10598][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 10606][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: URL: http://v4v6.ipv6-test.com/api/myip.php
[ 10619][D][HTTPClient.cpp:303] beginInternal(): protocol: http, host: v4v6.ipv6-test.com port: 80 url: /api/myip.php
[ 10630][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0

[ 10637][D][NetworkManager.cpp:91] hostByName(): Clearing DNS cache
[ 10655][D][NetworkManager.cpp:106] hostByName(): DNS found first IPv6 2001:41d0:701:1100::29c8
[ 11049][D][HTTPClient.cpp:1170] connect():  connected to v4v6.ipv6-test.com:80
[ 11462][D][HTTPClient.cpp:1321] handleHeaderResponse(): code: 200
[ 11468][D][HTTPClient.cpp:1328] handleHeaderResponse(): Transfer-Encoding: chunked
[ 11476][D][HTTPClient.cpp:642] sendRequest(): sendRequest code=200

[ 11482][D][HTTPClient.cpp:388] disconnect(): still data in buffer (2), clean up.

[ 11490][D][HTTPClient.cpp:393] disconnect(): tcp keep open for reuse
[ 11496][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: response=<2407:8800:bc61:1300:a3a:f2ff:fe65:db28>
[ 11511][I][Core2Logger.cpp:176] success(): [Core2Logger] Success

IPv6-only to IPv4-only, also works via DNS64+NAT64, by using a synthentic IPv6 DNS64 address -- effectively making the destination dual-stack. From the point of view of the destination the source address appears to be the IPv4 NAT address (same as for NAT44).

[ 15828][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 3, scenario 2, v0.1.0-156-gaf345f5
[ 15841][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28
[ 15855][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 0.0.0.0
[ 15863][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Link-Local IPv6 fe80::a3a:f2ff:fe65:db28%st1
sta: <UP>
      ether 08:3A:F2:65:DB:28
      inet 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255
      gateway 0.0.0.0 dns [ 15877][D][NetworkInterface.cpp:611] dnsIP(): DNS got IPv6: fd7c:e25e:67e8:0000:0000:0000:0000:0001
fd7c:e25e:67e8::1
      inet6 fe80::a3a:f2ff:fe65:db28%st1 type LINK_LOCAL
      inet6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28 type GLOBAL
      inet6 fd7c:e25e:67e8:0:a3a:f2ff:fe65:db28 type UNIQUE_LOCAL
[ 15909][D][NetworkInterface.cpp:611] dnsIP(): DNS got IPv6: fd7c:e25e:67e8:0000:0000:0000:0000:0001
[ 15923][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 fd7c:e25e:67e8::1
[ 15932][D][NetworkInterface.cpp:637] dnsIP(): DNS IPv4: 0.0.0.0
[ 15938][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 15946][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: URL: http://v4.ipv6-test.com/api/myip.php
[ 15956][D][HTTPClient.cpp:303] beginInternal(): protocol: http, host: v4.ipv6-test.com port: 80 url: /api/myip.php
[ 15966][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0

[ 15980][D][NetworkManager.cpp:106] hostByName(): DNS found first IPv6 64:ff9b::334b:4e67
[ 16304][D][HTTPClient.cpp:1170] connect():  connected to v4.ipv6-test.com:80
[ 16686][D][HTTPClient.cpp:1321] handleHeaderResponse(): code: 200
[ 16692][D][HTTPClient.cpp:1328] handleHeaderResponse(): Transfer-Encoding: chunked
[ 16700][D][HTTPClient.cpp:642] sendRequest(): sendRequest code=200

[ 16706][D][HTTPClient.cpp:388] disconnect(): still data in buffer (2), clean up.

[ 16714][D][HTTPClient.cpp:393] disconnect(): tcp keep open for reuse
[ 16720][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: response=<220.240.255.134>
[ 16759][I][Core2Logger.cpp:176] success(): [Core2Logger] Success

Failure, IPv6-only via HTTPS/TLS to dual-stack. Because TLS needs to use the hostname (for checking certificates), I presume it resolves internally in LWIP, similar to ESP-IDF. This will only be fixed when ESP-LWIP is updated to fix IPv6 DNS resolution (patch is being reviewed).

[ 18368][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 4, scenario 3, v0.1.0-156-gaf345f5
[ 18381][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28
[ 18395][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 0.0.0.0
[ 18403][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Link-Local IPv6 fe80::a3a:f2ff:fe65:db28%st1
sta: <UP>
      ether 08:3A:F2:65:DB:28
      inet 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255
      gateway 0.0.0.0 dns [ 18417][D][NetworkInterface.cpp:611] dnsIP(): DNS got IPv6: fd7c:e25e:67e8:0000:0000:0000:0000:0001
fd7c:e25e:67e8::1
      inet6 fe80::a3a:f2ff:fe65:db28%st1 type LINK_LOCAL
      inet6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28 type GLOBAL
      inet6 fd7c:e25e:67e8:0:a3a:f2ff:fe65:db28 type UNIQUE_LOCAL
[ 18448][D][NetworkInterface.cpp:611] dnsIP(): DNS got IPv6: fd7c:e25e:67e8:0000:0000:0000:0000:0001
[ 18463][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 fd7c:e25e:67e8::1
[ 18472][D][NetworkInterface.cpp:637] dnsIP(): DNS IPv4: 0.0.0.0
[ 18478][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 18486][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: TLS URL: https://v4v6.ipv6-test.com/api/myip.php
[ 18500][D][HTTPClient.cpp:303] beginInternal(): protocol: https, host: v4v6.ipv6-test.com port: 443 url: /api/myip.php
[ 18511][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0

[ 18518][D][NetworkManager.cpp:106] hostByName(): DNS found first IPv6 2001:41d0:701:1100::29c8
[ 18528][E][ssl_client.cpp:96] start_ssl_client(): connect on fd 48, errno: 118, "Host is unreachable"
[ 18537][I][NetworkClientSecure.cpp:147] connect(): Actual TLS start posponed.
[ 18544][E][NetworkClientSecure.cpp:152] connect(): start_ssl_client: connect failed: -1
[ 18552][D][HTTPClient.cpp:1163] connect(): failed connect to v4v6.ipv6-test.com:443
[ 18560][W][HTTPClient.cpp:1486] returnError(): error(-1): connection refused
[ 18567][E][NetworkClient.cpp:329] setSocketOption(): fail on 0, errno: 9, "Bad file number"
[ 18575][E][Core2Logger.cpp:192] log(): [Core2Logger] CORE2: HTTP GET error -1: connection refused

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 1, 2024

Failures are related to change of esp_netif_next_unsafe in ESP-IDF. I will pull the latest change out into a separate PR.

@@ -82,8 +45,9 @@ static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param)
*/
int NetworkManager::hostByName(const char* aHostname, IPAddress& aResult, bool preferV6)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like preferV6 is no longer needed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure what preferV6 was supposed to be for. It seemed to be a way to say in advance what type of address you want, except the whole point of DNS is to only know the name and not the address.

i.e. www.google.com -- yesterday it was IPv4 only, today it is dual stack, tomorrow it will be IPv6 only. But the code shouldn't care.

The programmer won't know where the device/code will be used, so can't specify what to use in advance.

The rules for destination addresses of RFC 6724 are to use whatever matches, i.e. if you have a public IPv6 and the destination is public IPv6, then use that; otherwise if you only have IPv4 then use that. This needs to be determined dynamically at run time. (what the patch to ESP-LWIP does, or the work around does as a short cut).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that in some utility programs you might want to display all DNS lookups. Unfortunately LWIP is limited to only one result, although you could get one IPv6 and one IPv4.

Although in that case you probably want at least 3 options -- the default to give whatever matches (4 or 6), and then an explicit way to look up either v4 or v6.

Note that a utility program might be running in an IPv4-only network, so the default will give a v4 address, but they might want to show the user both available addresses.

Although at that point, for such a utility, probably Arduino is not the right solution (i.e. go to underlying ESP-IDF).

I will remove the option (I think it was only added as part of the original refactoring).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was there exactly so some that want to prefer using V6 address, can say so. Then the DNS will return the addresses in the requested order. By default it will return the v4 if available.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, but I never understood how a programmer would know in advance what type of address is going to be needed.

Dynamic determination is much better, because that allows a device, or sample code, to run in any network.

Now that I have that working, there is no need for a programmer to have to use the option (and change configuration/recompile every time they change networks). The dynamic code will work in any network, for any destination.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I am fine with that. Please remove the argument :)

if (!aResult.fromString(aHostname)) {
Network.waitStatusBits(NET_DNS_IDLE_BIT, 16000);
Network.clearStatusBits(NET_DNS_IDLE_BIT | NET_DNS_DONE_BIT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing any reference to NET_DNS_IDLE_BIT and NET_DNS_DONE_BIT is also necessary. And if Network.[get|set|wait]StatusBits are only used for those two flags, then we can probably get rid of that too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll look at cleaning up.

@@ -82,8 +45,9 @@ static esp_err_t wifi_gethostbyname_tcpip_ctx(void *param)
*/
int NetworkManager::hostByName(const char* aHostname, IPAddress& aResult, bool preferV6)
{
// IDEA: Rename to getAddressInfo() ?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's keep this for historic reasons

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove the comment

@me-no-dev
Copy link
Member

@sgryphon any clues when yo can finish this? We can take over also to finalize the changes

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 3, 2024

@sgryphon any clues when yo can finish this? We can take over also to finalize the changes

I do have a day job, but get some time on weekends and the occasional evening.

One thing that is probably key if you can help at all, if you know the right people, is the change for ESP-LWIP, which has not been assigned to anyone, with no comments or feedback or anything. espressif/esp-lwip#66

If the result from esp_netif_get_dns_info is an IPv6 address, then parse to an IPAddress.
@me-no-dev
Copy link
Member

I can't comment on IDF's PR policies, as that is a totally separate project with it's subprojects and so on. My question was about this particular PR that is not connected to your PR in IDF. If you can wrap it up over that weekend that would be great. We kinda want to be able to release RC1 soon

@sgryphon sgryphon force-pushed the sgryphon/refactor-dns-getaddrinfo-ipv6 branch from f8336de to 22034bf Compare April 3, 2024 10:47
Replace hostbyname with getaddrinfo for better IPv6 support. The API is also
simpler, as it has no callbacks (they are handled internally). Allows
dual-stack networks to connect to IPv6-only destinations.

Still does not work for IPv6-only networks, as IPv6 DNS is not enabled in the
pre-built ESP-IDF libraries.
@sgryphon sgryphon force-pushed the sgryphon/refactor-dns-getaddrinfo-ipv6 branch from 22034bf to 5634137 Compare April 3, 2024 11:57
@me-no-dev me-no-dev merged commit 64235dc into espressif:master Apr 3, 2024
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants