Skip to content

WiFi + Ethernet (LAN8720): DNS Server Managment #7602

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

Closed
1 task done
gonzabrusco opened this issue Dec 19, 2022 · 16 comments
Closed
1 task done

WiFi + Ethernet (LAN8720): DNS Server Managment #7602

gonzabrusco opened this issue Dec 19, 2022 · 16 comments
Labels
Area: BT&Wifi BT & Wifi related issues Resolution: Awaiting response Waiting for response of author Status: Test needed Issue needs testing Type: Bug 🐛 All bugs
Milestone

Comments

@gonzabrusco
Copy link
Contributor

gonzabrusco commented Dec 19, 2022

Board

Custom ESP32 Board with a LAN8720

Device Description

Custom ESP32 Board with a LAN8720

Hardware Configuration

Custom ESP32 Board with a LAN8720

Version

v2.0.5

IDE Name

PlatformIO

Operating System

Windows 10

Flash frequency

40MHz

PSRAM enabled

no

Upload speed

115200

Description

Hello. I'm doing some tests with a custom board with the LAN8720 onboard.

I noticed that ETH.dnsIP(uint8_t dns_no) and WiFi.dnsIP(uint8_t dns_no) always return the same IPs. I think there's a problem in the way the DNS are being handled. Is it normal for both interfaces to share the same DNS?

The DNS set are always the ones of the latest interface that got IP (by DHCP). For example take a look at the following screenshot:

image

As you can see, the IP of the Ethernet and the WiFi interface are different, but the DNS are the same for some reason. In that image, the Ethernet connected first and then the WiFi, overriding the DNS that got Ethernet first (which does not make sense because those IPs are not even in the same subnet of the Ethernet IP).

Also I noticed another problem while using both interfaces at the same time. If the network cable is plugged before powering everything up, I can't never connect to my server using the following code:

ETH.begin();
WiFi.begin("Unexistent SSID", "Random Password");

The error the debug gives me is:
E][WiFiGeneric.cpp:1438] hostByName(): DNS Failed for test.mosquitto.org

The only way for this to start working, if by unplugging and plugging the Ethernet cable. Just then the DNS are set correctly.

But if I modify the code and add some lines, Ethernet works from the start (without needing to unplug and plug the Ethernet cable):

ETH.begin();
ETH.config(IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u));
WiFi.config(IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u));
WiFi.begin("Unexistent SSID", "Random Password");

This clearly seems like a bug or a bad managment of DNS servers. If DNS are shared, then it this means that Ethernet and WiFi can't be used together on the first place. And even if that was not possible, when running WiFi.begin() without a previous config, seems to reset or delete the DNS of the Ethernet interface.

Finally as a bonus bug WiFiClientSecure localIP() method always returns 0.0.255.0 but if I modify the script to connect without TLS, the localIP() method works fine on a regular WiFiClient.

Sketch

#include <WiFi.h>
#include <ETH.h>
#include <WiFiClientSecure.h>

WiFiClientSecure wifiClientSecure;

const char * mqttServer = "test.mosquitto.org";
const int mqttPort = 8883;

const char * ssid     = "Unexistent SSID";
const char * password = "Random Password";

bool wifiConnected = false;
bool ethernetConnected = false;

