From: dje--- via <qemu-devel@nongnu.org>
To: qemu-devel@nongnu.org
Cc: Samuel Thibault <samuel.thibault@ens-lyon.org>,
Doug Evans <dje@google.com>
Subject: [PATCH v2 2/2] net: Add -ipv6-hostfwd option, ipv6_hostfwd_add/remove commands
Date: Wed, 3 Feb 2021 13:37:29 -0800 [thread overview]
Message-ID: <20210203213729.1940893-3-dje@google.com> (raw)
In-Reply-To: <20210203213729.1940893-1-dje@google.com>
These are identical to their ipv4 counterparts, but for ipv6.
Signed-off-by: Doug Evans <dje@google.com>
---
hmp-commands.hx | 28 ++++++++++
include/net/slirp.h | 2 +
net/slirp.c | 129 +++++++++++++++++++++++++++++++++++++++++++-
qapi/net.json | 4 ++
4 files changed, 161 insertions(+), 2 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index d4001f9c5d..bd51173472 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1392,6 +1392,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",
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 a21a313302..2482dbd36c 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;
@@ -703,6 +710,59 @@ static const char *parse_in4_addr_port(const char *str, const char *kind,
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)
{
@@ -743,7 +803,12 @@ static void hmp_hostfwd_remove_worker(Monitor *mon, const QDict *qdict,
}
err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
} else {
- g_assert_not_reached();
+ 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);
}
monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
@@ -760,6 +825,11 @@ 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)
{
struct in_addr host_addr = { .s_addr = INADDR_ANY };
@@ -807,6 +877,55 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
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;
+ }
+
+ p = parse_in6_addr_port(p, "host", ':', '-', &host_addr, &host_port,
+ &errmsg);
+ if (p == NULL) {
+ goto fail_syntax;
+ }
+
+ if (parse_in6_addr_port(p, "guest", ':', '\0', &guest_addr, &guest_port,
+ &errmsg) == NULL) {
+ goto fail_syntax;
+ }
+ if (guest_port == 0) {
+ errmsg = g_strdup("Bad guest port");
+ goto fail_syntax;
+ }
+
+ 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;
+ }
+ return 0;
+
+ fail_syntax:
+ error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str,
+ errmsg);
+ g_free(errmsg);
+ return -1;
+}
+
static void hmp_hostfwd_add_worker(Monitor *mon, const QDict *qdict, int family)
{
const char *redir_str;
@@ -830,7 +949,7 @@ static void hmp_hostfwd_add_worker(Monitor *mon, const QDict *qdict, int family)
if (family == AF_INET) {
rc = slirp_hostfwd(s, redir_str, &err);
} else {
- g_assert_not_reached();
+ rc = slirp_ipv6_hostfwd(s, redir_str, &err);
}
if (rc < 0) {
error_report_err(err);
@@ -842,6 +961,11 @@ 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
/* automatic user mode samba server configuration */
@@ -1148,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..443473107a 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -161,6 +161,9 @@
# @hostfwd: redirect incoming TCP or UDP host connections to guest
# endpoints
#
+# @ipv6-hostfwd: redirect incoming IPV6 TCP or UDP host connections to
+# guest endpoints (since 6.0)
+#
# @guestfwd: forward guest TCP connections
#
# @tftp-server-name: RFC2132 "TFTP server name" string (Since 3.1)
@@ -189,6 +192,7 @@
'*smb': 'str',
'*smbserver': 'str',
'*hostfwd': ['String'],
+ '*ipv6-hostfwd': ['String'],
'*guestfwd': ['String'],
'*tftp-server-name': 'str' } }
--
2.30.0.365.g02bc693789-goog
next prev parent reply other threads:[~2021-02-03 21:40 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-03 21:37 [PATCH v2 0/2] Add support for ipv6 host forwarding dje--- via
2021-02-03 21:37 ` [PATCH v2 1/2] net/slirp.c: Refactor address parsing dje--- via
2021-02-03 21:39 ` Doug Evans
2021-02-03 22:15 ` Samuel Thibault
2021-02-03 22:31 ` Doug Evans
2021-02-08 11:09 ` Philippe Mathieu-Daudé
2021-02-08 18:59 ` Doug Evans
2021-02-28 22:44 ` Samuel Thibault
2021-02-03 21:37 ` dje--- via [this message]
2021-02-03 22:20 ` [PATCH v2 2/2] net: Add -ipv6-hostfwd option, ipv6_hostfwd_add/remove commands Samuel Thibault
2021-02-03 22:29 ` Doug Evans
2021-02-04 9:57 ` Daniel P. Berrangé
2021-02-03 21:45 ` [PATCH v2 0/2] Add support for ipv6 host forwarding no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210203213729.1940893-3-dje@google.com \
--to=qemu-devel@nongnu.org \
--cc=dje@google.com \
--cc=samuel.thibault@ens-lyon.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.