public inbox for qemu-devel@nongnu.org
 help / color / mirror / Atom feed
* [PATCH RFC] net/slirp: allow hostfwd socket paths with dashes
@ 2026-03-17  8:31 Michael Tokarev
  2026-03-17 13:33 ` Christopher Richez
  0 siblings, 1 reply; 2+ messages in thread
From: Michael Tokarev @ 2026-03-17  8:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-trivial, Michael Tokarev, Christopher Palmer-Richez

The format of hostfwd parameter is:
  hostfwd=hostpart-guestaddr:guestport
so a minus sign can not be part of the hostpart.
If hostpart specifies a unix socket path, this becomes problematic.

To solve this, look for the LAST minus/dash char in the string,
not first.

Unfortunately, [-guestaddr] is optional (defaults to 10.0.0.15),
so we still can't parse the thing in an uniform way.

Extend get_str_sep() to accept one more parameter, to indicate if
first or last separator is needed, and modify all callers to ask
for first separator.  Update slirp_hostfwd to search for the last
separator when parsing unix domain socket path.

Inspired-by: Christopher Palmer-Richez <crichez@pm.me>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/347
---
 net/slirp.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/net/slirp.c b/net/slirp.c
index 04925f3318..804d430890 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -49,12 +49,18 @@
 #include "migration/vmstate.h"
 #include "migration/qemu-file-types.h"
 
-static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+typedef enum {
+    SEP_FIRST,
+    SEP_LAST
+} sep_type;
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep,
+                       sep_type which)
 {
     const char *p, *p1;
     int len;
     p = *pp;
-    p1 = strchr(p, sep);
+    p1 = which == SEP_FIRST ? strchr(p, sep) : strrchr(p, sep);
     if (!p1)
         return -1;
     len = p1 - p;
@@ -479,7 +485,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
     }
 
     if (vnetwork) {
-        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/', SEP_FIRST) < 0) {
             if (!inet_aton(vnetwork, &net)) {
                 error_setg(errp, "Failed to parse netmask");
                 return -1;
@@ -760,7 +766,7 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
     }
 
     p = src_str;
-    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
 
@@ -772,7 +778,7 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
         goto fail_syntax;
     }
 
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     if (buf[0] != '\0' && !inet_aton(buf, &host_addr.sin_addr)) {
@@ -827,7 +833,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
     socklen_t host_addr_size;
 
     p = redir_str;
-    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         fail_reason = "No : separators";
         goto fail_syntax;
     }
@@ -848,7 +854,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
 
 #if !defined(WIN32) && SLIRP_CHECK_VERSION(4, 7, 0)
     if (is_unix) {
-        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &p, '-', SEP_LAST) < 0) {
             fail_reason = "Missing - separator";
             goto fail_syntax;
         }
@@ -888,7 +894,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
         host_addr.in.sin_family = AF_INET;
         host_addr.in.sin_addr.s_addr = INADDR_ANY;
 
-        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
             fail_reason = "Missing : separator";
             goto fail_syntax;
         }
@@ -898,7 +904,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
             goto fail_syntax;
         }
 
-        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &p, '-', SEP_FIRST) < 0) {
             fail_reason = "Bad host port separator";
             goto fail_syntax;
         }
@@ -913,7 +919,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
         host_addr_size = sizeof(host_addr.in);
     }
 
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         fail_reason = "Missing guest address";
         goto fail_syntax;
     }
@@ -1125,19 +1131,19 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
     int port;
 
     p = config_str;
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     if (strcmp(buf, "tcp") && buf[0] != '\0') {
         goto fail_syntax;
     }
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     if (buf[0] != '\0' && !inet_aton(buf, &server)) {
         goto fail_syntax;
     }
-    if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, '-', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     port = strtol(buf, &end, 10);
-- 
2.47.3



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

* Re: [PATCH RFC] net/slirp: allow hostfwd socket paths with dashes
  2026-03-17  8:31 [PATCH RFC] net/slirp: allow hostfwd socket paths with dashes Michael Tokarev
@ 2026-03-17 13:33 ` Christopher Richez
  0 siblings, 0 replies; 2+ messages in thread
