]> git.proxmox.com Git - mirror_qemu.git/commitdiff
slirp: Bind support for host forwarding rules
authorJan Kiszka <jan.kiszka@web.de>
Wed, 24 Jun 2009 12:42:28 +0000 (14:42 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Mon, 29 Jun 2009 13:52:45 +0000 (08:52 -0500)
Extend the hostfwd rule format so that the user can specify on which
host interface qemu should listen for incoming connections. If omitted,
binding will takes place against all interfaces.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
net.c
net.h
qemu-monitor.hx
qemu-options.hx
slirp/libslirp.h
slirp/slirp.c
slirp/socket.c
slirp/socket.h
slirp/tcp_subr.c
slirp/udp.c
slirp/udp.h

diff --git a/net.c b/net.c
index 883a23663870a1fc45a4bb4cf5c8e872e46307b4..ee321ab47f7853019cf640897ed0b3219152906e 100644 (file)
--- a/net.c
+++ b/net.c
@@ -685,7 +685,8 @@ const char *legacy_tftp_prefix;
 const char *legacy_bootp_filename;
 static VLANClientState *slirp_vc;
 
-static void slirp_hostfwd(Monitor *mon, const char *redir_str);
+static void slirp_hostfwd(Monitor *mon, const char *redir_str,
+                          int legacy_format);
 static void slirp_guestfwd(Monitor *mon, const char *config_str,
                            int legacy_format);
 
@@ -846,7 +847,8 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model,
             struct slirp_config_str *config = slirp_configs;
 
             if (config->flags & SLIRP_CFG_HOSTFWD) {
-                slirp_hostfwd(mon, config->str);
+                slirp_hostfwd(mon, config->str,
+                              config->flags & SLIRP_CFG_LEGACY);
             } else {
                 slirp_guestfwd(mon, config->str,
                                config->flags & SLIRP_CFG_LEGACY);
@@ -871,11 +873,12 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model,
     return 0;
 }
 
-void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str)
+void net_slirp_hostfwd_remove(Monitor *mon, const char *src_str)
 {
+    struct in_addr host_addr = { .s_addr = INADDR_ANY };
     int host_port;
     char buf[256] = "";
-    const char *p = port_str;
+    const char *p = src_str;
     int is_udp = 0;
     int n;
 
@@ -884,7 +887,7 @@ void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str)
         return;
     }
 
-    if (!port_str || !port_str[0])
+    if (!src_str || !src_str[0])
         goto fail_syntax;
 
     get_str_sep(buf, sizeof(buf), &p, ':');
@@ -897,20 +900,29 @@ void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str)
         goto fail_syntax;
     }
 
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+        goto fail_syntax;
+    }
+    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+        goto fail_syntax;
+    }
+
     host_port = atoi(p);
 
-    n = slirp_remove_hostfwd(is_udp, host_port);
+    n = slirp_remove_hostfwd(is_udp, host_addr, host_port);
 
-    monitor_printf(mon, "removed %d host forwarding rules for %s port %d\n",
-                   n, is_udp ? "udp" : "tcp", host_port);
+    monitor_printf(mon, "removed %d host forwarding rules for %s\n", n,
+                   src_str);
     return;
 
  fail_syntax:
     monitor_printf(mon, "invalid format\n");
 }
 
-static void slirp_hostfwd(Monitor *mon, const char *redir_str)
+static void slirp_hostfwd(Monitor *mon, const char *redir_str,
+                          int legacy_format)
 {
+    struct in_addr host_addr = { .s_addr = INADDR_ANY };
     struct in_addr guest_addr = { .s_addr = 0 };
     int host_port, guest_port;
     const char *p;
@@ -930,7 +942,16 @@ static void slirp_hostfwd(Monitor *mon, const char *redir_str)
         goto fail_syntax;
     }
 
-    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+    if (!legacy_format) {
+        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+            goto fail_syntax;
+        }
+        if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+            goto fail_syntax;
+        }
+    }
+
+    if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
         goto fail_syntax;
     }
     host_port = strtol(buf, &end, 0);
@@ -950,7 +971,8 @@ static void slirp_hostfwd(Monitor *mon, const char *redir_str)
         goto fail_syntax;
     }
 
-    if (slirp_add_hostfwd(is_udp, host_port, guest_addr, guest_port) < 0) {
+    if (slirp_add_hostfwd(is_udp, host_addr, host_port,
+                          guest_addr, guest_port) < 0) {
         config_error(mon, "could not set up host forwarding rule '%s'\n",
                      redir_str);
     }
@@ -967,7 +989,7 @@ void net_slirp_hostfwd_add(Monitor *mon, const char *redir_str)
         return;
     }
 
-    slirp_hostfwd(mon, redir_str);
+    slirp_hostfwd(mon, redir_str, 0);
 }
 
 void net_slirp_redir(const char *redir_str)
@@ -977,13 +999,13 @@ void net_slirp_redir(const char *redir_str)
     if (!slirp_inited) {
         config = qemu_malloc(sizeof(*config));
         pstrcpy(config->str, sizeof(config->str), redir_str);
-        config->flags = SLIRP_CFG_HOSTFWD;
+        config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
         config->next = slirp_configs;
         slirp_configs = config;
         return;
     }
 
-    slirp_hostfwd(NULL, redir_str);
+    slirp_hostfwd(NULL, redir_str, 1);
 }
 
 #ifndef _WIN32
diff --git a/net.h b/net.h
index 9edfab108ea3f848db4fdfce668168b03ae37299..016db3136563a40d768fd8054ff945c72a165660 100644 (file)
--- a/net.h
+++ b/net.h
@@ -133,7 +133,7 @@ void net_client_uninit(NICInfo *nd);
 int net_client_parse(const char *str);
 void net_slirp_smb(const char *exported_dir);
 void net_slirp_hostfwd_add(Monitor *mon, const char *redir_str);
-void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str);
+void net_slirp_hostfwd_remove(Monitor *mon, const char *src_str);
 void net_slirp_redir(const char *redir_str);
 void net_cleanup(void);
 int slirp_is_inited(void);
index 13c98bc9ac9a679ab3ca123b2d1fe643b50a284d..34f699288a3875434b59c84cf7a909dc36f6641c 100644 (file)
@@ -537,10 +537,11 @@ ETEXI
 
 #ifdef CONFIG_SLIRP
     { "hostfwd_add", "s", net_slirp_hostfwd_add,
-      "[tcp|udp]:hostport:[guestaddr]:guestport",
+      "[tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
       "redirect TCP or UDP connections from host to guest (requires -net user)" },
     { "hostfwd_remove", "s", net_slirp_hostfwd_remove,
-      "[tcp|udp]:hostport", "remove host-to-guest TCP or UDP redirection" },
+      "[tcp|udp]:[hostaddr]:hostport",
+      "remove host-to-guest TCP or UDP redirection" },
 #endif
 STEXI
 @item host_net_redir
index da5b0ac6a503445431f966de37be0ed3440c6225..2f21e0a430c472d52d9451cf2db242f2f1d8c1f7 100644 (file)
@@ -881,11 +881,12 @@ Note that a SAMBA server must be installed on the host OS in
 @file{/usr/sbin/smbd}. QEMU was tested successfully with smbd versions from
 Red Hat 9, Fedora Core 3 and OpenSUSE 11.x.
 
-@item hostfwd=[tcp|udp]:@var{hostport}:[@var{guestaddr}]:@var{guestport}
+@item hostfwd=[tcp|udp]:[@var{hostaddr}]:@var{hostport}-[@var{guestaddr}]:@var{guestport}
 Redirect incoming TCP or UDP connections to the host port @var{hostport} to
 the guest IP address @var{guestaddr} on guest port @var{guestport}. If
 @var{guestaddr} is not specified, its value is x.x.x.15 (default first address
-given by the built-in DHCP server). If no connection type is specified, TCP is
+given by the built-in DHCP server). By specifying @var{hostaddr}, the rule can
+be bound to a specific host interface. If no connection type is set, TCP is
 used. This option can be given multiple times.
 
 For example, to redirect host X11 connection from screen 1 to guest
@@ -893,7 +894,7 @@ screen 0, use the following:
 
 @example
 # on the host
-qemu -net user,hostfwd=tcp:6001::6000 [...]
+qemu -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...]
 # this host xterm should open in the guest X11 server
 xterm -display :1
 @end example
@@ -911,8 +912,8 @@ Then when you use on the host @code{telnet localhost 5555}, you
 connect to the guest telnet server.
 
 @item guestfwd=[tcp]:@var{server}:@var{port}-@var{dev}
-Forward guest TCP connections to port @var{port} on the host to character
-device @var{dev}. This option can be given multiple times.
+Forward guest TCP connections to the IP address @var{server} on port @var{port}
+to the character device @var{dev}. This option can be given multiple times.
 
 @end table
 
