port redirection support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1054 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/Changelog b/Changelog
index 4b6f315..430ef55 100644
--- a/Changelog
+++ b/Changelog
@@ -9,6 +9,7 @@
- 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 ba3ade8..7493d51 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -228,6 +228,44 @@
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 @@
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 47824b2..772427d 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -3,8 +3,10 @@
#ifdef _WIN32
#include <winsock2.h>
+int inet_aton(const char *cp, struct in_addr *ia);
#else
#include <sys/select.h>
+#include <arpa/inet.h>
#endif
void slirp_init(void);
@@ -20,4 +22,9 @@
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 405647b..bc2b155 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -617,3 +617,18 @@
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 e50d255..9052662 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -36,7 +36,7 @@
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 3ee666a..f0560b6 100644
--- a/slirp/tftp.h
+++ b/slirp/tftp.h
@@ -29,6 +29,4 @@
} x;
};
-extern char *tftp_prefix;
-
void tftp_input(struct mbuf *m);
diff --git a/vl.c b/vl.c
index f05d73a..5ba5b97 100644
--- a/vl.c
+++ b/vl.c
@@ -1382,6 +1382,78 @@
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 @@
"-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 @@
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 @@
#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 @@
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;