void eventHandler(arduino_event_id_t event, arduino_event_info_t info) {
    switch(event) {
        case ARDUINO_EVENT_WIFI_READY: // ESP32 WiFi ready
            Serial.println("LAN: Event WIFI_READY");
            break;
        case ARDUINO_EVENT_WIFI_SCAN_DONE: // ESP32 finish scanning AP
            Serial.println("LAN: Event WIFI_SCAN_DONE");
            break;
        case ARDUINO_EVENT_WIFI_STA_START: // ESP32 station start
            Serial.println("LAN: Event WIFI_STA_START");
            break;
        case ARDUINO_EVENT_WIFI_STA_STOP: // ESP32 station stop
            Serial.println("LAN: Event WIFI_STA_STOP");
            break;
        case ARDUINO_EVENT_WIFI_STA_CONNECTED: // ESP32 station connected to AP
            Serial.println("LAN: Event WIFI_STA_CONNECTED");
            Serial.printf("LAN: SSID: %s BSSID: %02x:%02x:%02x:%02x:%02x:%02x CHANNEL: %u AUTHMODE: ",(char*)info.wifi_sta_connected.ssid, info.wifi_sta_connected.bssid[0], info.wifi_sta_connected.bssid[1], info.wifi_sta_connected.bssid[2], info.wifi_sta_connected.bssid[3], info.wifi_sta_connected.bssid[4], info.wifi_sta_connected.bssid[5], info.wifi_sta_connected.channel);
            switch(info.wifi_sta_connected.authmode) {
                case WIFI_AUTH_OPEN:
                    Serial.println("OPEN");
                    break;
                case WIFI_AUTH_WEP:
                    Serial.println("WEP");
                    break;
                case WIFI_AUTH_WPA_PSK:
                    Serial.println("WPA");
                    break;
                case WIFI_AUTH_WPA2_PSK:
                    Serial.println("WPA2");
                    break;
                case WIFI_AUTH_WPA_WPA2_PSK:
                    Serial.println("WPA/WPA2");
                    break;
                case WIFI_AUTH_WPA2_ENTERPRISE:
                    Serial.println("WPA ENTERPRISE");
                    break;
                case WIFI_AUTH_WPA3_PSK:
                    Serial.println("WPA3");
                    break;
                case WIFI_AUTH_WPA2_WPA3_PSK:
                    Serial.println("WPA2/WPA3");
                    break;
                case WIFI_AUTH_WAPI_PSK:
                    Serial.println("WAPI");
                    break;
                default:
                    Serial.println("?");
                    break;
            }
            break;
        case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: //ESP32 station disconnected from AP
            Serial.println("LAN: Event WIFI_STA_DISCONNECTED");
            wifiConnected = false;
            break;
        case ARDUINO_EVENT_WIFI_STA_GOT_IP: // ESP32 station got IPv4 from connected AP. Si tiene IP estatica configurada tambien salta este evento.
            Serial.println("LAN: Event WIFI_STA_GOT_IP");
            Serial.print("LAN: IP: ");
            Serial.print(IPAddress(info.got_ip.ip_info.ip.addr));
            Serial.print(" Subnet Mask: ");
            Serial.print(IPAddress(info.got_ip.ip_info.netmask.addr));
            Serial.print(" Gateway: ");
            Serial.println(IPAddress(info.got_ip.ip_info.gw.addr));
            wifiConnected = true;
            break;
        case ARDUINO_EVENT_WIFI_AP_START: // ESP32 soft-AP start
            Serial.println("LAN: Event WIFI_AP_START");
            break;
        case ARDUINO_EVENT_WIFI_AP_STOP: // ESP32 soft-AP stop
            Serial.println("LAN: Event WIFI_AP_STOP");
            break;
        case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE: // The auth mode of AP connected by ESP32 station changed
            Serial.println("LAN: Event WIFI_STA_AUTHMODE_CHANGE");
            break;
        case ARDUINO_EVENT_WIFI_STA_GOT_IP6: // ESP32 station interface v6IP addr is preferred
            Serial.println("LAN: Event WIFI_STA_GOT_IP6");
            break;
        case ARDUINO_EVENT_WIFI_STA_LOST_IP: // ESP32 station lost IP and the IP is reset to 0
            Serial.println("LAN: Event WIFI_STA_LOST_IP");
            break;
        case ARDUINO_EVENT_WIFI_AP_STACONNECTED: // a station connected to ESP32 soft-AP
            Serial.println("LAN: Event WIFI_AP_STACONNECTED");
            break;
        case ARDUINO_EVENT_WIFI_AP_STADISCONNECTED: // a station disconnected from ESP32 soft-AP
            Serial.println("LAN: Event WIFI_AP_STADISCONNECTED");
            break;
        case ARDUINO_EVENT_WIFI_AP_STAIPASSIGNED: // ESP32 soft-AP assign an IP to a connected station
            Serial.println("LAN: Event WIFI_AP_STAIPASSIGNED");
            break;
        case ARDUINO_EVENT_WIFI_AP_PROBEREQRECVED: // Receive probe request packet in soft-AP interface
            Serial.println("LAN: Event WIFI_AP_PROBEREQRECVED");
            break;
        case ARDUINO_EVENT_WIFI_AP_GOT_IP6: // ESP32 ap interface v6IP addr is preferred
            Serial.println("LAN: Event WIFI_AP_GOT_IP6");
            break;
                case ARDUINO_EVENT_ETH_START: // ESP32 ethernet start
            Serial.println("LAN: Event ETH_START");
            break;
        case ARDUINO_EVENT_ETH_STOP: // ESP32 ethernet stop
            Serial.println("LAN: Event ETH_STOP");
            break;
        case ARDUINO_EVENT_ETH_CONNECTED: // ESP32 ethernet phy link up
            Serial.println("LAN: Event ETH_CONNECTED");
            break;
        case ARDUINO_EVENT_ETH_DISCONNECTED: // ESP32 ethernet phy link down
            Serial.println("LAN: Event ETH_DISCONNECTED");
            ethernetConnected = false;
            break;
        case ARDUINO_EVENT_ETH_GOT_IP: // ESP32 ethernet got IP from connected AP
            Serial.println("LAN: Event ETH_GOT_IP");
            Serial.print("LAN: IP: ");
            Serial.print(IPAddress(info.got_ip.ip_info.ip.addr));
            Serial.print(" Subnet Mask: ");
            Serial.print(IPAddress(info.got_ip.ip_info.netmask.addr));
            Serial.print(" Gateway: ");
            Serial.println(IPAddress(info.got_ip.ip_info.gw.addr));
            ethernetConnected = true;
            break;
        case ARDUINO_EVENT_ETH_GOT_IP6: // ESP32 ethernet interface v6IP addr is preferred
            Serial.println("LAN: Event ETH_GOT_IP6");
            break;
        case ARDUINO_EVENT_WIFI_FTM_REPORT:
            Serial.println("LAN: Event WIFI_FTM_REPORT");
            break;
        case ARDUINO_EVENT_WPS_ER_SUCCESS:
            Serial.println("LAN: Event WPS_ER_SUCCESS");
            break;
        case ARDUINO_EVENT_WPS_ER_FAILED:
            Serial.println("LAN: Event WPS_ER_FAILED");
            break;
        case ARDUINO_EVENT_WPS_ER_TIMEOUT:
            Serial.println("LAN: Event WPS_ER_TIMEOUT");
            break;
        case ARDUINO_EVENT_WPS_ER_PIN:
            Serial.println("LAN: Event WPS_ER_PIN");
            break;
        case ARDUINO_EVENT_WPS_ER_PBC_OVERLAP:
            Serial.println("LAN: Event WPS_ER_PBC_OVERLAP");
            break;
        case ARDUINO_EVENT_SC_SCAN_DONE:
            Serial.println("LAN: Event SC_SCAN_DONE");
            break;
        case ARDUINO_EVENT_SC_FOUND_CHANNEL:
            Serial.println("LAN: Event SC_FOUND_CHANNEL");
            break;
        case ARDUINO_EVENT_SC_GOT_SSID_PSWD:
            Serial.println("LAN: Event SC_GOT_SSID_PSWD");
            break;
        case ARDUINO_EVENT_SC_SEND_ACK_DONE:
            Serial.println("LAN: Event SC_SEND_ACK_DONE");
            break;
        case ARDUINO_EVENT_PROV_INIT:
            Serial.println("LAN: Event PROV_INIT");
            break;
        case ARDUINO_EVENT_PROV_DEINIT:
            Serial.println("LAN: Event PROV_DEINIT");
            break;
        case ARDUINO_EVENT_PROV_START:
            Serial.println("LAN: Event PROV_START");
            break;
        case ARDUINO_EVENT_PROV_END:
            Serial.println("LAN: Event PROV_END");
            break;
        case ARDUINO_EVENT_PROV_CRED_RECV:
            Serial.println("LAN: Event PROV_CRED_RECV");
            break;
        case ARDUINO_EVENT_PROV_CRED_FAIL:
            Serial.println("LAN: Event PROV_CRED_FAIL");
            break;
        case ARDUINO_EVENT_PROV_CRED_SUCCESS:
            Serial.println("LAN: Event PROV_CRED_SUCCESS");
            break;
        default:
            Serial.println("LAN: Event UNHANDLED");
            break;
    }
}



