Skip to content

Latest commit

 

History

History
223 lines (153 loc) · 7.73 KB

README.md

File metadata and controls

223 lines (153 loc) · 7.73 KB

ESP DNS Component

This component provides a flexible DNS resolution system for ESP32 devices with support for multiple DNS protocols. It allows applications to resolve domain names using various transport methods, including standard UDP/TCP DNS, and securely resolve them using DNS over TLS (DoT) and DNS over HTTPS (DoH).

Table of Contents

Features

  • Multiple Protocol Support Choose from various DNS protocols:

    • Standard UDP DNS (Port 53)
    • TCP DNS (Port 53)
    • DNS over TLS (DoT) (Port 853)
    • DNS over HTTPS (DoH) (Port 443)
  • Secure DNS Resolution: Supports encrypted DNS queries using TLS and HTTPS to protect privacy and prevent DNS spoofing.

  • Flexible Configuration: Easily configure DNS servers, ports, timeouts, and protocol-specific options.

  • LWIP Integration: Seamlessly integrates with the ESP-IDF networking stack through LWIP hooks.

  • Standard getaddrinfo() Interface: Use the standard getaddrinfo() function to resolve domain names.

Requirements

  • ESP-IDF v5.0 or newer
  • Network connectivity (Wi-Fi or Ethernet)
  • For DoT/DoH: Sufficient RAM for TLS operations

How to Use

1. Enable custom DNS resolution

To enable custom DNS resolution, configure the CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM setting either through menuconfig or by adding CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM=y to your sdkconfig.defaults file to pre-set the configuration during the build process.

2. Configure DNS Settings

Initialize the DNS component with your preferred configuration:

#include "esp_dns.h"

/* Configure DNS over HTTPS */
esp_dns_config_t dns_config = {
    .dns_server = "dns.google",            /* DNS server hostname or IP address */
    .port = ESP_DNS_DEFAULT_DOH_PORT,      /* Optional: Server port (443 is default for HTTPS) */
    .timeout_ms = ESP_DNS_DEFAULT_TIMEOUT_MS, /* Optional: Request timeout in milliseconds (10000ms default) */
    .tls_config = {
        /* Optional: Use ESP-IDF certificate bundle for validating popular DNS providers */
        .crt_bundle_attach = esp_crt_bundle_attach,

        /* Or provide a custom certificate in PEM format (string) for your DNS server */
        /* Note: Only PEM format is supported; DER format certificates are not supported yet */
        .cert_pem = server_root_cert_pem_start,

        /* Note: If both crt_bundle_attach and cert_pem are provided,
           crt_bundle_attach is preferred over cert_pem */
    },
    .protocol_config.doh_config = {
        .url_path = "/dns-query",          /* Optional: DoH endpoint path on the server ("/dns-query" default) */
    }
};

/* Initialize DNS component based on protocol */
esp_dns_handle_t dns_handle = NULL;

/* Call esp_dns_init_doh() to use DNS over HTTPS */
dns_handle = esp_dns_init_doh(&dns_config);

/* or Call esp_dns_init_dot() to use DNS over TLS */
dns_handle = esp_dns_init_dot(&dns_config);

/* or Call esp_dns_init_tcp() to use DNS over TCP */
dns_handle = esp_dns_init_tcp(&dns_config);

/* or Call esp_dns_init_udp() to use DNS over UDP */
dns_handle = esp_dns_init_udp(&dns_config);

if (dns_handle == NULL) {
    ESP_LOGE(TAG, "Failed to initialize DNS");
    return;
}

3. Resolve Domain Names

Once initialized, the component automatically handles DNS resolution through the standard getaddrinfo() function:

struct addrinfo hints = {
    .ai_family = AF_UNSPEC,
    .ai_socktype = SOCK_STREAM,
};
struct addrinfo res;
int err = getaddrinfo("www.example.com", "80", &hints, &res);
if (err != 0) {
    ESP_LOGE(TAG, "DNS lookup failed: %d", err);
    return;
}
/* Use the resolved addresses */
/* ... */

/* Free the address info when done */
freeaddrinfo(res);

4. Cleanup

When you're done using the DNS component, clean up resources based on the protocol used:

int ret = 0;
/* Call esp_dns_cleanup_doh() to cleanup DNS over HTTPS */
ret = esp_dns_cleanup_doh(dns_handle);

/* or Call esp_dns_cleanup_dot() to cleanup DNS over TLS */
ret = esp_dns_cleanup_dot(dns_handle);

/* or Call esp_dns_cleanup_tcp() to cleanup DNS over TCP */
ret = esp_dns_cleanup_tcp(dns_handle);

/* or Call esp_dns_cleanup_udp() to cleanup DNS over UDP */
ret = esp_dns_cleanup_udp(dns_handle);

if (ret != 0) {
    ESP_LOGE(TAG, "Failed to cleanup DNS");
}

Configuration

Setting Up the ESP DNS Component

  1. Navigate to your project directory.
  2. Execute idf.py menuconfig.
  3. Locate the Component config -> LWIP -> Hooks -> Netconn external resolve Hook section.
  4. Change the setting to Custom implementation.

Common Settings

Parameter Description Default Value
dns_server IP address or hostname of DNS server "8.8.8.8" (Google DNS)
port Server port number Protocol-dependent (53, 853, or 443)
timeout_ms Query timeout in milliseconds 10000 (10 seconds)

TLS Configuration (for DoT and DoH)

Parameter Description
crt_bundle_attach Function pointer to attach certificate bundle
server_cert SSL server certificate in PEM format
alpn_protos ALPN protocols for DoH (typically "h2")

Protocol-Specific Options

DoH Options

  • URL Path: URL path for DoH service (e.g., "/dns-query")

Certificate Options

When using secure DNS protocols (DoT and DoH), you have two certificate options:

  1. Certificate Bundle: Use ESP-IDF's certificate bundle for validating connections to popular DNS providers.
  2. Custom Certificate: Provide your own certificate in PEM format for custom DNS servers.

Limitations

  • The UDP DNS protocol implementation relies on the native LWIP DNS resolver.

  • Transport protocol selection must be configured through esp_dns_init_xxx() rather than getaddrinfo() parameters due to LWIP resolver hook limitations.

  • Maximum response size is limited by the buffer size (default: 512 bytes) for DNS over TLS (DOT) and TCP protocols.

  • Only one DNS protocol can be active at a time.

  • Resolution Speed:

    • UDP DNS is fastest but least secure
    • DoH typically has the highest latency but offers the best security

Performance Considerations

  • Memory Usage: DoH and DoT require more memory due to TLS overhead:

TBD: Fill in the memory usage for each protocol

How It Works

This component utilizes the CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM hook to override the core DNS functionality of LWIP and implement custom DNS over HTTPS resolution. To enable this, ensure that the configuration option Component config → LWIP → Hooks → Netconn external resolve Hook is set to Custom implementation.

Once you add this component to your project, it will replace the default LWIP DNS resolution automatically.

⚠️ Warning: This component cannot work alongside other components that use the CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM hook.

Troubleshooting

  • Connection Issues:

    • Ensure network connectivity and correct DNS server configuration
    • Verify that your network allows the required ports (53, 853, or 443)
  • Certificate Errors:

    • Verify that the correct certificate is provided for secure protocols
    • For public DNS servers, use the certificate bundle approach
  • Timeout Errors:

    • Increase the timeout value for slow network connections
    • Try a different DNS server that might be geographically closer
  • Memory Issues:

    • If you encounter memory errors, consider increasing the task stack size
    • For memory-constrained devices, prefer UDP DNS.