index e4c9c99c3ba2d128a3ad2c1716edb426439421dd..9be4425bb6789b0fbc1153a825425ada980ef903 100644 (file)
@@ -22,10 +22,9 @@ void slirp_input(const uint8_t *pkt, int pkt_len);
 int slirp_can_output(void);
 void slirp_output(const uint8_t *pkt, int pkt_len);
 
-int slirp_add_hostfwd(int is_udp, int host_port,
+int slirp_add_hostfwd(int is_udp, struct in_addr host_addr, int host_port,
                       struct in_addr guest_addr, int guest_port);
-int slirp_remove_hostfwd(int is_udp, int host_port);
-
+int slirp_remove_hostfwd(int is_udp, struct in_addr host_addr, int host_port);
 int slirp_add_exec(int do_pty, const void *args, struct in_addr guest_addr,
                    int guest_port);
 
index ad88121c2cd9478bf00dd1fc7efc241ee4ac6660..ab0a8548aacb28386a5a190dd6ba55f72c18c43a 100644 (file)
@@ -757,7 +757,7 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
 /* Unlistens a redirection
  *
  * Return value: number of redirs removed */
-int slirp_remove_hostfwd(int is_udp, int host_port)
+int slirp_remove_hostfwd(int is_udp, struct in_addr host_addr, int host_port)
 {
     struct socket *so;
     struct socket *head = (is_udp ? &udb : &tcb);
@@ -770,6 +770,7 @@ int slirp_remove_hostfwd(int is_udp, int host_port)
     for (so = head->so_next; so != head; so = so->so_next) {
         addr_len = sizeof(addr);
         if (getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
+            addr.sin_addr.s_addr == host_addr.s_addr &&
             addr.sin_port == port) {
             close(so->s);
             sofree(so);
@@ -781,19 +782,19 @@ int slirp_remove_hostfwd(int is_udp, int host_port)
     return n;
 }
 
-int slirp_add_hostfwd(int is_udp, int host_port,
+int slirp_add_hostfwd(int is_udp, struct in_addr host_addr, int host_port,
                       struct in_addr guest_addr, int guest_port)
 {
     if (!guest_addr.s_addr) {
         guest_addr = vdhcp_startaddr;
     }
     if (is_udp) {
-        if (!udp_listen(htons(host_port), guest_addr.s_addr,
+        if (!udp_listen(host_addr.s_addr, htons(host_port), guest_addr.s_addr,
                         htons(guest_port), 0))
             return -1;
     } else {
-        if (!solisten(htons(host_port), guest_addr.s_addr,
-                      htons(guest_port), 0))
+        if (!tcp_listen(host_addr.s_addr, htons(host_port), guest_addr.s_addr,
+                        htons(guest_port), 0))
             return -1;
     }
     return 0;
index 9f13f03cc69a1a82326c5e7b1f3fa8beeaa0d1d1..936021e84d583edc1267ead7e98bb3f3d6c01c61 100644 (file)
@@ -586,17 +586,17 @@ sosendto(struct socket *so, struct mbuf *m)
 }
 
 /*
- * XXX This should really be tcp_listen
+ * Listen for incoming TCP connections
  */
 struct socket *
-solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
+tcp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport, int flags)
 {
        struct sockaddr_in addr;
        struct socket *so;
        int s, opt = 1;
        socklen_t addrlen = sizeof(addr);
 
-       DEBUG_CALL("solisten");
+       DEBUG_CALL("tcp_listen");
        DEBUG_ARG("port = %d", port);
        DEBUG_ARG("laddr = %x", laddr);
        DEBUG_ARG("lport = %d", lport);
@@ -625,8 +625,8 @@ solisten(u_int port, u_int32_t laddr, u_int lport, int flags)
        so->so_laddr.s_addr = laddr; /* Ditto */
 
        addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = INADDR_ANY;
-       addr.sin_port = port;
+       addr.sin_addr.s_addr = haddr;
+       addr.sin_port = hport;
 
        if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
            (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
index f5adaba6e75ce65673b64064f0a6f6ecbeb73fce..ac36aaa4b591037865f06396e2c57fc3f51d4e04 100644 (file)
@@ -82,7 +82,7 @@ int sosendoob _P((struct socket *));
 int sowrite _P((struct socket *));
 void sorecvfrom _P((struct socket *));
 int sosendto _P((struct socket *, struct mbuf *));
-struct socket * solisten _P((u_int, u_int32_t, u_int, int));
+struct socket * tcp_listen _P((u_int32_t, u_int, u_int32_t, u_int, int));
 void soisfconnecting _P((register struct socket *));
 void soisfconnected _P((register struct socket *));
 void soisfdisconnected _P((struct socket *));
index 858d1ae59cfbdbf13c23b08dfbf1d8b2e6f82e27..6fa4223a4e36a3bcb1ceef00f67820edda6a27b8 100644 (file)
@@ -970,7 +970,7 @@ do_prompt:
                        laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
                        lport = htons((n5 << 8) | (n6));
 
-                       if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
+                       if ((so = tcp_listen(INADDR_ANY, 0, laddr, lport, SS_FACCEPTONCE)) == NULL)
                           return 1;
 
                        n6 = ntohs(so->so_fport);
@@ -1002,7 +1002,7 @@ do_prompt:
                        laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
                        lport = htons((n5 << 8) | (n6));
 
-                       if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
+                       if ((so = tcp_listen(INADDR_ANY, 0, laddr, lport, SS_FACCEPTONCE)) == NULL)
                           return 1;
 
                        n6 = ntohs(so->so_fport);
@@ -1042,7 +1042,7 @@ do_prompt:
                        lport += m->m_data[i] - '0';
                }
                if (m->m_data[m->m_len-1] == '\0' && lport != 0 &&
-                   (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
+                   (so = tcp_listen(INADDR_ANY, 0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
                     m->m_len = snprintf(m->m_data, m->m_hdr.mh_size, "%d",
                                         ntohs(so->so_fport)) + 1;
                return 1;
@@ -1057,7 +1057,7 @@ do_prompt:
 
                /* The %256s is for the broken mIRC */
                if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
-                       if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
+                       if ((so = tcp_listen(INADDR_ANY, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
                                return 1;
 
                        m->m_len = bptr - m->m_data; /* Adjust length */
@@ -1066,7 +1066,7 @@ do_prompt:
                                              (unsigned long)ntohl(so->so_faddr.s_addr),
                                              ntohs(so->so_fport), 1);
                } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
-                       if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
+                       if ((so = tcp_listen(INADDR_ANY, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
                                return 1;
 
                        m->m_len = bptr - m->m_data; /* Adjust length */
@@ -1075,7 +1075,7 @@ do_prompt:
                                              (unsigned long)ntohl(so->so_faddr.s_addr),
                                              ntohs(so->so_fport), n1, 1);
                } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
-                       if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
+                       if ((so = tcp_listen(INADDR_ANY, 0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
                                return 1;
 
                        m->m_len = bptr - m->m_data; /* Adjust length */
@@ -1190,7 +1190,8 @@ do_prompt:
 
                                /* try to get udp port between 6970 - 7170 */
                                for (p = 6970; p < 7071; p++) {
-                                       if (udp_listen( htons(p),
+                                       if (udp_listen(INADDR_ANY,
+                                                      htons(p),
                                                       so->so_laddr.s_addr,
                                                       htons(lport),
                                                       SS_FACCEPTONCE)) {
index ff3a39fb21acb3085f6ba4718e535cb4e7d47a2e..d675ad3e66774550e93673f188e7d8f9e8a86008 100644 (file)
@@ -627,7 +627,8 @@ struct cu_header {
 }
 
 struct socket *
-udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
+udp_listen(u_int32_t haddr, u_int hport, u_int32_t laddr, u_int lport,
+           int flags)
 {
        struct sockaddr_in addr;
        struct socket *so;
@@ -642,8 +643,8 @@ udp_listen(u_int port, u_int32_t laddr, u_int lport, int flags)
        insque(so,&udb);
 
        addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = INADDR_ANY;
-       addr.sin_port = port;
+       addr.sin_addr.s_addr = haddr;
+       addr.sin_port = hport;
 
        if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) {
                udp_detach(so);
index 51a07a2fccd523ad25b3599936ea7edf0de03cf6..d4c2bea60e0aa3f4f2e6a55cd73445224f30134d 100644 (file)
@@ -101,7 +101,7 @@ void udp_input _P((register struct mbuf *, int));
 int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *));
 int udp_attach _P((struct socket *));
 void udp_detach _P((struct socket *));
-struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
+struct socket * udp_listen _P((u_int32_t, u_int, u_int32_t, u_int, int));
 int udp_output2(struct socket *so, struct mbuf *m,
                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                 int iptos);