void setup()
{
    Serial.begin(115200);

    WiFi.disconnect(true);

    delay(1000);

    WiFi.onEvent(eventHandler);

    // This is my PHY power pin.
    pinMode(12, OUTPUT);
    digitalWrite(12, HIGH);
    delay(500);
    
    ETH.begin();
    //ETH.config(IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u));

    //WiFi.config(IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u),IPAddress(0u));
    WiFi.begin(ssid, password);

}

void loop() {
    static uint32_t timer = millis();
    static uint32_t timerMqtt = millis();

    if(millis() - timer > 5000) {
        timer = millis();
        Serial.print("WiFi IP: ");
        Serial.println(WiFi.localIP());
        Serial.print("WiFi DNS: ");
        Serial.print(WiFi.dnsIP(0));
        Serial.print(" ");
        Serial.println(WiFi.dnsIP(1));
        Serial.print("Ethernet IP: ");
        Serial.println(ETH.localIP());
        Serial.print("Ethernet DNS: ");
        Serial.print(ETH.dnsIP(0));
        Serial.print(" ");
        Serial.println(ETH.dnsIP(1));
    }

    if((ethernetConnected || wifiConnected)) {

        if(millis() - timerMqtt > 5000) {
            timerMqtt = millis();
     
            if(wifiClientSecure.connected()) {
                Serial.print("I'm connected from the interface with IP: ");
                Serial.println(wifiClientSecure.localIP());
            }
            else {
                Serial.println("I'm not connected!");
                wifiClientSecure.setInsecure();
                if(wifiClientSecure.connect(mqttServer, mqttPort)) {
                    Serial.println("I'm connected!");
                }
                else {
                    Serial.println("Failed to connect!");
                }
            }
        }
        
    }
}

