From af7f943e050ba26f0a4c29d38c8bc9dd50ef89be Mon Sep 17 00:00:00 2001 From: Leonardo Maccari Rufino Date: Mon, 5 Jun 2017 13:59:22 -0300 Subject: [PATCH] Subject: windows: support to bind to a specific IPv6 address --- lib/libwebsockets.c | 144 ++++++++++++++++++++++++++++++++------------ lib/lws-plat-esp32.c | 6 ++ lib/lws-plat-esp8266.c | 7 +++ lib/lws-plat-optee.c | 7 +++ lib/lws-plat-unix.c | 6 ++ lib/lws-plat-win.c | 63 +++++++++++++++++++ lib/private-libwebsockets.h | 7 +++ 7 files changed, 203 insertions(+), 37 deletions(-) diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 1f9182a..53cb12b 100755 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -1906,46 +1906,14 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, v = (struct sockaddr *)&serv_addr6; n = sizeof(struct sockaddr_in6); bzero((char *) &serv_addr6, sizeof(serv_addr6)); - if (iface && - interface_to_sa(vhost, iface, - (struct sockaddr_in *)v, n) < 0) { - lwsl_err("Unable to find interface %s\n", iface); - return -1; - } - -#ifndef WIN32 if (iface) { - struct ifaddrs *addrs, *addr; - char ip[NI_MAXHOST]; - unsigned int i; - - getifaddrs(&addrs); - for (addr = addrs; addr; addr = addr->ifa_next) { - if (!addr->ifa_addr || - addr->ifa_addr->sa_family != AF_INET6) - continue; - - getnameinfo(addr->ifa_addr, - sizeof(struct sockaddr_in6), - ip, sizeof(ip), - NULL, 0, NI_NUMERICHOST); - - i = 0; - while (ip[i]) - if (ip[i++] == '%') { - ip[i - 1] = '\0'; - break; - } - - if (!strcmp(ip, iface)) { - serv_addr6.sin6_scope_id = - if_nametoindex(addr->ifa_name); - break; - } + if (interface_to_sa(vhost, iface, + (struct sockaddr_in *)v, n) < 0) { + lwsl_err("Unable to find interface %s\n", iface); + return -1; } - freeifaddrs(addrs); + serv_addr6.sin6_scope_id = lws_get_addr_scope(iface); } -#endif serv_addr6.sin6_family = AF_INET6; serv_addr6.sin6_port = htons(port); @@ -2000,6 +1968,108 @@ lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, return port; } +#if defined(LWS_USE_IPV6) +LWS_EXTERN unsigned long +lws_get_addr_scope(const char *ipaddr) +{ + unsigned long scope = 0; + +#ifndef WIN32 + struct ifaddrs *addrs, *addr; + char ip[NI_MAXHOST]; + unsigned int i; + + getifaddrs(&addrs); + for (addr = addrs; addr; addr = addr->ifa_next) { + if (!addr->ifa_addr || + addr->ifa_addr->sa_family != AF_INET6) + continue; + + getnameinfo(addr->ifa_addr, + sizeof(struct sockaddr_in6), + ip, sizeof(ip), + NULL, 0, NI_NUMERICHOST); + + i = 0; + while (ip[i]) + if (ip[i++] == '%') { + ip[i - 1] = '\0'; + break; + } + + if (!strcmp(ip, ipaddr)) { + scope = if_nametoindex(addr->ifa_name); + break; + } + } + freeifaddrs(addrs); +#else + PIP_ADAPTER_ADDRESSES adapter, addrs = NULL; + PIP_ADAPTER_UNICAST_ADDRESS addr; + ULONG size = 0; + DWORD ret; + struct sockaddr_in6 *sockaddr; + char ip[NI_MAXHOST]; + unsigned int i; + int found = 0; + + for (i = 0; i < 5; i++) + { + ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, + NULL, addrs, &size); + if ((ret == NO_ERROR) || (ret == ERROR_NO_DATA)) { + break; + } else if (ret == ERROR_BUFFER_OVERFLOW) + { + if (addrs) + free(addrs); + addrs = (IP_ADAPTER_ADDRESSES *) malloc(size); + } else + { + if (addrs) + { + free(addrs); + addrs = NULL; + } + lwsl_err("Failed to get IPv6 address table (%d)", ret); + break; + } + } + + if ((ret == NO_ERROR) && (addrs)) + { + adapter = addrs; + while ((adapter) && (!found)) + { + addr = adapter->FirstUnicastAddress; + while ((addr) && (!found)) + { + if (addr->Address.lpSockaddr->sa_family == AF_INET6) + { + sockaddr = (struct sockaddr_in6 *) (addr->Address.lpSockaddr); + + lws_plat_inet_ntop(sockaddr->sin6_family, &sockaddr->sin6_addr, + ip, sizeof(ip)); + + if (!strcmp(ip, ipaddr)) { + scope = sockaddr->sin6_scope_id; + found = 1; + break; + } + } + addr = addr->Next; + } + adapter = adapter->Next; + } + } + if (addrs) + free(addrs); +#endif + + return scope; +} +#endif + LWS_EXTERN void lws_restart_ws_ping_pong_timer(struct lws *wsi) { diff --git a/lib/lws-plat-esp32.c b/lib/lws-plat-esp32.c index 3356963..37439ad 100644 --- a/lib/lws-plat-esp32.c +++ b/lib/lws-plat-esp32.c @@ -433,6 +433,12 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) return inet_ntop(af, src, dst, cnt); } +LWS_VISIBLE int +lws_plat_inet_pton(int af, const char *src, void *dst) +{ + return 1; // inet_pton(af, src, dst); +} + LWS_VISIBLE lws_fop_fd_t IRAM_ATTR _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename, const char *vpath, lws_fop_flags_t *flags) diff --git a/lib/lws-plat-esp8266.c b/lib/lws-plat-esp8266.c index d7f7e70..39f6930 100644 --- a/lib/lws-plat-esp8266.c +++ b/lib/lws-plat-esp8266.c @@ -631,6 +631,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) } LWS_VISIBLE int +lws_plat_inet_pton(int af, const char *src, void *dst) +{ + //return inet_pton(af, src, dst); + return 1; +} + +LWS_VISIBLE int lws_plat_init(struct lws_context *context, struct lws_context_creation_info *info) { diff --git a/lib/lws-plat-optee.c b/lib/lws-plat-optee.c index 20379bc..3006a6d 100644 --- a/lib/lws-plat-optee.c +++ b/lib/lws-plat-optee.c @@ -261,6 +261,13 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) return "lws_plat_inet_ntop"; } +LWS_VISIBLE int +lws_plat_inet_pton(int af, const char *src, void *dst) +{ + //return inet_pton(af, src, dst); + return 1; +} + LWS_VISIBLE lws_fop_fd_t _lws_plat_file_open(lws_plat_file_open(struct lws_plat_file_ops *fops, const char *filename, lws_fop_flags_t *flags) diff --git a/lib/lws-plat-unix.c b/lib/lws-plat-unix.c index b9f317b..b2679b6 100644 --- a/lib/lws-plat-unix.c +++ b/lib/lws-plat-unix.c @@ -616,6 +616,12 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) return inet_ntop(af, src, dst, cnt); } +LWS_VISIBLE int +lws_plat_inet_pton(int af, const char *src, void *dst) +{ + return inet_pton(af, src, dst); +} + LWS_VISIBLE lws_fop_fd_t _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename, const char *vpath, lws_fop_flags_t *flags) diff --git a/lib/lws-plat-win.c b/lib/lws-plat-win.c index 2c74a18..2d8b8eb 100644 --- a/lib/lws-plat-win.c +++ b/lib/lws-plat-win.c @@ -398,6 +398,16 @@ LWS_VISIBLE LWS_EXTERN int lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, size_t addrlen) { +#ifdef LWS_USE_IPV6 + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; + + if (ipv6) { + if (lws_plat_inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1) { + return 0; + } + } +#endif + long long address = inet_addr(ifname); if (address == INADDR_NONE) { @@ -525,6 +535,59 @@ lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt) return ok ? dst : NULL; } +LWS_VISIBLE int +lws_plat_inet_pton(int af, const char *src, void *dst) +{ + WCHAR *buffer; + DWORD bufferlen = strlen(src) + 1; + BOOL ok = FALSE; + + buffer = lws_malloc(bufferlen * 2); + if (!buffer) { + lwsl_err("Out of memory\n"); + return -1; + } + + if (MultiByteToWideChar(CP_ACP, 0, src, bufferlen, buffer, bufferlen) <= 0) { + lwsl_err("Failed to convert multi byte to wide char\n"); + lws_free(buffer); + return -1; + } + + if (af == AF_INET) { + struct sockaddr_in dstaddr; + int dstaddrlen = sizeof(dstaddr); + bzero(&dstaddr, sizeof(dstaddr)); + dstaddr.sin_family = AF_INET; + + if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) { + ok = TRUE; + memcpy(dst, &dstaddr.sin_addr, sizeof(dstaddr.sin_addr)); + } +#ifdef LWS_USE_IPV6 + } else if (af == AF_INET6) { + struct sockaddr_in6 dstaddr; + int dstaddrlen = sizeof(dstaddr); + bzero(&dstaddr, sizeof(dstaddr)); + dstaddr.sin6_family = AF_INET6; + + if (!WSAStringToAddressW(buffer, af, 0, (struct sockaddr *) &dstaddr, &dstaddrlen)) { + ok = TRUE; + memcpy(dst, &dstaddr.sin6_addr, sizeof(dstaddr.sin6_addr)); + } +#endif + } else + lwsl_err("Unsupported type\n"); + + if (!ok) { + int rv = WSAGetLastError(); + lwsl_err("WSAAddressToString() : %d\n", rv); + } + + lws_free(buffer); + return ok ? 1 : -1; +} + LWS_VISIBLE lws_fop_fd_t _lws_plat_file_open(const struct lws_plat_file_ops *fops, const char *filename, const char *vpath, lws_fop_flags_t *flags) diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 8f7f796..dcee160 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -1674,6 +1674,11 @@ LWS_EXTERN int lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port, const char *iface); +#if defined(LWS_USE_IPV6) +LWS_EXTERN unsigned long +lws_get_addr_scope(const char *ipaddr); +#endif + LWS_EXTERN void lws_close_free_wsi(struct lws *wsi, enum lws_close_status); @@ -2163,6 +2168,8 @@ LWS_EXTERN unsigned long long time_in_microseconds(void); LWS_EXTERN const char * LWS_WARN_UNUSED_RESULT lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt); +LWS_EXTERN int LWS_WARN_UNUSED_RESULT +lws_plat_inet_pton(int af, const char *src, void *dst); LWS_EXTERN int LWS_WARN_UNUSED_RESULT lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len); -- 2.7.4