diff mbox series

[RFC,4/4] net/slirp: add ipv6-hostfwd option for user netdev type

Message ID 1540512223-21199-5-git-send-email-max7255@yandex-team.ru (mailing list archive)
State New, archived
Headers show
Series slirp: support hostfwd for ipv6 addresses | expand

Commit Message

max7255 Oct. 26, 2018, 12:03 a.m. UTC
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(-)

Comments

Thomas Huth Oct. 26, 2018, 6:14 a.m. UTC | #1
On 2018-10-26 01:03, Maxim Samoylov wrote:
> 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,
> +    },

 Hi,

could you please remove the "[hub_id name]" touple here? I recently sent
a patch to deprecate it for the IPv4 version, too:

https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg03198.html

Also I think it would make sense if you mention in the help text that
IPv6 addresses have to be given with square brackets?

 Thanks,
  Thomas
Samuel Thibault Oct. 27, 2018, 11:38 a.m. UTC | #2
Maxim Samoylov, le ven. 26 oct. 2018 03:03:43 +0300, a ecrit:
> +void hmp_ipv6_hostfwd_remove(Monitor *mon, const QDict *qdict)
> +{

Similarly, a lot can be shared, by introducing 

const char *hmp_hostfwd_lookup(Monitor *mon, const QDict *qdict, int is_v6)

which will contain all the lookup and tcp/udp parsing part, and
just return the src_str (is_v6 to avoid testing only arg1).
hmp_hostfwd_remove and hmp_ipv6_hostfwd_remove can then just start by
calling it and get src_str that it can then use to parse the IPs.

> +    struct in6_addr host_addr = in6addr_any;
> +    if (*(p++) != '[') {
> +        goto fail_syntax;
> +    }

As mentioned, better explicit this in the helper message.

> +static int slirp_ipv6_hostfwd(SlirpState *s, const char *redir_str,
> +                              Error **errp)

For this one I wouldn't bother factorizing, though.

Samuel
max7255 Oct. 30, 2018, 2 p.m. UTC | #3
On 26.10.2018 09:14, Thomas Huth wrote:
> On 2018-10-26 01:03, Maxim Samoylov wrote:
>> 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,
>> +    },
> 
>   Hi,
> 
> could you please remove the "[hub_id name]" touple here? I recently sent
> a patch to deprecate it for the IPv4 version, too:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2018-09/msg03198.html
> 

Ok

> Also I think it would make sense if you mention in the help text that
> IPv6 addresses have to be given with square brackets?
> 
>   Thanks,
>    Thomas
>

Sure, missed that thing.

---
Maxim Samoylov, max7255@yandex-team.ru
Eric Blake Nov. 5, 2018, 11:05 p.m. UTC | #4
On 10/25/18 7:03 PM, Maxim Samoylov wrote:
> 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(-)

> +++ 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']} }

Missing documentation of the new member.  Don't forget a '(since 3.1)' 
comment (if this is still appropriate for the current release; which may 
be doubtful since we are in soft freeze, in which case it will be 3.2 or 
4.0, depending on what the next release is numbered).
diff mbox series

Patch

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: