Add port redirection option for networking with slirp.

Port forwarding allows the emulator to host servers that can be
accessed from outside the virtual network.

The code for parsing the preference option "redir" is adapted from
qemu code. The rest was already implemented.
This commit is contained in:
Charles Lehner 2012-10-30 01:32:38 -04:00
parent b4940ae29d
commit 349fad4d2f
3 changed files with 111 additions and 0 deletions

View File

@ -528,6 +528,18 @@ udpport <IP port number>
This item specifies the IP port number to use for the "UDP Tunnel" mode.
The default is 6066.
redir <port redirection description>
This item defines a port to be forwarded from the host to the client.
The format is "[protocol]:hostport:[clientaddress]:clientport", where
protocol is "udp" or "tcp" (default), hostport is the port on your
computer to forward to the Mac, clientaddress is the IP address of the Mac
in the virtual network (defaults to 10.0.2.15), and clientport is the port on
the Mac to be exposed. For example, if you have a web server in MacOS running
on port 80, you can expose it as port 8000 with the line below:
redir tcp:8000:10.0.2.15:80
rom <ROM file path>
This item specifies the file name of the Mac ROM file to be used by

View File

@ -66,6 +66,7 @@
#ifdef HAVE_SLIRP
#include "libslirp.h"
#include "ctl.h"
#endif
#include "cpu_emulation.h"
@ -131,6 +132,8 @@ static int16 ether_do_add_multicast(uint8 *addr);
static int16 ether_do_del_multicast(uint8 *addr);
static int16 ether_do_write(uint32 arg);
static void ether_do_interrupt(void);
static void slirp_add_redirs();
static int slirp_add_redir(const char *redir_str);
/*
@ -279,6 +282,9 @@ bool ether_init(void)
// Open slirp input pipe
if (pipe(slirp_input_fds) < 0)
return false;
// Set up port redirects
slirp_add_redirs();
}
#endif
@ -951,3 +957,95 @@ void ether_do_interrupt(void)
}
}
}
// Helper function for port forwarding
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;
}
// Set up port forwarding for slirp
static void slirp_add_redirs()
{
int index = 0;
const char *str;
while ((str = PrefsFindString("redir", index++)) != NULL) {
slirp_add_redir(str);
}
}
// Add a port forward/redirection for slirp
static int slirp_add_redir(const char *redir_str)
{
// code adapted from qemu source
struct in_addr guest_addr = { .s_addr = 0 };
int host_port, guest_port;
const char *p;
char buf[256];
int is_udp;
char *end;
char str[256];
p = redir_str;
if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
goto fail_syntax;
}
if (!strcmp(buf, "tcp") || buf[0] == '\0') {
is_udp = 0;
} else if (!strcmp(buf, "udp")) {
is_udp = 1;
} else {
goto fail_syntax;
}
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
goto fail_syntax;
}
host_port = strtol(buf, &end, 0);
if (*end != '\0' || host_port < 1 || host_port > 65535) {
goto fail_syntax;
}
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
goto fail_syntax;
}
// 0.0.0.0 doesn't seem to work, so default to a client address
// if none is specified
if (buf[0] == '\0' ?
!inet_aton(CTL_LOCAL, &guest_addr) :
!inet_aton(buf, &guest_addr)) {
goto fail_syntax;
}
guest_port = strtol(p, &end, 0);
if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
goto fail_syntax;
}
if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
sprintf(str, "could not set up host forwarding rule '%s'", redir_str);
WarningAlert(str);
return -1;
}
return 0;
fail_syntax:
sprintf(str, "invalid host forwarding rule '%s'", redir_str);
WarningAlert(str);
return -1;
}

View File

@ -46,6 +46,7 @@ prefs_desc common_prefs_items[] = {
{"etherconfig", TYPE_STRING, false,"path of network config script"},
{"udptunnel", TYPE_BOOLEAN, false, "tunnel all network packets over UDP"},
{"udpport", TYPE_INT32, false, "IP port number for tunneling"},
{"redir", TYPE_STRING, true, "port forwarding for slirp"},
{"rom", TYPE_STRING, false, "path of ROM file"},
{"bootdrive", TYPE_INT32, false, "boot drive number"},
{"bootdriver", TYPE_INT32, false, "boot driver number"},