diff --git a/net.c b/net.c index 883a236638..ee321ab47f 100644 --- 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 9edfab108e..016db31365 100644 --- 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); diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 13c98bc9ac..34f699288a 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -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 diff --git a/qemu-options.hx b/qemu-options.hx index da5b0ac6a5..2f21e0a430 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -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 diff --git a/slirp/libslirp.h b/slirp/libslirp.h index e4c9c99c3b..9be4425bb6 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -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); diff --git a/slirp/slirp.c b/slirp/slirp.c index ad88121c2c..ab0a8548aa 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -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; diff --git a/slirp/socket.c b/slirp/socket.c index 9f13f03cc6..936021e84d 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -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) || diff --git a/slirp/socket.h b/slirp/socket.h index f5adaba6e7..ac36aaa4b5 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -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 *)); diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 858d1ae59c..6fa4223a4e 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -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)) { diff --git a/slirp/udp.c b/slirp/udp.c index ff3a39fb21..d675ad3e66 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -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); diff --git a/slirp/udp.h b/slirp/udp.h index 51a07a2fcc..d4c2bea60e 100644 --- a/slirp/udp.h +++ b/slirp/udp.h @@ -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);