qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v7 0/4] Add support for ipv6 host forwarding
@ 2021-05-28 23:53 Doug Evans
  2021-05-28 23:53 ` [PATCH v7 1/4] slirp: Advance libslirp submodule to 4.5 release Doug Evans
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Doug Evans @ 2021-05-28 23:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov, Doug Evans

This patchset takes the original patch from Maxim,
https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
and updates it.

Option hostfwd is extended to support ipv6 addresses.
Commands hostfwd_add, hostfwd_remove are extended as well.

Changes from v6:

1/4: Update to use libslirp v4.5.0 tag

The libslirp parts of the patch have been committed to the libslirp repo,
and are now in QEMU's copy of the libslirp repo.
Advancing QEMU to use Libslirp v4.5.0 is being done separately.
Discussion of patch 1/4 is left to that thread:
https://lists.nongnu.org/archive/html/qemu-devel/2021-05/msg06010.html

2/4: No change

3/4: Add support for --enable-slirp=system
Tested with system libslirp 4.4.0.

4/4: No change

Changes from v5:

1/4 slirp: Advance libslirp submodule to current master
NOTE TO REVIEWERS: It may be a better use of everyone's time if a
maintainer takes on advancing QEMU's libslirp to libslirp's master.
Beyond that, I really don't know what to do except submit this patch as
is currently provided.

2/4: util/qemu-sockets.c: Split host:port parsing out of inet_parse

Also split out parsing of ipv4=on|off, ipv6=on|off

3/4: net/slirp.c: Refactor address parsing

Use InetSocketAddress and getaddrinfo().
Use new libslirp calls: slirp_remove_hostxfwd, slirp_add_hostxfwd.

4/4: net: Extend host forwarding to support IPv6

Recognize ipv4=,ipv6= options.

Note: v5's 3/5 "Recognize []:port (empty ipv6 address)" has been deleted:
the churn on this patch series needs to be reduced.
This change is not required, and can easily be done in a later patch.

Changes from v4:

1/5 slirp: Advance libslirp submodule to add ipv6 host-forward support
NOTE TO REVIEWERS: I need some hand-holding to know what The Right
way to submit this particular patch is.

- no change

2/5 util/qemu-sockets.c: Split host:port parsing out of inet_parse

- move recognition of "[]:port" to separate patch
- allow passing NULL for ip_v6
- fix some formatting issues

3/5 inet_parse_host_and_addr: Recognize []:port (empty ipv6 address)

- new in this patchset revision

4/5 net/slirp.c: Refactor address parsing

- was 3/4 in v4
- fix some formatting issues

5/5 net: Extend host forwarding to support IPv6

- was 4/4 in v4
- fix some formatting issues

Changes from v3:

1/4 slirp: Advance libslirp submodule to add ipv6 host-forward support

- pick up latest libslirp patch to reject ipv6 addr-any for guest address
  - libslirp currently only provides a stateless DHCPv6 server, which means
    it can't know in advance what the guest's IP address is, and thus
    cannot do the "addr-any -> guest ip address" translation that is done
    for ipv4

2/4 util/qemu-sockets.c: Split host:port parsing out of inet_parse

- this patch is new in v4
  - provides new utility: inet_parse_host_and_port, updates inet_parse
    to use it

3/4 net/slirp.c: Refactor address parsing

- this patch renamed from 2/3 to 3/4
- call inet_parse_host_and_port from util/qemu-sockets.c
- added tests/acceptance/hostfwd.py

4/4 net: Extend host forwarding to support IPv6

- this patch renamed from 3/3 to 4/4
- ipv6 support added to existing hostfwd option, commands
  - instead of creating new ipv6 option, commands
- added tests to tests/acceptance/hostfwd.py

Changes from v2:
- split out libslirp commit
- clarify spelling of ipv6 addresses in docs
- tighten parsing of ipv6 addresses

Change from v1:
- libslirp part is now upstream
- net/slirp.c changes split into two pieces (refactor, add ipv6)
- added docs

Doug Evans (4):
  slirp: Advance libslirp submodule to 4.5 release
  util/qemu-sockets.c: Split host:port parsing out of inet_parse
  net/slirp.c: Refactor address parsing
  net: Extend host forwarding to support IPv6

 hmp-commands.hx             |  18 ++-
 include/qemu/sockets.h      |   5 +
 net/slirp.c                 | 272 ++++++++++++++++++++++++++++--------
 slirp                       |   2 +-
 tests/acceptance/hostfwd.py | 185 ++++++++++++++++++++++++
 util/qemu-sockets.c         |  82 +++++++----
 6 files changed, 473 insertions(+), 91 deletions(-)
 create mode 100644 tests/acceptance/hostfwd.py

-- 
2.32.0.rc0.204.g9fa02ecfa5-goog



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v7 1/4] slirp: Advance libslirp submodule to 4.5 release
  2021-05-28 23:53 [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
@ 2021-05-28 23:53 ` Doug Evans
  2021-05-28 23:53 ` [PATCH v7 2/4] util/qemu-sockets.c: Split host:port parsing out of inet_parse Doug Evans
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Doug Evans @ 2021-05-28 23:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov, Doug Evans

5eraph (2):
      disable_dns option
      limit vnameserver_addr to port 53

Akihiro Suda (1):
      libslirp.h: fix SlirpConfig v3 documentation

Doug Evans (11):
      Add ipv6 host forward support
      tcpx_listen: Pass sizeof(addr) to memset
      Reject host forwarding to ipv6 "addr-any"
      Add /build/ to .gitignore
      New utility slirp_ether_ntoa
      m_cleanup_list: make static
      New API routine slirp_neighbor_info
      Move DEBUG_CALL("if_start") to DEBUG_VERBOSE_CALL
      tcpx_listen: tcp_newtcpcb doesn't fail
      slirp_add_host*fwd: Ensure all error paths set errno
      Perform lazy guest address resolution for IPv6

Dr. David Alan Gilbert (1):
      ip_stripoptions use memmove

Giuseppe Scrivano (1):
      socket: consume empty packets

Hafiz Abid Qadeer (1):
      Fix a typo that can cause slow socket response on Windows.

Jindrich Novy (4):
      Fix possible infinite loops and use-after-free
      Use secure string copy to avoid overflow
      Be sure to initialize sockaddr structure
      Check lseek() for failure

Marc-André Lureau (28):
      Merge branch 'master' into 'master'
      Merge branch 'fix-slirpconfig-3-doc' into 'master'
      Fix use-afte-free in ip_reass() (CVE-2020-1983)
      Update CHANGELOG
      Merge branch 'cve-2020-1983' into 'master'
      Release v4.3.0
      Merge branch 'release-v4.3.0' into 'master'
      changelog: post-release
      util: do not silently truncate
      Merge branch 'slirp-fmt-truncate' into 'master'
      Release v4.3.1
      Merge branch 'release-v4.3.1' into 'master'
      changelog: post-release
      .gitlab-ci: add a Coverity stage
      Merge branch 'coverity' into 'master'
      Merge branch 'ios-support' into 'master'
      Merge branch 'master' into 'master'
      Remove the QEMU-special make build-system
      Merge branch 'qemu' into 'master'
      Release v4.4.0
      Merge branch '4.4.0-release' into 'master'
      changelog: post-release
      Remove some needless (void)casts
      Fix unused variables
      Merge branch 'gitignore-build' into 'master'
      Merge branch 'macos-deployment-target' into 'master'
      Merge branch 'philmd' into 'master'
      Release v4.5.0

Nathaniel Wesley Filardo (1):
      fork_exec_child_setup: improve signal handling

Paolo Bonzini (2):
      meson: remove meson-dist script
      meson: support compiling as subproject

Philippe Mathieu-Daudé (4):
      Fix win32 builds by using the SLIRP_PACKED definition
      Fix constness warnings
      Remove unnecessary break
      Remove alloca() call in get_dns_addr_resolv_conf()

Prasad J Pandit (1):
      slirp: check pkt_len before reading protocol header

Ralf Haferkamp (2):
      Drop bogus IPv6 messages
      Fix MTU check

Samuel Thibault (48):
      Merge branch 'ip6_payload_len' into 'master'
      Merge branch 'lp1878043' into 'master'
      udp, udp6, icmp: handle TTL value
      icmp, icmp6: Add icmp_forward_error and icmp6_forward_error
      udp, udp6, icmp, icmp6: Enable forwarding errors on Linux
      TCPIPHDR_DELTA: Fix potential negative value
      sosendoob: better document what urgc is used for
      Merge branch 'G_GNUC_PRINTF' into 'master'
      Merge branch 'CVE-2020-29129' into 'master'
      Merge branch 'ttl' into 'master'
      Merge branch 'errors' into 'master'
      Merge branch 'consume-empty-packet' into 'master'
      Merge branch 'void' into 'master'
      Merge branch 'master' into 'master'
      Merge branch 'unused' into 'master'
      Merge branch 'socket_delay' into 'master'
      tcp_subr: simplify code
      Merge branch 'ipv6-host-fwd-9-patch' into 'master'
      Document the slirp API
      Complete timeout documentation
      Merge branch 'memset-sizeof' into 'master'
      Merge branch 'reject-ipv6-addr-any' into 'master'
      ip6_output: fix memory leak on fast-send
      Merge branch 'ndp-leak' into 'master'
      Merge branch 'memory_leaks' into 'master'
      TODO for generalizing the hostfwd calls
      socket.h: add missing sbuf.h inclusion
      Expose udpx_listen and tcpx_listen as taking sockaddr
      Disable polling for PRI on MacOS
      Merge branch 'macos-pri' into 'master'
      Merge branch 'x_listen' into 'master'
      udpx/tcpx_listen: Add missing const qualifier
      sockaddr_*: add missing const qualifiers
      Merge branch 'm-cleanup-list-prototype' into 'master'
      Merge branch 'neighbor-info' into 'master'
      udpx/tcpx_listen: Use struct sockaddr * types
      Add ipv4/ipv6-agnostic host forwarding functions
      hostfwd: Add SLIRP_HOSTFWD_V6ONLY flag
      Merge branch 'hostxfwd' into 'master'
      Merge branch 'verbose-if-start' into 'master'
      Remove slirp_add/remove_ipv6_hostfwd
      Merge branch 'listen-errno' into 'master'
      Merge branch 'newtcpcb-no-fail' into 'master'
      Merge branch 'listen_v6only' into 'master'
      Merge branch 'lazy-ipv6-resolution' into 'master'
      ndp_table: For unspecified address, return broadcast ethernet address
      Merge branch 'master' into 'master'
      SlirpCb: explicit that it is fine for a guest to drop frames

Stefan Weil (1):
      Add G_GNUC_PRINTF to local function slirp_vsnprintf

WaluigiWare64 (1):
      Set macOS deployment target to macOS 10.4 Without a macOS deployment target, the resulting library does not work on macOS versions lower than it was currently built on. For example, if libslirp was built on macOS 10.15, it would not work on macOS 10.14.

jeremy marchand (4):
      m_free: remove the M_EXT flag after freeing the mbuf extended buffer
      refactor m_cleanup as requested in slirp/libslirp!68
      m_cleanup: fix memory leaks
      m_cleanup: set qh_link and qh_rlink to the list head

osy (1):
      Add DNS resolving for iOS

Signed-off-by: Doug Evans <dje@google.com>
---

Changes from v6:

The libslirp parts of the patch have been committed to the libslirp repo,
and are now in QEMU's copy of the libslirp repo.
Advancing QEMU to use Libslirp v4.5.0 is being done separately.
Discussion of patch 1/4 is left to that thread:
https://lists.nongnu.org/archive/html/qemu-devel/2021-05/msg06010.html

Changes from v5:

1/4 slirp: Advance libslirp submodule to current master
NOTE TO REVIEWERS: It may be a better use of everyone's time if a
maintainer takes on advancing QEMU's libslirp to libslirp's master.
Beyond that, I really don't know what to do except submit this patch as
is currently provided.

 slirp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/slirp b/slirp
index 8f43a99191..a62890e711 160000
--- a/slirp
+++ b/slirp
@@ -1 +1 @@
-Subproject commit 8f43a99191afb47ca3f3c6972f6306209f367ece
+Subproject commit a62890e71126795ca593affa747f669bed88e89c
-- 
2.32.0.rc0.204.g9fa02ecfa5-goog



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v7 2/4] util/qemu-sockets.c: Split host:port parsing out of inet_parse
  2021-05-28 23:53 [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
  2021-05-28 23:53 ` [PATCH v7 1/4] slirp: Advance libslirp submodule to 4.5 release Doug Evans
@ 2021-05-28 23:53 ` Doug Evans
  2021-05-28 23:53 ` [PATCH v7 3/4] net/slirp.c: Refactor address parsing Doug Evans
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Doug Evans @ 2021-05-28 23:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov, Doug Evans

The parsing is moved into new function inet_parse_host_port.
Also split out is ipv4=flag, ipv6=flag processing into inet_parse_ipv46.
This is done in preparation for using these functions in net/slirp.c.

Signed-off-by: Doug Evans <dje@google.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---

Changes from v6:

No changes.

Changes from v5:

Also split out parsing of ipv4=on|off, ipv6=on|off

 include/qemu/sockets.h |  3 ++
 util/qemu-sockets.c    | 65 +++++++++++++++++++++++++++++-------------
 2 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 7d1f813576..94f4e8de83 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -31,6 +31,9 @@ int socket_set_fast_reuse(int fd);
 
 int inet_ai_family_from_address(InetSocketAddress *addr,
                                 Error **errp);
+const char *inet_parse_host_port(InetSocketAddress *addr,
+                                 const char *str, Error **errp);
+int inet_parse_ipv46(InetSocketAddress *addr, const char *optstr, Error **errp);
 int inet_parse(InetSocketAddress *addr, const char *str, Error **errp);
 int inet_connect(const char *str, Error **errp);
 int inet_connect_saddr(InetSocketAddress *saddr, Error **errp);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 2463c49773..aa883eb84f 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -615,14 +615,12 @@ static int inet_parse_flag(const char *flagname, const char *optstr, bool *val,
     return 0;
 }
 
-int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
+const char *inet_parse_host_port(InetSocketAddress *addr, const char *str,
+                                 Error **errp)
 {
-    const char *optstr, *h;
     char host[65];
     char port[33];
-    int to;
     int pos;
-    char *begin;
 
     memset(addr, 0, sizeof(*addr));
 
@@ -632,38 +630,32 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
         host[0] = '\0';
         if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) {
             error_setg(errp, "error parsing port in address '%s'", str);
-            return -1;
+            return NULL;
         }
     } else if (str[0] == '[') {
         /* IPv6 addr */
         if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) {
             error_setg(errp, "error parsing IPv6 address '%s'", str);
-            return -1;
+            return NULL;
         }
     } else {
         /* hostname or IPv4 addr */
         if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) {
             error_setg(errp, "error parsing address '%s'", str);
-            return -1;
+            return NULL;
         }
     }
 
     addr->host = g_strdup(host);
     addr->port = g_strdup(port);
 
-    /* parse options */
-    optstr = str + pos;
-    h = strstr(optstr, ",to=");
-    if (h) {
-        h += 4;
-        if (sscanf(h, "%d%n", &to, &pos) != 1 ||
-            (h[pos] != '\0' && h[pos] != ',')) {
-            error_setg(errp, "error parsing to= argument");
-            return -1;
-        }
-        addr->has_to = true;
-        addr->to = to;
-    }
+    return str + pos;
+}
+
+int inet_parse_ipv46(InetSocketAddress *addr, const char *optstr, Error **errp)
+{
+    char *begin;
+
     begin = strstr(optstr, ",ipv4");
     if (begin) {
         if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) {
@@ -678,6 +670,39 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
         }
         addr->has_ipv6 = true;
     }
+
+    return 0;
+}
+
+int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
+{
+    const char *optstr, *h;
+    int to;
+    int pos;
+    char *begin;
+
+    optstr = inet_parse_host_port(addr, str, errp);
+    if (optstr == NULL) {
+        return -1;
+    }
+
+    /* parse options */
+
+    if (inet_parse_ipv46(addr, optstr, errp) < 0) {
+        return -1;
+    }
+
+    h = strstr(optstr, ",to=");
+    if (h) {
+        h += 4;
+        if (sscanf(h, "%d%n", &to, &pos) != 1 ||
+            (h[pos] != '\0' && h[pos] != ',')) {
+            error_setg(errp, "error parsing to= argument");
+            return -1;
+        }
+        addr->has_to = true;
+        addr->to = to;
+    }
     begin = strstr(optstr, ",keep-alive");
     if (begin) {
         if (inet_parse_flag("keep-alive", begin + strlen(",keep-alive"),
-- 
2.32.0.rc0.204.g9fa02ecfa5-goog



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v7 3/4] net/slirp.c: Refactor address parsing
  2021-05-28 23:53 [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
  2021-05-28 23:53 ` [PATCH v7 1/4] slirp: Advance libslirp submodule to 4.5 release Doug Evans
  2021-05-28 23:53 ` [PATCH v7 2/4] util/qemu-sockets.c: Split host:port parsing out of inet_parse Doug Evans
@ 2021-05-28 23:53 ` Doug Evans
  2021-05-28 23:53 ` [PATCH v7 4/4] net: Extend host forwarding to support IPv6 Doug Evans
  2021-06-10  1:41 ` [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
  4 siblings, 0 replies; 8+ messages in thread
From: Doug Evans @ 2021-05-28 23:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov, Doug Evans

... in preparation for adding ipv6 host forwarding support.

Tested:
avocado run tests/acceptance/hostfwd.py

Signed-off-by: Doug Evans <dje@google.com>
---

Changes from v6:

Add support for --enable-slirp=system
Tested with system libslirp 4.4.0.

Changes from v5:

Use InetSocketAddress and getaddrinfo().
Use new libslirp calls: slirp_remove_hostxfwd, slirp_add_hostxfwd.

 include/qemu/sockets.h      |   2 +
 net/slirp.c                 | 236 ++++++++++++++++++++++++++----------
 tests/acceptance/hostfwd.py |  91 ++++++++++++++
 util/qemu-sockets.c         |  17 ++-
 4 files changed, 278 insertions(+), 68 deletions(-)
 create mode 100644 tests/acceptance/hostfwd.py

diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 94f4e8de83..6fd71775ce 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -29,6 +29,8 @@ int socket_set_fast_reuse(int fd);
 #define SHUT_RDWR 2
 #endif
 
+int sockaddr_getport(const struct sockaddr *addr);
+
 int inet_ai_family_from_address(InetSocketAddress *addr,
                                 Error **errp);
 const char *inet_parse_host_port(InetSocketAddress *addr,
diff --git a/net/slirp.c b/net/slirp.c
index ad3a838e0b..2349eb2c23 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -641,14 +641,106 @@ static SlirpState *slirp_lookup(Monitor *mon, const char *id)
     }
 }
 
+static const char *parse_protocol(const char *str, bool *is_udp,
+                                  Error **errp)
+{
+    char buf[10];
+    const char *p = str;
+
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        error_setg(errp, "missing protocol name separator");
+        return NULL;
+    }
+
+    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+        *is_udp = false;
+    } else if (!strcmp(buf, "udp")) {
+        *is_udp = true;
+    } else {
+        error_setg(errp, "bad protocol name '%s'", buf);
+        return NULL;
+    }
+
+    return p;
+}
+
+static int parse_hostfwd_sockaddr(const char *str, int socktype,
+                                  struct sockaddr_storage *saddr,
+                                  Error **errp)
+{
+    struct addrinfo hints, *res = NULL, *e;
+    InetSocketAddress *addr = g_new(InetSocketAddress, 1);
+    int gai_rc;
+    int rc = -1;
+
+    const char *optstr = inet_parse_host_port(addr, str, errp);
+    if (optstr == NULL) {
+        goto fail_return;
+    }
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_PASSIVE; /* ignored if host is not ""(->NULL) */
+    hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
+    hints.ai_socktype = socktype;
+    hints.ai_family = PF_INET;
+
+    /*
+     * Calling getaddrinfo for guest addresses is dubious, but addresses are
+     * restricted to numeric only. Convert "" to NULL for getaddrinfo's
+     * benefit.
+     */
+    gai_rc = getaddrinfo(*addr->host ? addr->host : NULL,
+                         *addr->port ? addr->port : NULL, &hints, &res);
+    if (gai_rc != 0) {
+        error_setg(errp, "address resolution failed for '%s': %s",
+                   str, gai_strerror(gai_rc));
+        goto fail_return;
+    }
+    if (res->ai_next != NULL) {
+        /*
+         * The caller only wants one address, and except for "any" for both
+         * ipv4 and ipv6 (which we've already precluded above), we shouldn't
+         * get more than one. To assist debugging print all we find.
+         */
+        GString *s = g_string_new(NULL);
+        for (e = res; e != NULL; e = e->ai_next) {
+            char host[NI_MAXHOST];
+            char serv[NI_MAXSERV];
+            int ret = getnameinfo((struct sockaddr *)e->ai_addr, e->ai_addrlen,
+                                  host, sizeof(host),
+                                  serv, sizeof(serv),
+                                  NI_NUMERICHOST | NI_NUMERICSERV);
+            if (ret == 0) {
+                g_string_append_printf(s, "\n  %s:%s", host, serv);
+            } else {
+                g_string_append_printf(s, "\n  unknown, got: %s",
+                                       gai_strerror(ret));
+            }
+        }
+        error_setg(errp, "multiple addresses resolved for '%s':%s",
+                   str, s->str);
+        g_string_free(s, TRUE);
+        goto fail_return;
+    }
+
+    memcpy(saddr, res->ai_addr, res->ai_addrlen);
+    rc = 0;
+
+ fail_return:
+    qapi_free_InetSocketAddress(addr);
+    if (res) {
+        freeaddrinfo(res);
+    }
+    return rc;
+}
+
 void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
 {
-    struct in_addr host_addr = { .s_addr = INADDR_ANY };
-    int host_port;
-    char buf[256];
+    struct sockaddr_storage host_addr;
     const char *src_str, *p;
     SlirpState *s;
-    int is_udp = 0;
+    bool is_udp;
+    Error *error = NULL;
     int err;
     const char *arg1 = qdict_get_str(qdict, "arg1");
     const char *arg2 = qdict_get_try_str(qdict, "arg2");
@@ -664,110 +756,130 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
         return;
     }
 
+    g_assert(src_str != NULL);
     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 {
+    p = parse_protocol(p, &is_udp, &error);
+    if (p == NULL) {
         goto fail_syntax;
     }
 
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
-        goto fail_syntax;
-    }
-    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+    if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM,
+                               &host_addr, &error) < 0) {
         goto fail_syntax;
     }
 
-    if (qemu_strtoi(p, NULL, 10, &host_port)) {
-        goto fail_syntax;
+#if SLIRP_CHECK_VERSION(4, 5, 0)
+    {
+        int flags = is_udp ? SLIRP_HOSTFWD_UDP : 0;
+        err = slirp_remove_hostxfwd(s->slirp, (struct sockaddr *) &host_addr,
+                                    sizeof(host_addr), flags);
     }
-
-    err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
+#else
+    if (host_addr.ss_family != AF_INET) {
+        monitor_printf(mon,
+                       "Could not remove host forwarding rule '%s':"
+                       " only IPv4 supported",
+                       src_str);
+        return;
+    } else {
+        struct sockaddr_in *host_in_addr = (struct sockaddr_in *) &host_addr;
+        err = slirp_remove_hostfwd(s->slirp, is_udp,
+                                   host_in_addr->sin_addr,
+                                   ntohs(host_in_addr->sin_port));
+    }
+#endif
 
     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", error_get_pretty(error));
+    error_free(error);
 }
 
 static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
 {
-    struct in_addr host_addr = { .s_addr = INADDR_ANY };
-    struct in_addr guest_addr = { .s_addr = 0 };
-    int host_port, guest_port;
+    struct sockaddr_storage host_addr, guest_addr;
     const char *p;
     char buf[256];
-    int is_udp;
-    char *end;
-    const char *fail_reason = "Unknown reason";
+    bool is_udp;
+    Error *error = NULL;
+    int port;
 
+    g_assert(redir_str != NULL);
     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 (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
-        fail_reason = "Missing : separator";
-        goto fail_syntax;
-    }
-    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
-        fail_reason = "Bad host address";
+    p = parse_protocol(p, &is_udp, &error);
+    if (p == NULL) {
         goto fail_syntax;
     }
 
     if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
-        fail_reason = "Bad host port separator";
+        error_setg(&error, "missing host-guest separator");
         goto fail_syntax;
     }
-    host_port = strtol(buf, &end, 0);
-    if (*end != '\0' || host_port < 0 || host_port > 65535) {
-        fail_reason = "Bad host port";
+
+    if (parse_hostfwd_sockaddr(buf, is_udp ? SOCK_DGRAM : SOCK_STREAM,
+                               &host_addr, &error) < 0) {
+        error_prepend(&error, "For host address: ");
         goto fail_syntax;
     }
 
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
-        fail_reason = "Missing guest address";
+    if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM,
+                               &guest_addr, &error) < 0) {
+        error_prepend(&error, "For guest address: ");
         goto fail_syntax;
     }
-    if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
-        fail_reason = "Bad guest address";
+    port = sockaddr_getport((struct sockaddr *) &guest_addr);
+    if (port == 0) {
+        error_setg(&error, "For guest address: invalid port '0'");
         goto fail_syntax;
     }
 
-    guest_port = strtol(p, &end, 0);
-    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
-        fail_reason = "Bad guest port";
-        goto fail_syntax;
+#if SLIRP_CHECK_VERSION(4, 5, 0)
+    {
+        int flags = is_udp ? SLIRP_HOSTFWD_UDP : 0;
+        if (slirp_add_hostxfwd(s->slirp,
+                               (struct sockaddr *) &host_addr,
+                               sizeof(host_addr),
+                               (struct sockaddr *) &guest_addr,
+                               sizeof(guest_addr),
+                               flags) < 0) {
+            error_setg(errp, "Could not set up host forwarding rule '%s': %s",
+                       redir_str, strerror(errno));
+            return -1;
+        }
     }
-
-    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'",
+#else
+    if (host_addr.ss_family != AF_INET || guest_addr.ss_family != AF_INET) {
+        error_setg(errp,
+                   "Could not set up host forwarding rule '%s':"
+                   " only IPv4 supported",
                    redir_str);
         return -1;
+    } else {
+        struct sockaddr_in *host_in_addr = (struct sockaddr_in *) &host_addr;
+        struct sockaddr_in *guest_in_addr = (struct sockaddr_in *) &guest_addr;
+        if (slirp_add_hostfwd(s->slirp, is_udp,
+                              host_in_addr->sin_addr,
+                              ntohs(host_in_addr->sin_port),
+                              guest_in_addr->sin_addr,
+                              ntohs(guest_in_addr->sin_port)) < 0) {
+            error_setg(errp, "Could not set up host forwarding rule '%s'",
+                       redir_str);
+            return -1;
+        }
     }
+#endif
+
     return 0;
 
  fail_syntax:
     error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str,
-               fail_reason);
+               error_get_pretty(error));
+    error_free(error);
     return -1;
 }
 
diff --git a/tests/acceptance/hostfwd.py b/tests/acceptance/hostfwd.py
new file mode 100644
index 0000000000..9b9db142c3
--- /dev/null
+++ b/tests/acceptance/hostfwd.py
@@ -0,0 +1,91 @@
+# Hostfwd command tests
+#
+# Copyright 2021 Google LLC
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+
+
+from avocado_qemu import Test
+
+
+class Hostfwd(Test):
+    """
+    :avocado: tags=hostfwd
+    """
+    def hmc(self, cmd):
+        return self.vm.command('human-monitor-command', command_line=cmd)
+
+    def test_qmp_hostfwd_ipv4(self):
+        self.vm.add_args('-nodefaults',
+                         '-netdev', 'user,id=vnet',
+                         '-device', 'virtio-net,netdev=vnet')
+        self.vm.launch()
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022-:22'), '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022'),
+                          'host forwarding rule for tcp::65022 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add tcp::65022-:22'), '')
+        self.assertEquals(self.hmc('hostfwd_remove tcp::65022'),
+                          'host forwarding rule for tcp::65022 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), '')
+        self.assertEquals(self.hmc('hostfwd_remove udp::65042'),
+                          'host forwarding rule for udp::65042 removed\r\n')
+
+    def test_qmp_hostfwd_ipv4_functional_errors(self):
+        """Verify handling of various kinds of errors given valid addresses."""
+        self.vm.add_args('-nodefaults',
+                         '-netdev', 'user,id=vnet',
+                         '-device', 'virtio-net,netdev=vnet')
+        self.vm.launch()
+        self.assertEquals(self.hmc('hostfwd_remove ::65022'),
+                          'host forwarding rule for ::65022 not found\r\n')
+        self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), '')
+        self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'),
+                          "Could not set up host forwarding rule" + \
+                          " 'udp::65042-:42': Address already in use\r\n")
+        self.assertEquals(self.hmc('hostfwd_remove ::65042'),
+                          'host forwarding rule for ::65042 not found\r\n')
+        self.assertEquals(self.hmc('hostfwd_remove udp::65042'),
+                          'host forwarding rule for udp::65042 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_remove udp::65042'),
+                          'host forwarding rule for udp::65042 not found\r\n')
+
+    def test_qmp_hostfwd_ipv4_parsing_errors(self):
+        """Verify handling of various kinds of parsing errors."""
+        self.vm.add_args('-nodefaults',
+                         '-netdev', 'user,id=vnet',
+                         '-device', 'virtio-net,netdev=vnet')
+        self.vm.launch()
+        self.assertEquals(self.hmc('hostfwd_remove abc::42'),
+                          "Invalid format: bad protocol name 'abc'\r\n")
+        self.assertEquals(self.hmc('hostfwd_add abc::65022-:22'),
+                          "Invalid host forwarding rule 'abc::65022-:22'" + \
+                          " (bad protocol name 'abc')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :foo'),
+                          "Invalid host forwarding rule ':foo'" + \
+                          " (missing host-guest separator)\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :a.b.c.d:66-:66'),
+                          "Invalid host forwarding rule ':a.b.c.d:66-:66'" + \
+                          " (For host address: address resolution failed for" \
+                          " 'a.b.c.d:66': Name or service not known)\r\n")
+        self.assertEquals(self.hmc('hostfwd_add ::66-a.b.c.d:66'),
+                          "Invalid host forwarding rule '::66-a.b.c.d:66'" + \
+                          " (For guest address: address resolution failed" + \
+                          " for 'a.b.c.d:66': Name or service not known)\r\n")
+        self.assertEquals(self.hmc('hostfwd_add ::-1-foo'),
+                          "Invalid host forwarding rule '::-1-foo'" + \
+                          " (For host address: error parsing port in" + \
+                          " address ':')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add ::66-foo'),
+                          "Invalid host forwarding rule '::66-foo' (For" + \
+                          " guest address: error parsing address 'foo')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add ::66-:0'),
+                          "Invalid host forwarding rule '::66-:0'" + \
+                          " (For guest address: invalid port '0')\r\n")
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index aa883eb84f..52fe056fbf 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -46,23 +46,28 @@
 #endif
 
 
-static int inet_getport(struct addrinfo *e)
+int sockaddr_getport(const struct sockaddr *addr)
 {
-    struct sockaddr_in *i4;
-    struct sockaddr_in6 *i6;
+    const struct sockaddr_in *i4;
+    const struct sockaddr_in6 *i6;
 
-    switch (e->ai_family) {
+    switch (addr->sa_family) {
     case PF_INET6:
-        i6 = (void*)e->ai_addr;
+        i6 = (void *)addr;
         return ntohs(i6->sin6_port);
     case PF_INET:
-        i4 = (void*)e->ai_addr;
+        i4 = (void *)addr;
         return ntohs(i4->sin_port);
     default:
         return 0;
     }
 }
 
+static int inet_getport(struct addrinfo *e)
+{
+    return sockaddr_getport(e->ai_addr);
+}
+
 static void inet_setport(struct addrinfo *e, int port)
 {
     struct sockaddr_in *i4;
-- 
2.32.0.rc0.204.g9fa02ecfa5-goog



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v7 4/4] net: Extend host forwarding to support IPv6
  2021-05-28 23:53 [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
                   ` (2 preceding siblings ...)
  2021-05-28 23:53 ` [PATCH v7 3/4] net/slirp.c: Refactor address parsing Doug Evans
@ 2021-05-28 23:53 ` Doug Evans
  2021-06-10  1:41 ` [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
  4 siblings, 0 replies; 8+ messages in thread
From: Doug Evans @ 2021-05-28 23:53 UTC (permalink / raw)
  To: qemu-devel
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov, Doug Evans

Net option "-hostfwd" now supports IPv6 addresses.
Commands hostfwd_add, hostfwd_remove now support IPv6 addresses.

Tested:
avocado run tests/acceptance/hostfwd.py

Signed-off-by: Doug Evans <dje@google.com>
---

Changes from v6:

No changes.

Changes from v5:

Recognize ipv4=,ipv6= options.

 hmp-commands.hx             | 18 ++++++-
 net/slirp.c                 | 54 +++++++++++++++++----
 tests/acceptance/hostfwd.py | 94 +++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+), 11 deletions(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 435c591a1c..05f88e893b 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1322,7 +1322,8 @@ ERST
     {
         .name       = "hostfwd_add",
         .args_type  = "arg1:s,arg2:s?",
-        .params     = "[netdev_id] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
+        .params     = "[netdev_id] [tcp|udp]:[hostaddr]:hostport\n"
+                      "[,ipv4=on|off][,ipv6=on|off]-[guestaddr]:guestport",
         .help       = "redirect TCP or UDP connections from host to guest (requires -net user)",
         .cmd        = hmp_hostfwd_add,
     },
@@ -1330,13 +1331,20 @@ ERST
 SRST
 ``hostfwd_add``
   Redirect TCP or UDP connections from host to guest (requires -net user).
+  IPV6 addresses are wrapped in square brackets, IPV4 addresses are not.
+
+  Examples:
+  hostfwd_add net0 tcp:127.0.0.1:10022-:22
+  hostfwd_add net0 tcp:[::1]:10022-[fe80::1:2:3:4]:22
+  hostfwd_add net0 ::10022,ipv6-:22
 ERST
 
 #ifdef CONFIG_SLIRP
     {
         .name       = "hostfwd_remove",
         .args_type  = "arg1:s,arg2:s?",
-        .params     = "[netdev_id] [tcp|udp]:[hostaddr]:hostport",
+        .params     = "[netdev_id] [tcp|udp]:[hostaddr]:hostport\n"
+                      "[,ipv4=on|off][,ipv6=on|off]",
         .help       = "remove host-to-guest TCP or UDP redirection",
         .cmd        = hmp_hostfwd_remove,
     },
@@ -1345,6 +1353,12 @@ ERST
 SRST
 ``hostfwd_remove``
   Remove host-to-guest TCP or UDP redirection.
+  IPV6 addresses are wrapped in square brackets, IPV4 addresses are not.
+
+  Examples:
+  hostfwd_remove net0 tcp:127.0.0.1:10022
+  hostfwd_remove net0 tcp:[::1]:10022
+  hostfwd_remove net0 ::10022,ipv6
 ERST
 
     {
diff --git a/net/slirp.c b/net/slirp.c
index 2349eb2c23..075a283d35 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -664,25 +664,55 @@ static const char *parse_protocol(const char *str, bool *is_udp,
     return p;
 }
 
-static int parse_hostfwd_sockaddr(const char *str, int socktype,
+static int parse_hostfwd_sockaddr(const char *str, int family, int socktype,
                                   struct sockaddr_storage *saddr,
-                                  Error **errp)
+                                  bool *v6_only, Error **errp)
 {
     struct addrinfo hints, *res = NULL, *e;
     InetSocketAddress *addr = g_new(InetSocketAddress, 1);
     int gai_rc;
     int rc = -1;
+    Error *err = NULL;
 
     const char *optstr = inet_parse_host_port(addr, str, errp);
     if (optstr == NULL) {
         goto fail_return;
     }
 
+    if (inet_parse_ipv46(addr, optstr, errp) < 0) {
+        goto fail_return;
+    }
+
+    if (v6_only) {
+        bool v4 = addr->has_ipv4 && addr->ipv4;
+        bool v6 = addr->has_ipv6 && addr->ipv6;
+        *v6_only = v6 && !v4;
+    }
+
     memset(&hints, 0, sizeof(hints));
     hints.ai_flags = AI_PASSIVE; /* ignored if host is not ""(->NULL) */
     hints.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV;
     hints.ai_socktype = socktype;
-    hints.ai_family = PF_INET;
+    hints.ai_family = inet_ai_family_from_address(addr, &err);
+    if (err) {
+        error_propagate(errp, err);
+        goto fail_return;
+    }
+    if (family != PF_UNSPEC) {
+        /* Guest must use same family as host (for now). */
+        if (hints.ai_family != PF_UNSPEC && hints.ai_family != family) {
+            error_setg(errp,
+                       "unexpected address family for %s: expecting %s",
+                       str, family == PF_INET ? "ipv4" : "ipv6");
+            goto fail_return;
+        }
+        hints.ai_family = family;
+    }
+
+    /* For backward compatibility, treat an empty host spec as IPv4. */
+    if (*addr->host == '\0' && hints.ai_family == PF_UNSPEC) {
+        hints.ai_family = PF_INET;
+    }
 
     /*
      * Calling getaddrinfo for guest addresses is dubious, but addresses are
@@ -764,8 +794,8 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
         goto fail_syntax;
     }
 
-    if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM,
-                               &host_addr, &error) < 0) {
+    if (parse_hostfwd_sockaddr(p, PF_UNSPEC, is_udp ? SOCK_DGRAM : SOCK_STREAM,
+                               &host_addr, /*v6_only=*/NULL, &error) < 0) {
         goto fail_syntax;
     }
 
@@ -807,6 +837,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
     bool is_udp;
     Error *error = NULL;
     int port;
+    bool v6_only;
 
     g_assert(redir_str != NULL);
     p = redir_str;
@@ -821,14 +852,16 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
         goto fail_syntax;
     }
 
-    if (parse_hostfwd_sockaddr(buf, is_udp ? SOCK_DGRAM : SOCK_STREAM,
-                               &host_addr, &error) < 0) {
+    if (parse_hostfwd_sockaddr(buf, PF_UNSPEC,
+                               is_udp ? SOCK_DGRAM : SOCK_STREAM,
+                               &host_addr, &v6_only, &error) < 0) {
         error_prepend(&error, "For host address: ");
         goto fail_syntax;
     }
 
-    if (parse_hostfwd_sockaddr(p, is_udp ? SOCK_DGRAM : SOCK_STREAM,
-                               &guest_addr, &error) < 0) {
+    if (parse_hostfwd_sockaddr(p, host_addr.ss_family,
+                               is_udp ? SOCK_DGRAM : SOCK_STREAM,
+                               &guest_addr, /*v6_only=*/NULL, &error) < 0) {
         error_prepend(&error, "For guest address: ");
         goto fail_syntax;
     }
@@ -841,6 +874,9 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
 #if SLIRP_CHECK_VERSION(4, 5, 0)
     {
         int flags = is_udp ? SLIRP_HOSTFWD_UDP : 0;
+        if (v6_only) {
+            flags |= SLIRP_HOSTFWD_V6ONLY;
+        }
         if (slirp_add_hostxfwd(s->slirp,
                                (struct sockaddr *) &host_addr,
                                sizeof(host_addr),
diff --git a/tests/acceptance/hostfwd.py b/tests/acceptance/hostfwd.py
index 9b9db142c3..f8493c5bdc 100644
--- a/tests/acceptance/hostfwd.py
+++ b/tests/acceptance/hostfwd.py
@@ -37,6 +37,17 @@ def test_qmp_hostfwd_ipv4(self):
         self.assertEquals(self.hmc('hostfwd_add udp::65042-:42'), '')
         self.assertEquals(self.hmc('hostfwd_remove udp::65042'),
                           'host forwarding rule for udp::65042 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4-:22'), '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv4'),
+                          'host forwarding rule for tcp::65022,ipv4 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4=on-:22'),
+                          '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv4=on'),
+                          'host forwarding rule for tcp::65022,ipv4=on removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv6=off-:22'),
+                          '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv6=off'),
+                          'host forwarding rule for tcp::65022,ipv6=off removed\r\n')
 
     def test_qmp_hostfwd_ipv4_functional_errors(self):
         """Verify handling of various kinds of errors given valid addresses."""
@@ -89,3 +100,86 @@ def test_qmp_hostfwd_ipv4_parsing_errors(self):
         self.assertEquals(self.hmc('hostfwd_add ::66-:0'),
                           "Invalid host forwarding rule '::66-:0'" + \
                           " (For guest address: invalid port '0')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4=abc-:22'),
+                          "Invalid host forwarding rule" + \
+                          " 'tcp::65022,ipv4=abc-:22' (For host address:" + \
+                          " error parsing 'ipv4' flag '=abc')\r\n")
+
+    def test_qmp_hostfwd_ipv6(self):
+        self.vm.add_args('-nodefaults',
+                         '-netdev', 'user,id=vnet',
+                         '-device', 'virtio-net,netdev=vnet')
+        self.vm.launch()
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp:[::1]:65022-[fe80::1]:22'),
+                          '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp:[::1]:65022'),
+                          'host forwarding rule for tcp:[::1]:65022 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add udp:[::1]:65042-[fe80::1]:42'),
+                          '')
+        self.assertEquals(self.hmc('hostfwd_remove udp:[::1]:65042'),
+                          'host forwarding rule for udp:[::1]:65042 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv6=on-:22'), '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv6=on'),
+                          'host forwarding rule for tcp::65022,ipv6=on removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv4=off-:22'), '')
+        self.assertEquals(self.hmc('hostfwd_remove vnet tcp::65022,ipv4=off'),
+                          'host forwarding rule for tcp::65022,ipv4=off removed\r\n')
+
+    def test_qmp_hostfwd_ipv6_functional_errors(self):
+        """Verify handling of various kinds of errors given valid addresses."""
+        self.vm.add_args('-nodefaults',
+                         '-netdev', 'user,id=vnet',
+                         '-device', 'virtio-net,netdev=vnet')
+        self.vm.launch()
+        self.assertEquals(self.hmc('hostfwd_remove :[::1]:65022'),
+                          'host forwarding rule for :[::1]:65022 not found\r\n')
+        self.assertEquals(self.hmc('hostfwd_add udp:[::1]:65042-[fe80::1]:42'),
+                          '')
+        self.assertEquals(self.hmc('hostfwd_add udp:[::1]:65042-[fe80::1]:42'),
+                          "Could not set up host forwarding rule" + \
+                          " 'udp:[::1]:65042-[fe80::1]:42': Address already in use\r\n")
+        self.assertEquals(self.hmc('hostfwd_remove :[::1]:65042'),
+                          'host forwarding rule for :[::1]:65042 not found\r\n')
+        self.assertEquals(self.hmc('hostfwd_remove udp:[::1]:65042'),
+                          'host forwarding rule for udp:[::1]:65042 removed\r\n')
+        self.assertEquals(self.hmc('hostfwd_remove udp:[::1]:65042'),
+                          'host forwarding rule for udp:[::1]:65042 not found\r\n')
+
+    def test_qmp_hostfwd_ipv6_errors(self):
+        """Verify handling of various kinds of errors."""
+        self.vm.add_args('-nodefaults',
+                         '-netdev', 'user,id=vnet',
+                         '-device', 'virtio-net,netdev=vnet')
+        self.vm.launch()
+        self.assertEquals(self.hmc('hostfwd_add :[::1-'),
+                          "Invalid host forwarding rule ':[::1-'" + \
+                          " (For host address: error parsing IPv6 address '[::1')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :[::1]:66-[fe80::1'),
+                          "Invalid host forwarding rule ':[::1]:66-[fe80::1'" + \
+                          " (For guest address: error parsing IPv6 address" + \
+                          " '[fe80::1')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :[:::]:66-foo'),
+                          "Invalid host forwarding rule ':[:::]:66-foo'" + \
+                          " (For host address: address resolution failed for" + \
+                          " '[:::]:66': Name or service not known)\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :[::1]-foo'),
+                          "Invalid host forwarding rule ':[::1]-foo'" + \
+                          " (For host address: error parsing IPv6 address '[::1]')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :[::1]:66-[foo]'),
+                          "Invalid host forwarding rule ':[::1]:66-[foo]'" + \
+                          " (For guest address: error parsing IPv6 address '[foo]')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :[::1]:66-[fe80::1]:0'),
+                          "Invalid host forwarding rule ':[::1]:66-[fe80::1]:0'" + \
+                          " (For guest address: invalid port '0')\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :[::1]:66-1.2.3.4:66'),
+                          "Invalid host forwarding rule ':[::1]:66-1.2.3.4:66'" + \
+                          " (For guest address: address resolution failed for" + \
+                          " '1.2.3.4:66': Address family for hostname not supported)\r\n")
+        self.assertEquals(self.hmc('hostfwd_add :1.2.3.4:66-[fe80::1]:66'),
+                          "Invalid host forwarding rule ':1.2.3.4:66-[fe80::1]:66'" + \
+                          " (For guest address: address resolution failed for" + \
+                          " '[fe80::1]:66': Address family for hostname not" + \
+                          " supported)\r\n")
+        self.assertEquals(self.hmc('hostfwd_add vnet tcp::65022,ipv6=abc-:22'),
+                          "Invalid host forwarding rule 'tcp::65022,ipv6=abc-:22'" + \
+                          " (For host address: error parsing 'ipv6' flag '=abc')\r\n")
-- 
2.32.0.rc0.204.g9fa02ecfa5-goog



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v7 0/4] Add support for ipv6 host forwarding
  2021-05-28 23:53 [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
                   ` (3 preceding siblings ...)
  2021-05-28 23:53 ` [PATCH v7 4/4] net: Extend host forwarding to support IPv6 Doug Evans
@ 2021-06-10  1:41 ` Doug Evans
  2021-06-15 11:24   ` Doug Evans
  4 siblings, 1 reply; 8+ messages in thread
From: Doug Evans @ 2021-06-10  1:41 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov

[-- Attachment #1: Type: text/plain, Size: 4456 bytes --]

Ping.

On Fri, May 28, 2021 at 4:53 PM Doug Evans <dje@google.com> wrote:

> This patchset takes the original patch from Maxim,
> https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
> and updates it.
>
> Option hostfwd is extended to support ipv6 addresses.
> Commands hostfwd_add, hostfwd_remove are extended as well.
>
> Changes from v6:
>
> 1/4: Update to use libslirp v4.5.0 tag
>
> The libslirp parts of the patch have been committed to the libslirp repo,
> and are now in QEMU's copy of the libslirp repo.
> Advancing QEMU to use Libslirp v4.5.0 is being done separately.
> Discussion of patch 1/4 is left to that thread:
> https://lists.nongnu.org/archive/html/qemu-devel/2021-05/msg06010.html
>
> 2/4: No change
>
> 3/4: Add support for --enable-slirp=system
> Tested with system libslirp 4.4.0.
>
> 4/4: No change
>
> Changes from v5:
>
> 1/4 slirp: Advance libslirp submodule to current master
> NOTE TO REVIEWERS: It may be a better use of everyone's time if a
> maintainer takes on advancing QEMU's libslirp to libslirp's master.
> Beyond that, I really don't know what to do except submit this patch as
> is currently provided.
>
> 2/4: util/qemu-sockets.c: Split host:port parsing out of inet_parse
>
> Also split out parsing of ipv4=on|off, ipv6=on|off
>
> 3/4: net/slirp.c: Refactor address parsing
>
> Use InetSocketAddress and getaddrinfo().
> Use new libslirp calls: slirp_remove_hostxfwd, slirp_add_hostxfwd.
>
> 4/4: net: Extend host forwarding to support IPv6
>
> Recognize ipv4=,ipv6= options.
>
> Note: v5's 3/5 "Recognize []:port (empty ipv6 address)" has been deleted:
> the churn on this patch series needs to be reduced.
> This change is not required, and can easily be done in a later patch.
>
> Changes from v4:
>
> 1/5 slirp: Advance libslirp submodule to add ipv6 host-forward support
> NOTE TO REVIEWERS: I need some hand-holding to know what The Right
> way to submit this particular patch is.
>
> - no change
>
> 2/5 util/qemu-sockets.c: Split host:port parsing out of inet_parse
>
> - move recognition of "[]:port" to separate patch
> - allow passing NULL for ip_v6
> - fix some formatting issues
>
> 3/5 inet_parse_host_and_addr: Recognize []:port (empty ipv6 address)
>
> - new in this patchset revision
>
> 4/5 net/slirp.c: Refactor address parsing
>
> - was 3/4 in v4
> - fix some formatting issues
>
> 5/5 net: Extend host forwarding to support IPv6
>
> - was 4/4 in v4
> - fix some formatting issues
>
> Changes from v3:
>
> 1/4 slirp: Advance libslirp submodule to add ipv6 host-forward support
>
> - pick up latest libslirp patch to reject ipv6 addr-any for guest address
>   - libslirp currently only provides a stateless DHCPv6 server, which means
>     it can't know in advance what the guest's IP address is, and thus
>     cannot do the "addr-any -> guest ip address" translation that is done
>     for ipv4
>
> 2/4 util/qemu-sockets.c: Split host:port parsing out of inet_parse
>
> - this patch is new in v4
>   - provides new utility: inet_parse_host_and_port, updates inet_parse
>     to use it
>
> 3/4 net/slirp.c: Refactor address parsing
>
> - this patch renamed from 2/3 to 3/4
> - call inet_parse_host_and_port from util/qemu-sockets.c
> - added tests/acceptance/hostfwd.py
>
> 4/4 net: Extend host forwarding to support IPv6
>
> - this patch renamed from 3/3 to 4/4
> - ipv6 support added to existing hostfwd option, commands
>   - instead of creating new ipv6 option, commands
> - added tests to tests/acceptance/hostfwd.py
>
> Changes from v2:
> - split out libslirp commit
> - clarify spelling of ipv6 addresses in docs
> - tighten parsing of ipv6 addresses
>
> Change from v1:
> - libslirp part is now upstream
> - net/slirp.c changes split into two pieces (refactor, add ipv6)
> - added docs
>
> Doug Evans (4):
>   slirp: Advance libslirp submodule to 4.5 release
>   util/qemu-sockets.c: Split host:port parsing out of inet_parse
>   net/slirp.c: Refactor address parsing
>   net: Extend host forwarding to support IPv6
>
>  hmp-commands.hx             |  18 ++-
>  include/qemu/sockets.h      |   5 +
>  net/slirp.c                 | 272 ++++++++++++++++++++++++++++--------
>  slirp                       |   2 +-
>  tests/acceptance/hostfwd.py | 185 ++++++++++++++++++++++++
>  util/qemu-sockets.c         |  82 +++++++----
>  6 files changed, 473 insertions(+), 91 deletions(-)
>  create mode 100644 tests/acceptance/hostfwd.py
>
> --
> 2.32.0.rc0.204.g9fa02ecfa5-goog
>
>

[-- Attachment #2: Type: text/html, Size: 5591 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v7 0/4] Add support for ipv6 host forwarding
  2021-06-10  1:41 ` [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
@ 2021-06-15 11:24   ` Doug Evans
  2021-06-15 23:42     ` max7255
  0 siblings, 1 reply; 8+ messages in thread
From: Doug Evans @ 2021-06-15 11:24 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Samuel Thibault, Daniel P . Berrangé,
	Marc-André Lureau, Maxim Samoylov

[-- Attachment #1: Type: text/plain, Size: 4674 bytes --]

Ping.

On Wed, Jun 9, 2021 at 9:41 PM Doug Evans <dje@google.com> wrote:

> Ping.
>
> On Fri, May 28, 2021 at 4:53 PM Doug Evans <dje@google.com> wrote:
>
>> This patchset takes the original patch from Maxim,
>> https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
>> and updates it.
>>
>> Option hostfwd is extended to support ipv6 addresses.
>> Commands hostfwd_add, hostfwd_remove are extended as well.
>>
>> Changes from v6:
>>
>> 1/4: Update to use libslirp v4.5.0 tag
>>
>> The libslirp parts of the patch have been committed to the libslirp repo,
>> and are now in QEMU's copy of the libslirp repo.
>> Advancing QEMU to use Libslirp v4.5.0 is being done separately.
>> Discussion of patch 1/4 is left to that thread:
>> https://lists.nongnu.org/archive/html/qemu-devel/2021-05/msg06010.html
>>
>> 2/4: No change
>>
>> 3/4: Add support for --enable-slirp=system
>> Tested with system libslirp 4.4.0.
>>
>> 4/4: No change
>>
>> Changes from v5:
>>
>> 1/4 slirp: Advance libslirp submodule to current master
>> NOTE TO REVIEWERS: It may be a better use of everyone's time if a
>> maintainer takes on advancing QEMU's libslirp to libslirp's master.
>> Beyond that, I really don't know what to do except submit this patch as
>> is currently provided.
>>
>> 2/4: util/qemu-sockets.c: Split host:port parsing out of inet_parse
>>
>> Also split out parsing of ipv4=on|off, ipv6=on|off
>>
>> 3/4: net/slirp.c: Refactor address parsing
>>
>> Use InetSocketAddress and getaddrinfo().
>> Use new libslirp calls: slirp_remove_hostxfwd, slirp_add_hostxfwd.
>>
>> 4/4: net: Extend host forwarding to support IPv6
>>
>> Recognize ipv4=,ipv6= options.
>>
>> Note: v5's 3/5 "Recognize []:port (empty ipv6 address)" has been deleted:
>> the churn on this patch series needs to be reduced.
>> This change is not required, and can easily be done in a later patch.
>>
>> Changes from v4:
>>
>> 1/5 slirp: Advance libslirp submodule to add ipv6 host-forward support
>> NOTE TO REVIEWERS: I need some hand-holding to know what The Right
>> way to submit this particular patch is.
>>
>> - no change
>>
>> 2/5 util/qemu-sockets.c: Split host:port parsing out of inet_parse
>>
>> - move recognition of "[]:port" to separate patch
>> - allow passing NULL for ip_v6
>> - fix some formatting issues
>>
>> 3/5 inet_parse_host_and_addr: Recognize []:port (empty ipv6 address)
>>
>> - new in this patchset revision
>>
>> 4/5 net/slirp.c: Refactor address parsing
>>
>> - was 3/4 in v4
>> - fix some formatting issues
>>
>> 5/5 net: Extend host forwarding to support IPv6
>>
>> - was 4/4 in v4
>> - fix some formatting issues
>>
>> Changes from v3:
>>
>> 1/4 slirp: Advance libslirp submodule to add ipv6 host-forward support
>>
>> - pick up latest libslirp patch to reject ipv6 addr-any for guest address
>>   - libslirp currently only provides a stateless DHCPv6 server, which
>> means
>>     it can't know in advance what the guest's IP address is, and thus
>>     cannot do the "addr-any -> guest ip address" translation that is done
>>     for ipv4
>>
>> 2/4 util/qemu-sockets.c: Split host:port parsing out of inet_parse
>>
>> - this patch is new in v4
>>   - provides new utility: inet_parse_host_and_port, updates inet_parse
>>     to use it
>>
>> 3/4 net/slirp.c: Refactor address parsing
>>
>> - this patch renamed from 2/3 to 3/4
>> - call inet_parse_host_and_port from util/qemu-sockets.c
>> - added tests/acceptance/hostfwd.py
>>
>> 4/4 net: Extend host forwarding to support IPv6
>>
>> - this patch renamed from 3/3 to 4/4
>> - ipv6 support added to existing hostfwd option, commands
>>   - instead of creating new ipv6 option, commands
>> - added tests to tests/acceptance/hostfwd.py
>>
>> Changes from v2:
>> - split out libslirp commit
>> - clarify spelling of ipv6 addresses in docs
>> - tighten parsing of ipv6 addresses
>>
>> Change from v1:
>> - libslirp part is now upstream
>> - net/slirp.c changes split into two pieces (refactor, add ipv6)
>> - added docs
>>
>> Doug Evans (4):
>>   slirp: Advance libslirp submodule to 4.5 release
>>   util/qemu-sockets.c: Split host:port parsing out of inet_parse
>>   net/slirp.c: Refactor address parsing
>>   net: Extend host forwarding to support IPv6
>>
>>  hmp-commands.hx             |  18 ++-
>>  include/qemu/sockets.h      |   5 +
>>  net/slirp.c                 | 272 ++++++++++++++++++++++++++++--------
>>  slirp                       |   2 +-
>>  tests/acceptance/hostfwd.py | 185 ++++++++++++++++++++++++
>>  util/qemu-sockets.c         |  82 +++++++----
>>  6 files changed, 473 insertions(+), 91 deletions(-)
>>  create mode 100644 tests/acceptance/hostfwd.py
>>
>> --
>> 2.32.0.rc0.204.g9fa02ecfa5-goog
>>
>>

[-- Attachment #2: Type: text/html, Size: 6012 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v7 0/4] Add support for ipv6 host forwarding
  2021-06-15 11:24   ` Doug Evans
@ 2021-06-15 23:42     ` max7255
  0 siblings, 0 replies; 8+ messages in thread
From: max7255 @ 2021-06-15 23:42 UTC (permalink / raw)
  To: Doug Evans, QEMU Developers
  Cc: Samuel Thibault, Daniel P . Berrangé, Marc-André Lureau

Hi!

Looking good for me.

Thanks for finishing this!
The whole patchset also looks simpler now.

On 6/15/21 2:24 PM, Doug Evans wrote:
> Ping.
> 
> On Wed, Jun 9, 2021 at 9:41 PM Doug Evans <dje@google.com 
> <mailto:dje@google.com>> wrote:
> 
>     Ping.
> 
>     On Fri, May 28, 2021 at 4:53 PM Doug Evans <dje@google.com
>     <mailto:dje@google.com>> wrote:
> 
>         This patchset takes the original patch from Maxim,
>         https://www.mail-archive.com/qemu-devel@nongnu.org/msg569573.html
>         and updates it.
> 
>         Option hostfwd is extended to support ipv6 addresses.
>         Commands hostfwd_add, hostfwd_remove are extended as well.
> 
>         Changes from v6:
> 
>         1/4: Update to use libslirp v4.5.0 tag
> 
>         The libslirp parts of the patch have been committed to the
>         libslirp repo,
>         and are now in QEMU's copy of the libslirp repo.
>         Advancing QEMU to use Libslirp v4.5.0 is being done separately.
>         Discussion of patch 1/4 is left to that thread:
>         https://lists.nongnu.org/archive/html/qemu-devel/2021-05/msg06010.html
> 
>         2/4: No change
> 
>         3/4: Add support for --enable-slirp=system
>         Tested with system libslirp 4.4.0.
> 
>         4/4: No change
> 
>         Changes from v5:
> 
>         1/4 slirp: Advance libslirp submodule to current master
>         NOTE TO REVIEWERS: It may be a better use of everyone's time if a
>         maintainer takes on advancing QEMU's libslirp to libslirp's master.
>         Beyond that, I really don't know what to do except submit this
>         patch as
>         is currently provided.
> 
>         2/4: util/qemu-sockets.c: Split host:port parsing out of inet_parse
> 
>         Also split out parsing of ipv4=on|off, ipv6=on|off
> 
>         3/4: net/slirp.c: Refactor address parsing
> 
>         Use InetSocketAddress and getaddrinfo().
>         Use new libslirp calls: slirp_remove_hostxfwd, slirp_add_hostxfwd.
> 
>         4/4: net: Extend host forwarding to support IPv6
> 
>         Recognize ipv4=,ipv6= options.
> 
>         Note: v5's 3/5 "Recognize []:port (empty ipv6 address)" has been
>         deleted:
>         the churn on this patch series needs to be reduced.
>         This change is not required, and can easily be done in a later
>         patch.
> 
>         Changes from v4:
> 
>         1/5 slirp: Advance libslirp submodule to add ipv6 host-forward
>         support
>         NOTE TO REVIEWERS: I need some hand-holding to know what The Right
>         way to submit this particular patch is.
> 
>         - no change
> 
>         2/5 util/qemu-sockets.c: Split host:port parsing out of inet_parse
> 
>         - move recognition of "[]:port" to separate patch
>         - allow passing NULL for ip_v6
>         - fix some formatting issues
> 
>         3/5 inet_parse_host_and_addr: Recognize []:port (empty ipv6 address)
> 
>         - new in this patchset revision
> 
>         4/5 net/slirp.c: Refactor address parsing
> 
>         - was 3/4 in v4
>         - fix some formatting issues
> 
>         5/5 net: Extend host forwarding to support IPv6
> 
>         - was 4/4 in v4
>         - fix some formatting issues
> 
>         Changes from v3:
> 
>         1/4 slirp: Advance libslirp submodule to add ipv6 host-forward
>         support
> 
>         - pick up latest libslirp patch to reject ipv6 addr-any for
>         guest address
>            - libslirp currently only provides a stateless DHCPv6 server,
>         which means
>              it can't know in advance what the guest's IP address is,
>         and thus
>              cannot do the "addr-any -> guest ip address" translation
>         that is done
>              for ipv4
> 
>         2/4 util/qemu-sockets.c: Split host:port parsing out of inet_parse
> 
>         - this patch is new in v4
>            - provides new utility: inet_parse_host_and_port, updates
>         inet_parse
>              to use it
> 
>         3/4 net/slirp.c: Refactor address parsing
> 
>         - this patch renamed from 2/3 to 3/4
>         - call inet_parse_host_and_port from util/qemu-sockets.c
>         - added tests/acceptance/hostfwd.py
> 
>         4/4 net: Extend host forwarding to support IPv6
> 
>         - this patch renamed from 3/3 to 4/4
>         - ipv6 support added to existing hostfwd option, commands
>            - instead of creating new ipv6 option, commands
>         - added tests to tests/acceptance/hostfwd.py
> 
>         Changes from v2:
>         - split out libslirp commit
>         - clarify spelling of ipv6 addresses in docs
>         - tighten parsing of ipv6 addresses
> 
>         Change from v1:
>         - libslirp part is now upstream
>         - net/slirp.c changes split into two pieces (refactor, add ipv6)
>         - added docs
> 
>         Doug Evans (4):
>            slirp: Advance libslirp submodule to 4.5 release
>            util/qemu-sockets.c: Split host:port parsing out of inet_parse
>            net/slirp.c: Refactor address parsing
>            net: Extend host forwarding to support IPv6
> 
>           hmp-commands.hx             |  18 ++-
>           include/qemu/sockets.h      |   5 +
>           net/slirp.c                 | 272
>         ++++++++++++++++++++++++++++--------
>           slirp                       |   2 +-
>           tests/acceptance/hostfwd.py | 185 ++++++++++++++++++++++++
>           util/qemu-sockets.c         |  82 +++++++----
>           6 files changed, 473 insertions(+), 91 deletions(-)
>           create mode 100644 tests/acceptance/hostfwd.py
> 
>         -- 
>         2.32.0.rc0.204.g9fa02ecfa5-goog
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-06-15 23:44 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-28 23:53 [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
2021-05-28 23:53 ` [PATCH v7 1/4] slirp: Advance libslirp submodule to 4.5 release Doug Evans
2021-05-28 23:53 ` [PATCH v7 2/4] util/qemu-sockets.c: Split host:port parsing out of inet_parse Doug Evans
2021-05-28 23:53 ` [PATCH v7 3/4] net/slirp.c: Refactor address parsing Doug Evans
2021-05-28 23:53 ` [PATCH v7 4/4] net: Extend host forwarding to support IPv6 Doug Evans
2021-06-10  1:41 ` [PATCH v7 0/4] Add support for ipv6 host forwarding Doug Evans
2021-06-15 11:24   ` Doug Evans
2021-06-15 23:42     ` max7255

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).