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

Fix IPv6-only DNS by checking IPv6 first if have a public scope address #9443

Conversation

sgryphon
Copy link
Contributor

@sgryphon sgryphon commented Apr 1, 2024

Description of Change

On top of the IPv6 change to use getaddrinfo(), this implements a fix for IPv6-only networks by checking if we have an IPv6 public scope address, and if we do then check IPv6 first. If there is no IPv6-address, or we are on an IPv4-only network, then the change has no effect.

By checking IPv6 first when available, it allows devices to work across all network types -- IPv4-only, IPv6-only, and dual stack, connecting to all destination types -- IPv4-only, IPv6-only, and dual-stack servers.

Previously, while IPv6-only to IPv6-only worked, trying to connect from IPv6-only to dual stack (including DNS64) did not work, as the IPv4 address was always returned (and unreachable).

Note that this change does not do much unless IPv6 is enabled (Libs change): it will simply change the dual-stack preference order to IPv6-first, but IPv6-only will still fail if there is no DNS to query.

Tests scenarios

I have tested on a M5Stack Core2, with an ESP32 chip.

I have tested across different network types, and different destination types. Now that the TLS IPv6 support bug is merged, this now works across both HTTP and HTTPS connections.

Note: If IPv6 is never enabled, then the code is backwards compatible and behaves as if it is on an IPv4 only network.

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

PlatformIO configuration for testing. I have build and uploaded a version of the libs with the required configuration change, so that I can test using PlatformIO:

platform = https://github.com/sgryphon/platform-espressif32.git#sgryphon/add-esp32-arduino-libs
platform_packages = 
  platformio/framework-arduinoespressif32-libs @ https://github.com/sgryphon/esp32-arduino-libs.git#sgryphon/test-fix-ipv6-config
  platformio/framework-arduinoespressif32 @ https://github.com/sgryphon/arduino-esp32.git#sgryphon/dns-ipv6-check-first-if-have-addr

Some 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)

IPv6-only to dual-stack:

