From patchwork Wed Nov 25 18:48:54 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark McLoughlin X-Patchwork-Id: 39418 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id E5971B6F1C for ; Thu, 26 Nov 2009 05:58:43 +1100 (EST) Received: from localhost ([127.0.0.1]:44548 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NDN4W-00014D-6C for incoming@patchwork.ozlabs.org; Wed, 25 Nov 2009 13:58:36 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NDMye-0007Lx-Bn for qemu-devel@nongnu.org; Wed, 25 Nov 2009 13:52:32 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1NDMyZ-0007GQ-K1 for qemu-devel@nongnu.org; Wed, 25 Nov 2009 13:52:29 -0500 Received: from [199.232.76.173] (port=48988 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NDMyW-0007GC-Qw for qemu-devel@nongnu.org; Wed, 25 Nov 2009 13:52:24 -0500 Received: from mx1.redhat.com ([209.132.183.28]:9141) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NDMyV-0000Dd-Eg for qemu-devel@nongnu.org; Wed, 25 Nov 2009 13:52:24 -0500 Received: from int-mx05.intmail.prod.int.phx2.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.18]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id nAPIqM6m023373 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 25 Nov 2009 13:52:22 -0500 Received: from blaa.localdomain (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx05.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id nAPIqLhs027235; Wed, 25 Nov 2009 13:52:22 -0500 Received: by blaa.localdomain (Postfix, from userid 500) id 4C51439B4; Wed, 25 Nov 2009 18:49:39 +0000 (GMT) From: Mark McLoughlin To: qemu-devel@nongnu.org Date: Wed, 25 Nov 2009 18:48:54 +0000 Message-Id: <1259174977-26212-2-git-send-email-markmc@redhat.com> In-Reply-To: <1259174977-26212-1-git-send-email-markmc@redhat.com> References: <1259174977-26212-1-git-send-email-markmc@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.18 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: Mark McLoughlin Subject: [Qemu-devel] [PATCH 01/44] net: move slirp code from net.c to net/slirp.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Signed-off-by: Mark McLoughlin --- Makefile | 1 + monitor.c | 1 + net.c | 718 +------------------------------------------------------- net.h | 8 +- net/slirp.c | 752 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ net/slirp.h | 51 ++++ vl.c | 1 + 7 files changed, 814 insertions(+), 718 deletions(-) create mode 100644 net/slirp.c create mode 100644 net/slirp.h diff --git a/Makefile b/Makefile index 63a7128..45362fa 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,7 @@ net-nested-$(CONFIG_WIN32) += tap-win32.o net-nested-$(CONFIG_BSD) += tap-bsd.o net-nested-$(CONFIG_SOLARIS) += tap-solaris.o net-nested-$(CONFIG_AIX) += tap-aix.o +net-nested-$(CONFIG_SLIRP) += slirp.o net-obj-y += $(addprefix net/, $(net-nested-y)) ###################################################################### diff --git a/monitor.c b/monitor.c index 3286ba2..fa1561a 100644 --- a/monitor.c +++ b/monitor.c @@ -32,6 +32,7 @@ #include "hw/loader.h" #include "gdbstub.h" #include "net.h" +#include "net/slirp.h" #include "qemu-char.h" #include "sysemu.h" #include "monitor.h" diff --git a/net.c b/net.c index 9ea66e3..9b030a1 100644 --- a/net.c +++ b/net.c @@ -40,9 +40,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -98,6 +96,7 @@ #include "qemu-common.h" #include "net.h" #include "net/tap.h" +#include "net/slirp.h" #include "monitor.h" #include "sysemu.h" #include "qemu-timer.h" @@ -107,15 +106,13 @@ #include "qemu-log.h" #include "qemu-config.h" -#include "slirp/libslirp.h" - static QTAILQ_HEAD(, VLANState) vlans; static QTAILQ_HEAD(, VLANClientState) non_vlan_clients; /***********************************************************/ /* network device redirectors */ -#if defined(DEBUG_NET) || defined(DEBUG_SLIRP) +#if defined(DEBUG_NET) static void hex_dump(FILE *f, const uint8_t *buf, int size) { int len, i, j, c; @@ -406,7 +403,7 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque) return NULL; } -static VLANClientState * +VLANClientState * qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, const char *client_str) { @@ -725,597 +722,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); } -#if defined(CONFIG_SLIRP) - -/* slirp network adapter */ - -#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; -}; - -typedef struct SlirpState { - QTAILQ_ENTRY(SlirpState) entry; - VLANClientState *vc; - Slirp *slirp; -#ifndef _WIN32 - char smb_dir[128]; -#endif -} SlirpState; - -static struct slirp_config_str *slirp_configs; -const char *legacy_tftp_prefix; -const char *legacy_bootp_filename; -static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = - QTAILQ_HEAD_INITIALIZER(slirp_stacks); - -static int slirp_hostfwd(SlirpState *s, const char *redir_str, - int legacy_format); -static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format); - -#ifndef _WIN32 -static const char *legacy_smb_export; - -static int slirp_smb(SlirpState *s, const char *exported_dir, - struct in_addr vserver_addr); -static void slirp_smb_cleanup(SlirpState *s); -#else -static inline void slirp_smb_cleanup(SlirpState *s) { } -#endif - -int slirp_can_output(void *opaque) -{ - SlirpState *s = opaque; - - return qemu_can_send_packet(s->vc); -} - -void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) -{ - SlirpState *s = opaque; - -#ifdef DEBUG_SLIRP - printf("slirp output:\n"); - hex_dump(stdout, pkt, pkt_len); -#endif - qemu_send_packet(s->vc, pkt, pkt_len); -} - -static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) -{ - SlirpState *s = vc->opaque; - -#ifdef DEBUG_SLIRP - printf("slirp input:\n"); - hex_dump(stdout, buf, size); -#endif - slirp_input(s->slirp, buf, size); - return size; -} - -static void net_slirp_cleanup(VLANClientState *vc) -{ - SlirpState *s = vc->opaque; - - slirp_cleanup(s->slirp); - slirp_smb_cleanup(s); - QTAILQ_REMOVE(&slirp_stacks, s, entry); - qemu_free(s); -} - -static int net_slirp_init(VLANState *vlan, const char *model, - 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) -{ - /* default settings according to historic slirp */ - struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ - struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.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 - SlirpState *s; - char buf[20]; - uint32_t addr; - int shift; - char *end; - struct slirp_config_str *config; - - 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 - - s = qemu_mallocz(sizeof(SlirpState)); - s->slirp = slirp_init(restricted, net, mask, host, vhostname, - tftp_export, bootfile, dhcp, dns, s); - QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); - - for (config = slirp_configs; config; config = config->next) { - if (config->flags & SLIRP_CFG_HOSTFWD) { - if (slirp_hostfwd(s, config->str, - config->flags & SLIRP_CFG_LEGACY) < 0) - return -1; - } else { - if (slirp_guestfwd(s, config->str, - config->flags & SLIRP_CFG_LEGACY) < 0) - return -1; - } - } -#ifndef _WIN32 - if (!smb_export) { - smb_export = legacy_smb_export; - } - if (smb_export) { - if (slirp_smb(s, smb_export, smbsrv) < 0) - return -1; - } -#endif - - s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP, - vlan, NULL, model, name, NULL, - slirp_receive, NULL, NULL, - net_slirp_cleanup, s); - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); - return 0; -} - -static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, - const char *stack) -{ - VLANClientState *vc; - - if (vlan) { - vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); - if (!vc) { - return NULL; - } - if (strcmp(vc->model, "user")) { - monitor_printf(mon, "invalid device specified\n"); - return NULL; - } - return vc->opaque; - } else { - if (QTAILQ_EMPTY(&slirp_stacks)) { - monitor_printf(mon, "user mode network stack not in use\n"); - return NULL; - } - return QTAILQ_FIRST(&slirp_stacks); - } -} - -void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) -{ - struct in_addr host_addr = { .s_addr = INADDR_ANY }; - int host_port; - char buf[256] = ""; - const char *src_str, *p; - SlirpState *s; - int is_udp = 0; - int err; - const char *arg1 = qdict_get_str(qdict, "arg1"); - const char *arg2 = qdict_get_try_str(qdict, "arg2"); - const char *arg3 = qdict_get_try_str(qdict, "arg3"); - - if (arg2) { - s = slirp_lookup(mon, arg1, arg2); - src_str = arg3; - } else { - s = slirp_lookup(mon, NULL, NULL); - src_str = arg1; - } - if (!s) { - return; - } - - if (!src_str || !src_str[0]) - goto fail_syntax; - - p = src_str; - get_str_sep(buf, sizeof(buf), &p, ':'); - - 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; - } - if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { - goto fail_syntax; - } - - host_port = atoi(p); - - err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp, - host_addr, host_port); - - monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, - err ? "removed" : "not found"); - return; - - fail_syntax: - monitor_printf(mon, "invalid format\n"); -} - -static int slirp_hostfwd(SlirpState *s, 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; - char buf[256]; - int is_udp; - char *end; - - 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 (!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); - 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' && !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_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, - guest_port) < 0) { - qemu_error("could not set up host forwarding rule '%s'\n", - redir_str); - return -1; - } - return 0; - - fail_syntax: - qemu_error("invalid host forwarding rule '%s'\n", redir_str); - return -1; -} - -void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) -{ - const char *redir_str; - SlirpState *s; - const char *arg1 = qdict_get_str(qdict, "arg1"); - const char *arg2 = qdict_get_try_str(qdict, "arg2"); - const char *arg3 = qdict_get_try_str(qdict, "arg3"); - - if (arg2) { - s = slirp_lookup(mon, arg1, arg2); - redir_str = arg3; - } else { - s = slirp_lookup(mon, NULL, NULL); - redir_str = arg1; - } - if (s) { - slirp_hostfwd(s, redir_str, 0); - } - -} - -int net_slirp_redir(const char *redir_str) -{ - struct slirp_config_str *config; - - if (QTAILQ_EMPTY(&slirp_stacks)) { - config = qemu_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), redir_str); - config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - return 0; - } - - return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); -} - -#ifndef _WIN32 - -/* automatic user mode samba server configuration */ -static void slirp_smb_cleanup(SlirpState *s) -{ - char cmd[128]; - - if (s->smb_dir[0] != '\0') { - snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); - system(cmd); - s->smb_dir[0] = '\0'; - } -} - -static int slirp_smb(SlirpState* s, const char *exported_dir, - struct in_addr vserver_addr) -{ - static int instance; - char smb_conf[128]; - char smb_cmdline[128]; - FILE *f; - - snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", - (long)getpid(), instance++); - if (mkdir(s->smb_dir, 0700) < 0) { - qemu_error("could not create samba server dir '%s'\n", s->smb_dir); - return -1; - } - snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); - - f = fopen(smb_conf, "w"); - if (!f) { - slirp_smb_cleanup(s); - qemu_error("could not create samba server configuration file '%s'\n", - smb_conf); - return -1; - } - fprintf(f, - "[global]\n" - "private dir=%s\n" - "smb ports=0\n" - "socket address=127.0.0.1\n" - "pid directory=%s\n" - "lock directory=%s\n" - "log file=%s/log.smbd\n" - "smb passwd file=%s/smbpasswd\n" - "security = share\n" - "[qemu]\n" - "path=%s\n" - "read only=no\n" - "guest ok=yes\n", - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - s->smb_dir, - exported_dir - ); - fclose(f); - - snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", - SMBD_COMMAND, smb_conf); - - if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { - slirp_smb_cleanup(s); - qemu_error("conflicting/invalid smbserver address\n"); - return -1; - } - return 0; -} - -/* automatic user mode samba server configuration (legacy interface) */ -int 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"); - return -1; - } - legacy_smb_export = exported_dir; - if (!QTAILQ_EMPTY(&slirp_stacks)) { - return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, - vserver_addr); - } - return 0; -} - -#endif /* !defined(_WIN32) */ - -struct GuestFwd { - CharDriverState *hd; - struct in_addr server; - int port; - Slirp *slirp; -}; - -static int guestfwd_can_read(void *opaque) -{ - struct GuestFwd *fwd = opaque; - return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); -} - -static void guestfwd_read(void *opaque, const uint8_t *buf, int size) -{ - struct GuestFwd *fwd = opaque; - slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); -} - -static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format) -{ - struct in_addr server = { .s_addr = 0 }; - struct GuestFwd *fwd; - const char *p; - char buf[128]; - char *end; - int port; - - 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; - } - - 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) { - qemu_error("could not open guest forwarding device '%s'\n", buf); - qemu_free(fwd); - return -1; - } - - if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { - qemu_error("conflicting/invalid host:port in guest forwarding " - "rule '%s'\n", config_str); - qemu_free(fwd); - return -1; - } - fwd->server = server; - fwd->port = port; - fwd->slirp = s->slirp; - - qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, - NULL, fwd); - return 0; - - fail_syntax: - qemu_error("invalid guest forwarding rule '%s'\n", config_str); - return -1; -} - -void do_info_usernet(Monitor *mon) -{ - SlirpState *s; - - QTAILQ_FOREACH(s, &slirp_stacks, entry) { - monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name); - slirp_connection_info(s->slirp, mon); - } -} - -#endif /* CONFIG_SLIRP */ - #if defined(CONFIG_VDE) typedef struct VDEState { VLANClientState *vc; @@ -2116,101 +1522,6 @@ static int net_init_nic(QemuOpts *opts, return idx; } -#if defined(CONFIG_SLIRP) -static int net_init_slirp_configs(const char *name, const char *value, void *opaque) -{ - struct slirp_config_str *config; - - if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { - return 0; - } - - config = qemu_mallocz(sizeof(*config)); - - pstrcpy(config->str, sizeof(config->str), value); - - if (!strcmp(name, "hostfwd")) { - config->flags = SLIRP_CFG_HOSTFWD; - } - - config->next = slirp_configs; - slirp_configs = config; - - return 0; -} - -static int net_init_slirp(QemuOpts *opts, - Monitor *mon, - const char *name, - VLANState *vlan) -{ - struct slirp_config_str *config; - const char *vhost; - const char *vhostname; - const char *vdhcp_start; - const char *vnamesrv; - const char *tftp_export; - const char *bootfile; - const char *smb_export; - const char *vsmbsrv; - char *vnet = NULL; - int restricted = 0; - int ret; - - vhost = qemu_opt_get(opts, "host"); - vhostname = qemu_opt_get(opts, "hostname"); - vdhcp_start = qemu_opt_get(opts, "dhcpstart"); - vnamesrv = qemu_opt_get(opts, "dns"); - tftp_export = qemu_opt_get(opts, "tftp"); - bootfile = qemu_opt_get(opts, "bootfile"); - smb_export = qemu_opt_get(opts, "smb"); - vsmbsrv = qemu_opt_get(opts, "smbserver"); - - if (qemu_opt_get(opts, "ip")) { - const char *ip = qemu_opt_get(opts, "ip"); - int l = strlen(ip) + strlen("/24") + 1; - - vnet = qemu_malloc(l); - - /* emulate legacy ip= parameter */ - pstrcpy(vnet, l, ip); - pstrcat(vnet, l, "/24"); - } - - if (qemu_opt_get(opts, "net")) { - if (vnet) { - qemu_free(vnet); - } - vnet = qemu_strdup(qemu_opt_get(opts, "net")); - } - - if (qemu_opt_get(opts, "restrict") && - qemu_opt_get(opts, "restrict")[0] == 'y') { - restricted = 1; - } - - qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); - - ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, - vhostname, tftp_export, bootfile, vdhcp_start, - vnamesrv, smb_export, vsmbsrv); - - while (slirp_configs) { - config = slirp_configs; - slirp_configs = config->next; - qemu_free(config); - } - - if (ret != -1 && vlan) { - vlan->nb_host_devs++; - } - - qemu_free(vnet); - - return ret; -} -#endif /* CONFIG_SLIRP */ - static int net_init_socket(QemuOpts *opts, Monitor *mon, const char *name, @@ -2860,29 +2171,12 @@ int net_init_clients(void) int net_client_parse(QemuOptsList *opts_list, const char *optarg) { #if defined(CONFIG_SLIRP) - /* handle legacy -net channel,port:chr */ - if (!strcmp(opts_list->name, "net") && - !strncmp(optarg, "channel,", strlen("channel,"))) { - int ret; - - optarg += strlen("channel,"); - - if (QTAILQ_EMPTY(&slirp_stacks)) { - struct slirp_config_str *config; - - config = qemu_malloc(sizeof(*config)); - pstrcpy(config->str, sizeof(config->str), optarg); - config->flags = SLIRP_CFG_LEGACY; - config->next = slirp_configs; - slirp_configs = config; - ret = 0; - } else { - ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); - } - + int ret; + if (net_slirp_parse_legacy(opts_list, optarg, &ret)) { return ret; } #endif + if (!qemu_opts_parse(opts_list, optarg, "type")) { return -1; } diff --git a/net.h b/net.h index 4ffce91..42ac42d 100644 --- a/net.h +++ b/net.h @@ -87,6 +87,8 @@ VLANClientState *qemu_new_vlan_client(net_client_type type, void *opaque); void qemu_del_vlan_client(VLANClientState *vc); VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); +VLANClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id, + const char *client_str); int qemu_can_send_packet(VLANClientState *vc); ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt); @@ -108,8 +110,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models, void do_info_network(Monitor *mon); void do_set_link(Monitor *mon, const QDict *qdict); -void do_info_usernet(Monitor *mon); - /* NIC info */ #define MAX_NICS 8 @@ -156,10 +156,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev); void net_client_uninit(NICInfo *nd); int net_client_parse(QemuOptsList *opts_list, const char *str); int net_init_clients(void); -int net_slirp_smb(const char *exported_dir); -void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); -void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); -int net_slirp_redir(const char *redir_str); void net_cleanup(void); void net_set_boot_mask(int boot_mask); void net_host_device_add(Monitor *mon, const QDict *qdict); diff --git a/net/slirp.c b/net/slirp.c new file mode 100644 index 0000000..d6d5772 --- /dev/null +++ b/net/slirp.c @@ -0,0 +1,752 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "net/slirp.h" + +#include "config-host.h" + +#include "net.h" +#include "monitor.h" +#include "sysemu.h" +#include "qemu_socket.h" +#include "slirp/libslirp.h" + +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; +} + +/* slirp network adapter */ + +#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; +}; + +typedef struct SlirpState { + QTAILQ_ENTRY(SlirpState) entry; + VLANClientState *vc; + Slirp *slirp; +#ifndef _WIN32 + char smb_dir[128]; +#endif +} SlirpState; + +static struct slirp_config_str *slirp_configs; +const char *legacy_tftp_prefix; +const char *legacy_bootp_filename; +static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = + QTAILQ_HEAD_INITIALIZER(slirp_stacks); + +static int slirp_hostfwd(SlirpState *s, const char *redir_str, + int legacy_format); +static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format); + +#ifndef _WIN32 +static const char *legacy_smb_export; + +static int slirp_smb(SlirpState *s, const char *exported_dir, + struct in_addr vserver_addr); +static void slirp_smb_cleanup(SlirpState *s); +#else +static inline void slirp_smb_cleanup(SlirpState *s) { } +#endif + +int slirp_can_output(void *opaque) +{ + SlirpState *s = opaque; + + return qemu_can_send_packet(s->vc); +} + +void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) +{ + SlirpState *s = opaque; + + qemu_send_packet(s->vc, pkt, pkt_len); +} + +static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +{ + SlirpState *s = vc->opaque; + + slirp_input(s->slirp, buf, size); + + return size; +} + +static void net_slirp_cleanup(VLANClientState *vc) +{ + SlirpState *s = vc->opaque; + + slirp_cleanup(s->slirp); + slirp_smb_cleanup(s); + QTAILQ_REMOVE(&slirp_stacks, s, entry); + qemu_free(s); +} + +static int net_slirp_init(VLANState *vlan, const char *model, + 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) +{ + /* default settings according to historic slirp */ + struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ + struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.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 + SlirpState *s; + char buf[20]; + uint32_t addr; + int shift; + char *end; + struct slirp_config_str *config; + + 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 + + s = qemu_mallocz(sizeof(SlirpState)); + s->slirp = slirp_init(restricted, net, mask, host, vhostname, + tftp_export, bootfile, dhcp, dns, s); + QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); + + for (config = slirp_configs; config; config = config->next) { + if (config->flags & SLIRP_CFG_HOSTFWD) { + if (slirp_hostfwd(s, config->str, + config->flags & SLIRP_CFG_LEGACY) < 0) + return -1; + } else { + if (slirp_guestfwd(s, config->str, + config->flags & SLIRP_CFG_LEGACY) < 0) + return -1; + } + } +#ifndef _WIN32 + if (!smb_export) { + smb_export = legacy_smb_export; + } + if (smb_export) { + if (slirp_smb(s, smb_export, smbsrv) < 0) + return -1; + } +#endif + + s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP, + vlan, NULL, model, name, NULL, + slirp_receive, NULL, NULL, + net_slirp_cleanup, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), + "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); + return 0; +} + +static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, + const char *stack) +{ + VLANClientState *vc; + + if (vlan) { + vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); + if (!vc) { + return NULL; + } + if (strcmp(vc->model, "user")) { + monitor_printf(mon, "invalid device specified\n"); + return NULL; + } + return vc->opaque; + } else { + if (QTAILQ_EMPTY(&slirp_stacks)) { + monitor_printf(mon, "user mode network stack not in use\n"); + return NULL; + } + return QTAILQ_FIRST(&slirp_stacks); + } +} + +void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) +{ + struct in_addr host_addr = { .s_addr = INADDR_ANY }; + int host_port; + char buf[256] = ""; + const char *src_str, *p; + SlirpState *s; + int is_udp = 0; + int err; + const char *arg1 = qdict_get_str(qdict, "arg1"); + const char *arg2 = qdict_get_try_str(qdict, "arg2"); + const char *arg3 = qdict_get_try_str(qdict, "arg3"); + + if (arg2) { + s = slirp_lookup(mon, arg1, arg2); + src_str = arg3; + } else { + s = slirp_lookup(mon, NULL, NULL); + src_str = arg1; + } + if (!s) { + return; + } + + if (!src_str || !src_str[0]) + goto fail_syntax; + + p = src_str; + get_str_sep(buf, sizeof(buf), &p, ':'); + + 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; + } + if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { + goto fail_syntax; + } + + host_port = atoi(p); + + err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp, + host_addr, host_port); + + monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, + err ? "removed" : "not found"); + return; + + fail_syntax: + monitor_printf(mon, "invalid format\n"); +} + +static int slirp_hostfwd(SlirpState *s, 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; + char buf[256]; + int is_udp; + char *end; + + 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 (!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); + 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' && !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_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, + guest_port) < 0) { + qemu_error("could not set up host forwarding rule '%s'\n", + redir_str); + return -1; + } + return 0; + + fail_syntax: + qemu_error("invalid host forwarding rule '%s'\n", redir_str); + return -1; +} + +void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) +{ + const char *redir_str; + SlirpState *s; + const char *arg1 = qdict_get_str(qdict, "arg1"); + const char *arg2 = qdict_get_try_str(qdict, "arg2"); + const char *arg3 = qdict_get_try_str(qdict, "arg3"); + + if (arg2) { + s = slirp_lookup(mon, arg1, arg2); + redir_str = arg3; + } else { + s = slirp_lookup(mon, NULL, NULL); + redir_str = arg1; + } + if (s) { + slirp_hostfwd(s, redir_str, 0); + } + +} + +int net_slirp_redir(const char *redir_str) +{ + struct slirp_config_str *config; + + if (QTAILQ_EMPTY(&slirp_stacks)) { + config = qemu_malloc(sizeof(*config)); + pstrcpy(config->str, sizeof(config->str), redir_str); + config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; + config->next = slirp_configs; + slirp_configs = config; + return 0; + } + + return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); +} + +#ifndef _WIN32 + +/* automatic user mode samba server configuration */ +static void slirp_smb_cleanup(SlirpState *s) +{ + char cmd[128]; + + if (s->smb_dir[0] != '\0') { + snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); + system(cmd); + s->smb_dir[0] = '\0'; + } +} + +static int slirp_smb(SlirpState* s, const char *exported_dir, + struct in_addr vserver_addr) +{ + static int instance; + char smb_conf[128]; + char smb_cmdline[128]; + FILE *f; + + snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", + (long)getpid(), instance++); + if (mkdir(s->smb_dir, 0700) < 0) { + qemu_error("could not create samba server dir '%s'\n", s->smb_dir); + return -1; + } + snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); + + f = fopen(smb_conf, "w"); + if (!f) { + slirp_smb_cleanup(s); + qemu_error("could not create samba server configuration file '%s'\n", + smb_conf); + return -1; + } + fprintf(f, + "[global]\n" + "private dir=%s\n" + "smb ports=0\n" + "socket address=127.0.0.1\n" + "pid directory=%s\n" + "lock directory=%s\n" + "log file=%s/log.smbd\n" + "smb passwd file=%s/smbpasswd\n" + "security = share\n" + "[qemu]\n" + "path=%s\n" + "read only=no\n" + "guest ok=yes\n", + s->smb_dir, + s->smb_dir, + s->smb_dir, + s->smb_dir, + s->smb_dir, + exported_dir + ); + fclose(f); + + snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", + SMBD_COMMAND, smb_conf); + + if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { + slirp_smb_cleanup(s); + qemu_error("conflicting/invalid smbserver address\n"); + return -1; + } + return 0; +} + +/* automatic user mode samba server configuration (legacy interface) */ +int 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"); + return -1; + } + legacy_smb_export = exported_dir; + if (!QTAILQ_EMPTY(&slirp_stacks)) { + return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, + vserver_addr); + } + return 0; +} + +#endif /* !defined(_WIN32) */ + +struct GuestFwd { + CharDriverState *hd; + struct in_addr server; + int port; + Slirp *slirp; +}; + +static int guestfwd_can_read(void *opaque) +{ + struct GuestFwd *fwd = opaque; + return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); +} + +static void guestfwd_read(void *opaque, const uint8_t *buf, int size) +{ + struct GuestFwd *fwd = opaque; + slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); +} + +static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format) +{ + struct in_addr server = { .s_addr = 0 }; + struct GuestFwd *fwd; + const char *p; + char buf[128]; + char *end; + int port; + + 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; + } + + 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) { + qemu_error("could not open guest forwarding device '%s'\n", buf); + qemu_free(fwd); + return -1; + } + + if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { + qemu_error("conflicting/invalid host:port in guest forwarding " + "rule '%s'\n", config_str); + qemu_free(fwd); + return -1; + } + fwd->server = server; + fwd->port = port; + fwd->slirp = s->slirp; + + qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, + NULL, fwd); + return 0; + + fail_syntax: + qemu_error("invalid guest forwarding rule '%s'\n", config_str); + return -1; +} + +void do_info_usernet(Monitor *mon) +{ + SlirpState *s; + + QTAILQ_FOREACH(s, &slirp_stacks, entry) { + monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name); + slirp_connection_info(s->slirp, mon); + } +} + +static int net_init_slirp_configs(const char *name, const char *value, void *opaque) +{ + struct slirp_config_str *config; + + if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { + return 0; + } + + config = qemu_mallocz(sizeof(*config)); + + pstrcpy(config->str, sizeof(config->str), value); + + if (!strcmp(name, "hostfwd")) { + config->flags = SLIRP_CFG_HOSTFWD; + } + + config->next = slirp_configs; + slirp_configs = config; + + return 0; +} + +int net_init_slirp(QemuOpts *opts, + Monitor *mon, + const char *name, + VLANState *vlan) +{ + struct slirp_config_str *config; + const char *vhost; + const char *vhostname; + const char *vdhcp_start; + const char *vnamesrv; + const char *tftp_export; + const char *bootfile; + const char *smb_export; + const char *vsmbsrv; + char *vnet = NULL; + int restricted = 0; + int ret; + + vhost = qemu_opt_get(opts, "host"); + vhostname = qemu_opt_get(opts, "hostname"); + vdhcp_start = qemu_opt_get(opts, "dhcpstart"); + vnamesrv = qemu_opt_get(opts, "dns"); + tftp_export = qemu_opt_get(opts, "tftp"); + bootfile = qemu_opt_get(opts, "bootfile"); + smb_export = qemu_opt_get(opts, "smb"); + vsmbsrv = qemu_opt_get(opts, "smbserver"); + + if (qemu_opt_get(opts, "ip")) { + const char *ip = qemu_opt_get(opts, "ip"); + int l = strlen(ip) + strlen("/24") + 1; + + vnet = qemu_malloc(l); + + /* emulate legacy ip= parameter */ + pstrcpy(vnet, l, ip); + pstrcat(vnet, l, "/24"); + } + + if (qemu_opt_get(opts, "net")) { + if (vnet) { + qemu_free(vnet); + } + vnet = qemu_strdup(qemu_opt_get(opts, "net")); + } + + if (qemu_opt_get(opts, "restrict") && + qemu_opt_get(opts, "restrict")[0] == 'y') { + restricted = 1; + } + + qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); + + ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, + vhostname, tftp_export, bootfile, vdhcp_start, + vnamesrv, smb_export, vsmbsrv); + + while (slirp_configs) { + config = slirp_configs; + slirp_configs = config->next; + qemu_free(config); + } + + if (ret != -1 && vlan) { + vlan->nb_host_devs++; + } + + qemu_free(vnet); + + return ret; +} + +int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret) +{ + if (strcmp(opts_list->name, "net") != 0 || + strncmp(optarg, "channel,", strlen("channel,")) != 0) { + return 0; + } + + /* handle legacy -net channel,port:chr */ + optarg += strlen("channel,"); + + if (QTAILQ_EMPTY(&slirp_stacks)) { + struct slirp_config_str *config; + + config = qemu_malloc(sizeof(*config)); + pstrcpy(config->str, sizeof(config->str), optarg); + config->flags = SLIRP_CFG_LEGACY; + config->next = slirp_configs; + slirp_configs = config; + *ret = 0; + } else { + *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); + } + + return 1; +} + diff --git a/net/slirp.h b/net/slirp.h new file mode 100644 index 0000000..c17de8e --- /dev/null +++ b/net/slirp.h @@ -0,0 +1,51 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_NET_SLIRP_H +#define QEMU_NET_SLIRP_H + +#include "qemu-common.h" +#include "qdict.h" +#include "qemu-option.h" + +#ifdef CONFIG_SLIRP + +int net_init_slirp(QemuOpts *opts, + Monitor *mon, + const char *name, + VLANState *vlan); + +void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict); +void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict); + +int net_slirp_redir(const char *redir_str); + +int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret); + +int net_slirp_smb(const char *exported_dir); + +void do_info_usernet(Monitor *mon); + +#endif + +#endif /* QEMU_NET_SLIRP_H */ diff --git a/vl.c b/vl.c index ee43808..6038e2d 100644 --- a/vl.c +++ b/vl.c @@ -140,6 +140,7 @@ int main(int argc, char **argv) #include "hw/loader.h" #include "bt-host.h" #include "net.h" +#include "net/slirp.h" #include "monitor.h" #include "console.h" #include "sysemu.h"