Debug Message

WiFi IP: 0.0.0.0
WiFi DNS: 0.0.0.0 0.0.0.0
Ethernet IP: 192.168.10.74
Ethernet DNS: 0.0.0.0 0.0.0.0
I'm not connected!
[403506][E][WiFiGeneric.cpp:1438] hostByName(): DNS Failed for test.mosquitto.org
[403506][E][WiFiClientSecure.cpp:135] connect(): start_ssl_client: -1
Failed to connect!

Other Steps to Reproduce

No response

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@gonzabrusco gonzabrusco added the Status: Awaiting triage Issue is waiting for triage label Dec 19, 2022
@gonzabrusco gonzabrusco changed the title Ethernet + WiFi: Shared DNS. WiFi + Ethernet (LAN8720): Shared DNS? Dec 19, 2022
@gonzabrusco gonzabrusco changed the title WiFi + Ethernet (LAN8720): Shared DNS? WiFi + Ethernet (LAN8720): DNS Server Managment Dec 19, 2022
@me-no-dev
Copy link
Member

Ethernet would need to be updated here and here to use the netif API, like it's done for WiFi. That should fix the problem 🤞

@me-no-dev me-no-dev added Type: Bug 🐛 All bugs Area: BT&Wifi BT & Wifi related issues and removed Status: Awaiting triage Issue is waiting for triage labels Dec 19, 2022
@gonzabrusco
Copy link
Contributor Author

gonzabrusco commented Dec 20, 2022

@me-no-dev not sure if it's "just that". Because as you can see in my tests, Ethernet does not work if you power on everything with the Ethernet cable plugged and just calling ETH.begin() and WiFi.begin() with an unexistent SSID.

As you can see, that particular bug occurs without calling any config(). So I think the bug it's a bit more complex. It's not just the setters and getters of the DNS servers. It's the way Ethernet and Wifi initializes.

If I just call ETH.begin() without calling WiFi.begin() it works right away (with the Ethernet cable plugged before powering up). But if you call WiFi.begin() with an unexistent SSID right after ETH.begin() the DNS resolution starts to fail.

So I think WiFi.begin() is also messing with the Ethernet DNS.

The only way to fix this bug is to call both config() methods as stated on the bug report.

@TD-er
Copy link
Contributor

TD-er commented Dec 23, 2022

When closing WiFi, you also erase the DNS entries.

What I do in ESPEasy as a work-around is that I keep a copy of the received DNS records from the DHCP.
Then I restore the DNS settings whenever a DNS lookup failed.

Typical use case:

  • ESP is booted with Ethernet cable not connected.
  • WiFi is started to find an AP to connect to.
  • Eth gets connected + gets IP from DHCP server
  • WiFi is turned off -> clears DNS entries.

@TD-er
Copy link
Contributor

TD-er commented Jan 7, 2023

I have done some more research on this topic.

For sure the DNS server IPs get reset (or set to some random value) when the WiFi interface is turned off.
However, it used to be that on the next DHCP lease renew, those would be restored.

