diff --git a/lib/core-net/network.c b/lib/core-net/network.c index c4b3404df..44fb8d8c5 100644 --- a/lib/core-net/network.c +++ b/lib/core-net/network.c @@ -22,13 +22,14 @@ #include "core/private.h" #if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE) -LWS_VISIBLE int +static int interface_to_sa(struct lws_vhost *vh, const char *ifname, - struct sockaddr_in *addr, size_t addrlen) + struct sockaddr_in *addr, size_t addrlen, int allow_ipv6) { int ipv6 = 0; #ifdef LWS_WITH_IPV6 - ipv6 = LWS_IPV6_ENABLED(vh); + if (allow_ipv6) + ipv6 = LWS_IPV6_ENABLED(vh); #endif (void)vh; @@ -205,7 +206,7 @@ bail: LWS_EXTERN int lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, - const char *iface) + const char *iface, int ipv6_allowed) { #ifdef LWS_WITH_UNIX_SOCK struct sockaddr_un serv_unix; @@ -248,13 +249,13 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, } else #endif #if defined(LWS_WITH_IPV6) && !defined(LWS_WITH_ESP32) - if (LWS_IPV6_ENABLED(vhost)) { + if (ipv6_allowed && LWS_IPV6_ENABLED(vhost)) { v = (struct sockaddr *)&serv_addr6; n = sizeof(struct sockaddr_in6); bzero((char *) &serv_addr6, sizeof(serv_addr6)); if (iface) { m = interface_to_sa(vhost, iface, - (struct sockaddr_in *)v, n); + (struct sockaddr_in *)v, n, 1); if (m == LWS_ITOSA_NOT_USABLE) { lwsl_info("%s: netif %s: Not usable\n", __func__, iface); @@ -282,7 +283,7 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, #if !defined(LWS_WITH_ESP32) && !defined(LWS_PLAT_OPTEE) if (iface) { m = interface_to_sa(vhost, iface, - (struct sockaddr_in *)v, n); + (struct sockaddr_in *)v, n, 0); if (m == LWS_ITOSA_NOT_USABLE) { lwsl_info("%s: netif %s: Not usable\n", __func__, iface); diff --git a/lib/core-net/private.h b/lib/core-net/private.h index 887bbbd8e..3716b6bfe 100644 --- a/lib/core-net/private.h +++ b/lib/core-net/private.h @@ -648,7 +648,7 @@ lws_role_by_name(const char *name); LWS_EXTERN int lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, - const char *iface); + const char *iface, int ipv6_allowed); #if defined(LWS_WITH_IPV6) LWS_EXTERN unsigned long diff --git a/lib/core/private.h b/lib/core/private.h index 3155ba2b7..90fec4376 100644 --- a/lib/core/private.h +++ b/lib/core/private.h @@ -472,9 +472,6 @@ lws_b64_selftest(void); #define get_daemonize_pid() (0) #endif -LWS_EXTERN int LWS_WARN_UNUSED_RESULT -interface_to_sa(struct lws_vhost *vh, const char *ifname, - struct sockaddr_in *addr, size_t addrlen); LWS_EXTERN void lwsl_emit_stderr(int level, const char *line); #if !defined(LWS_WITH_TLS) diff --git a/lib/plat/unix/unix-sockets.c b/lib/plat/unix/unix-sockets.c index 2b5528677..63dc2374c 100644 --- a/lib/plat/unix/unix-sockets.c +++ b/lib/plat/unix/unix-sockets.c @@ -210,6 +210,7 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, memcpy(&addr6->sin6_addr.s6_addr[12], &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr, sizeof(struct in_addr)); + lwsl_debug("%s: uplevelling ipv4 bind to ipv6\n", __func__); } else #endif memcpy(addr, diff --git a/lib/roles/http/client/client-handshake.c b/lib/roles/http/client/client-handshake.c index a7e9fdc8a..6b88cc885 100644 --- a/lib/roles/http/client/client-handshake.c +++ b/lib/roles/http/client/client-handshake.c @@ -51,7 +51,7 @@ lws_client_connect_2(struct lws *wsi) char ipv6only = lws_check_opt(wsi->vhost->options, LWS_SERVER_OPTION_IPV6_V6ONLY_MODIFY | LWS_SERVER_OPTION_IPV6_V6ONLY_VALUE); - + struct sockaddr_in addr; #if defined(__ANDROID__) ipv6only = 0; #endif @@ -228,6 +228,18 @@ create_new_conn: * start off allowing ipv6 on connection if vhost allows it */ wsi->ipv6 = LWS_IPV6_ENABLED(wsi->vhost); +#ifdef LWS_WITH_IPV6 + if (wsi->stash) + iface = wsi->stash->iface; + else + iface = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_IFACE); + + if (wsi->ipv6 && iface && + inet_pton(AF_INET, iface, &addr.sin_addr) == 1) { + lwsl_notice("%s: client connection forced to IPv4\n", __func__); + wsi->ipv6 = 0; + } +#endif #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) @@ -464,7 +476,7 @@ ads_known: if (iface) { n = lws_socket_bind(wsi->vhost, wsi->desc.sockfd, 0, - iface); + iface, wsi->ipv6); if (n < 0) { cce = "unable to bind socket"; goto failed; diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index ed5258baa..cbf83866d 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -84,7 +84,7 @@ _lws_vhost_init_server(const struct lws_context_creation_info *info, * of the interface he wants to bind to... */ is = lws_socket_bind(vhost, LWS_SOCK_INVALID, vhost->listen_port, - vhost->iface); + vhost->iface, 1); lwsl_debug("initial if check says %d\n", is); if (is == LWS_ITOSA_BUSY) @@ -233,7 +233,7 @@ done_list: #endif lws_plat_set_socket_options(vhost, sockfd, 0); - is = lws_socket_bind(vhost, sockfd, vhost->listen_port, vhost->iface); + is = lws_socket_bind(vhost, sockfd, vhost->listen_port, vhost->iface, 1); if (is == LWS_ITOSA_BUSY) { /* treat as fatal */ compatible_close(sockfd);