From: Christopher Richez @ 2026-03-17 13:33 UTC (permalink / raw)
  To: Michael Tokarev; +Cc: qemu-devel, qemu-trivial

This is much neater than my patch for this, thank you for taking the time to do it this way!

-------- Original Message --------
On Tuesday, 03/17/26 at 04:32 Michael Tokarev <mjt@tls.msk.ru> wrote:
The format of hostfwd parameter is:
  hostfwd=hostpart-guestaddr:guestport
so a minus sign can not be part of the hostpart.
If hostpart specifies a unix socket path, this becomes problematic.

To solve this, look for the LAST minus/dash char in the string,
not first.

Unfortunately, [-guestaddr] is optional (defaults to 10.0.0.15),
so we still can't parse the thing in an uniform way.

Extend get_str_sep() to accept one more parameter, to indicate if
first or last separator is needed, and modify all callers to ask
for first separator.  Update slirp_hostfwd to search for the last
separator when parsing unix domain socket path.

Inspired-by: Christopher Palmer-Richez <crichez@pm.me>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/347
---
 net/slirp.c | 32 +++++++++++++++++++-------------
 1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/net/slirp.c b/net/slirp.c
index 04925f3318..804d430890 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -49,12 +49,18 @@
 #include "migration/vmstate.h"
 #include "migration/qemu-file-types.h"

-static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+typedef enum {
+    SEP_FIRST,
+    SEP_LAST
+} sep_type;
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep,
+                       sep_type which)
 {
     const char *p, *p1;
     int len;
     p = *pp;
-    p1 = strchr(p, sep);
+    p1 = which == SEP_FIRST ? strchr(p, sep) : strrchr(p, sep);
     if (!p1)
         return -1;
     len = p1 - p;
@@ -479,7 +485,7 @@ static int net_slirp_init(NetClientState *peer, const char *model,
     }

     if (vnetwork) {
-        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/', SEP_FIRST) < 0) {
             if (!inet_aton(vnetwork, &net)) {
                 error_setg(errp, "Failed to parse netmask");
                 return -1;
@@ -760,7 +766,7 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
     }

     p = src_str;
-    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }

@@ -772,7 +778,7 @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
         goto fail_syntax;
     }

-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     if (buf[0] != '\0' && !inet_aton(buf, &host_addr.sin_addr)) {
@@ -827,7 +833,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
     socklen_t host_addr_size;

     p = redir_str;
-    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (!p || get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         fail_reason = "No : separators";
         goto fail_syntax;
     }
@@ -848,7 +854,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)

 #if !defined(WIN32) && SLIRP_CHECK_VERSION(4, 7, 0)
     if (is_unix) {
-        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &p, '-', SEP_LAST) < 0) {
             fail_reason = "Missing - separator";
             goto fail_syntax;
         }
@@ -888,7 +894,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
         host_addr.in.sin_family = AF_INET;
         host_addr.in.sin_addr.s_addr = INADDR_ANY;

-        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
             fail_reason = "Missing : separator";
             goto fail_syntax;
         }
@@ -898,7 +904,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
             goto fail_syntax;
         }

-        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+        if (get_str_sep(buf, sizeof(buf), &p, '-', SEP_FIRST) < 0) {
             fail_reason = "Bad host port separator";
             goto fail_syntax;
         }
@@ -913,7 +919,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
         host_addr_size = sizeof(host_addr.in);
     }

-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         fail_reason = "Missing guest address";
         goto fail_syntax;
     }
@@ -1125,19 +1131,19 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
     int port;

     p = config_str;
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     if (strcmp(buf, "tcp") && buf[0] != '\0') {
         goto fail_syntax;
     }
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, ':', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     if (buf[0] != '\0' && !inet_aton(buf, &server)) {
         goto fail_syntax;
     }
-    if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+    if (get_str_sep(buf, sizeof(buf), &p, '-', SEP_FIRST) < 0) {
         goto fail_syntax;
     }
     port = strtol(buf, &end, 10);
--
2.47.3





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

end of thread, other threads:[~2026-03-17 13:34 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17  8:31 [PATCH RFC] net/slirp: allow hostfwd socket paths with dashes Michael Tokarev
2026-03-17 13:33 ` Christopher Richez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox