Просмотр исходного кода

Add support for IPv6 in WAMR (#1411)

For now this implementation only covers posix platforms, as defined in MVP #1336
Marcin Kolny 3 лет назад
Родитель
Сommit
0ffac101a1

+ 1 - 1
core/iwasm/libraries/debug-engine/gdbserver.c

@@ -59,7 +59,7 @@ wasm_create_gdbserver(const char *host, int32 *port)
 
     memset(server->receive_ctx, 0, sizeof(rsp_recv_context_t));
 
-    if (0 != os_socket_create(&listen_fd, 1)) {
+    if (0 != os_socket_create(&listen_fd, true, true)) {
         LOG_ERROR("wasm gdb server error: create socket failed");
         goto fail;
     }

+ 40 - 5
core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c

@@ -31,21 +31,38 @@ ipv4_addr_to_wasi_addr(uint32_t addr_num, uint16_t port, __wasi_addr_t *out)
     out->addr.ip4.addr.n3 = (addr_num & 0x000000FF);
 }
 
+static void
+ipv6_addr_to_wasi_addr(uint16_t *addr, uint16_t port, __wasi_addr_t *out)
+{
+    out->kind = IPv6;
+    out->addr.ip6.port = ntohs(port);
+    out->addr.ip6.addr.n0 = ntohs(addr[0]);
+    out->addr.ip6.addr.n1 = ntohs(addr[1]);
+    out->addr.ip6.addr.n2 = ntohs(addr[2]);
+    out->addr.ip6.addr.n3 = ntohs(addr[3]);
+    out->addr.ip6.addr.h0 = ntohs(addr[4]);
+    out->addr.ip6.addr.h1 = ntohs(addr[5]);
+    out->addr.ip6.addr.h2 = ntohs(addr[6]);
+    out->addr.ip6.addr.h3 = ntohs(addr[7]);
+}
+
 static __wasi_errno_t
 sockaddr_to_wasi_addr(const struct sockaddr *sock_addr, socklen_t addrlen,
                       __wasi_addr_t *wasi_addr)
 {
     __wasi_errno_t ret = __WASI_ERRNO_SUCCESS;
     if (AF_INET == sock_addr->sa_family) {
-        assert(sizeof(struct sockaddr_in) == addrlen);
+        assert(sizeof(struct sockaddr_in) <= addrlen);
 
         ipv4_addr_to_wasi_addr(
             ((struct sockaddr_in *)sock_addr)->sin_addr.s_addr,
             ((struct sockaddr_in *)sock_addr)->sin_port, wasi_addr);
     }
     else if (AF_INET6 == sock_addr->sa_family) {
-        // TODO: IPV6
-        ret = __WASI_ERRNO_AFNOSUPPORT;
+        assert(sizeof(struct sockaddr_in6) == addrlen);
+        ipv6_addr_to_wasi_addr(
+            (uint16_t *)((struct sockaddr_in6 *)sock_addr)->sin6_addr.s6_addr,
+            ((struct sockaddr_in6 *)sock_addr)->sin6_port, wasi_addr);
     }
     else {
         ret = __WASI_ERRNO_AFNOSUPPORT;
@@ -78,8 +95,26 @@ wasi_addr_to_sockaddr(const __wasi_addr_t *wasi_addr,
             break;
         }
         case IPv6:
-            // TODO: IPV6
-            return __WASI_ERRNO_AFNOSUPPORT;
+        {
+            struct sockaddr_in6 sock_addr_in6 = { 0 };
+            uint16_t *addr_buf = (uint16_t *)sock_addr_in6.sin6_addr.s6_addr;
+
+            addr_buf[0] = htons(wasi_addr->addr.ip6.addr.n0);
+            addr_buf[1] = htons(wasi_addr->addr.ip6.addr.n1);
+            addr_buf[2] = htons(wasi_addr->addr.ip6.addr.n2);
+            addr_buf[3] = htons(wasi_addr->addr.ip6.addr.n3);
+            addr_buf[4] = htons(wasi_addr->addr.ip6.addr.h0);
+            addr_buf[5] = htons(wasi_addr->addr.ip6.addr.h1);
+            addr_buf[6] = htons(wasi_addr->addr.ip6.addr.h2);
+            addr_buf[7] = htons(wasi_addr->addr.ip6.addr.h3);
+
+            sock_addr_in6.sin6_family = AF_INET6;
+            sock_addr_in6.sin6_port = htons(wasi_addr->addr.ip6.port);
+            memcpy(sock_addr, &sock_addr_in6, sizeof(sock_addr_in6));
+
+            *addrlen = sizeof(sock_addr_in6);
+            break;
+        }
         default:
             return __WASI_ERRNO_AFNOSUPPORT;
     }

+ 143 - 46
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c

@@ -2948,6 +2948,35 @@ wasi_ssp_sock_addr_remote(
     return __WASI_ESUCCESS;
 }
 
+static bool
+wasi_addr_to_string(__wasi_addr_t *addr, char *buf, size_t buflen)
+{
+    if (addr->kind == IPv4) {
+        const char *format = "%u.%u.%u.%u";
+
+        assert(buflen >= 16);
+
+        snprintf(buf, buflen, format, addr->addr.ip4.addr.n0,
+                 addr->addr.ip4.addr.n1, addr->addr.ip4.addr.n2,
+                 addr->addr.ip4.addr.n3);
+
+        return true;
+    }
+    else if (addr->kind == IPv6) {
+        const char *format = "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x";
+        __wasi_addr_ip6_t ipv6 = addr->addr.ip6.addr;
+
+        assert(buflen >= 40);
+
+        snprintf(buf, buflen, format, ipv6.n0, ipv6.n1, ipv6.n2, ipv6.n3,
+                 ipv6.h0, ipv6.h1, ipv6.h2, ipv6.h3);
+
+        return true;
+    }
+
+    return false;
+}
+
 __wasi_errno_t
 wasi_ssp_sock_bind(
 #if !defined(WASMTIME_SSP_STATIC_CURFDS)
@@ -2955,15 +2984,15 @@ wasi_ssp_sock_bind(
 #endif
     __wasi_fd_t fd, __wasi_addr_t *addr)
 {
-    char buf[24] = { 0 };
-    const char *format = "%u.%u.%u.%u";
+    char buf[48] = { 0 };
     struct fd_object *fo;
     __wasi_errno_t error;
-    int port = addr->addr.ip4.port;
+    int port = addr->kind == IPv4 ? addr->addr.ip4.port : addr->addr.ip6.port;
     int ret;
 
-    snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
-             addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
+    if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
+        return __WASI_EPROTONOSUPPORT;
+    }
 
     if (!addr_pool_search(addr_pool, buf)) {
         return __WASI_EACCES;
@@ -3017,7 +3046,8 @@ wasi_ssp_sock_addr_resolve(
         addr_info_size < *max_info_size ? addr_info_size : *max_info_size;
 
     for (size_t i = 0; i < actual_info_size; i++) {
-        addr_info[i].type = wamr_addr_info[i].is_tcp ? SOCK_STREAM : SOCK_DGRAM;
+        addr_info[i].type =
+            wamr_addr_info[i].is_tcp ? SOCKET_STREAM : SOCKET_DGRAM;
         if (wamr_addr_info[i].is_ipv4) {
             ipv4_addr_to_wasi_addr(*(uint32_t *)wamr_addr_info[i].addr,
                                    wamr_addr_info[i].port, &addr_info[i].addr);
@@ -3039,14 +3069,14 @@ wasi_ssp_sock_connect(
 #endif
     __wasi_fd_t fd, __wasi_addr_t *addr)
 {
-    char buf[24] = { 0 };
-    const char *format = "%u.%u.%u.%u";
+    char buf[48] = { 0 };
     struct fd_object *fo;
     __wasi_errno_t error;
     int ret;
 
-    snprintf(buf, 24, format, addr->addr.ip4.addr.n0, addr->addr.ip4.addr.n1,
-             addr->addr.ip4.addr.n2, addr->addr.ip4.addr.n3);
+    if (!wasi_addr_to_string(addr, buf, sizeof(buf))) {
+        return __WASI_EPROTONOSUPPORT;
+    }
 
     if (!addr_pool_search(addr_pool, buf)) {
         return __WASI_EACCES;
@@ -3056,7 +3086,9 @@ wasi_ssp_sock_connect(
     if (error != __WASI_ESUCCESS)
         return error;
 
-    ret = os_socket_connect(fd_number(fo), buf, addr->addr.ip4.port);
+    ret = os_socket_connect(fd_number(fo), buf,
+                            addr->kind == IPv4 ? addr->addr.ip4.port
+                                               : addr->addr.ip6.port);
     fd_object_release(fo);
     if (BHT_OK != ret) {
         return convert_errno(errno);
@@ -3097,7 +3129,8 @@ wasi_ssp_sock_open(
     __wasi_fd_t *sockfd)
 {
     bh_socket_t sock;
-    int tcp_or_udp = 0;
+    bool is_tcp = SOCKET_DGRAM == socktype ? false : true;
+    bool is_ipv4 = INET6 ? false : true;
     int ret;
     __wasi_filetype_t wasi_type;
     __wasi_rights_t max_base, max_inheriting;
@@ -3105,13 +3138,7 @@ wasi_ssp_sock_open(
 
     (void)poolfd;
 
-    if (INET4 != af) {
-        return __WASI_EAFNOSUPPORT;
-    }
-
-    tcp_or_udp = SOCKET_DGRAM == socktype ? 0 : 1;
-
-    ret = os_socket_create(&sock, tcp_or_udp);
+    ret = os_socket_create(&sock, is_ipv4, is_tcp);
     if (BHT_OK != ret) {
         return convert_errno(errno);
     }
@@ -3337,9 +3364,8 @@ fd_prestats_destroy(struct fd_prestats *pt)
 bool
 addr_pool_init(struct addr_pool *addr_pool)
 {
-    addr_pool->next = NULL;
-    addr_pool->addr = 0;
-    addr_pool->mask = 0;
+    memset(addr_pool, 0, sizeof(*addr_pool));
+
     return true;
 }
 
@@ -3348,6 +3374,7 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
 {
     struct addr_pool *cur = addr_pool;
     struct addr_pool *next;
+    bh_inet_network_output_t target;
 
     if (!addr_pool) {
         return false;
@@ -3359,9 +3386,20 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
 
     next->next = NULL;
     next->mask = mask;
-    if (os_socket_inet_network(addr, &next->addr) != BHT_OK) {
-        wasm_runtime_free(next);
-        return false;
+
+    if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
+        // If parsing IPv4 fails, try IPv6
+        if (os_socket_inet_network(false, addr, &target) != BHT_OK) {
+            wasm_runtime_free(next);
+            return false;
+        }
+        next->type = IPv6;
+        bh_memcpy_s(next->addr.ip6, sizeof(next->addr.ip6), target.ipv6,
+                    sizeof(target.ipv6));
+    }
+    else {
+        next->type = IPv4;
+        next->addr.ip4 = target.ipv4;
     }
 
     /* attach with */
@@ -3372,47 +3410,106 @@ addr_pool_insert(struct addr_pool *addr_pool, const char *addr, uint8 mask)
     return true;
 }
 
+static inline size_t
+min(size_t a, size_t b)
+{
+    return a > b ? b : a;
+}
+
+static void
+init_address_mask(uint8_t *buf, size_t buflen, size_t mask)
+{
+    size_t element_size = sizeof(uint8_t) * 8;
+
+    for (size_t i = 0; i < buflen; i++) {
+        if (mask <= i * element_size) {
+            buf[i] = 0;
+        }
+        else {
+            size_t offset = min(mask - i * element_size, element_size);
+            buf[i] = (~0u) << (element_size - offset);
+        }
+    }
+}
+
+/* target must be in network byte order */
 static bool
-compare_address(const struct addr_pool *addr_pool_entry, const char *addr)
+compare_address(const struct addr_pool *addr_pool_entry,
+                bh_inet_network_output_t *target)
 {
-    /* host order */
-    uint32 target;
-    uint32 address = addr_pool_entry->addr;
-    /* 0.0.0.0 means any address */
-    if (0 == address) {
-        return true;
+    uint8_t maskbuf[16] = { 0 };
+    uint8_t basebuf[16] = { 0 };
+    size_t addr_size;
+    uint8_t max_addr_mask;
+
+    if (addr_pool_entry->type == IPv4) {
+        uint32_t addr_ip4 = htonl(addr_pool_entry->addr.ip4);
+        bh_memcpy_s(basebuf, sizeof(addr_ip4), &addr_ip4, sizeof(addr_ip4));
+        addr_size = 4;
     }
+    else {
+        uint16_t partial_addr_ip6;
+        for (int i = 0; i < 8; i++) {
+            partial_addr_ip6 = htons(addr_pool_entry->addr.ip6[i]);
+            bh_memcpy_s(&basebuf[i * sizeof(partial_addr_ip6)],
+                        sizeof(partial_addr_ip6), &partial_addr_ip6,
+                        sizeof(partial_addr_ip6));
+        }
+        addr_size = 16;
+    }
+    max_addr_mask = addr_size * 8;
 
-    if (os_socket_inet_network(addr, &target) != BHT_OK) {
-        return false;
+    /* IPv4 0.0.0.0 or IPv6 :: means any address */
+    if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) {
+        return true;
     }
 
-    const uint32 max_mask_value = 32;
-    /* no support for invalid mask values */
-    if (addr_pool_entry->mask > max_mask_value) {
+    /* No support for invalid mask value */
+    if (addr_pool_entry->mask > max_addr_mask) {
         return false;
     }
 
-    /* convert mask number into 32-bit mask value, i.e. mask /24 will be
-    converted to 4294967040 (binary: 11111111 11111111 11111111 00000000) */
-    uint32 mask = 0;
-    for (int i = 0; i < addr_pool_entry->mask; i++) {
-        mask |= 1 << (max_mask_value - 1 - i);
+    init_address_mask(maskbuf, addr_size, addr_pool_entry->mask);
+
+    for (size_t i = 0; i < addr_size; i++) {
+        uint8_t addr_mask = target->data[i] & maskbuf[i];
+        uint8_t range_mask = basebuf[i] & maskbuf[i];
+        if (addr_mask != range_mask) {
+            return false;
+        }
     }
 
-    uint32 first_address = address & mask;
-    uint32 last_address = address | (~mask);
-    return first_address <= target && target <= last_address;
+    return true;
 }
 
 bool
 addr_pool_search(struct addr_pool *addr_pool, const char *addr)
 {
     struct addr_pool *cur = addr_pool->next;
+    bh_inet_network_output_t target;
+    __wasi_addr_type_t addr_type;
+
+    if (os_socket_inet_network(true, addr, &target) != BHT_OK) {
+        size_t i;
+
+        if (os_socket_inet_network(false, addr, &target) != BHT_OK) {
+            return false;
+        }
+        addr_type = IPv6;
+        for (i = 0; i < sizeof(target.ipv6) / sizeof(target.ipv6[0]); i++) {
+            target.ipv6[i] = htons(target.ipv6[i]);
+        }
+    }
+    else {
+        addr_type = IPv4;
+        target.ipv4 = htonl(target.ipv4);
+    }
 
     while (cur) {
-        if (compare_address(cur, addr))
+        if (cur->type == addr_type && compare_address(cur, &target)) {
             return true;
+        }
+
         cur = cur->next;
     }
 

+ 6 - 2
core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h

@@ -47,9 +47,13 @@ struct argv_environ_values {
 };
 
 struct addr_pool {
-    struct addr_pool *next;
     /* addr and mask in host order */
-    uint32 addr;
+    union {
+        uint32 ip4;
+        uint16 ip6[8];
+    } addr;
+    struct addr_pool *next;
+    __wasi_addr_type_t type;
     uint8 mask;
 };
 

+ 58 - 20
core/shared/platform/common/posix/posix_socket.c

@@ -9,28 +9,45 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
-static void
-textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out)
+static bool
+textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out)
 {
+    struct sockaddr_in *v4;
+    struct sockaddr_in6 *v6;
+
     assert(textual);
 
-    out->sin_family = AF_INET;
-    out->sin_port = htons(port);
-    out->sin_addr.s_addr = inet_addr(textual);
+    v4 = (struct sockaddr_in *)out;
+    if (inet_pton(AF_INET, textual, &v4->sin_addr.s_addr) == 1) {
+        v4->sin_family = AF_INET;
+        v4->sin_port = htons(port);
+        return true;
+    }
+
+    v6 = (struct sockaddr_in6 *)out;
+    if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) {
+        v6->sin6_family = AF_INET6;
+        v6->sin6_port = htons(port);
+        return true;
+    }
+
+    return false;
 }
 
 int
-os_socket_create(bh_socket_t *sock, int tcp_or_udp)
+os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
 {
+    int af = is_ipv4 ? AF_INET : AF_INET6;
+
     if (!sock) {
         return BHT_ERROR;
     }
 
-    if (1 == tcp_or_udp) {
-        *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (is_tcp) {
+        *sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
     }
-    else if (0 == tcp_or_udp) {
-        *sock = socket(AF_INET, SOCK_DGRAM, 0);
+    else {
+        *sock = socket(af, SOCK_DGRAM, 0);
     }
 
     return (*sock == -1) ? BHT_ERROR : BHT_OK;
@@ -39,7 +56,7 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
 int
 os_socket_bind(bh_socket_t socket, const char *host, int *port)
 {
-    struct sockaddr_in addr;
+    struct sockaddr_storage addr;
     struct linger ling;
     socklen_t socklen;
     int ret;
@@ -60,7 +77,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
         goto fail;
     }
 
-    textual_addr_to_sockaddr(host, *port, &addr);
+    if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr)) {
+        goto fail;
+    }
 
     ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr));
     if (ret < 0) {
@@ -72,7 +91,9 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port)
         goto fail;
     }
 
-    *port = ntohs(addr.sin_port);
+    *port = ntohs(addr.ss_family == AF_INET
+                      ? ((struct sockaddr_in *)&addr)->sin_port
+                      : ((struct sockaddr_in6 *)&addr)->sin6_port);
 
     return BHT_OK;
 
@@ -113,7 +134,7 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
     struct sockaddr addr_tmp;
     unsigned int len = sizeof(struct sockaddr);
 
-    *sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len);
+    *sock = accept(server_sock, &addr_tmp, &len);
 
     if (*sock < 0) {
         return BHT_ERROR;
@@ -125,11 +146,13 @@ os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr,
 int
 os_socket_connect(bh_socket_t socket, const char *addr, int port)
 {
-    struct sockaddr_in addr_in = { 0 };
-    socklen_t addr_len = sizeof(struct sockaddr_in);
+    struct sockaddr_storage addr_in = { 0 };
+    socklen_t addr_len = sizeof(struct sockaddr_storage);
     int ret = 0;
 
-    textual_addr_to_sockaddr(addr, port, &addr_in);
+    if (!textual_addr_to_sockaddr(addr, port, (struct sockaddr *)&addr_in)) {
+        return BHT_ERROR;
+    }
 
     ret = connect(socket, (struct sockaddr *)&addr_in, addr_len);
     if (ret == -1) {
@@ -166,13 +189,28 @@ os_socket_shutdown(bh_socket_t socket)
 }
 
 int
-os_socket_inet_network(const char *cp, uint32 *out)
+os_socket_inet_network(bool is_ipv4, const char *cp,
+                       bh_inet_network_output_t *out)
 {
     if (!cp)
         return BHT_ERROR;
 
-    /* Note: ntohl(INADDR_NONE) == INADDR_NONE */
-    *out = ntohl(inet_addr(cp));
+    if (is_ipv4) {
+        if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
+            return BHT_ERROR;
+        }
+        /* Note: ntohl(INADDR_NONE) == INADDR_NONE */
+        out->ipv4 = ntohl(out->ipv4);
+    }
+    else {
+        if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
+            return BHT_ERROR;
+        }
+        for (int i = 0; i < 8; i++) {
+            out->ipv6[i] = ntohs(out->ipv6[i]);
+        }
+    }
+
     return BHT_OK;
 }
 

+ 19 - 5
core/shared/platform/include/platform_api_extension.h

@@ -296,12 +296,13 @@ os_sem_unlink(const char *name);
  * Create a socket
  *
  * @param sock [OUTPUT] the pointer of socket
- * @param tcp_or_udp 1 for tcp, 0 for udp
+ * @param is_ipv4 true for IPv4, false for IPv6
+ * @param is_tcp true for tcp, false for udp
  *
  * @return 0 if success, -1 otherwise
  */
 int
-os_socket_create(bh_socket_t *sock, int tcp_or_udp);
+os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp);
 
 /**
  * Assign the address and port to the socket
@@ -412,17 +413,30 @@ os_socket_close(bh_socket_t socket);
 int
 os_socket_shutdown(bh_socket_t socket);
 
+typedef union {
+    uint32 ipv4;
+    uint16 ipv6[8];
+    uint8_t data[0];
+} bh_inet_network_output_t;
+
 /**
  * converts cp into a number in host byte order suitable for use as
  * an Internet network address
  *
- * @param cp a string in IPv4 numbers-and-dots notation
+ * @param is_ipv4 a flag that indicates whether the string is an IPv4 or
+ * IPv6 address
+ *
+ * @param cp a string in IPv4 numbers-and-dots notation or IPv6
+ * numbers-and-colons notation
+ *
+ * @param out an output buffer to store binary address
  *
- * @return On success, the converted address is  returned.
+ * @return On success, the function returns 0.
  * If the input is invalid, -1 is returned
  */
 int
-os_socket_inet_network(const char *cp, uint32 *out);
+os_socket_inet_network(bool is_ipv4, const char *cp,
+                       bh_inet_network_output_t *out);
 
 typedef struct {
     uint8_t addr[16];

+ 109 - 46
core/shared/platform/linux-sgx/sgx_socket.c

@@ -92,7 +92,7 @@ swap16(uint8 *pData)
     *(pData + 1) = value;
 }
 
-static uint32
+uint32
 htonl(uint32 value)
 {
     uint32 ret;
@@ -111,7 +111,7 @@ ntohl(uint32 value)
     return htonl(value);
 }
 
-static uint16
+uint16
 htons(uint16 value)
 {
     uint16 ret;
@@ -132,58 +132,97 @@ ntohs(uint16 value)
 
 /* Coming from musl, under MIT license */
 static int
-__inet_aton(const char *s0, struct in_addr *dest)
+hexval(unsigned c)
 {
-    const char *s = s0;
-    unsigned char *d = (void *)dest;
-    unsigned long a[4] = { 0 };
-    char *z;
-    int i;
+    if (c - '0' < 10)
+        return c - '0';
+    c |= 32;
+    if (c - 'a' < 6)
+        return c - 'a' + 10;
+    return -1;
+}
 
-    for (i = 0; i < 4; i++) {
-        a[i] = strtoul(s, &z, 0);
-        if (z == s || (*z && *z != '.') || !isdigit(*s))
-            return 0;
-        if (!*z)
-            break;
-        s = z + 1;
+/* Coming from musl, under MIT license */
+static int
+inet_pton(int af, const char *restrict s, void *restrict a0)
+{
+    uint16_t ip[8];
+    unsigned char *a = a0;
+    int i, j, v, d, brk = -1, need_v4 = 0;
+
+    if (af == AF_INET) {
+        for (i = 0; i < 4; i++) {
+            for (v = j = 0; j < 3 && isdigit(s[j]); j++)
+                v = 10 * v + s[j] - '0';
+            if (j == 0 || (j > 1 && s[0] == '0') || v > 255)
+                return 0;
+            a[i] = v;
+            if (s[j] == 0 && i == 3)
+                return 1;
+            if (s[j] != '.')
+                return 0;
+            s += j + 1;
+        }
+        return 0;
+    }
+    else if (af != AF_INET6) {
+        errno = EAFNOSUPPORT;
+        return -1;
     }
-    if (i == 4)
+
+    if (*s == ':' && *++s != ':')
         return 0;
-    switch (i) {
-        case 0:
-            a[1] = a[0] & 0xffffff;
-            a[0] >>= 24;
-        case 1:
-            a[2] = a[1] & 0xffff;
-            a[1] >>= 16;
-        case 2:
-            a[3] = a[2] & 0xff;
-            a[2] >>= 8;
-    }
-    for (i = 0; i < 4; i++) {
-        if (a[i] > 255)
+
+    for (i = 0;; i++) {
+        if (s[0] == ':' && brk < 0) {
+            brk = i;
+            ip[i & 7] = 0;
+            if (!*++s)
+                break;
+            if (i == 7)
+                return 0;
+            continue;
+        }
+        for (v = j = 0; j < 4 && (d = hexval(s[j])) >= 0; j++)
+            v = 16 * v + d;
+        if (j == 0)
+            return 0;
+        ip[i & 7] = v;
+        if (!s[j] && (brk >= 0 || i == 7))
+            break;
+        if (i == 7)
             return 0;
-        d[i] = a[i];
+        if (s[j] != ':') {
+            if (s[j] != '.' || (i < 6 && brk < 0))
+                return 0;
+            need_v4 = 1;
+            i++;
+            break;
+        }
+        s += j + 1;
     }
+    if (brk >= 0) {
+        memmove(ip + brk + 7 - i, ip + brk, 2 * (i + 1 - brk));
+        for (j = 0; j < 7 - i; j++)
+            ip[brk + j] = 0;
+    }
+    for (j = 0; j < 8; j++) {
+        *a++ = ip[j] >> 8;
+        *a++ = ip[j];
+    }
+    if (need_v4 && inet_pton(AF_INET, (void *)s, a - 4) <= 0)
+        return 0;
     return 1;
 }
 
-/* Coming from musl, under MIT license */
 static int
 inet_addr(const char *p)
 {
     struct in_addr a;
-    if (!__inet_aton(p, &a))
+    if (!inet_pton(AF_INET, p, &a))
         return -1;
     return a.s_addr;
 }
-
-static int
-inet_network(const char *p)
-{
-    return ntohl(inet_addr(p));
-}
 /** In-enclave implementation of POSIX functions end **/
 
 static int
@@ -528,21 +567,30 @@ os_socket_connect(bh_socket_t socket, const char *addr, int port)
 }
 
 int
-os_socket_create(bh_socket_t *sock, int tcp_or_udp)
+os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
 {
+    int af;
+
     if (!sock) {
         return BHT_ERROR;
     }
 
-    if (1 == tcp_or_udp) {
-        if (ocall_socket(sock, AF_INET, SOCK_STREAM, IPPROTO_TCP)
-            != SGX_SUCCESS) {
+    if (is_ipv4) {
+        af = AF_INET;
+    }
+    else {
+        errno = ENOSYS;
+        return BHT_ERROR;
+    }
+
+    if (is_tcp) {
+        if (ocall_socket(sock, af, SOCK_STREAM, IPPROTO_TCP) != SGX_SUCCESS) {
             TRACE_OCALL_FAIL();
             return -1;
         }
     }
-    else if (0 == tcp_or_udp) {
-        if (ocall_socket(sock, AF_INET, SOCK_DGRAM, 0) != SGX_SUCCESS) {
+    else {
+        if (ocall_socket(sock, af, SOCK_DGRAM, 0) != SGX_SUCCESS) {
             TRACE_OCALL_FAIL();
             return -1;
         }
@@ -557,12 +605,27 @@ os_socket_create(bh_socket_t *sock, int tcp_or_udp)
 }
 
 int
-os_socket_inet_network(const char *cp, uint32 *out)
+os_socket_inet_network(bool is_ipv4, const char *cp,
+                       bh_inet_network_output_t *out)
 {
     if (!cp)
         return BHT_ERROR;
 
-    *out = inet_network(cp);
+    if (is_ipv4) {
+        if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
+            return BHT_ERROR;
+        }
+        /* Note: ntohl(INADDR_NONE) == INADDR_NONE */
+        out->ipv4 = ntohl(out->ipv4);
+    }
+    else {
+        if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
+            return BHT_ERROR;
+        }
+        for (int i = 0; i < 8; i++) {
+            out->ipv6[i] = ntohs(out->ipv6[i]);
+        }
+    }
 
     return BHT_OK;
 }

+ 7 - 0
core/shared/platform/linux-sgx/sgx_socket.h

@@ -47,6 +47,7 @@ extern "C" {
 
 /* Address families.  */
 #define AF_INET 2 /* IP protocol family.  */
+#define AF_INET6 10 /* IP version 6.  */
 
 /* Standard well-defined IP protocols.  */
 #define IPPROTO_TCP 6 /* Transmission Control Protocol.  */
@@ -98,6 +99,12 @@ struct sockaddr {
 uint32_t
 ntohl(uint32_t value);
 
+uint32_t
+htonl(uint32_t value);
+
+uint16_t
+htons(uint16_t value);
+
 int
 socket(int domain, int type, int protocol);
 

+ 33 - 7
core/shared/platform/windows/win_socket.c

@@ -37,17 +37,27 @@ deinit_winsock()
 }
 
 int
-os_socket_create(bh_socket_t *sock, int tcp_or_udp)
+os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp)
 {
+    int af;
+
     if (!sock) {
         return BHT_ERROR;
     }
 
-    if (1 == tcp_or_udp) {
-        *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (is_ipv4) {
+        af = AF_INET;
     }
-    else if (0 == tcp_or_udp) {
-        *sock = socket(AF_INET, SOCK_DGRAM, 0);
+    else {
+        errno = ENOSYS;
+        return BHT_ERROR;
+    }
+
+    if (is_tcp) {
+        *sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
+    }
+    else {
+        *sock = socket(af, SOCK_DGRAM, 0);
     }
 
     return (*sock == -1) ? BHT_ERROR : BHT_OK;
@@ -154,12 +164,28 @@ os_socket_shutdown(bh_socket_t socket)
 }
 
 int
-os_socket_inet_network(const char *cp, uint32 *out)
+os_socket_inet_network(bool is_ipv4, const char *cp,
+                       bh_inet_network_output_t *out)
 {
     if (!cp)
         return BHT_ERROR;
 
-    *out = inet_addr(cp);
+    if (is_ipv4) {
+        if (inet_pton(AF_INET, cp, &out->ipv4) != 1) {
+            return BHT_ERROR;
+        }
+        /* Note: ntohl(INADDR_NONE) == INADDR_NONE */
+        out->ipv4 = ntohl(out->ipv4);
+    }
+    else {
+        if (inet_pton(AF_INET6, cp, out->ipv6) != 1) {
+            return BHT_ERROR;
+        }
+        for (int i = 0; i < 8; i++) {
+            out->ipv6[i] = ntohs(out->ipv6[i]);
+        }
+    }
+
     return BHT_OK;
 }
 

+ 41 - 14
samples/socket-api/wasm-src/tcp_client.c

@@ -2,6 +2,7 @@
  * Copyright (C) 2019 Intel Corporation.  All rights reserved.
  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  */
+#include "tcp_utils.h"
 
 #include <arpa/inet.h>
 #include <netinet/in.h>
@@ -14,28 +15,50 @@
 #include <wasi_socket_ext.h>
 #endif
 
+static void
+init_sockaddr_inet(struct sockaddr_in *addr)
+{
+    /* 127.0.0.1:1234 */
+    addr->sin_family = AF_INET;
+    addr->sin_port = htons(1234);
+    addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+}
+
+static void
+init_sockaddr_inet6(struct sockaddr_in6 *addr)
+{
+    /* [::1]:1234 */
+    addr->sin6_family = AF_INET6;
+    addr->sin6_port = htons(1234);
+    addr->sin6_addr = in6addr_loopback;
+}
+
 int
 main(int argc, char *argv[])
 {
-    int socket_fd, ret, total_size = 0;
+    int socket_fd, ret, total_size = 0, af;
     char buffer[1024] = { 0 };
-    char ip_string[16] = { 0 };
-    struct sockaddr_in server_address = { 0 };
-    struct sockaddr_in local_address = { 0 };
+    char ip_string[64] = { 0 };
     socklen_t len;
+    struct sockaddr_storage server_address = { 0 };
+    struct sockaddr_storage local_address = { 0 };
+
+    if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
+        af = AF_INET6;
+        init_sockaddr_inet6((struct sockaddr_in6 *)&server_address);
+    }
+    else {
+        af = AF_INET;
+        init_sockaddr_inet((struct sockaddr_in *)&server_address);
+    }
 
     printf("[Client] Create socket\n");
-    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+    socket_fd = socket(af, SOCK_STREAM, 0);
     if (socket_fd == -1) {
         perror("Create socket failed");
         return EXIT_FAILURE;
     }
 
-    /* 127.0.0.1:1234 */
-    server_address.sin_family = AF_INET;
-    server_address.sin_port = htons(1234);
-    server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
     printf("[Client] Connect socket\n");
     if (connect(socket_fd, (struct sockaddr *)&server_address,
                 sizeof(server_address))
@@ -53,11 +76,15 @@ main(int argc, char *argv[])
         return EXIT_FAILURE;
     }
 
-    inet_ntop(AF_INET, &local_address.sin_addr, ip_string,
-              sizeof(ip_string) / sizeof(ip_string[0]));
+    if (sockaddr_to_string((struct sockaddr *)&local_address, ip_string,
+                           sizeof(ip_string) / sizeof(ip_string[0]))
+        != 0) {
+        printf("[Client] failed to parse local address\n");
+        close(socket_fd);
+        return EXIT_FAILURE;
+    }
 
-    printf("[Client] Local address is: %s:%d\n", ip_string,
-           ntohs(local_address.sin_port));
+    printf("[Client] Local address is: %s\n", ip_string);
 
     printf("[Client] Client receive\n");
     while (1) {

+ 40 - 13
samples/socket-api/wasm-src/tcp_server.c

@@ -2,6 +2,8 @@
  * Copyright (C) 2019 Intel Corporation.  All rights reserved.
  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  */
+#include "tcp_utils.h"
+
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <pthread.h>
@@ -41,28 +43,50 @@ run(void *arg)
     return NULL;
 }
 
+static void
+init_sockaddr_inet(struct sockaddr_in *addr)
+{
+    /* 0.0.0.0:1234 */
+    addr->sin_family = AF_INET;
+    addr->sin_port = htons(1234);
+    addr->sin_addr.s_addr = htonl(INADDR_ANY);
+}
+
+static void
+init_sockaddr_inet6(struct sockaddr_in6 *addr)
+{
+    /* [::]:1234 */
+    addr->sin6_family = AF_INET6;
+    addr->sin6_port = htons(1234);
+    addr->sin6_addr = in6addr_any;
+}
+
 int
 main(int argc, char *argv[])
 {
-    int socket_fd = -1, addrlen = 0;
-    struct sockaddr_in addr = { 0 };
+    int socket_fd = -1, addrlen = 0, af;
+    struct sockaddr_storage addr = { 0 };
     unsigned connections = 0;
     pthread_t workers[WORKER_NUM] = { 0 };
     int client_sock_fds[WORKER_NUM] = { 0 };
-    char ip_string[16];
+    char ip_string[64];
+
+    if (argc > 1 && strcmp(argv[1], "inet6") == 0) {
+        af = AF_INET6;
+        init_sockaddr_inet6((struct sockaddr_in6 *)&addr);
+    }
+    else {
+        af = AF_INET;
+        init_sockaddr_inet((struct sockaddr_in *)&addr);
+    }
 
     printf("[Server] Create socket\n");
-    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+    socket_fd = socket(af, SOCK_STREAM, 0);
     if (socket_fd < 0) {
         perror("Create socket failed");
         goto fail;
     }
 
-    /* 0.0.0.0:1234 */
-    addr.sin_family = AF_INET;
-    addr.sin_port = htons(1234);
-    addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
     printf("[Server] Bind socket\n");
     addrlen = sizeof(addr);
     if (bind(socket_fd, (struct sockaddr *)&addr, addrlen) < 0) {
@@ -85,11 +109,14 @@ main(int argc, char *argv[])
             break;
         }
 
-        inet_ntop(AF_INET, &addr.sin_addr, ip_string,
-                  sizeof(ip_string) / sizeof(ip_string[0]));
+        if (sockaddr_to_string((struct sockaddr *)&addr, ip_string,
+                               sizeof(ip_string) / sizeof(ip_string[0]))
+            != 0) {
+            printf("[Server] failed to parse client address\n");
+            goto fail;
+        }
 
-        printf("[Server] Client connected (%s:%d)\n", ip_string,
-               ntohs(addr.sin_port));
+        printf("[Server] Client connected (%s)\n", ip_string);
         if (pthread_create(&workers[connections], NULL, run,
                            &client_sock_fds[connections])) {
             perror("Create a worker thread failed");

+ 48 - 0
samples/socket-api/wasm-src/tcp_utils.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef TCP_UTILS_H
+#define TCP_UTILS_H
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+int
+sockaddr_to_string(struct sockaddr *addr, char *str, size_t len)
+{
+    uint16_t port;
+    char ip_string[64];
+    void *addr_buf;
+    int ret;
+
+    switch (addr->sa_family) {
+        case AF_INET:
+        {
+            struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
+            port = addr_in->sin_port;
+            addr_buf = &addr_in->sin_addr;
+            break;
+        }
+        case AF_INET6:
+        {
+            struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
+            port = addr_in6->sin6_port;
+            addr_buf = &addr_in6->sin6_addr;
+            break;
+        }
+        default:
+            return -1;
+    }
+
+    inet_ntop(addr->sa_family, addr_buf, ip_string,
+              sizeof(ip_string) / sizeof(ip_string[0]));
+
+    ret = snprintf(str, len, "%s:%d", ip_string, ntohs(port));
+
+    return ret > 0 && (size_t)ret < len ? 0 : -1;
+}
+
+#endif /* TCP_UTILS_H */