diff --git a/Changelog b/Changelog index 4b6f315be1..430ef55c0e 100644 --- a/Changelog +++ b/Changelog @@ -9,6 +9,7 @@ version 0.6.1: - VMware 3 and 4 read-only disk image support (untested) - Support for up to 4 serial ports - TFTP server support (Magnus Damm) + - Port redirection support in user mode networking version 0.6.0: diff --git a/qemu-doc.texi b/qemu-doc.texi index ba3ade8618..7493d519d7 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -228,6 +228,44 @@ example of its use. Use the user mode network stack. This is the default if no tun/tap network init script is found. +@item -tftp prefix +When using the user mode network stack, activate a built-in TFTP +server. All filenames beginning with @var{prefix} can be downloaded +from the host to the guest using a TFTP client. The TFTP client on the +guest must be configured in binary mode (use the command @code{bin} of +the Unix TFTP client). The host IP address on the guest is as usual +10.0.2.2. + +@item -redir [tcp|udp]:host-port:[guest-host]:guest-port + +When using the user mode network stack, redirect incoming TCP or UDP +connections to the host port @var{host-port} to the guest +@var{guest-host} on guest port @var{guest-port}. If @var{guest-host} +is not specified, its value is 10.0.2.15 (default address given by the +built-in DHCP server). + +For example, to redirect host X11 connection from screen 1 to guest +screen 0, use the following: + +@example +# on the host +qemu -redir tcp:6001::6000 [...] +# this host xterm should open in the guest X11 server +xterm -display :1 +@end example + +To redirect telnet connections from host port 5555 to telnet port on +the guest, use the following: + +@example +# on the host +qemu -redir tcp:5555::23 [...] +telnet localhost 5555 +@end example + +Then when you use on the host @code{telnet localhost 5555}, you +connect to the guest telnet server. + @item -dummy-net Use the dummy network stack: no packet will be received by the network cards. @@ -652,7 +690,12 @@ Note that @code{ping} is not supported reliably to the internet as it would require root priviledges. It means you can only ping the local router (10.0.2.2). -The user mode network is currently only supported on a Unix host. +When using the built-in TFTP server, the router is also the TFTP +server. + +When using the @option{-redir} option, TCP or UDP connections can be +redirected from the host to the guest. It allows for example to +redirect X11, telnet or SSH connections. @node direct_linux_boot @section Direct Linux Boot diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 47824b2413..772427d110 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -3,8 +3,10 @@ #ifdef _WIN32 #include +int inet_aton(const char *cp, struct in_addr *ia); #else #include +#include #endif void slirp_init(void); @@ -20,4 +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_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port); + +extern const char *tftp_prefix; + #endif diff --git a/slirp/slirp.c b/slirp/slirp.c index 405647b48c..bc2b15509a 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -617,3 +617,18 @@ void if_encap(const uint8_t *ip_data, int ip_data_len) memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); slirp_output(buf, ip_data_len + ETH_HLEN); } + +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port) +{ + if (is_udp) { + if (!udp_listen(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)) + return -1; + } + return 0; +} diff --git a/slirp/tftp.c b/slirp/tftp.c index e50d255393..90526625c0 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -36,7 +36,7 @@ struct tftp_session { struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; -char *tftp_prefix; +const char *tftp_prefix; static void tftp_session_update(struct tftp_session *spt) { diff --git a/slirp/tftp.h b/slirp/tftp.h index 3ee666a153..f0560b6ab0 100644 --- a/slirp/tftp.h +++ b/slirp/tftp.h @@ -29,6 +29,4 @@ struct tftp_t { } x; }; -extern char *tftp_prefix; - void tftp_input(struct mbuf *m); diff --git a/vl.c b/vl.c index f05d73a955..5ba5b97a56 100644 --- a/vl.c +++ b/vl.c @@ -1382,6 +1382,78 @@ static int net_slirp_init(NetDriverState *nd) return 0; } +static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) +{ + const char *p, *p1; + int len; + p = *pp; + p1 = strchr(p, sep); + if (!p1) + return -1; + len = p1 - p; + p1++; + if (buf_size > 0) { + if (len > buf_size - 1) + len = buf_size - 1; + memcpy(buf, p, len); + buf[len] = '\0'; + } + *pp = p1; + return 0; +} + +static void net_slirp_redir(const char *redir_str) +{ + int is_udp; + char buf[256], *r; + const char *p; + struct in_addr guest_addr; + int host_port, guest_port; + + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + + p = redir_str; + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + if (!strcmp(buf, "tcp")) { + is_udp = 0; + } else if (!strcmp(buf, "udp")) { + is_udp = 1; + } else { + goto fail; + } + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + host_port = strtol(buf, &r, 0); + if (r == buf) + goto fail; + + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + goto fail; + if (buf[0] == '\0') { + pstrcpy(buf, sizeof(buf), "10.0.2.15"); + } + if (!inet_aton(buf, &guest_addr)) + goto fail; + + guest_port = strtol(p, &r, 0); + if (r == p) + goto fail; + + if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { + fprintf(stderr, "qemu: could not set up redirection\n"); + exit(1); + } + return; + fail: + fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); + exit(1); +} + #endif /* CONFIG_SLIRP */ #if !defined(_WIN32) @@ -2334,7 +2406,9 @@ void help(void) "-tun-fd fd use this fd as already opened tap/tun interface\n" #ifdef CONFIG_SLIRP "-user-net use user mode network stack [default if no tap/tun script]\n" - "-tftp prefix allow tftp access to files starting with prefix [only with -user-net enabled]\n" + "-tftp prefix allow tftp access to files starting with prefix [-user-net]\n" + "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" + " redirect TCP or UDP connections from host to guest [-user-net]\n" #endif "-dummy-net use dummy network stack\n" "\n" @@ -2410,6 +2484,7 @@ enum { QEMU_OPTION_tun_fd, QEMU_OPTION_user_net, QEMU_OPTION_tftp, + QEMU_OPTION_redir, QEMU_OPTION_dummy_net, QEMU_OPTION_kernel, @@ -2463,6 +2538,7 @@ const QEMUOption qemu_options[] = { #ifdef CONFIG_SLIRP { "user-net", 0, QEMU_OPTION_user_net }, { "tftp", HAS_ARG, QEMU_OPTION_tftp }, + { "redir", HAS_ARG, QEMU_OPTION_redir }, #endif { "dummy-net", 0, QEMU_OPTION_dummy_net }, @@ -2756,14 +2832,14 @@ int main(int argc, char **argv) break; #ifdef CONFIG_SLIRP case QEMU_OPTION_tftp: - { - extern const char *tftp_prefix; tftp_prefix = optarg; - } - break; + break; case QEMU_OPTION_user_net: net_if_type = NET_IF_USER; break; + case QEMU_OPTION_redir: + net_slirp_redir(optarg); + break; #endif case QEMU_OPTION_dummy_net: net_if_type = NET_IF_DUMMY;