All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maxim Samoylov <max7255@yandex-team.ru>
To: qemu-devel@nongnu.org
Cc: max7255@yandex-team.ru
Subject: [Qemu-devel] [PATCH RFC 4/4] net/slirp: add ipv6-hostfwd option for user netdev type
Date: Fri, 26 Oct 2018 03:03:43 +0300	[thread overview]
Message-ID: <1540512223-21199-5-git-send-email-max7255@yandex-team.ru> (raw)
In-Reply-To: <1540512223-21199-1-git-send-email-max7255@yandex-team.ru>

This allows forwarding TCP6 and UDP6 connections down to
netdev=user connected guests.

Signed-off-by: Maxim Samoylov <max7255@yandex-team.ru>
---
 hmp-commands.hx     |  31 ++++++++
 include/net/slirp.h |   2 +
 net/slirp.c         | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 qapi/net.json       |   3 +-
 4 files changed, 249 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index db0c681..b0e1a08 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1448,6 +1448,37 @@ STEXI
 Remove host-to-guest TCP or UDP redirection.
 ETEXI
 
+#ifdef CONFIG_SLIRP
+    {
+        .name       = "ipv6_hostfwd_add",
+        .args_type  = "arg1:s,arg2:s?,arg3:s?",
+        .params     = "[hub_id name]|[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
+STEXI
+@item hostfwd_add
+@findex hostfwd_add
+Redirect TCP6 or UDP6 connections from host to guest (requires -net user).
+ETEXI
+
+#ifdef CONFIG_SLIRP
+    {
+        .name       = "ipv6_hostfwd_remove",
+        .args_type  = "arg1:s,arg2:s?,arg3:s?",
+        .params     = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr6]:hostport",
+        .help       = "remove host-to-guest TCP6 or UDP6 redirection",
+        .cmd        = hmp_ipv6_hostfwd_remove,
+    },
+
+#endif
+STEXI
+@item hostfwd_remove
+@findex hostfwd_remove
+Remove host-to-guest TCP6 or UDP6 redirection.
+ETEXI
+
     {
         .name       = "balloon",
         .args_type  = "value:M",
diff --git a/include/net/slirp.h b/include/net/slirp.h
index bad3e1e..4796a5c 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 f6dc039..abe112b 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -67,6 +67,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;
@@ -89,6 +90,8 @@ static QTAILQ_HEAD(slirp_stacks, 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
@@ -386,6 +389,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;
@@ -504,6 +511,73 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
     monitor_printf(mon, "invalid format\n");
 }
 
+void hmp_ipv6_hostfwd_remove(Monitor *mon, const QDict *qdict)
+{
+    struct in6_addr host_addr = in6addr_any;
+    int host_port;
+    char buf[256];
+    const char *src_str, *p;
+    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");
+    const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+    if (arg2) {
+        s = slirp_lookup(mon, arg1, arg2);
+        src_str = arg3;
+    } else {
+        s = slirp_lookup(mon, NULL, NULL);
+        src_str = arg1;
+    }
+    if (!s) {
+        return;
+    }
+
+    p = src_str;
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        is_udp = 0;
+    } else if (!strcmp(buf, "udp")) {
+        is_udp = 1;
+    } else {
+        goto fail_syntax;
+    }
+
+    if (*(p++) != '[') {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ']') < 0) {
+        goto fail_syntax;
+    }
+
+    if (!inet_pton(AF_INET6, buf, &host_addr)) {
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+
+    if (qemu_strtoi(p, NULL, 10, &host_port) < 0) {
+        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,
+                   err ? "not found" : "removed");
+    return;
+
+ fail_syntax:
+    monitor_printf(mon, "invalid format\n");
+}
+
 static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
 {
     struct in_addr host_addr = { .s_addr = INADDR_ANY };
@@ -577,6 +651,119 @@ 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;
+    char buf[256];
+    int is_udp;
+    const char *end;
+    const char *fail_reason = "Unknown reason";
+
+    memset(&guest_addr, 0, sizeof(guest_addr));
+
+    p = redir_str;
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        fail_reason = "No : separators";
+        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";
+        goto fail_syntax;
+    }
+
+    if (*(p++) != '[') {
+        fail_reason = "IPv6 address must be enclosed in square brackets";
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ']') < 0) {
+        fail_reason = "IPv6 address must be enclosed in square brackets";
+        goto fail_syntax;
+    }
+
+    if (!inet_pton(AF_INET6, buf, &host_addr)) {
+        fail_reason = "Bad host address";
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0 ||
+        buf[0] != '\0') {
+        fail_reason = "Bad ipv6 address and port separator";
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+        fail_reason = "Bad host port separator";
+        goto fail_syntax;
+    }
+
+    if (qemu_strtoi(buf, &end, 0, &host_port)) {
+        fail_reason = "Bad host port";
+        goto fail_syntax;
+    }
+
+    if (*end != '\0' || host_port < 0 || host_port > 65535) {
+        fail_reason = "Host port out of range";
+        goto fail_syntax;
+    }
+
+    if (*p == '\0') {
+        fail_reason = "Missing guest ipv6 address";
+        goto fail_syntax;
+    }
+
+    if (*(p++) != '[') {
+        fail_reason = "IPv6 address must be enclosed in square brackets";
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p,  ']') < 0) {
+        fail_reason = "IPv6 address must be enclosed in square brackets";
+        goto fail_syntax;
+    }
+
+    if (!inet_pton(AF_INET6, buf, &guest_addr)) {
+        fail_reason = "Bad guest address";
+        goto fail_syntax;
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0 || buf[0] != '\0') {
+        fail_reason = "Bad ipv6 address and port separator";
+        goto fail_syntax;
+    }
+
+    if (qemu_strtoi(p, &end, 0, &guest_port) < 0) {
+        fail_reason = "Bad guest port";
+        goto fail_syntax;
+    }
+
+    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
+        fail_reason = "Guest port number out of range";
+        goto fail_syntax;
+    }
+
+    if (slirp_add_ipv6_hostfwd(s->slirp, is_udp, host_addr, host_port,
+                               guest_addr, guest_port) < 0) {
+        error_report("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,
+               fail_reason);
+    return -1;
+}
+
 void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
 {
     const char *redir_str;
@@ -604,6 +791,32 @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
 
 }
 
