diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2009-06-24 14:42:28 +0200 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2009-06-29 08:52:45 -0500 |
commit | c92ef6a22d3c71538fcc48fb61ad353f7ba03b62 (patch) | |
tree | 867e01eb52981f2b493c745b5c0dadf97b492824 /net.c | |
parent | a13a4126c8b94355bbe43e47275b97ce5bef003c (diff) |
slirp: Rework external configuration interface
With the internal IP configuration made more flexible, we can now
enhance the user interface. This patch adds a number of new options to
"-net user": net (address and mask), host, dhcpstart, dns and smbserver.
It also renames "redir" to "hostfwd" and "channel" to "guestfwd" in
order to (hopefully) clarify their meanings. The format of guestfwd is
extended so that the user can define not only the port but also the
virtual server's IP address the forwarding starts from.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'net.c')
-rw-r--r-- | net.c | 316 |
1 files changed, 239 insertions, 77 deletions
@@ -669,12 +669,14 @@ static void config_error(Monitor *mon, const char *fmt, ...) /* slirp network adapter */ -#define SLIRP_CFG_REDIR 1 +#define SLIRP_CFG_HOSTFWD 1 +#define SLIRP_CFG_LEGACY 2 struct slirp_config_str { struct slirp_config_str *next; int flags; char str[1024]; + int legacy_format; }; static int slirp_inited; @@ -683,13 +685,14 @@ const char *legacy_tftp_prefix; const char *legacy_bootp_filename; static VLANClientState *slirp_vc; -static void slirp_redirection(Monitor *mon, const char *redir_str); -static void vmchannel_init(Monitor *mon, const char *config_str); +static void slirp_hostfwd(Monitor *mon, const char *redir_str); +static void slirp_guestfwd(Monitor *mon, const char *config_str, + int legacy_format); #ifndef _WIN32 static const char *legacy_smb_export; -static void slirp_smb(const char *exported_dir); +static void slirp_smb(const char *exported_dir, struct in_addr vserver_addr); #endif int slirp_can_output(void) @@ -731,31 +734,122 @@ static void net_slirp_cleanup(VLANClientState *vc) } static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model, - const char *name, int restricted, const char *ip, - const char *tftp_export, const char *bootfile, - const char *smb_export) + const char *name, int restricted, + const char *vnetwork, const char *vhost, + const char *vhostname, const char *tftp_export, + const char *bootfile, const char *vdhcp_start, + const char *vnameserver, const char *smb_export, + const char *vsmbserver) { if (slirp_in_use) { /* slirp only supports a single instance so far */ return -1; } if (!slirp_inited) { + /* default settings according to historic slirp */ + struct in_addr net = { .s_addr = htonl(0x0a000000) }; /* 10.0.0.0 */ + struct in_addr mask = { .s_addr = htonl(0xff000000) }; /* 255.0.0.0 */ + struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ + struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ + struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ +#ifndef _WIN32 + struct in_addr smbsrv = { .s_addr = 0 }; +#endif + char buf[20]; + uint32_t addr; + int shift; + char *end; + if (!tftp_export) { tftp_export = legacy_tftp_prefix; } if (!bootfile) { bootfile = legacy_bootp_filename; } + + if (vnetwork) { + if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { + if (!inet_aton(vnetwork, &net)) { + return -1; + } + addr = ntohl(net.s_addr); + if (!(addr & 0x80000000)) { + mask.s_addr = htonl(0xff000000); /* class A */ + } else if ((addr & 0xfff00000) == 0xac100000) { + mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ + } else if ((addr & 0xc0000000) == 0x80000000) { + mask.s_addr = htonl(0xffff0000); /* class B */ + } else if ((addr & 0xffff0000) == 0xc0a80000) { + mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ + } else if ((addr & 0xffff0000) == 0xc6120000) { + mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ + } else if ((addr & 0xe0000000) == 0xe0000000) { + mask.s_addr = htonl(0xffffff00); /* class C */ + } else { + mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ + } + } else { + if (!inet_aton(buf, &net)) { + return -1; + } + shift = strtol(vnetwork, &end, 10); + if (*end != '\0') { + if (!inet_aton(vnetwork, &mask)) { + return -1; + } + } else if (shift < 4 || shift > 32) { + return -1; + } else { + mask.s_addr = htonl(0xffffffff << (32 - shift)); + } + } + net.s_addr &= mask.s_addr; + host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); + dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); + dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); + } + + if (vhost && !inet_aton(vhost, &host)) { + return -1; + } + if ((host.s_addr & mask.s_addr) != net.s_addr) { + return -1; + } + + if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) { + return -1; + } + if ((dhcp.s_addr & mask.s_addr) != net.s_addr || + dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) { + return -1; + } + + if (vnameserver && !inet_aton(vnameserver, &dns)) { + return -1; + } + if ((dns.s_addr & mask.s_addr) != net.s_addr || + dns.s_addr == host.s_addr) { + return -1; + } + +#ifndef _WIN32 + if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { + return -1; + } +#endif + + slirp_init(restricted, net, mask, host, vhostname, tftp_export, + bootfile, dhcp, dns); slirp_inited = 1; - slirp_init(restricted, ip, tftp_export, bootfile); while (slirp_configs) { struct slirp_config_str *config = slirp_configs; - if (config->flags & SLIRP_CFG_REDIR) { - slirp_redirection(mon, config->str); + if (config->flags & SLIRP_CFG_HOSTFWD) { + slirp_hostfwd(mon, config->str); } else { - vmchannel_init(mon, config->str); + slirp_guestfwd(mon, config->str, + config->flags & SLIRP_CFG_LEGACY); } slirp_configs = config->next; qemu_free(config); @@ -765,7 +859,7 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model, smb_export = legacy_smb_export; } if (smb_export) { - slirp_smb(smb_export); + slirp_smb(smb_export, smbsrv); } #endif } @@ -777,7 +871,7 @@ static int net_slirp_init(Monitor *mon, VLANState *vlan, const char *model, return 0; } -static void net_slirp_redir_rm(Monitor *mon, const char *port_str) +static void net_slirp_hostfwd_remove(Monitor *mon, const char *port_str) { int host_port; char buf[256] = ""; @@ -803,23 +897,24 @@ static void net_slirp_redir_rm(Monitor *mon, const char *port_str) host_port = atoi(p); - n = slirp_redir_rm(is_udp, host_port); + n = slirp_remove_hostfwd(is_udp, host_port); - monitor_printf(mon, "removed %d redirections to %s port %d\n", n, - is_udp ? "udp" : "tcp", host_port); + monitor_printf(mon, "removed %d host forwarding rules for %s port %d\n", + n, is_udp ? "udp" : "tcp", host_port); return; fail_syntax: monitor_printf(mon, "invalid format\n"); } -static void slirp_redirection(Monitor *mon, const char *redir_str) +static void slirp_hostfwd(Monitor *mon, const char *redir_str) { - struct in_addr guest_addr; + struct in_addr guest_addr = { .s_addr = 0 }; int host_port, guest_port; const char *p; - char buf[256], *r; + char buf[256]; int is_udp; + char *end; p = redir_str; if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { @@ -836,33 +931,31 @@ static void slirp_redirection(Monitor *mon, const char *redir_str) if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; } - host_port = strtol(buf, &r, 0); - if (r == buf) { + 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; } - if (buf[0] == '\0') { - pstrcpy(buf, sizeof(buf), "10.0.2.15"); - } - if (!inet_aton(buf, &guest_addr)) { + if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { goto fail_syntax; } - guest_port = strtol(p, &r, 0); - if (r == p) { + 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) { - config_error(mon, "could not set up redirection '%s'\n", redir_str); + if (slirp_add_hostfwd(is_udp, host_port, guest_addr, guest_port) < 0) { + config_error(mon, "could not set up host forwarding rule '%s'\n", + redir_str); } return; fail_syntax: - config_error(mon, "invalid redirection format '%s'\n", redir_str); + config_error(mon, "invalid host forwarding rule '%s'\n", redir_str); } void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2) @@ -875,7 +968,7 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 } else { config = qemu_malloc(sizeof(*config)); pstrcpy(config->str, sizeof(config->str), redir_str); - config->flags = SLIRP_CFG_REDIR; + config->flags = SLIRP_CFG_HOSTFWD; config->next = slirp_configs; slirp_configs = config; } @@ -883,11 +976,11 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 } if (!strcmp(redir_str, "remove")) { - net_slirp_redir_rm(mon, redir_opt2); + net_slirp_hostfwd_remove(mon, redir_opt2); return; } - slirp_redirection(mon, redir_str); + slirp_hostfwd(mon, redir_str); } #ifndef _WIN32 @@ -925,7 +1018,7 @@ static void smb_exit(void) erase_dir(smb_dir); } -static void slirp_smb(const char *exported_dir) +static void slirp_smb(const char *exported_dir, struct in_addr vserver_addr) { char smb_conf[1024]; char smb_cmdline[1024]; @@ -971,19 +1064,24 @@ static void slirp_smb(const char *exported_dir) snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", SMBD_COMMAND, smb_conf); - slirp_add_exec(0, smb_cmdline, 4, 139); + if (slirp_add_exec(0, smb_cmdline, vserver_addr, 139) < 0) { + fprintf(stderr, "conflicting/invalid smbserver address\n"); + exit(1); + } } /* automatic user mode samba server configuration (legacy interface) */ void net_slirp_smb(const char *exported_dir) { + struct in_addr vserver_addr = { .s_addr = 0 }; + if (legacy_smb_export) { fprintf(stderr, "-smb given twice\n"); exit(1); } legacy_smb_export = exported_dir; if (slirp_inited) { - slirp_smb(exported_dir); + slirp_smb(exported_dir, vserver_addr); } } @@ -994,51 +1092,85 @@ void do_info_slirp(Monitor *mon) slirp_stats(); } -struct VMChannel { +struct GuestFwd { CharDriverState *hd; + struct in_addr server; int port; }; -static int vmchannel_can_read(void *opaque) +static int guestfwd_can_read(void *opaque) { - struct VMChannel *vmc = (struct VMChannel*)opaque; - return slirp_socket_can_recv(4, vmc->port); + struct GuestFwd *fwd = opaque; + return slirp_socket_can_recv(fwd->server, fwd->port); } -static void vmchannel_read(void *opaque, const uint8_t *buf, int size) +static void guestfwd_read(void *opaque, const uint8_t *buf, int size) { - struct VMChannel *vmc = (struct VMChannel*)opaque; - slirp_socket_recv(4, vmc->port, buf, size); + struct GuestFwd *fwd = opaque; + slirp_socket_recv(fwd->server, fwd->port, buf, size); } -static void vmchannel_init(Monitor *mon, const char *config_str) +static void slirp_guestfwd(Monitor *mon, const char *config_str, + int legacy_format) { - struct VMChannel *vmc; - char *devname; - char name[20]; + struct in_addr server = { .s_addr = 0 }; + struct GuestFwd *fwd; + const char *p; + char buf[128]; + char *end; int port; - port = strtol(config_str, &devname, 10); - if (port < 1 || port > 65535 || *devname != ':') { - config_error(mon, "invalid vmchannel port number\n"); - return; + p = config_str; + if (legacy_format) { + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + } else { + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (strcmp(buf, "tcp") && buf[0] != '\0') { + goto fail_syntax; + } + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { + goto fail_syntax; + } + if (buf[0] != '\0' && !inet_aton(buf, &server)) { + goto fail_syntax; + } + if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { + goto fail_syntax; + } + } + port = strtol(buf, &end, 10); + if (*end != '\0' || port < 1 || port > 65535) { + goto fail_syntax; } - devname++; - vmc = qemu_malloc(sizeof(struct VMChannel)); - snprintf(name, sizeof(name), "vmchannel%d", port); - vmc->hd = qemu_chr_open(name, devname, NULL); - if (!vmc->hd) { - config_error(mon, "could not open vmchannel device '%s'\n", devname); - qemu_free(vmc); + fwd = qemu_malloc(sizeof(struct GuestFwd)); + snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); + fwd->hd = qemu_chr_open(buf, p, NULL); + if (!fwd->hd) { + config_error(mon, "could not open guest forwarding device '%s'\n", + buf); + qemu_free(fwd); return; } - vmc->port = port; + fwd->server = server; + fwd->port = port; - slirp_add_exec(3, vmc->hd, 4, port); - qemu_chr_add_handlers(vmc->hd, vmchannel_can_read, vmchannel_read, - NULL, vmc); + if (slirp_add_exec(3, fwd->hd, server, port) < 0) { + config_error(mon, "conflicting/invalid host:port in guest forwarding " + "rule '%s'\n", config_str); + qemu_free(fwd); + return; + } + qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, + NULL, fwd); return; + + fail_syntax: + config_error(mon, "invalid guest forwarding rule '%s'\n", config_str); } #endif /* CONFIG_SLIRP */ @@ -2252,15 +2384,21 @@ int net_client_init(Monitor *mon, const char *device, const char *p) #ifdef CONFIG_SLIRP if (!strcmp(device, "user")) { static const char * const slirp_params[] = { - "vlan", "name", "hostname", "restrict", "ip", "tftp", "bootfile", - "smb", "redir", "channel", NULL + "vlan", "name", "hostname", "restrict", "ip", "net", "host", + "tftp", "bootfile", "dhcpstart", "dns", "smb", "smbserver", + "hostfwd", "guestfwd", NULL }; struct slirp_config_str *config; + int restricted = 0; + char *vnet = NULL; + char *vhost = NULL; + char *vhostname = NULL; char *tftp_export = NULL; char *bootfile = NULL; + char *vdhcp_start = NULL; + char *vnamesrv = NULL; char *smb_export = NULL; - int restricted = 0; - char *ip = NULL; + char *vsmbsrv = NULL; const char *q; if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { @@ -2268,14 +2406,29 @@ int net_client_init(Monitor *mon, const char *device, const char *p) ret = -1; goto out; } + if (get_param_value(buf, sizeof(buf), "ip", p)) { + /* emulate legacy parameter */ + vnet = qemu_malloc(strlen(buf) + strlen("/24") + 1); + strcpy(vnet, buf); + strcat(vnet, "/24"); + } + if (get_param_value(buf, sizeof(buf), "net", p)) { + vnet = qemu_strdup(buf); + } + if (get_param_value(buf, sizeof(buf), "host", p)) { + vhost = qemu_strdup(buf); + } if (get_param_value(buf, sizeof(buf), "hostname", p)) { - pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); + vhostname = qemu_strdup(buf); } if (get_param_value(buf, sizeof(buf), "restrict", p)) { restricted = (buf[0] == 'y') ? 1 : 0; } - if (get_param_value(buf, sizeof(buf), "ip", p)) { - ip = qemu_strdup(buf); + if (get_param_value(buf, sizeof(buf), "dhcpstart", p)) { + vdhcp_start = qemu_strdup(buf); + } + if (get_param_value(buf, sizeof(buf), "dns", p)) { + vnamesrv = qemu_strdup(buf); } if (get_param_value(buf, sizeof(buf), "tftp", p)) { tftp_export = qemu_strdup(buf); @@ -2285,15 +2438,18 @@ int net_client_init(Monitor *mon, const char *device, const char *p) } if (get_param_value(buf, sizeof(buf), "smb", p)) { smb_export = qemu_strdup(buf); + if (get_param_value(buf, sizeof(buf), "smbserver", p)) { + vsmbsrv = qemu_strdup(buf); + } } q = p; while (1) { config = qemu_malloc(sizeof(*config)); if (!get_next_param_value(config->str, sizeof(config->str), - "redir", &q)) { + "hostfwd", &q)) { break; } - config->flags = SLIRP_CFG_REDIR; + config->flags = SLIRP_CFG_HOSTFWD; config->next = slirp_configs; slirp_configs = config; config = NULL; @@ -2302,7 +2458,7 @@ int net_client_init(Monitor *mon, const char *device, const char *p) while (1) { config = qemu_malloc(sizeof(*config)); if (!get_next_param_value(config->str, sizeof(config->str), - "channel", &q)) { + "guestfwd", &q)) { break; } config->flags = 0; @@ -2312,23 +2468,29 @@ int net_client_init(Monitor *mon, const char *device, const char *p) } qemu_free(config); vlan->nb_host_devs++; - ret = net_slirp_init(mon, vlan, device, name, restricted, ip, - tftp_export, bootfile, smb_export); - qemu_free(ip); + ret = net_slirp_init(mon, vlan, device, name, restricted, vnet, vhost, + vhostname, tftp_export, bootfile, vdhcp_start, + vnamesrv, smb_export, vsmbsrv); + qemu_free(vnet); + qemu_free(vhost); + qemu_free(vhostname); qemu_free(tftp_export); qemu_free(bootfile); + qemu_free(vdhcp_start); + qemu_free(vnamesrv); qemu_free(smb_export); + qemu_free(vsmbsrv); } else if (!strcmp(device, "channel")) { if (!slirp_inited) { struct slirp_config_str *config; config = qemu_malloc(sizeof(*config)); pstrcpy(config->str, sizeof(config->str), p); - config->flags = 0; + config->flags = SLIRP_CFG_LEGACY; config->next = slirp_configs; slirp_configs = config; } else { - vmchannel_init(mon, p); + slirp_guestfwd(mon, p, 1); } ret = 0; } else |