On the latest SDK revisions, things have changed for the worse.
Where these DNS IP addresses used to be cleared to 0.0.0.0, on my nodes they now get some seemingly random value of 253.0.0.0
No idea if that's part of another field in the DHCP reply, or perhaps some uninitialized value somewhere.

Another change is that this mangling of the DNS server IPs is done on every DHCP lease renewal.
Thus in my network, which has the DHCP lease time set to 10 minutes, this already occurs after 5-ish minutes.

So not only is it a really poor design decision to only have a single set of DNS IPs instead of per interface, but also clearing it when shutting down one interface will mess up the DNS config of another.
I think a better solution would be to clear (or set with static IP config) the DNS server IPs when starting a new connection, not when closing the interface.

Also the DHCP lease renewal apparently differs from the initial DHCP request.
Or at least handling of the result differs.

The work-around I just implemented for ESPEasy is to cache the DNS server IPs per interface.
Every time I intend to do a DNS lookup, or make a connection, I check to see if the DNS server IPs should be restored from the cache.
When initiating a new connection on that interface, I clear the cached values.

If/When someone is going to look into this, I would also make a feature request to get access to some extra DHCP optional fields, like syslog server IP and NTP server IP.

@s-hadinger
Copy link
Contributor

The limitation comes from LWIP which uses the same pair of DNS servers for all interfaces, whether IPv4 or IPv6.

In Tasmota, I had to make sure that we keep a copy of 2x DNS IPv4 and 2x DNS IPv6 servers, and force them back in place whenever LWIP clears them.

https://github.com/arendst/Tasmota/blob/7465ff0c7f3341555d11c219e0a6b5f60c7ff6e8/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp#L64-L129

@TD-er
Copy link
Contributor

TD-er commented Jan 7, 2023

Ah, that's even nastier. Did not realize you only had the same 2 for both IPv4 and IPv6.
Can you "combine" them? Like 1st one for IPv6 and 2nd one for IPv4 if you prefer IPv6 lookup first?

@s-hadinger
Copy link
Contributor

No you can't. The resolver always prefers the first one and moved to second if the first times out

@Jason2866
Copy link
Collaborator

@VojtechBartoska @me-no-dev Can this bug added too milestone 2.0.7?
There is alot of workaround code needed to handle this bug.

@me-no-dev
Copy link
Member

@Jason2866 it will not make it to 2.0.7 unless someone submits a PR with fixes. We already have quite a bit to look into and 2.0.7 needs to come out fast

@Jason2866
Copy link
Collaborator

Ahh, okay. Sorry no PR to fix.

@mrengineer7777
Copy link
Collaborator

Possibly related #8672

@VojtechBartoska
Copy link
Contributor

Hi @gonzabrusco is this still valid in version 2.0.14? Can you please test if you still face the issue on latest release of 2.X? Thanks

@VojtechBartoska VojtechBartoska added the Resolution: Awaiting response Waiting for response of author label Dec 11, 2023
@VojtechBartoska
Copy link
Contributor

This will be probably covered by #8760

@VojtechBartoska VojtechBartoska modified the milestones: 3.0.0, 3.0.0-RC1 Feb 20, 2024
@gonzabrusco
Copy link
Contributor Author

Sorry. I can't test it right now. I will let you know later or when 3.0.0 is released. @VojtechBartoska

@VojtechBartoska VojtechBartoska moved this from Todo to In Progress in Arduino ESP32 Core Project Roadmap Feb 21, 2024
@VojtechBartoska
Copy link
Contributor

Hello, can you please validate this against 3.0.0-RC1 version? Thanks

@VojtechBartoska VojtechBartoska modified the milestones: 3.0.0-RC1, 3.0.0-RC2 Apr 12, 2024
@VojtechBartoska VojtechBartoska added the Status: Test needed Issue needs testing label Apr 12, 2024
@VojtechBartoska VojtechBartoska moved this from In Progress to In Review in Arduino ESP32 Core Project Roadmap Apr 12, 2024
@VojtechBartoska
Copy link
Contributor

This is supposed to be solved, I am closing this ticket. If needed, you can reopen. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: BT&Wifi BT & Wifi related issues Resolution: Awaiting response Waiting for response of author Status: Test needed Issue needs testing Type: Bug 🐛 All bugs
Projects
Development

No branches or pull requests

7 participants