+void hmp_ipv6_hostfwd_add(Monitor *mon, const QDict *qdict)
+{
+    const char *redir_str;
+    SlirpState *s;
+    const char *arg1 = qdict_get_str(qdict, "arg1");
+    const char *arg2 = qdict_get_try_str(qdict, "arg2");
+    const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+    if (arg2) {
+        s = slirp_lookup(mon, arg1, arg2);
+        redir_str = arg3;
+    } else if (arg2) {
+        s = slirp_lookup(mon, NULL, arg1);
+        redir_str = arg2;
+    } else {
+        s = slirp_lookup(mon, NULL, NULL);
+        redir_str = arg1;
+    }
+    if (s) {
+        Error *err = NULL;
+        if (slirp_ipv6_hostfwd(s, redir_str, &err) < 0) {
+            error_report_err(err);
+        }
+    }
+}
+
 #ifndef _WIN32
 
 /* automatic user mode samba server configuration */
@@ -906,6 +1119,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 8f99fd9..4f67caf 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -201,7 +201,8 @@
     '*smbserver': 'str',
     '*hostfwd':   ['String'],
     '*guestfwd':  ['String'],
-    '*tftp-server-name': 'str' } }
+    '*tftp-server-name': 'str',
+    '*ipv6-hostfwd': ['String']} }
 
 ##
 # @NetdevTapOptions:
-- 
2.7.4

  parent reply	other threads:[~2018-10-26  0:04 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-26  0:03 [Qemu-devel] [PATCH RFC 0/4] slirp: support hostfwd for ipv6 addresses Maxim Samoylov
2018-10-26  0:03 ` [Qemu-devel] [PATCH RFC 1/4] slirp: add helper for tcp6 socket creation Maxim Samoylov
2018-10-27 11:11   ` Samuel Thibault
2018-10-27 11:13     ` Samuel Thibault
2018-10-30 13:58     ` Maxim Samoylov
2018-10-30 16:00       ` Samuel Thibault
2018-10-26  0:03 ` [Qemu-devel] [PATCH RFC 2/4] slirp: add helper for udp6 " Maxim Samoylov
2018-10-27 11:13   ` Samuel Thibault
2018-10-26  0:03 ` [Qemu-devel] [PATCH RFC 3/4] slirp: add helpers for ipv6 hostfwd manipulation Maxim Samoylov
2018-10-27 11:23   ` Samuel Thibault
2018-10-26  0:03 ` Maxim Samoylov [this message]
2018-10-26  6:14   ` [Qemu-devel] [PATCH RFC 4/4] net/slirp: add ipv6-hostfwd option for user netdev type Thomas Huth
2018-10-30 14:00     ` Maxim Samoylov
2018-10-27 11:38   ` Samuel Thibault
2018-11-05 23:05   ` Eric Blake

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=1540512223-21199-5-git-send-email-max7255@yandex-team.ru \
    --to=max7255@yandex-team.ru \
    --cc=qemu-devel@nongnu.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.