From d42f35de5d5416825a02fd4457e32ac781e6cd9d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 22 Mar 2023 09:24:14 +1300 Subject: [PATCH] Wrap ipv6 code a bit more (#4574) * Wrap ipv6 code a bit more for when ipv6 support should not be compiled in * More checks * More uses * Fix --- esphome/components/api/api_server.cpp | 2 +- .../ethernet/ethernet_component.cpp | 13 ++++++++ esphome/components/mqtt/mqtt_client.cpp | 14 ++++++-- esphome/components/network/__init__.py | 8 +++-- esphome/components/ota/ota_component.cpp | 2 +- .../components/socket/bsd_sockets_impl.cpp | 5 ++- esphome/components/socket/headers.h | 15 +++++++-- esphome/components/socket/socket.cpp | 32 +++++++++++++++++-- esphome/components/socket/socket.h | 5 ++- .../wifi/wifi_component_esp32_arduino.cpp | 20 +++++++++--- .../wifi/wifi_component_esp_idf.cpp | 16 +++++++++- 11 files changed, 112 insertions(+), 20 deletions(-) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 6e28637241..acde0966ba 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -45,7 +45,7 @@ void APIServer::setup() { struct sockaddr_storage server; - socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_)); + socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_); if (sl == 0) { ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); this->mark_failed(); diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 7120223cc9..4792728a71 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -255,14 +255,22 @@ void EthernetComponent::start_connect_() { if (this->manual_ip_.has_value()) { if (uint32_t(this->manual_ip_->dns1) != 0) { ip_addr_t d; +#if LWIP_IPV6 d.type = IPADDR_TYPE_V4; d.u_addr.ip4.addr = static_cast(this->manual_ip_->dns1); +#else + d.addr = static_cast(this->manual_ip_->dns1); +#endif dns_setserver(0, &d); } if (uint32_t(this->manual_ip_->dns1) != 0) { ip_addr_t d; +#if LWIP_IPV6 d.type = IPADDR_TYPE_V4; d.u_addr.ip4.addr = static_cast(this->manual_ip_->dns2); +#else + d.addr = static_cast(this->manual_ip_->dns2); +#endif dns_setserver(1, &d); } } else { @@ -289,8 +297,13 @@ void EthernetComponent::dump_connect_params_() { const ip_addr_t *dns_ip1 = dns_getserver(0); const ip_addr_t *dns_ip2 = dns_getserver(1); +#if LWIP_IPV6 ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str()); ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str()); +#else + ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->addr).str().c_str()); + ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str()); +#endif esp_err_t err; diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index acb863244e..af2828ff15 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -2,16 +2,16 @@ #ifdef USE_MQTT +#include +#include "esphome/components/network/util.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/components/network/util.h" -#include #ifdef USE_LOGGER #include "esphome/components/logger/logger.h" #endif -#include "lwip/err.h" #include "lwip/dns.h" +#include "lwip/err.h" #include "mqtt_component.h" namespace esphome { @@ -104,7 +104,11 @@ void MQTTClientComponent::start_dnslookup_() { // Got IP immediately this->dns_resolved_ = true; #ifdef USE_ESP32 +#if LWIP_IPV6 this->ip_ = addr.u_addr.ip4.addr; +#else + this->ip_ = addr.addr; +#endif #endif #ifdef USE_ESP8266 this->ip_ = addr.addr; @@ -160,8 +164,12 @@ void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t * a_this->dns_resolve_error_ = true; } else { #ifdef USE_ESP32 +#if LWIP_IPV6 a_this->ip_ = ipaddr->u_addr.ip4.addr; +#else + a_this->ip_ = ipaddr->addr; #endif +#endif // USE_ESP32 #ifdef USE_ESP8266 a_this->ip_ = ipaddr->addr; #endif diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 40d420c48c..96cfc51ff5 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -22,6 +22,8 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): - if CONF_ENABLE_IPV6 in config and config[CONF_ENABLE_IPV6]: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", True) - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", True) + if CONF_ENABLE_IPV6 in config: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) + add_idf_sdkconfig_option( + "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + ) diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp index 0195cb4616..39ba3dbed4 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/ota/ota_component.cpp @@ -65,7 +65,7 @@ void OTAComponent::setup() { struct sockaddr_storage server; - socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_)); + socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_); if (sl == 0) { ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); this->mark_failed(); diff --git a/esphome/components/socket/bsd_sockets_impl.cpp b/esphome/components/socket/bsd_sockets_impl.cpp index b21341e4d6..3a08e3ea52 100644 --- a/esphome/components/socket/bsd_sockets_impl.cpp +++ b/esphome/components/socket/bsd_sockets_impl.cpp @@ -20,7 +20,9 @@ std::string format_sockaddr(const struct sockaddr_storage &storage) { char buf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) != nullptr) return std::string{buf}; - } else if (storage.ss_family == AF_INET6) { + } +#if LWIP_IPV6 + else if (storage.ss_family == AF_INET6) { const struct sockaddr_in6 *addr = reinterpret_cast(&storage); char buf[INET6_ADDRSTRLEN]; // Format IPv4-mapped IPv6 addresses as regular IPv4 addresses @@ -32,6 +34,7 @@ std::string format_sockaddr(const struct sockaddr_storage &storage) { if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) != nullptr) return std::string{buf}; } +#endif return {}; } diff --git a/esphome/components/socket/headers.h b/esphome/components/socket/headers.h index 1e79c8a1ab..20d8fdb8c9 100644 --- a/esphome/components/socket/headers.h +++ b/esphome/components/socket/headers.h @@ -15,19 +15,28 @@ /* Address families. */ #define AF_UNSPEC 0 #define AF_INET 2 -#define AF_INET6 10 #define PF_INET AF_INET -#define PF_INET6 AF_INET6 #define PF_UNSPEC AF_UNSPEC + #define IPPROTO_IP 0 #define IPPROTO_TCP 6 + +#if LWIP_IPV6 +#define AF_INET6 10 +#define PF_INET6 AF_INET6 + #define IPPROTO_IPV6 41 #define IPPROTO_ICMPV6 58 +#endif #define TCP_NODELAY 0x01 #define F_GETFL 3 #define F_SETFL 4 + +#ifdef O_NONBLOCK +#undef O_NONBLOCK +#endif #define O_NONBLOCK 1 #define SHUT_RD 0 @@ -58,6 +67,7 @@ struct sockaddr_in { char sin_zero[SIN_ZERO_LEN]; }; +#if LWIP_IPV6 // NOLINTNEXTLINE(readability-identifier-naming) struct sockaddr_in6 { uint8_t sin6_len; /* length of this structure */ @@ -67,6 +77,7 @@ struct sockaddr_in6 { struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* Set of interfaces for scope */ }; +#endif // NOLINTNEXTLINE(readability-identifier-naming) struct sockaddr { diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 22a4c11df8..3fe7491d57 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -14,6 +14,34 @@ std::unique_ptr socket_ip(int type, int protocol) { #endif } +socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port) { +#if LWIP_IPV6 + if (addrlen < sizeof(sockaddr_in6)) { + errno = EINVAL; + return 0; + } + auto *server = reinterpret_cast(addr); + memset(server, 0, sizeof(sockaddr_in6)); + server->sin6_family = AF_INET6; + server->sin6_port = htons(port); + ip6_addr_t ip6; + inet6_aton(ip_address, &ip6); + memcpy(server->sin6_addr.un.u32_addr, ip6.addr, sizeof(ip6.addr)); + return sizeof(sockaddr_in6); +#else + if (addrlen < sizeof(sockaddr_in)) { + errno = EINVAL; + return 0; + } + auto *server = reinterpret_cast(addr); + memset(server, 0, sizeof(sockaddr_in)); + server->sin_family = AF_INET; + server->sin_addr.s_addr = inet_addr(ip_address); + server->sin_port = htons(port); + return sizeof(sockaddr_in); +#endif +} + socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) { #if LWIP_IPV6 if (addrlen < sizeof(sockaddr_in6)) { @@ -23,7 +51,7 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po auto *server = reinterpret_cast(addr); memset(server, 0, sizeof(sockaddr_in6)); server->sin6_family = AF_INET6; - server->sin6_port = port; + server->sin6_port = htons(port); server->sin6_addr = in6addr_any; return sizeof(sockaddr_in6); #else @@ -35,7 +63,7 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po memset(server, 0, sizeof(sockaddr_in)); server->sin_family = AF_INET; server->sin_addr.s_addr = ESPHOME_INADDR_ANY; - server->sin_port = port; + server->sin_port = htons(port); return sizeof(sockaddr_in); #endif } diff --git a/esphome/components/socket/socket.h b/esphome/components/socket/socket.h index ecf117deeb..175cb21a4a 100644 --- a/esphome/components/socket/socket.h +++ b/esphome/components/socket/socket.h @@ -44,7 +44,10 @@ std::unique_ptr socket(int domain, int type, int protocol); /// Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol. std::unique_ptr socket_ip(int type, int protocol); -/// Set a sockaddr to the any address for the IP version used by socket_ip(). +/// Set a sockaddr to the specified address and port for the IP version used by socket_ip(). +socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port); + +/// Set a sockaddr to the any address and specified port for the IP version used by socket_ip(). socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port); } // namespace socket diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 54ed7638d2..ab04224161 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -4,19 +4,19 @@ #include -#include #include +#include #ifdef USE_WIFI_WPA2_EAP #include #endif -#include "lwip/err.h" -#include "lwip/dns.h" #include "lwip/apps/sntp.h" +#include "lwip/dns.h" +#include "lwip/err.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" -#include "esphome/core/application.h" #include "esphome/core/util.h" namespace esphome { @@ -128,13 +128,23 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } ip_addr_t dns; +#if LWIP_IPV6 dns.type = IPADDR_TYPE_V4; +#endif if (uint32_t(manual_ip->dns1) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns1); +#else + dns.addr = static_cast(manual_ip->dns1); +#endif dns_setserver(0, &dns); } if (uint32_t(manual_ip->dns2) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns2); +#else + dns.addr = static_cast(manual_ip->dns2); +#endif dns_setserver(1, &dns); } diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 2883164495..0f3c3a0ca8 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -451,13 +451,23 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } ip_addr_t dns; +#if LWIP_IPV6 dns.type = IPADDR_TYPE_V4; +#endif if (uint32_t(manual_ip->dns1) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns1); +#else + dns.addr = static_cast(manual_ip->dns1); +#endif dns_setserver(0, &dns); } if (uint32_t(manual_ip->dns2) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns2); +#else + dns.addr = static_cast(manual_ip->dns2); +#endif dns_setserver(1, &dns); } @@ -639,7 +649,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) { const auto &it = data->data.ip_got_ip; -#ifdef LWIP_IPV6_AUTOCONFIG +#if LWIP_IPV6_AUTOCONFIG tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); #endif ESP_LOGV(TAG, "Event: Got IP static_ip=%s gateway=%s", format_ip4_addr(it.ip_info.ip).c_str(), @@ -912,7 +922,11 @@ network::IPAddress WiFiComponent::wifi_gateway_ip_() { } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { const ip_addr_t *dns_ip = dns_getserver(num); +#if LWIP_IPV6 return {dns_ip->u_addr.ip4.addr}; +#else + return {dns_ip->addr}; +#endif } } // namespace wifi