* [PATCH 0/2] Add ipv6 hostfwd support
@ 2021-01-21 8:23 dje--- via
2021-01-21 8:23 ` [PATCH 1/2] slirp: " dje--- via
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: dje--- via @ 2021-01-21 8:23 UTC (permalink / raw)
To: qemu-devel; +Cc: Samuel Thibault, Doug Evans
Hi. This patchset takes the original patch from Maxim,
https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
and updates it.
The first patch is the slirp additions, the second patch adds the u/i.
Doug Evans (2):
slirp: Add ipv6 hostfwd support
net: Add ipv6_hostfwd option
Slirp:
src/libslirp.h | 6 +++
src/slirp.c | 51 +++++++++++++++++++++--
src/socket.c | 109 +++++++++++++++++++++++++++++++++++--------------
src/socket.h | 9 ++++
src/udp.c | 73 ++++++++++++++++++++++++++-------
src/udp.h | 2 +
6 files changed, 202 insertions(+), 48 deletions(-)
QEMU:
hmp-commands.hx | 29 ++++-
include/net/slirp.h | 2 +
net/slirp.c | 311 +++++++++++++++++++++++++++++++++++---------
qapi/net.json | 1 +
slirp | 2 +-
5 files changed, 279 insertions(+), 66 deletions(-)
--
2.30.0.296.g2bfb1c46d8-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] slirp: Add ipv6 hostfwd support
2021-01-21 8:23 [PATCH 0/2] Add ipv6 hostfwd support dje--- via
@ 2021-01-21 8:23 ` dje--- via
2021-01-21 8:23 ` [PATCH 2/2] net: Add ipv6_hostfwd option dje--- via
2021-01-21 9:41 ` [PATCH 0/2] Add ipv6 hostfwd support Marc-André Lureau
2 siblings, 0 replies; 7+ messages in thread
From: dje--- via @ 2021-01-21 8:23 UTC (permalink / raw)
To: qemu-devel; +Cc: Samuel Thibault, Doug Evans
Signed-off-by: Doug Evans <dje@google.com>
---
src/libslirp.h | 6 +++
src/slirp.c | 51 +++++++++++++++++++++--
src/socket.c | 109 +++++++++++++++++++++++++++++++++++--------------
src/socket.h | 9 ++++
src/udp.c | 73 ++++++++++++++++++++++++++-------
src/udp.h | 2 +
6 files changed, 202 insertions(+), 48 deletions(-)
diff --git a/src/libslirp.h b/src/libslirp.h
index 27e1f61..280d3d0 100644
--- a/src/libslirp.h
+++ b/src/libslirp.h
@@ -142,6 +142,12 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port, struct in_addr guest_addr, int guest_port);
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port);
+int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp,
+ struct in6_addr host_addr, int host_port,
+ struct in6_addr guest_addr, int guest_port);
+int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp,
+ struct in6_addr host_addr, int host_port);
+
int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port);
int slirp_add_unix(Slirp *slirp, const char *unixsock,
diff --git a/src/slirp.c b/src/slirp.c
index abb6f9a..a07ef83 100644
--- a/src/slirp.c
+++ b/src/slirp.c
@@ -1091,7 +1091,6 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
}
/* Drop host forwarding rule, return 0 if found. */
-/* TODO: IPv6 */
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port)
{
@@ -1105,7 +1104,10 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
addr_len = sizeof(addr);
if ((so->so_state & SS_HOSTFWD) &&
getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
- addr.sin_addr.s_addr == host_addr.s_addr && addr.sin_port == port) {
+ addr_len == sizeof(addr) &&
+ addr.sin_family == AF_INET &&
+ addr.sin_addr.s_addr == host_addr.s_addr &&
+ addr.sin_port == port) {
so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
closesocket(so->s);
sofree(so);
@@ -1116,7 +1118,6 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
return -1;
}
-/* TODO: IPv6 */
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
int host_port, struct in_addr guest_addr, int guest_port)
{
@@ -1135,6 +1136,50 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
return 0;
}
+int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp,
+ struct in6_addr host_addr, int host_port)
+{
+ struct socket *so;
+ struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
+ struct sockaddr_in6 addr;
+ int port = htons(host_port);
+ socklen_t addr_len;
+
+ for (so = head->so_next; so != head; so = so->so_next) {
+ addr_len = sizeof(addr);
+ if ((so->so_state & SS_HOSTFWD) &&
+ getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
+ addr_len == sizeof(addr) &&
+ addr.sin6_family == AF_INET6 &&
+ !memcmp(&addr.sin6_addr, &host_addr, sizeof(host_addr)) &&
+ addr.sin6_port == port) {
+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+ closesocket(so->s);
+ sofree(so);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp,
+ struct in6_addr host_addr, int host_port,
+ struct in6_addr guest_addr, int guest_port)
+{
+ if (is_udp) {
+ if (!udp6_listen(slirp, host_addr, htons(host_port),
+ guest_addr, htons(guest_port), SS_HOSTFWD))
+ return -1;
+ } else {
+ if (!tcp6_listen(slirp, host_addr, htons(host_port),
+ guest_addr, htons(guest_port), SS_HOSTFWD))
+ return -1;
+ }
+
+ return 0;
+}
+
/* TODO: IPv6 */
static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
int guest_port)
diff --git a/src/socket.c b/src/socket.c
index c0b02ad..46be587 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -736,22 +736,18 @@ int sosendto(struct socket *so, struct mbuf *m)
/*
* Listen for incoming TCP connections
*/
-struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
- uint32_t laddr, unsigned lport, int flags)
+static struct socket *tcpx_listen(Slirp *slirp, int family,
+ in4or6_addr haddr, unsigned hport,
+ in4or6_addr laddr, unsigned lport,
+ int flags)
{
- /* TODO: IPv6 */
- struct sockaddr_in addr;
+ union {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } addr;
struct socket *so;
int s, opt = 1;
socklen_t addrlen = sizeof(addr);
- memset(&addr, 0, addrlen);
-
- DEBUG_CALL("tcp_listen");
- DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){ .s_addr = haddr }));
- DEBUG_ARG("hport = %d", ntohs(hport));
- DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){ .s_addr = laddr }));
- DEBUG_ARG("lport = %d", ntohs(lport));
- DEBUG_ARG("flags = %x", flags);
so = socreate(slirp);
@@ -770,20 +766,35 @@ struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
so->so_state &= SS_PERSISTENT_MASK;
so->so_state |= (SS_FACCEPTCONN | flags);
- so->so_lfamily = AF_INET;
- so->so_lport = lport; /* Kept in network format */
- so->so_laddr.s_addr = laddr; /* Ditto */
+ so->so_lfamily = family;
+ /* Address,port are kept in network format */
+ if (family == AF_INET) {
+ so->so_laddr.s_addr = laddr.addr4;
+ so->so_lport = lport;
+ } else {
+ so->so_laddr6 = laddr.addr6;
+ so->so_lport6 = lport;
+ }
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = haddr;
- addr.sin_port = hport;
+ memset(&addr, 0, addrlen);
+ if (family == AF_INET) {
+ addr.addr4.sin_family = family;
+ addr.addr4.sin_addr.s_addr = haddr.addr4;
+ addr.addr4.sin_port = hport;
+ addrlen = sizeof(addr.addr4);
+ } else {
+ addr.addr6.sin6_family = family;
+ addr.addr6.sin6_addr = haddr.addr6;
+ addr.addr6.sin6_port = hport;
+ addrlen = sizeof(addr.addr6);
+ }
- if (((s = slirp_socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
+ s = slirp_socket(family, SOCK_STREAM, 0);
+ if ((s < 0) ||
(slirp_socket_set_fast_reuse(s) < 0) ||
- (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+ (bind(s, (struct sockaddr *)&addr, addrlen) < 0) ||
(listen(s, 1) < 0)) {
int tmperrno = errno; /* Don't clobber the real reason we failed */
-
if (s >= 0) {
closesocket(s);
}
@@ -797,22 +808,60 @@ struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
return NULL;
}
setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
- opt = 1;
- setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
+ slirp_socket_set_nodelay(s);
getsockname(s, (struct sockaddr *)&addr, &addrlen);
- so->so_ffamily = AF_INET;
- so->so_fport = addr.sin_port;
- if (addr.sin_addr.s_addr == 0 ||
- addr.sin_addr.s_addr == loopback_addr.s_addr)
- so->so_faddr = slirp->vhost_addr;
- else
- so->so_faddr = addr.sin_addr;
+ if (family == AF_INET) {
+ so->fhost.sin = addr.addr4;
+ } else {
+ so->fhost.sin6 = addr.addr6;
+ }
+ sotranslate_accept(so);
so->s = s;
return so;
}
+struct socket *tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
+ uint32_t laddr, unsigned lport, int flags)
+{
+ DEBUG_CALL("tcp_listen");
+ DEBUG_ARG("haddr = %s", inet_ntoa((struct in_addr){ .s_addr = haddr }));
+ DEBUG_ARG("hport = %d", ntohs(hport));
+ DEBUG_ARG("laddr = %s", inet_ntoa((struct in_addr){ .s_addr = laddr }));
+ DEBUG_ARG("lport = %d", ntohs(lport));
+ DEBUG_ARG("flags = %x", flags);
+
+ in4or6_addr haddr4, laddr4;
+
+ haddr4.addr4 = haddr;
+ laddr4.addr4 = laddr;
+ return tcpx_listen(slirp, AF_INET, haddr4, hport, laddr4, lport, flags);
+}
+
+struct socket *
+tcp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport,
+ struct in6_addr laddr, u_int lport, int flags)
+{
+ DEBUG_CALL("tcp6_listen");
+ char addrstr[INET6_ADDRSTRLEN];
+ const char *str = inet_ntop(AF_INET6, &haddr, addrstr, INET6_ADDRSTRLEN);
+ g_assert(str != NULL);
+ DEBUG_ARG("haddr = %s", str);
+ DEBUG_ARG("hport = %d", ntohs(hport));
+ str = inet_ntop(AF_INET6, &laddr, addrstr, INET6_ADDRSTRLEN);
+ g_assert(str != NULL);
+ DEBUG_ARG("laddr = %s", str);
+ DEBUG_ARG("lport = %d", ntohs(lport));
+ DEBUG_ARG("flags = %x", flags);
+
+ in4or6_addr haddr6, laddr6;
+
+ haddr6.addr6 = haddr;
+ laddr6.addr6 = laddr;
+ return tcpx_listen(slirp, AF_INET6, haddr6, hport, laddr6, lport, flags);
+}
+
/*
* Various session state calls
* XXX Should be #define's
diff --git a/src/socket.h b/src/socket.h
index a6a1e5e..425c607 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -11,6 +11,13 @@
#define SO_EXPIRE 240000
#define SO_EXPIREFAST 10000
+/* Helps unify some in/in6 routines. */
+union in4or6_addr {
+ uint32_t addr4;
+ struct in6_addr addr6;
+};
+typedef union in4or6_addr in4or6_addr;
+
/*
* Our socket structure
*/
@@ -148,6 +155,8 @@ int sowrite(struct socket *);
void sorecvfrom(struct socket *);
int sosendto(struct socket *, struct mbuf *);
struct socket *tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
+struct socket *tcp6_listen(Slirp *, struct in6_addr, u_int,
+ struct in6_addr, u_int, int);
void soisfconnecting(register struct socket *);
void soisfconnected(register struct socket *);
void sofwdrain(struct socket *);
diff --git a/src/udp.c b/src/udp.c
index 050cee4..52502b9 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -353,17 +353,20 @@ static uint8_t udp_tos(struct socket *so)
return 0;
}
-struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
- uint32_t laddr, unsigned lport, int flags)
+static struct socket *udpx_listen(Slirp *slirp, int family,
+ in4or6_addr haddr, unsigned hport,
+ in4or6_addr laddr, unsigned lport,
+ int flags)
{
- /* TODO: IPv6 */
- struct sockaddr_in addr;
+ union {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } addr;
struct socket *so;
- socklen_t addrlen = sizeof(struct sockaddr_in);
+ socklen_t addrlen;
- memset(&addr, 0, sizeof(addr));
so = socreate(slirp);
- so->s = slirp_socket(AF_INET, SOCK_DGRAM, 0);
+ so->s = slirp_socket(family, SOCK_DGRAM, 0);
if (so->s < 0) {
sofree(so);
return NULL;
@@ -371,9 +374,18 @@ struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
so->so_expire = curtime + SO_EXPIRE;
insque(so, &slirp->udb);
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = haddr;
- addr.sin_port = hport;
+ memset(&addr, 0, sizeof(addr));
+ if (family == AF_INET) {
+ addr.addr4.sin_family = family;
+ addr.addr4.sin_addr.s_addr = haddr.addr4;
+ addr.addr4.sin_port = hport;
+ addrlen = sizeof(addr.addr4);
+ } else {
+ addr.addr6.sin6_family = family;
+ addr.addr6.sin6_addr = haddr.addr6;
+ addr.addr6.sin6_port = hport;
+ addrlen = sizeof(addr.addr6);
+ }
if (bind(so->s, (struct sockaddr *)&addr, addrlen) < 0) {
udp_detach(so);
@@ -382,16 +394,47 @@ struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
slirp_socket_set_fast_reuse(so->s);
getsockname(so->s, (struct sockaddr *)&addr, &addrlen);
- so->fhost.sin = addr;
+ if (family == AF_INET) {
+ so->fhost.sin = addr.addr4;
+ } else {
+ so->fhost.sin6 = addr.addr6;
+ }
sotranslate_accept(so);
- so->so_lfamily = AF_INET;
- so->so_lport = lport;
- so->so_laddr.s_addr = laddr;
+
+ so->so_lfamily = family;
+ if (family == AF_INET) {
+ so->so_laddr.s_addr = laddr.addr4;
+ so->so_lport = lport;
+ } else {
+ so->so_laddr6 = laddr.addr6;
+ so->so_lport6 = lport;
+ }
+
if (flags != SS_FACCEPTONCE)
so->so_expire = 0;
-
so->so_state &= SS_PERSISTENT_MASK;
so->so_state |= SS_ISFCONNECTED | flags;
return so;
}
+
+struct socket *udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport,
+ uint32_t laddr, unsigned lport, int flags)
+{
+ in4or6_addr haddr4, laddr4;
+
+ haddr4.addr4 = haddr;
+ laddr4.addr4 = laddr;
+ return udpx_listen(slirp, AF_INET, haddr4, hport, laddr4, lport, flags);
+}
+
+struct socket *
+udp6_listen(Slirp *slirp, struct in6_addr haddr, u_int hport,
+ struct in6_addr laddr, u_int lport, int flags)
+{
+ in4or6_addr haddr6, laddr6;
+
+ haddr6.addr6 = haddr;
+ laddr6.addr6 = laddr;
+ return udpx_listen(slirp, AF_INET6, haddr6, hport, laddr6, lport, flags);
+}
diff --git a/src/udp.h b/src/udp.h
index c3b83fd..b3fbeac 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -80,6 +80,8 @@ void udp_input(register struct mbuf *, int);
int udp_attach(struct socket *, unsigned short af);
void udp_detach(struct socket *);
struct socket *udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned, int);
+struct socket *udp6_listen(Slirp *slirp, struct in6_addr, u_int,
+ struct in6_addr, u_int, int);
int udp_output(struct socket *so, struct mbuf *m, struct sockaddr_in *saddr,
struct sockaddr_in *daddr, int iptos);
--
2.30.0.296.g2bfb1c46d8-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] net: Add ipv6_hostfwd option
2021-01-21 8:23 [PATCH 0/2] Add ipv6 hostfwd support dje--- via
2021-01-21 8:23 ` [PATCH 1/2] slirp: " dje--- via
@ 2021-01-21 8:23 ` dje--- via
2021-01-21 22:30 ` Eric Blake
2021-01-21 9:41 ` [PATCH 0/2] Add ipv6 hostfwd support Marc-André Lureau
2 siblings, 1 reply; 7+ messages in thread
From: dje--- via @ 2021-01-21 8:23 UTC (permalink / raw)
To: qemu-devel; +Cc: Samuel Thibault, Doug Evans
Signed-off-by: Doug Evans <dje@google.com>
---
hmp-commands.hx | 29 ++++-
include/net/slirp.h | 2 +
net/slirp.c | 311 +++++++++++++++++++++++++++++++++++---------
qapi/net.json | 1 +
slirp | 2 +-
5 files changed, 279 insertions(+), 66 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 73e0832ea1..fa404123b7 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1398,6 +1398,34 @@ SRST
Remove host-to-guest TCP or UDP redirection.
ERST
+#ifdef CONFIG_SLIRP
+ {
+ .name = "ipv6_hostfwd_add",
+ .args_type = "arg1:s,arg2:s?",
+ .params = "[netdev_id] [tcp|udp]:[hostaddr6]:hostport-[guestaddr6]:guestport",
+ .help = "redirect TCP6 or UDP6 connections from host to guest (requires -net user)",
+ .cmd = hmp_ipv6_hostfwd_add,
+ },
+#endif
+SRST
+``ipv6_hostfwd_add``
+ Redirect TCP6 or UDP6 connections from host to guest (requires -net user).
+ERST
+
+#ifdef CONFIG_SLIRP
+ {
+ .name = "ipv6_hostfwd_remove",
+ .args_type = "arg1:s,arg2:s?",
+ .params = "[netdev_id] [tcp|udp]:[hostaddr6]:hostport",
+ .help = "remove host-to-guest TCP6 or UDP6 redirection",
+ .cmd = hmp_ipv6_hostfwd_remove,
+ },
+#endif
+SRST
+``ipv6_hostfwd_remove``
+ Remove host-to-guest TCP6 or UDP6 redirection.
+ERST
+
{
.name = "balloon",
.args_type = "value:M",
@@ -1866,4 +1894,3 @@ ERST
.sub_table = hmp_info_cmds,
.flags = "p",
},
-
diff --git a/include/net/slirp.h b/include/net/slirp.h
index bad3e1e241..4796a5cd39 100644
--- a/include/net/slirp.h
+++ b/include/net/slirp.h
@@ -29,6 +29,8 @@
void hmp_hostfwd_add(Monitor *mon, const QDict *qdict);
void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict);
+void hmp_ipv6_hostfwd_add(Monitor *mon, const QDict *qdict);
+void hmp_ipv6_hostfwd_remove(Monitor *mon, const QDict *qdict);
void hmp_info_usernet(Monitor *mon, const QDict *qdict);
diff --git a/net/slirp.c b/net/slirp.c
index 8350c6d45f..5870a3284a 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -70,6 +70,7 @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
/* slirp network adapter */
#define SLIRP_CFG_HOSTFWD 1
+#define SLIRP_CFG_IPV6_HOSTFWD 2
struct slirp_config_str {
struct slirp_config_str *next;
@@ -101,6 +102,8 @@ static QTAILQ_HEAD(, SlirpState) slirp_stacks =
QTAILQ_HEAD_INITIALIZER(slirp_stacks);
static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
+static int slirp_ipv6_hostfwd(SlirpState *s, const char *redir_str,
+ Error **errp);
static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp);
#ifndef _WIN32
@@ -586,6 +589,10 @@ static int net_slirp_init(NetClientState *peer, const char *model,
if (slirp_hostfwd(s, config->str, errp) < 0) {
goto error;
}
+ } else if (config->flags & SLIRP_CFG_IPV6_HOSTFWD) {
+ if (slirp_ipv6_hostfwd(s, config->str, errp) < 0) {
+ goto error;
+ }
} else {
if (slirp_guestfwd(s, config->str, errp) < 0) {
goto error;
@@ -631,15 +638,136 @@ static SlirpState *slirp_lookup(Monitor *mon, const char *id)
}
}
-void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
+/*
+ * Parse a protocol name of the form "name<sep>".
+ * Valid protocols are "tcp" and "udp". An empty string means "tcp".
+ * Returns a pointer to the end of the parsed string on success, and stores
+ * the result in *is_udp.
+ * Otherwise returns NULL and stores the error message in *errmsg, which must
+ * be freed by the caller.
+ */
+static const char *parse_protocol(const char *str, int sep, int *is_udp,
+ char **errmsg)
+{
+ char buf[10];
+ const char *p = str;
+
+ if (get_str_sep(buf, sizeof(buf), &p, sep) < 0) {
+ *errmsg = g_strdup("Missing protcol name separator");
+ return NULL;
+ }
+
+ if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+ *is_udp = 0;
+ } else if (!strcmp(buf, "udp")) {
+ *is_udp = 1;
+ } else {
+ *errmsg = g_strdup("Bad protcol name");
+ return NULL;
+ }
+
+ return p;
+}
+
+/*
+ * Parse an ipv4 address/port of the form "addr<addr_sep>port<port_sep>".
+ * "kind" is either "host" or "guest" and is included in error messages.
+ * An empty address means INADDR_ANY.
+ * Returns a pointer to the end of the parsed string on success, and stores
+ * the results in *addr, *port.
+ * Otherwise returns NULL and stores the error message in *errmsg, which must
+ * be freed by the caller.
+ */
+static const char *parse_in4_addr_port(const char *str, const char *kind,
+ int addr_sep, int port_sep,
+ struct in_addr *addr, int *port,
+ char **errmsg)
{
- struct in_addr host_addr = { .s_addr = INADDR_ANY };
- int host_port;
char buf[256];
- const char *src_str, *p;
+ const char *p = str;
+
+ if (get_str_sep(buf, sizeof(buf), &p, addr_sep) < 0) {
+ *errmsg = g_strdup_printf("Missing %s address separator", kind);
+ return NULL;
+ }
+ if (buf[0] == '\0') {
+ addr->s_addr = INADDR_ANY;
+ } else if (!inet_aton(buf, addr)) {
+ *errmsg = g_strdup_printf("Bad %s address", kind);
+ return NULL;
+ }
+
+ if (get_str_sep(buf, sizeof(buf), &p, port_sep) < 0) {
+ *errmsg = g_strdup_printf("Missing %s port separator", kind);
+ return NULL;
+ }
+ if (qemu_strtoi(buf, NULL, 10, port) < 0 ||
+ *port < 0 || *port > 65535) {
+ *errmsg = g_strdup_printf("Bad %s port", kind);
+ return NULL;
+ }
+
+ return p;
+}
+
+/*
+ * Parse an ipv6 address/port of the form "addr<addr_sep>port<port_sep>".
+ * "kind" is either "host" or "guest" and is included in error messages.
+ * An empty address means in6addr_any.
+ * Returns a pointer to the end of the parsed string on success, and stores
+ * the results in *addr, *port.
+ * Otherwise returns NULL and stores the error message in *errmsg, which must
+ * be freed by the caller.
+ */
+static const char *parse_in6_addr_port(const char *str, const char *kind,
+ int addr_sep, int port_sep,
+ struct in6_addr *addr, int *port,
+ char **errmsg)
+{
+ char buf[256];
+ const char *p = str;
+
+ if (*(p++) != '[') {
+ *errmsg = g_strdup_printf("IPv6 %s address must be enclosed"
+ " in square brackets", kind);
+ return NULL;
+ }
+ if (get_str_sep(buf, sizeof(buf), &p, ']') < 0) {
+ *errmsg = g_strdup_printf("IPv6 %s address must be enclosed"
+ " in square brackets", kind);
+ return NULL;
+ }
+ if (buf[0] == '\0') {
+ *addr = in6addr_any;
+ } else if (!inet_pton(AF_INET6, buf, addr)) {
+ *errmsg = g_strdup_printf("Bad %s address", kind);
+ return NULL;
+ }
+
+ /* Ignore the part between the ']' and addr_sep. */
+ if (get_str_sep(buf, sizeof(buf), &p, addr_sep) < 0) {
+ *errmsg = g_strdup_printf("Missing %s address separator", kind);
+ return NULL;
+ }
+
+ if (get_str_sep(buf, sizeof(buf), &p, port_sep) < 0) {
+ *errmsg = g_strdup_printf("Missing %s port separator", kind);
+ return NULL;
+ }
+ if (qemu_strtoi(buf, NULL, 10, port) < 0 ||
+ *port < 0 || *port > 65535) {
+ *errmsg = g_strdup_printf("Bad %s port", kind);
+ return NULL;
+ }
+
+ return p;
+}
+
+static void hmp_hostfwd_remove_worker(Monitor *mon, const QDict *qdict,
+ int family)
+{
+ const char *src_str;
SlirpState *s;
- int is_udp = 0;
- int err;
const char *arg1 = qdict_get_str(qdict, "arg1");
const char *arg2 = qdict_get_try_str(qdict, "arg2");
@@ -654,38 +782,52 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
return;
}
- p = src_str;
- if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
+ int host_port;
+ int is_udp;
+ char *errmsg = NULL;
+ int err;
- if (!strcmp(buf, "tcp") || buf[0] == '\0') {
- is_udp = 0;
- } else if (!strcmp(buf, "udp")) {
- is_udp = 1;
- } else {
- goto fail_syntax;
- }
+ g_assert(src_str != NULL);
+ const char *p = src_str;
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+ p = parse_protocol(p, ':', &is_udp, &errmsg);
+ if (p == NULL) {
goto fail_syntax;
}
- if (qemu_strtoi(p, NULL, 10, &host_port)) {
- goto fail_syntax;
+ if (family == AF_INET) {
+ struct in_addr host_addr;
+ if (parse_in4_addr_port(p, "host", ':', '\0', &host_addr, &host_port,
+ &errmsg) == NULL) {
+ goto fail_syntax;
+ }
+ err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
+ } else {
+ struct in6_addr host_addr;
+ if (parse_in6_addr_port(p, "host", ':', '\0', &host_addr, &host_port,
+ &errmsg) == NULL) {
+ goto fail_syntax;
+ }
+ err = slirp_remove_ipv6_hostfwd(s->slirp, is_udp, host_addr, host_port);
}
- err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
-
monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
err ? "not found" : "removed");
return;
fail_syntax:
- monitor_printf(mon, "invalid format\n");
+ monitor_printf(mon, "Invalid format: %s\n", errmsg);
+ g_free(errmsg);
+}
+
+void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
+{
+ hmp_hostfwd_remove_worker(mon, qdict, AF_INET);
+}
+
+void hmp_ipv6_hostfwd_remove(Monitor *mon, const QDict *qdict)
+{
+ hmp_hostfwd_remove_worker(mon, qdict, AF_INET6);
}
static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
@@ -694,61 +836,83 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
struct in_addr guest_addr = { .s_addr = 0 };
int host_port, guest_port;
const char *p;
- char buf[256];
int is_udp;
- char *end;
- const char *fail_reason = "Unknown reason";
+ char *errmsg = NULL;
+ g_assert(redir_str != NULL);
p = redir_str;
- if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- fail_reason = "No : separators";
+
+ p = parse_protocol(p, ':', &is_udp, &errmsg);
+ if (p == NULL) {
goto fail_syntax;
}
- if (!strcmp(buf, "tcp") || buf[0] == '\0') {
- is_udp = 0;
- } else if (!strcmp(buf, "udp")) {
- is_udp = 1;
- } else {
- fail_reason = "Bad protocol name";
+
+ p = parse_in4_addr_port(p, "host", ':', '-', &host_addr, &host_port,
+ &errmsg);
+ if (p == NULL) {
goto fail_syntax;
}
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- fail_reason = "Missing : separator";
+ if (parse_in4_addr_port(p, "guest", ':', '\0', &guest_addr, &guest_port,
+ &errmsg) == NULL) {
goto fail_syntax;
}
- if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
- fail_reason = "Bad host address";
+ if (guest_port == 0) {
+ errmsg = g_strdup("Bad guest port");
goto fail_syntax;
}
- if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
- fail_reason = "Bad host port separator";
- goto fail_syntax;
+ if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
+ guest_port) < 0) {
+ error_setg(errp, "Could not set up host forwarding rule '%s'",
+ redir_str);
+ return -1;
}
- host_port = strtol(buf, &end, 0);
- if (*end != '\0' || host_port < 0 || host_port > 65535) {
- fail_reason = "Bad host port";
+ return 0;
+
+ fail_syntax:
+ error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str,
+ errmsg);
+ g_free(errmsg);
+ return -1;
+}
+
+static int slirp_ipv6_hostfwd(SlirpState *s, const char *redir_str,
+ Error **errp)
+{
+ struct in6_addr host_addr = in6addr_any;
+ struct in6_addr guest_addr;
+ int host_port, guest_port;
+ const char *p;
+ int is_udp;
+ char *errmsg = NULL;
+
+ memset(&guest_addr, 0, sizeof(guest_addr));
+ g_assert(redir_str != NULL);
+ p = redir_str;
+
+ p = parse_protocol(p, ':', &is_udp, &errmsg);
+ if (p == NULL) {
goto fail_syntax;
}
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- fail_reason = "Missing guest address";
+ p = parse_in6_addr_port(p, "host", ':', '-', &host_addr, &host_port,
+ &errmsg);
+ if (p == NULL) {
goto fail_syntax;
}
- if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
- fail_reason = "Bad guest address";
+
+ if (parse_in6_addr_port(p, "guest", ':', '\0', &guest_addr, &guest_port,
+ &errmsg) == NULL) {
goto fail_syntax;
}
-
- guest_port = strtol(p, &end, 0);
- if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
- fail_reason = "Bad guest port";
+ if (guest_port == 0) {
+ errmsg = g_strdup("Bad guest port");
goto fail_syntax;
}
- if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
- guest_port) < 0) {
+ if (slirp_add_ipv6_hostfwd(s->slirp, is_udp, host_addr, host_port,
+ guest_addr, guest_port) < 0) {
error_setg(errp, "Could not set up host forwarding rule '%s'",
redir_str);
return -1;
@@ -757,11 +921,12 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
fail_syntax:
error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str,
- fail_reason);
+ errmsg);
+ g_free(errmsg);
return -1;
}
-void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
+static void hmp_hostfwd_add_worker(Monitor *mon, const QDict *qdict, int family)
{
const char *redir_str;
SlirpState *s;
@@ -775,13 +940,30 @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
s = slirp_lookup(mon, NULL);
redir_str = arg1;
}
- if (s) {
- Error *err = NULL;
- if (slirp_hostfwd(s, redir_str, &err) < 0) {
- error_report_err(err);
- }
+ if (!s) {
+ return;
+ }
+
+ Error *err = NULL;
+ int rc;
+ if (family == AF_INET) {
+ rc = slirp_hostfwd(s, redir_str, &err);
+ } else {
+ rc = slirp_ipv6_hostfwd(s, redir_str, &err);
+ }
+ if (rc < 0) {
+ error_report_err(err);
}
+}
+
+void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
+{
+ hmp_hostfwd_add_worker(mon, qdict, AF_INET);
+}
+void hmp_ipv6_hostfwd_add(Monitor *mon, const QDict *qdict)
+{
+ hmp_hostfwd_add_worker(mon, qdict, AF_INET6);
}
#ifndef _WIN32
@@ -1090,6 +1272,7 @@ int net_init_slirp(const Netdev *netdev, const char *name,
/* all optional fields are initialized to "all bits zero" */
net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
+ net_init_slirp_configs(user->ipv6_hostfwd, SLIRP_CFG_IPV6_HOSTFWD);
net_init_slirp_configs(user->guestfwd, 0);
ret = net_slirp_init(peer, "user", name, user->q_restrict,
diff --git a/qapi/net.json b/qapi/net.json
index c31748c87f..34ea92277c 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -189,6 +189,7 @@
'*smb': 'str',
'*smbserver': 'str',
'*hostfwd': ['String'],
+ '*ipv6-hostfwd': ['String'],
'*guestfwd': ['String'],
'*tftp-server-name': 'str' } }
diff --git a/slirp b/slirp
index 8f43a99191..6c0db866ef 160000
--- a/slirp
+++ b/slirp
@@ -1 +1 @@
-Subproject commit 8f43a99191afb47ca3f3c6972f6306209f367ece
+Subproject commit 6c0db866ef5e11a3b87640e57769fbf9b0a1e3b8
--
2.30.0.296.g2bfb1c46d8-goog
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Add ipv6 hostfwd support
2021-01-21 8:23 [PATCH 0/2] Add ipv6 hostfwd support dje--- via
2021-01-21 8:23 ` [PATCH 1/2] slirp: " dje--- via
2021-01-21 8:23 ` [PATCH 2/2] net: Add ipv6_hostfwd option dje--- via
@ 2021-01-21 9:41 ` Marc-André Lureau
2021-01-21 20:28 ` dje--- via
2 siblings, 1 reply; 7+ messages in thread
From: Marc-André Lureau @ 2021-01-21 9:41 UTC (permalink / raw)
To: Doug Evans; +Cc: Samuel Thibault, QEMU
Hi Doug,
On Thu, Jan 21, 2021 at 12:24 PM dje--- via <qemu-devel@nongnu.org> wrote:
>
> Hi. This patchset takes the original patch from Maxim,
> https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
> and updates it.
>
> The first patch is the slirp additions, the second patch adds the u/i.
libslirp is maintained on gitlab. Can you open a merge request?
https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests
thanks
>
> Doug Evans (2):
> slirp: Add ipv6 hostfwd support
> net: Add ipv6_hostfwd option
>
> Slirp:
> src/libslirp.h | 6 +++
> src/slirp.c | 51 +++++++++++++++++++++--
> src/socket.c | 109 +++++++++++++++++++++++++++++++++++--------------
> src/socket.h | 9 ++++
> src/udp.c | 73 ++++++++++++++++++++++++++-------
> src/udp.h | 2 +
> 6 files changed, 202 insertions(+), 48 deletions(-)
>
> QEMU:
> hmp-commands.hx | 29 ++++-
> include/net/slirp.h | 2 +
> net/slirp.c | 311 +++++++++++++++++++++++++++++++++++---------
> qapi/net.json | 1 +
> slirp | 2 +-
> 5 files changed, 279 insertions(+), 66 deletions(-)
>
> --
> 2.30.0.296.g2bfb1c46d8-goog
>
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Add ipv6 hostfwd support
2021-01-21 9:41 ` [PATCH 0/2] Add ipv6 hostfwd support Marc-André Lureau
@ 2021-01-21 20:28 ` dje--- via
2021-01-21 20:40 ` Marc-André Lureau
0 siblings, 1 reply; 7+ messages in thread
From: dje--- via @ 2021-01-21 20:28 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: Samuel Thibault, QEMU
[-- Attachment #1: Type: text/plain, Size: 1757 bytes --]
On Thu, Jan 21, 2021 at 1:41 AM Marc-André Lureau <
marcandre.lureau@gmail.com> wrote:
> Hi Doug,
>
> On Thu, Jan 21, 2021 at 12:24 PM dje--- via <qemu-devel@nongnu.org> wrote:
> >
> > Hi. This patchset takes the original patch from Maxim,
> > https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
> > and updates it.
> >
> > The first patch is the slirp additions, the second patch adds the u/i.
>
> libslirp is maintained on gitlab. Can you open a merge request?
> https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests
>
> thanks
>
Hi. Sure, no problem.
I wasn't sure what the procedure is but figured it would come out during
the review.
How does review of libslirp patches work?
I gather Samuel is a libslirp maintainer so I'm guessing it just needs to
be approved here (after appropriate review) and then afterwards I should
file the merge request?
>
> >
> > Doug Evans (2):
> > slirp: Add ipv6 hostfwd support
> > net: Add ipv6_hostfwd option
> >
> > Slirp:
> > src/libslirp.h | 6 +++
> > src/slirp.c | 51 +++++++++++++++++++++--
> > src/socket.c | 109 +++++++++++++++++++++++++++++++++++--------------
> > src/socket.h | 9 ++++
> > src/udp.c | 73 ++++++++++++++++++++++++++-------
> > src/udp.h | 2 +
> > 6 files changed, 202 insertions(+), 48 deletions(-)
> >
> > QEMU:
> > hmp-commands.hx | 29 ++++-
> > include/net/slirp.h | 2 +
> > net/slirp.c | 311 +++++++++++++++++++++++++++++++++++---------
> > qapi/net.json | 1 +
> > slirp | 2 +-
> > 5 files changed, 279 insertions(+), 66 deletions(-)
> >
> > --
> > 2.30.0.296.g2bfb1c46d8-goog
> >
> >
>
>
> --
> Marc-André Lureau
>
[-- Attachment #2: Type: text/html, Size: 3022 bytes --]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Add ipv6 hostfwd support
2021-01-21 20:28 ` dje--- via
@ 2021-01-21 20:40 ` Marc-André Lureau
0 siblings, 0 replies; 7+ messages in thread
From: Marc-André Lureau @ 2021-01-21 20:40 UTC (permalink / raw)
To: Doug Evans; +Cc: Samuel Thibault, QEMU
Hi Doug
On Fri, Jan 22, 2021 at 12:29 AM Doug Evans <dje@google.com> wrote:
>
> On Thu, Jan 21, 2021 at 1:41 AM Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>>
>> Hi Doug,
>>
>> On Thu, Jan 21, 2021 at 12:24 PM dje--- via <qemu-devel@nongnu.org> wrote:
>> >
>> > Hi. This patchset takes the original patch from Maxim,
>> > https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
>> > and updates it.
>> >
>> > The first patch is the slirp additions, the second patch adds the u/i.
>>
>> libslirp is maintained on gitlab. Can you open a merge request?
>> https://gitlab.freedesktop.org/slirp/libslirp/-/merge_requests
>>
>> thanks
>
>
>
> Hi. Sure, no problem.
> I wasn't sure what the procedure is but figured it would come out during the review.
> How does review of libslirp patches work?
We do the reviews on the gitlab MR (of the individual patches).
> I gather Samuel is a libslirp maintainer so I'm guessing it just needs to be approved here (after appropriate review) and then afterwards I should file the merge request?
Any of the libslirp maintainer can merge after reviews (including me).
Then anybody can propose a patch to update libslirp in qemu, get
reviews/comments, and Samuel can send the pull request. Sometimes
someone else sends it.
Note that libslirp is packaged in a number of distributions these days
(https://repology.org/project/libslirp/versions), and that qemu may
link to it depending on how it is built.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] net: Add ipv6_hostfwd option
2021-01-21 8:23 ` [PATCH 2/2] net: Add ipv6_hostfwd option dje--- via
@ 2021-01-21 22:30 ` Eric Blake
0 siblings, 0 replies; 7+ messages in thread
From: Eric Blake @ 2021-01-21 22:30 UTC (permalink / raw)
To: Doug Evans, qemu-devel; +Cc: Samuel Thibault
On 1/21/21 2:23 AM, dje--- via wrote:
> Signed-off-by: Doug Evans <dje@google.com>
> ---
Rather light on the commit message description. The one-line summary
does a good job of saying "what" the commit does, but the rest of the
commit body should say "why" the commit is worthwhile, rather than being
silent.
> hmp-commands.hx | 29 ++++-
> include/net/slirp.h | 2 +
> net/slirp.c | 311 +++++++++++++++++++++++++++++++++++---------
> qapi/net.json | 1 +
> slirp | 2 +-
> 5 files changed, 279 insertions(+), 66 deletions(-)
>
> +++ b/qapi/net.json
> @@ -189,6 +189,7 @@
> '*smb': 'str',
> '*smbserver': 'str',
> '*hostfwd': ['String'],
> + '*ipv6-hostfwd': ['String'],
Missing documentation, including a 'since 6.0' tag on the new member.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2021-01-21 22:32 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-21 8:23 [PATCH 0/2] Add ipv6 hostfwd support dje--- via
2021-01-21 8:23 ` [PATCH 1/2] slirp: " dje--- via
2021-01-21 8:23 ` [PATCH 2/2] net: Add ipv6_hostfwd option dje--- via
2021-01-21 22:30 ` Eric Blake
2021-01-21 9:41 ` [PATCH 0/2] Add ipv6 hostfwd support Marc-André Lureau
2021-01-21 20:28 ` dje--- via
2021-01-21 20:40 ` Marc-André Lureau
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.