Add support for IPv6 in WAMR (#1411)
For now this implementation only covers posix platforms, as defined in MVP #1336
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 bool
|
||||
compare_address(const struct addr_pool *addr_pool_entry, const char *addr)
|
||||
static inline size_t
|
||||
min(size_t a, size_t b)
|
||||
{
|
||||
/* host order */
|
||||
uint32 target;
|
||||
uint32 address = addr_pool_entry->addr;
|
||||
/* 0.0.0.0 means any address */
|
||||
if (0 == address) {
|
||||
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,
|
||||
bh_inet_network_output_t *target)
|
||||
{
|
||||
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;
|
||||
|
||||
/* IPv4 0.0.0.0 or IPv6 :: means any address */
|
||||
if (basebuf[0] == 0 && !memcmp(basebuf, basebuf + 1, addr_size - 1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (os_socket_inet_network(addr, &target) != BHT_OK) {
|
||||
/* No support for invalid mask value */
|
||||
if (addr_pool_entry->mask > max_addr_mask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32 max_mask_value = 32;
|
||||
/* no support for invalid mask values */
|
||||
if (addr_pool_entry->mask > max_mask_value) {
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user