[  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

IPv6-only via HTTPS/TLS to dual-stack.

[ 24949][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Button 4, scenario 3, v0.1.0-160-g02b6d90-dev
[ 24962][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: Global IPv6 2407:8800:bc61:1300:a3a:f2ff:fe65:db28
[ 24973][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: IPv4 0.0.0.0
*sta: <UP,Wildspace,CH:1,RSSI:-57,N,WPA2_PSK> (DHCPC,GARP,IP_MOD,V6_REP)
      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 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
[ 25035][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS0 fd7c:e25e:67e8::1
[ 25054][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: DNS1 0.0.0.0
[ 25061][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: TLS URL: https://v4v6.ipv6-test.com/api/myip.php
[ 25075][D][HTTPClient.cpp:303] beginInternal(): protocol: https, host: v4v6.ipv6-test.com port: 443 url: /api/myip.php
[ 25086][D][HTTPClient.cpp:598] sendRequest(): request type: 'GET' redirCount: 0
[ 25094][D][NetworkManager.cpp:106] hostByName(): DNS found IPv6 first 2001:41d0:701:1100::29c8
[ 27088][D][HTTPClient.cpp:1170] connect():  connected to v4v6.ipv6-test.com:443
[ 27702][D][HTTPClient.cpp:1321] handleHeaderResponse(): code: 200
[ 27708][D][HTTPClient.cpp:1328] handleHeaderResponse(): Transfer-Encoding: chunked
[ 27716][D][HTTPClient.cpp:642] sendRequest(): sendRequest code=200
[ 27723][D][HTTPClient.cpp:388] disconnect(): still data in buffer (2), clean up.
[ 27730][D][HTTPClient.cpp:393] disconnect(): tcp keep open for reuse
[ 27736][I][Core2Logger.cpp:198] log(): [Core2Logger] CORE2: response=<2407:8800:bc61:1300:a3a:f2ff:fe65:db28>
[ 27751][I][Core2Logger.cpp:176] success(): [Core2Logger] Success

Related links

Now that the TLS change is merged, once the Libs are also rebuilt (the config is already merged), this addresses the issues in #9143, and in the IPv6 discussion.

An alternative fix, that implements RFC6724 destination address selection, has been proposed for LWIP; this would make AF_UNSPEC work and remove the need for the work around checking for IPv6 separately: espressif/esp-lwip#66

@sgryphon sgryphon changed the title Fix IPv6-only DNS by checking IPv6 first if have an IPv6 public address Fix IPv6-only DNS by checking IPv6 first if have a public scope address Apr 1, 2024
Copy link
Contributor

github-actions bot commented Apr 1, 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 2d0bab7

@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from 8287cf8 to d5591b0 Compare April 1, 2024 09:43
@me-no-dev me-no-dev added Area: LIB Builder Depends on Lib Builder Status: Blocked upstream 🛑 PR is waiting on upstream changes to be merged first labels Apr 1, 2024
@VojtechBartoska VojtechBartoska added this to the 3.0.1 milestone Apr 3, 2024
@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 4, 2024

I need a bit more testing on this branch after the other changes.

@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch 2 times, most recently from c4f5437 to 3ac49e9 Compare April 4, 2024 03:13
@me-no-dev
Copy link
Member

your lib-builder changes are not here yet :) when something is updated in IDF a new set of libs will be pushed to the idf-release/v5.1 branch here (5.1 libs PR)

@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from 3ac49e9 to 2a8ff99 Compare April 6, 2024 11:27
@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 6, 2024

I have re-tested everything with the latest changes.

I also tested a dual-stack network but with IPv6 not enabled, i.e. don't call WiFi.enableIPv6(), and it behaves as if it is on an IPv4 only network, so fully backwards compatible (if code can't handle IPv6 at all, e.g. tries to output to a string buffer that is too small, etc).

I also built the libs with the config changes and pushed to my own repo, so I could try a PlatformIO build with everything set up.

The check for if you have a global IPv6 also now uses Arduino functions like getNetifByID() and hasGlobalIPv6(), rather than low level functions, as it reads nicer.

This is ready to merge, but really needs the libs config update to be of much use.

There are still some problems with TLS / HTTPS, which most production systems should be using, but they need the fix in LWIP, and TLS uses the DNS directly at the lower level.

@me-no-dev
Copy link
Member

The contents of this PR do exactly what preferV6 used to do for hostByName. Get the V6 address if available, else return V4.

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 7, 2024

The contents of this PR do exactly what preferV6 used to do for hostByName. Get the V6 address if available, else return V4.

Kind of, except preferV6 was a fixed value, whereas checking IPv6 first is dynamic based on whether you have a public (i.e. global, not link scope) IPv6 address.

If the target is dual stack, then it has both IPv4 and IPv6

If you have IPv4 only, you want the IPv4 address; if you only have IPv6 then you want the IPv6 address.

So you can't have a fixed preference decided by the programmer when they wrote the code, but have to look at the actual addresses you have been given (depending on what is available on the network and run time).

@me-no-dev
Copy link
Member

@sgryphon you must have not read the code before. It was checking exactly if we have a global address and if so, it allows to set if you prefer V6 or V4 address. You just did not see that code after the refactoring (placeholder left with ToDo)

@me-no-dev
Copy link
Member

Please rebase the PR so it fixes the conflicts.

@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from 2a8ff99 to 01d7efb Compare April 7, 2024 14:33
@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 7, 2024

Rebase done.

placeholder left with ToDo

Yes, I implemented the ToDo. i.e. the first part of the code that checks if you have a global IPv6.

I also added back in the IPv6 check because the code is now using getaddrinfo(), which has different parameters.

The old code to host passed in either V4_V6 or V6_V4 as a preference order to hostbyname (i.e. manual preference order).

getaddrinfo() doesn't do that -- you pass in AF_UNSPEC for any (which should match your address but the LWIP bug hard codes to V4_V6), or you can limit to one address family only, i.e. AF_INET or AF_INET6.

To implement the preference order, based on actual addresses, the code checks if we have a global IPv6 (no longer a TODO), and if so, looks for AF_INET6 first (if no IPv6, then it doesn't). If AF_INET6 fails, then it falls back to AF_UNSPEC (which currently prefers IPv4).

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 7, 2024

... But, I finally worked out how to the Libs building with my LWIP fix, espressif/esp-lwip#66.

With the LWIP fix, then AF_UNSPEC returns the correct destination address selection according to RFC 6724, i.e. if you have an IPv6 it prefers IPv6, so the work around is not needed.

i.e. Current Arduino-ESP32 + LWIP fix works, and this PR is not needed.

If possible, I would prefer the LWIP fix get merged instead, as that is where the issue really needs to be fixed, for all of ESP-IDF (not just Arduino).

The PlatformIO config, with reference to my build of Libs with the LWIP fix is:

platform = https://github.com/sgryphon/platform-espressif32.git#sgryphon/add-esp32-arduino-libs
platform_packages = 
  platformio/framework-arduinoespressif32-libs @ https://github.com/sgryphon/esp32-arduino-libs.git#sgryphon/test-fix-ipv6-lwip-and-config
  platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git

@me-no-dev
Copy link
Member

i've marked it as blocked, but this PR is not really blocked by anything, is it? I do not find it nice to ask DNS twice. Can we make it optional through preferV6?

@me-no-dev
Copy link
Member

BTW. let's split this into two PRs. One will detect if public V6 address exists (and reset DNS cache), the other will do the preferV6. I can merge the first one right away

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 9, 2024

i've marked it as blocked, but this PR is not really blocked by anything, is it?

Well, it doesn't have a lot of value until the Libs config change is available.

By itself, this will only change the dual stack preference order from V4/V6 to V6/V4, but it still won't work in IPv6 only.

When the Libs change is merged, and IPv6-only is working, this change will then be required so that dual-stack destinations don't try and use the IPv4 address and fail.

You are welcome to merge this one now, as is (although I would much prefer the LWIP fix).

I do not find it nice to ask DNS twice

I agree, if we can get the fix applied to LWIP that would be a much better solution.

LWIP may have to do multiple DNS queries anyway, e.g. if V6 fails then it will do a second query for V4 (because LWIP only supports one result at a time).

But this is only relevant if we have both addresses.

A lot of the time only one query will be made, e.g. if in an IPv4-only network (or IPv6 is disabled) then the first DNS will be skipped. Or with IPv6 if the first succeeds, the second is not made.

make it optional through preferV6

Not entirely sure what you want here.

Preference then only applies if we have both addresses, so for a single type of address we need to call the relevant DNS (4 OR 6).

We could add a check for if we have an IPv4, and then allow an alternate preference to check IPv4 first. (RFC 6724 default is to preference IPv6)

We would then call LWIP DNS with only AF_UNSPEC, although internally it will still do two DNS checks if needed.

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 9, 2024

I also looked into the TLS (HTTPS / SSL) issues, which I thought were the same as ESP-IDF, because even with the LWIP fix the TLS connections were still failing. I have found the problem and have a fix up in another branch; I have tested a few scenarios and it is working, but need to finish testing all scenarios before I put up the PR.

As I would encourage systems to always use HTTPS, getting it working is important.

@me-no-dev
Copy link
Member

Will you please split the PR so I can merge the change of IP detection?

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 9, 2024

Related TLS fix is here: #9470

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 9, 2024

Will you please split the PR so I can merge the change of IP detection?

I'm not entirely sure what the IP detection would do by itself, and trying to understand what you want.

@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 9, 2024

Okay, I think I found what you want -- although I don't think it will achieve much.

One will detect if public V6 address exists (and reset DNS cache), the other will do the preferV6

I can split it like that, although I don't think it will do much. i.e. the first change won't fix anything (I'm not sure what resetting DNS cache will achieve).

The rest of the code is nothing about preferences or preferring, but about solving the problem that if you are IPv6-only then you need to get an IPv6 address to connect to, whereas if you are IPv4 only you need to get an IPv4 address. That is not a preference, but a bug fix to be able to connect IPv6 to a dual-stack destination.

(The only time a preference would apply would be dual-stack to dual-stack where either will work; I don't suggest allowing a preference, but just following RFC6724 that prioritises IPv6.)

So 3 things:

  1. Detect IPv6 and refresh cache if changed (I don't think this will do anything useful)
  2. Fix the IPv6-only to dual-stack bug, by using the detected IPv6 to determine the order we check DNS.
  3. Add a preference option for the dual-stack to dual-stack situation (I don't think this is necessary and would just stick with RFC6724 defaults -- note that the RFC does detail an override mechanism, which is supported in my LWIP code)

@me-no-dev
Copy link
Member

Detect IPv6 and refresh cache if changed (I don't think this will do anything useful)

very useful if you first got your IPv4 address. Please split the PR

@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from 01d7efb to 16a7b9b Compare April 9, 2024 22:32
@sgryphon
Copy link
Contributor Author

sgryphon commented Apr 9, 2024

I have split the PRs. The new PR has the IP address type check and DNS cache refresh. #9476

This one only adds the IPv6 fix as a second commit (i.e. consider it targetting the other PR).

The full diff for this will contain both changes, but you can look at the individual commits for details.

@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from 16a7b9b to 07dc0a6 Compare April 10, 2024 12:44
@sgryphon
Copy link
Contributor Author

Rebased on latest main, with just the IPv6 DNS fix commit

@@ -86,12 +86,36 @@ int NetworkManager::hostByName(const char* aHostname, IPAddress& aResult)
log_d("Clearing DNS cache");
}

struct addrinfo hints;
Copy link
Member

Choose a reason for hiding this comment

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

this is a better way to init the structure. especially in CPP. Please keep it that way and only change the relevant fields before each call to lwip_getaddrinfo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed.

@me-no-dev me-no-dev removed Area: LIB Builder Depends on Lib Builder Status: Blocked upstream 🛑 PR is waiting on upstream changes to be merged first labels Apr 11, 2024
@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from 07dc0a6 to f0d14f8 Compare April 11, 2024 21:22
…ublic address

Work around because AF_UNSPEC does not check available addresses when
determining result.

If you have a global scope IPv6 address, then first check for IPv6 DNS result;
if you don't have an IPv6, or there is no IPv6 result, then check IPv4.

This allows IPv6-only networks to connect to dual-stack destinations, as they
will get the IPv6 address (rather than the unusable IPv4).

It also means a dual-stack host to a dual-stack destination will preference
IPv6.

There is no effect if you are on an IPv4-only network, or it is an IPv4-only
destination.
@sgryphon sgryphon force-pushed the sgryphon/dns-ipv6-check-first-if-have-addr branch from f0d14f8 to 2d0bab7 Compare April 11, 2024 21:23
@me-no-dev me-no-dev merged commit 3a0dd1c into espressif:master Apr 12, 2024
39 checks passed
P-R-O-C-H-Y pushed a commit to P-R-O-C-H-Y/arduino-esp32 that referenced this pull request Apr 16, 2024
…ublic address (espressif#9443)

Work around because AF_UNSPEC does not check available addresses when
determining result.

If you have a global scope IPv6 address, then first check for IPv6 DNS result;
if you don't have an IPv6, or there is no IPv6 result, then check IPv4.

This allows IPv6-only networks to connect to dual-stack destinations, as they
will get the IPv6 address (rather than the unusable IPv4).

It also means a dual-stack host to a dual-stack destination will preference
IPv6.

There is no effect if you are on an IPv4-only network, or it is an IPv4-only
destination.
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.

3 participants