diff options
author | Nicholas Ngai <nicholas@ngai.me> | 2021-09-27 14:21:45 -0700 |
---|---|---|
committer | Nicholas Ngai <nicholas@ngai.me> | 2021-09-27 14:21:45 -0700 |
commit | 92346097c2148d1a7ff73223d20409db4ac6ba22 (patch) | |
tree | ed0b67e72894061d34f96f0aee6bfd2cd70f5d89 /src | |
parent | 23db43abdb5740287bbb7cbf5cc99eb22e121298 (diff) | |
download | slirp-92346097c2148d1a7ff73223d20409db4ac6ba22.zip slirp-92346097c2148d1a7ff73223d20409db4ac6ba22.tar.gz slirp-92346097c2148d1a7ff73223d20409db4ac6ba22.tar.bz2 |
Support Unix sockets in hostfwd
QEMU has an issue open
(https://gitlab.com/qemu-project/qemu/-/issues/347) to forward a Unix
domain socket to guest TCP port. Both of these protocols support stream
modes of operation (and user-mode networking can only access the stream
anyway), so this patch enables Unix-to-TCP hostfwds.
Like with localhost hostfwds, the sotranslate_accept function will
translate a Unix domain socket connection to a TCP connection
originating from vhost_addr and a randomized ephemeral port.
Signed-off-by: Nicholas Ngai <nicholas@ngai.me>
Diffstat (limited to 'src')
-rw-r--r-- | src/libslirp.h | 1 | ||||
-rw-r--r-- | src/socket.c | 19 | ||||
-rw-r--r-- | src/socket.h | 26 | ||||
-rw-r--r-- | src/state.c | 2 |
4 files changed, 34 insertions, 14 deletions
diff --git a/src/libslirp.h b/src/libslirp.h index 5760d53..afb6663 100644 --- a/src/libslirp.h +++ b/src/libslirp.h @@ -13,6 +13,7 @@ #else #include <netinet/in.h> #include <arpa/inet.h> +#include <sys/un.h> #endif #include "libslirp-version.h" diff --git a/src/socket.c b/src/socket.c index 2c1b789..09ce6bf 100644 --- a/src/socket.c +++ b/src/socket.c @@ -769,18 +769,6 @@ struct socket *tcpx_listen(Slirp *slirp, socklen_t addrlen; DEBUG_CALL("tcpx_listen"); - /* AF_INET6 addresses are bigger than AF_INET, so this is big enough. */ - char addrstr[INET6_ADDRSTRLEN]; - char portstr[6]; - int ret; - ret = getnameinfo(haddr, haddrlen, addrstr, sizeof(addrstr), portstr, sizeof(portstr), NI_NUMERICHOST|NI_NUMERICSERV); - g_assert(ret == 0); - DEBUG_ARG("haddr = %s", addrstr); - DEBUG_ARG("hport = %s", portstr); - ret = getnameinfo(laddr, laddrlen, addrstr, sizeof(addrstr), portstr, sizeof(portstr), NI_NUMERICHOST|NI_NUMERICSERV); - g_assert(ret == 0); - DEBUG_ARG("laddr = %s", addrstr); - DEBUG_ARG("lport = %s", portstr); DEBUG_ARG("flags = %x", flags); /* @@ -1041,6 +1029,13 @@ void sotranslate_accept(struct socket *so) } break; + case AF_UNIX: + /* Translate Unix socket to random ephemeral source port. */ + so->so_ffamily = AF_INET; + so->so_faddr = slirp->vhost_addr; + so->so_fport = g_rand_int_range(slirp->grand, 49152, 65536); + break; + default: break; } diff --git a/src/socket.h b/src/socket.h index a73175d..5f6242e 100644 --- a/src/socket.h +++ b/src/socket.h @@ -6,6 +6,8 @@ #ifndef SLIRP_SOCKET_H #define SLIRP_SOCKET_H +#include <string.h> + #include "misc.h" #include "sbuf.h" @@ -23,6 +25,16 @@ typedef union in4or6_addr in4or6_addr; * Our socket structure */ +union slirp_sockaddr_host { + struct sockaddr sa; + struct sockaddr_storage ss; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +#ifndef _WIN32 + struct sockaddr_un sun; +#endif +}; + union slirp_sockaddr { struct sockaddr sa; struct sockaddr_storage ss; @@ -47,11 +59,12 @@ struct socket { struct tcpiphdr *so_ti; /* Pointer to the original ti within * so_mconn, for non-blocking connections */ uint32_t so_urgc; - union slirp_sockaddr fhost; /* Foreign host */ + union slirp_sockaddr_host fhost; /* Foreign host */ #define so_faddr fhost.sin.sin_addr #define so_fport fhost.sin.sin_port #define so_faddr6 fhost.sin6.sin6_addr #define so_fport6 fhost.sin6.sin6_port +#define so_fpath fhost.sun.sun_path #define so_ffamily fhost.ss.ss_family union slirp_sockaddr lhost; /* Local host */ @@ -128,6 +141,13 @@ static inline int sockaddr_equal(const struct sockaddr_storage *a, return (in6_equal(&a6->sin6_addr, &b6->sin6_addr) && a6->sin6_port == b6->sin6_port); } +#ifndef _WIN32 + case AF_UNIX: { + const struct sockaddr_un *aun = (const struct sockaddr_un *)a; + const struct sockaddr_un *bun = (const struct sockaddr_un *)b; + return strncmp(aun->sun_path, bun->sun_path, sizeof(aun->sun_path)) == 0; + } +#endif default: g_assert_not_reached(); } @@ -142,6 +162,10 @@ static inline socklen_t sockaddr_size(const struct sockaddr_storage *a) return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); +#ifndef _WIN32 + case AF_UNIX: + return sizeof(struct sockaddr_un); +#endif default: g_assert_not_reached(); } diff --git a/src/state.c b/src/state.c index 22af77b..181d338 100644 --- a/src/state.c +++ b/src/state.c @@ -273,7 +273,7 @@ static const VMStateDescription vmstate_slirp_socket = { VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4), /* v4 and newer */ VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr, - union slirp_sockaddr), + union slirp_sockaddr_host), VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr, union slirp_sockaddr), |