qemu/net/slirp.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "qemu/osdep.h"
  26#include "net/slirp.h"
  27
  28
  29#ifndef _WIN32
  30#include <pwd.h>
  31#include <sys/wait.h>
  32#endif
  33#include "net/net.h"
  34#include "clients.h"
  35#include "hub.h"
  36#include "monitor/monitor.h"
  37#include "qemu/error-report.h"
  38#include "qemu/sockets.h"
  39#include "slirp/libslirp.h"
  40#include "slirp/ip6.h"
  41#include "chardev/char-fe.h"
  42#include "sysemu/sysemu.h"
  43#include "qemu/cutils.h"
  44#include "qapi/error.h"
  45#include "qapi/qmp/qdict.h"
  46
  47static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
  48{
  49    const char *p, *p1;
  50    int len;
  51    p = *pp;
  52    p1 = strchr(p, sep);
  53    if (!p1)
  54        return -1;
  55    len = p1 - p;
  56    p1++;
  57    if (buf_size > 0) {
  58        if (len > buf_size - 1)
  59            len = buf_size - 1;
  60        memcpy(buf, p, len);
  61        buf[len] = '\0';
  62    }
  63    *pp = p1;
  64    return 0;
  65}
  66
  67/* slirp network adapter */
  68
  69#define SLIRP_CFG_HOSTFWD 1
  70
  71struct slirp_config_str {
  72    struct slirp_config_str *next;
  73    int flags;
  74    char str[1024];
  75};
  76
  77typedef struct SlirpState {
  78    NetClientState nc;
  79    QTAILQ_ENTRY(SlirpState) entry;
  80    Slirp *slirp;
  81    Notifier exit_notifier;
  82#ifndef _WIN32
  83    gchar *smb_dir;
  84#endif
  85} SlirpState;
  86
  87static struct slirp_config_str *slirp_configs;
  88static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
  89    QTAILQ_HEAD_INITIALIZER(slirp_stacks);
  90
  91static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
  92static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp);
  93
  94#ifndef _WIN32
  95static int slirp_smb(SlirpState *s, const char *exported_dir,
  96                     struct in_addr vserver_addr, Error **errp);
  97static void slirp_smb_cleanup(SlirpState *s);
  98#else
  99static inline void slirp_smb_cleanup(SlirpState *s) { }
 100#endif
 101
 102void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
 103{
 104    SlirpState *s = opaque;
 105
 106    qemu_send_packet(&s->nc, pkt, pkt_len);
 107}
 108
 109static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, size_t size)
 110{
 111    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
 112
 113    slirp_input(s->slirp, buf, size);
 114
 115    return size;
 116}
 117
 118static void slirp_smb_exit(Notifier *n, void *data)
 119{
 120    SlirpState *s = container_of(n, SlirpState, exit_notifier);
 121    slirp_smb_cleanup(s);
 122}
 123
 124static void net_slirp_cleanup(NetClientState *nc)
 125{
 126    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
 127
 128    slirp_cleanup(s->slirp);
 129    if (s->exit_notifier.notify) {
 130        qemu_remove_exit_notifier(&s->exit_notifier);
 131    }
 132    slirp_smb_cleanup(s);
 133    QTAILQ_REMOVE(&slirp_stacks, s, entry);
 134}
 135
 136static NetClientInfo net_slirp_info = {
 137    .type = NET_CLIENT_DRIVER_USER,
 138    .size = sizeof(SlirpState),
 139    .receive = net_slirp_receive,
 140    .cleanup = net_slirp_cleanup,
 141};
 142
 143static int net_slirp_init(NetClientState *peer, const char *model,
 144                          const char *name, int restricted,
 145                          bool ipv4, const char *vnetwork, const char *vhost,
 146                          bool ipv6, const char *vprefix6, int vprefix6_len,
 147                          const char *vhost6,
 148                          const char *vhostname, const char *tftp_export,
 149                          const char *bootfile, const char *vdhcp_start,
 150                          const char *vnameserver, const char *vnameserver6,
 151                          const char *smb_export, const char *vsmbserver,
 152                          const char **dnssearch, const char *vdomainname,
 153                          const char *tftp_server_name,
 154                          Error **errp)
 155{
 156    /* default settings according to historic slirp */
 157    struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
 158    struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
 159    struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
 160    struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
 161    struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
 162    struct in6_addr ip6_prefix;
 163    struct in6_addr ip6_host;
 164    struct in6_addr ip6_dns;
 165#ifndef _WIN32
 166    struct in_addr smbsrv = { .s_addr = 0 };
 167#endif
 168    NetClientState *nc;
 169    SlirpState *s;
 170    char buf[20];
 171    uint32_t addr;
 172    int shift;
 173    char *end;
 174    struct slirp_config_str *config;
 175
 176    if (!ipv4 && (vnetwork || vhost || vnameserver)) {
 177        error_setg(errp, "IPv4 disabled but netmask/host/dns provided");
 178        return -1;
 179    }
 180
 181    if (!ipv6 && (vprefix6 || vhost6 || vnameserver6)) {
 182        error_setg(errp, "IPv6 disabled but prefix/host6/dns6 provided");
 183        return -1;
 184    }
 185
 186    if (!ipv4 && !ipv6) {
 187        /* It doesn't make sense to disable both */
 188        error_setg(errp, "IPv4 and IPv6 disabled");
 189        return -1;
 190    }
 191
 192    if (vnetwork) {
 193        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
 194            if (!inet_aton(vnetwork, &net)) {
 195                error_setg(errp, "Failed to parse netmask");
 196                return -1;
 197            }
 198            addr = ntohl(net.s_addr);
 199            if (!(addr & 0x80000000)) {
 200                mask.s_addr = htonl(0xff000000); /* class A */
 201            } else if ((addr & 0xfff00000) == 0xac100000) {
 202                mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
 203            } else if ((addr & 0xc0000000) == 0x80000000) {
 204                mask.s_addr = htonl(0xffff0000); /* class B */
 205            } else if ((addr & 0xffff0000) == 0xc0a80000) {
 206                mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
 207            } else if ((addr & 0xffff0000) == 0xc6120000) {
 208                mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
 209            } else if ((addr & 0xe0000000) == 0xe0000000) {
 210                mask.s_addr = htonl(0xffffff00); /* class C */
 211            } else {
 212                mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
 213            }
 214        } else {
 215            if (!inet_aton(buf, &net)) {
 216                error_setg(errp, "Failed to parse netmask");
 217                return -1;
 218            }
 219            shift = strtol(vnetwork, &end, 10);
 220            if (*end != '\0') {
 221                if (!inet_aton(vnetwork, &mask)) {
 222                    error_setg(errp,
 223                               "Failed to parse netmask (trailing chars)");
 224                    return -1;
 225                }
 226            } else if (shift < 4 || shift > 32) {
 227                error_setg(errp,
 228                           "Invalid netmask provided (must be in range 4-32)");
 229                return -1;
 230            } else {
 231                mask.s_addr = htonl(0xffffffff << (32 - shift));
 232            }
 233        }
 234        net.s_addr &= mask.s_addr;
 235        host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
 236        dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
 237        dns.s_addr  = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
 238    }
 239
 240    if (vhost && !inet_aton(vhost, &host)) {
 241        error_setg(errp, "Failed to parse host");
 242        return -1;
 243    }
 244    if ((host.s_addr & mask.s_addr) != net.s_addr) {
 245        error_setg(errp, "Host doesn't belong to network");
 246        return -1;
 247    }
 248
 249    if (vnameserver && !inet_aton(vnameserver, &dns)) {
 250        error_setg(errp, "Failed to parse DNS");
 251        return -1;
 252    }
 253    if ((dns.s_addr & mask.s_addr) != net.s_addr) {
 254        error_setg(errp, "DNS doesn't belong to network");
 255        return -1;
 256    }
 257    if (dns.s_addr == host.s_addr) {
 258        error_setg(errp, "DNS must be different from host");
 259        return -1;
 260    }
 261
 262    if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
 263        error_setg(errp, "Failed to parse DHCP start address");
 264        return -1;
 265    }
 266    if ((dhcp.s_addr & mask.s_addr) != net.s_addr) {
 267        error_setg(errp, "DHCP doesn't belong to network");
 268        return -1;
 269    }
 270    if (dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
 271        error_setg(errp, "DNS must be different from host and DNS");
 272        return -1;
 273    }
 274
 275#ifndef _WIN32
 276    if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
 277        error_setg(errp, "Failed to parse SMB address");
 278        return -1;
 279    }
 280#endif
 281
 282#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
 283    /* No inet_pton helper before Vista... */
 284    if (vprefix6) {
 285        /* Unsupported */
 286        error_setg(errp, "IPv6 prefix not supported");
 287        return -1;
 288    }
 289    memset(&ip6_prefix, 0, sizeof(ip6_prefix));
 290    ip6_prefix.s6_addr[0] = 0xfe;
 291    ip6_prefix.s6_addr[1] = 0xc0;
 292#else
 293    if (!vprefix6) {
 294        vprefix6 = "fec0::";
 295    }
 296    if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
 297        error_setg(errp, "Failed to parse IPv6 prefix");
 298        return -1;
 299    }
 300#endif
 301
 302    if (!vprefix6_len) {
 303        vprefix6_len = 64;
 304    }
 305    if (vprefix6_len < 0 || vprefix6_len > 126) {
 306        error_setg(errp,
 307                   "Invalid prefix provided (prefix len must be in range 0-126");
 308        return -1;
 309    }
 310
 311    if (vhost6) {
 312#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
 313        error_setg(errp, "IPv6 host not supported");
 314        return -1;
 315#else
 316        if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
 317            error_setg(errp, "Failed to parse IPv6 host");
 318            return -1;
 319        }
 320        if (!in6_equal_net(&ip6_prefix, &ip6_host, vprefix6_len)) {
 321            error_setg(errp, "IPv6 Host doesn't belong to network");
 322            return -1;
 323        }
 324#endif
 325    } else {
 326        ip6_host = ip6_prefix;
 327        ip6_host.s6_addr[15] |= 2;
 328    }
 329
 330    if (vnameserver6) {
 331#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
 332        error_setg(errp, "IPv6 DNS not supported");
 333        return -1;
 334#else
 335        if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
 336            error_setg(errp, "Failed to parse IPv6 DNS");
 337            return -1;
 338        }
 339        if (!in6_equal_net(&ip6_prefix, &ip6_dns, vprefix6_len)) {
 340            error_setg(errp, "IPv6 DNS doesn't belong to network");
 341            return -1;
 342        }
 343#endif
 344    } else {
 345        ip6_dns = ip6_prefix;
 346        ip6_dns.s6_addr[15] |= 3;
 347    }
 348
 349    if (vdomainname && !*vdomainname) {
 350        error_setg(errp, "'domainname' parameter cannot be empty");
 351        return -1;
 352    }
 353
 354    if (vdomainname && strlen(vdomainname) > 255) {
 355        error_setg(errp, "'domainname' parameter cannot exceed 255 bytes");
 356        return -1;
 357    }
 358
 359    if (vhostname && strlen(vhostname) > 255) {
 360        error_setg(errp, "'vhostname' parameter cannot exceed 255 bytes");
 361        return -1;
 362    }
 363
 364    if (tftp_server_name && strlen(tftp_server_name) > 255) {
 365        error_setg(errp, "'tftp-server-name' parameter cannot exceed 255 bytes");
 366        return -1;
 367    }
 368
 369    nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
 370
 371    snprintf(nc->info_str, sizeof(nc->info_str),
 372             "net=%s,restrict=%s", inet_ntoa(net),
 373             restricted ? "on" : "off");
 374
 375    s = DO_UPCAST(SlirpState, nc, nc);
 376
 377    s->slirp = slirp_init(restricted, ipv4, net, mask, host,
 378                          ipv6, ip6_prefix, vprefix6_len, ip6_host,
 379                          vhostname, tftp_server_name,
 380                          tftp_export, bootfile, dhcp,
 381                          dns, ip6_dns, dnssearch, vdomainname, s);
 382    QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
 383
 384    for (config = slirp_configs; config; config = config->next) {
 385        if (config->flags & SLIRP_CFG_HOSTFWD) {
 386            if (slirp_hostfwd(s, config->str, errp) < 0) {
 387                goto error;
 388            }
 389        } else {
 390            if (slirp_guestfwd(s, config->str, errp) < 0) {
 391                goto error;
 392            }
 393        }
 394    }
 395#ifndef _WIN32
 396    if (smb_export) {
 397        if (slirp_smb(s, smb_export, smbsrv, errp) < 0) {
 398            goto error;
 399        }
 400    }
 401#endif
 402
 403    s->exit_notifier.notify = slirp_smb_exit;
 404    qemu_add_exit_notifier(&s->exit_notifier);
 405    return 0;
 406
 407error:
 408    qemu_del_net_client(nc);
 409    return -1;
 410}
 411
 412static SlirpState *slirp_lookup(Monitor *mon, const char *hub_id,
 413                                const char *name)
 414{
 415    if (name) {
 416        NetClientState *nc;
 417        if (hub_id) {
 418            nc = net_hub_find_client_by_name(strtol(hub_id, NULL, 0), name);
 419            if (!nc) {
 420                monitor_printf(mon, "unrecognized (hub-id, stackname) pair\n");
 421                return NULL;
 422            }
 423            warn_report("Using 'hub-id' is deprecated, specify the netdev id "
 424                        "directly instead");
 425        } else {
 426            nc = qemu_find_netdev(name);
 427            if (!nc) {
 428                monitor_printf(mon, "unrecognized netdev id '%s'\n", name);
 429                return NULL;
 430            }
 431        }
 432        if (strcmp(nc->model, "user")) {
 433            monitor_printf(mon, "invalid device specified\n");
 434            return NULL;
 435        }
 436        return DO_UPCAST(SlirpState, nc, nc);
 437    } else {
 438        if (QTAILQ_EMPTY(&slirp_stacks)) {
 439            monitor_printf(mon, "user mode network stack not in use\n");
 440            return NULL;
 441        }
 442        return QTAILQ_FIRST(&slirp_stacks);
 443    }
 444}
 445
 446void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
 447{
 448    struct in_addr host_addr = { .s_addr = INADDR_ANY };
 449    int host_port;
 450    char buf[256];
 451    const char *src_str, *p;
 452    SlirpState *s;
 453    int is_udp = 0;
 454    int err;
 455    const char *arg1 = qdict_get_str(qdict, "arg1");
 456    const char *arg2 = qdict_get_try_str(qdict, "arg2");
 457    const char *arg3 = qdict_get_try_str(qdict, "arg3");
 458
 459    if (arg3) {
 460        s = slirp_lookup(mon, arg1, arg2);
 461        src_str = arg3;
 462    } else if (arg2) {
 463        s = slirp_lookup(mon, NULL, arg1);
 464        src_str = arg2;
 465    } else {
 466        s = slirp_lookup(mon, NULL, NULL);
 467        src_str = arg1;
 468    }
 469    if (!s) {
 470        return;
 471    }
 472
 473    p = src_str;
 474    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 475        goto fail_syntax;
 476    }
 477
 478    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
 479        is_udp = 0;
 480    } else if (!strcmp(buf, "udp")) {
 481        is_udp = 1;
 482    } else {
 483        goto fail_syntax;
 484    }
 485
 486    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 487        goto fail_syntax;
 488    }
 489    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
 490        goto fail_syntax;
 491    }
 492
 493    if (qemu_strtoi(p, NULL, 10, &host_port)) {
 494        goto fail_syntax;
 495    }
 496
 497    err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
 498
 499    monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
 500                   err ? "not found" : "removed");
 501    return;
 502
 503 fail_syntax:
 504    monitor_printf(mon, "invalid format\n");
 505}
 506
 507static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
 508{
 509    struct in_addr host_addr = { .s_addr = INADDR_ANY };
 510    struct in_addr guest_addr = { .s_addr = 0 };
 511    int host_port, guest_port;
 512    const char *p;
 513    char buf[256];
 514    int is_udp;
 515    char *end;
 516    const char *fail_reason = "Unknown reason";
 517
 518    p = redir_str;
 519    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 520        fail_reason = "No : separators";
 521        goto fail_syntax;
 522    }
 523    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
 524        is_udp = 0;
 525    } else if (!strcmp(buf, "udp")) {
 526        is_udp = 1;
 527    } else {
 528        fail_reason = "Bad protocol name";
 529        goto fail_syntax;
 530    }
 531
 532    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 533        fail_reason = "Missing : separator";
 534        goto fail_syntax;
 535    }
 536    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
 537        fail_reason = "Bad host address";
 538        goto fail_syntax;
 539    }
 540
 541    if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
 542        fail_reason = "Bad host port separator";
 543        goto fail_syntax;
 544    }
 545    host_port = strtol(buf, &end, 0);
 546    if (*end != '\0' || host_port < 0 || host_port > 65535) {
 547        fail_reason = "Bad host port";
 548        goto fail_syntax;
 549    }
 550
 551    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 552        fail_reason = "Missing guest address";
 553        goto fail_syntax;
 554    }
 555    if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
 556        fail_reason = "Bad guest address";
 557        goto fail_syntax;
 558    }
 559
 560    guest_port = strtol(p, &end, 0);
 561    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
 562        fail_reason = "Bad guest port";
 563        goto fail_syntax;
 564    }
 565
 566    if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
 567                          guest_port) < 0) {
 568        error_setg(errp, "Could not set up host forwarding rule '%s'",
 569                   redir_str);
 570        return -1;
 571    }
 572    return 0;
 573
 574 fail_syntax:
 575    error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str,
 576               fail_reason);
 577    return -1;
 578}
 579
 580void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
 581{
 582    const char *redir_str;
 583    SlirpState *s;
 584    const char *arg1 = qdict_get_str(qdict, "arg1");
 585    const char *arg2 = qdict_get_try_str(qdict, "arg2");
 586    const char *arg3 = qdict_get_try_str(qdict, "arg3");
 587
 588    if (arg3) {
 589        s = slirp_lookup(mon, arg1, arg2);
 590        redir_str = arg3;
 591    } else if (arg2) {
 592        s = slirp_lookup(mon, NULL, arg1);
 593        redir_str = arg2;
 594    } else {
 595        s = slirp_lookup(mon, NULL, NULL);
 596        redir_str = arg1;
 597    }
 598    if (s) {
 599        Error *err = NULL;
 600        if (slirp_hostfwd(s, redir_str, &err) < 0) {
 601            error_report_err(err);
 602        }
 603    }
 604
 605}
 606
 607#ifndef _WIN32
 608
 609/* automatic user mode samba server configuration */
 610static void slirp_smb_cleanup(SlirpState *s)
 611{
 612    int ret;
 613
 614    if (s->smb_dir) {
 615        gchar *cmd = g_strdup_printf("rm -rf %s", s->smb_dir);
 616        ret = system(cmd);
 617        if (ret == -1 || !WIFEXITED(ret)) {
 618            error_report("'%s' failed.", cmd);
 619        } else if (WEXITSTATUS(ret)) {
 620            error_report("'%s' failed. Error code: %d",
 621                         cmd, WEXITSTATUS(ret));
 622        }
 623        g_free(cmd);
 624        g_free(s->smb_dir);
 625        s->smb_dir = NULL;
 626    }
 627}
 628
 629static int slirp_smb(SlirpState* s, const char *exported_dir,
 630                     struct in_addr vserver_addr, Error **errp)
 631{
 632    char *smb_conf;
 633    char *smb_cmdline;
 634    struct passwd *passwd;
 635    FILE *f;
 636
 637    passwd = getpwuid(geteuid());
 638    if (!passwd) {
 639        error_setg(errp, "Failed to retrieve user name");
 640        return -1;
 641    }
 642
 643    if (access(CONFIG_SMBD_COMMAND, F_OK)) {
 644        error_setg(errp, "Could not find '%s', please install it",
 645                   CONFIG_SMBD_COMMAND);
 646        return -1;
 647    }
 648
 649    if (access(exported_dir, R_OK | X_OK)) {
 650        error_setg(errp, "Error accessing shared directory '%s': %s",
 651                   exported_dir, strerror(errno));
 652        return -1;
 653    }
 654
 655    s->smb_dir = g_dir_make_tmp("qemu-smb.XXXXXX", NULL);
 656    if (!s->smb_dir) {
 657        error_setg(errp, "Could not create samba server dir");
 658        return -1;
 659    }
 660    smb_conf = g_strdup_printf("%s/%s", s->smb_dir, "smb.conf");
 661
 662    f = fopen(smb_conf, "w");
 663    if (!f) {
 664        slirp_smb_cleanup(s);
 665        error_setg(errp,
 666                   "Could not create samba server configuration file '%s'",
 667                    smb_conf);
 668        g_free(smb_conf);
 669        return -1;
 670    }
 671    fprintf(f,
 672            "[global]\n"
 673            "private dir=%s\n"
 674            "interfaces=127.0.0.1\n"
 675            "bind interfaces only=yes\n"
 676            "pid directory=%s\n"
 677            "lock directory=%s\n"
 678            "state directory=%s\n"
 679            "cache directory=%s\n"
 680            "ncalrpc dir=%s/ncalrpc\n"
 681            "log file=%s/log.smbd\n"
 682            "smb passwd file=%s/smbpasswd\n"
 683            "security = user\n"
 684            "map to guest = Bad User\n"
 685            "load printers = no\n"
 686            "printing = bsd\n"
 687            "disable spoolss = yes\n"
 688            "usershare max shares = 0\n"
 689            "[qemu]\n"
 690            "path=%s\n"
 691            "read only=no\n"
 692            "guest ok=yes\n"
 693            "force user=%s\n",
 694            s->smb_dir,
 695            s->smb_dir,
 696            s->smb_dir,
 697            s->smb_dir,
 698            s->smb_dir,
 699            s->smb_dir,
 700            s->smb_dir,
 701            s->smb_dir,
 702            exported_dir,
 703            passwd->pw_name
 704            );
 705    fclose(f);
 706
 707    smb_cmdline = g_strdup_printf("%s -l %s -s %s",
 708             CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf);
 709    g_free(smb_conf);
 710
 711    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 ||
 712        slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) {
 713        slirp_smb_cleanup(s);
 714        g_free(smb_cmdline);
 715        error_setg(errp, "Conflicting/invalid smbserver address");
 716        return -1;
 717    }
 718    g_free(smb_cmdline);
 719    return 0;
 720}
 721
 722#endif /* !defined(_WIN32) */
 723
 724struct GuestFwd {
 725    CharBackend hd;
 726    struct in_addr server;
 727    int port;
 728    Slirp *slirp;
 729};
 730
 731static int guestfwd_can_read(void *opaque)
 732{
 733    struct GuestFwd *fwd = opaque;
 734    return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
 735}
 736
 737static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
 738{
 739    struct GuestFwd *fwd = opaque;
 740    slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
 741}
 742
 743static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
 744{
 745    struct in_addr server = { .s_addr = 0 };
 746    struct GuestFwd *fwd;
 747    const char *p;
 748    char buf[128];
 749    char *end;
 750    int port;
 751
 752    p = config_str;
 753    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 754        goto fail_syntax;
 755    }
 756    if (strcmp(buf, "tcp") && buf[0] != '\0') {
 757        goto fail_syntax;
 758    }
 759    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 760        goto fail_syntax;
 761    }
 762    if (buf[0] != '\0' && !inet_aton(buf, &server)) {
 763        goto fail_syntax;
 764    }
 765    if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
 766        goto fail_syntax;
 767    }
 768    port = strtol(buf, &end, 10);
 769    if (*end != '\0' || port < 1 || port > 65535) {
 770        goto fail_syntax;
 771    }
 772
 773    snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
 774
 775    if ((strlen(p) > 4) && !strncmp(p, "cmd:", 4)) {
 776        if (slirp_add_exec(s->slirp, 0, &p[4], &server, port) < 0) {
 777            error_setg(errp, "Conflicting/invalid host:port in guest "
 778                       "forwarding rule '%s'", config_str);
 779            return -1;
 780        }
 781    } else {
 782        Error *err = NULL;
 783        /*
 784         * FIXME: sure we want to support implicit
 785         * muxed monitors here?
 786         */
 787        Chardev *chr = qemu_chr_new_mux_mon(buf, p);
 788
 789        if (!chr) {
 790            error_setg(errp, "Could not open guest forwarding device '%s'",
 791                       buf);
 792            return -1;
 793        }
 794
 795        fwd = g_new(struct GuestFwd, 1);
 796        qemu_chr_fe_init(&fwd->hd, chr, &err);
 797        if (err) {
 798            error_propagate(errp, err);
 799            g_free(fwd);
 800            return -1;
 801        }
 802
 803        if (slirp_add_exec(s->slirp, 3, &fwd->hd, &server, port) < 0) {
 804            error_setg(errp, "Conflicting/invalid host:port in guest "
 805                       "forwarding rule '%s'", config_str);
 806            g_free(fwd);
 807            return -1;
 808        }
 809        fwd->server = server;
 810        fwd->port = port;
 811        fwd->slirp = s->slirp;
 812
 813        qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
 814                                 NULL, NULL, fwd, NULL, true);
 815    }
 816    return 0;
 817
 818 fail_syntax:
 819    error_setg(errp, "Invalid guest forwarding rule '%s'", config_str);
 820    return -1;
 821}
 822
 823void hmp_info_usernet(Monitor *mon, const QDict *qdict)
 824{
 825    SlirpState *s;
 826
 827    QTAILQ_FOREACH(s, &slirp_stacks, entry) {
 828        int id;
 829        bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0;
 830        monitor_printf(mon, "Hub %d (%s):\n",
 831                       got_hub_id ? id : -1,
 832                       s->nc.name);
 833        slirp_connection_info(s->slirp, mon);
 834    }
 835}
 836
 837static void
 838net_init_slirp_configs(const StringList *fwd, int flags)
 839{
 840    while (fwd) {
 841        struct slirp_config_str *config;
 842
 843        config = g_malloc0(sizeof(*config));
 844        pstrcpy(config->str, sizeof(config->str), fwd->value->str);
 845        config->flags = flags;
 846        config->next = slirp_configs;
 847        slirp_configs = config;
 848
 849        fwd = fwd->next;
 850    }
 851}
 852
 853static const char **slirp_dnssearch(const StringList *dnsname)
 854{
 855    const StringList *c = dnsname;
 856    size_t i = 0, num_opts = 0;
 857    const char **ret;
 858
 859    while (c) {
 860        num_opts++;
 861        c = c->next;
 862    }
 863
 864    if (num_opts == 0) {
 865        return NULL;
 866    }
 867
 868    ret = g_malloc((num_opts + 1) * sizeof(*ret));
 869    c = dnsname;
 870    while (c) {
 871        ret[i++] = c->value->str;
 872        c = c->next;
 873    }
 874    ret[i] = NULL;
 875    return ret;
 876}
 877
 878int net_init_slirp(const Netdev *netdev, const char *name,
 879                   NetClientState *peer, Error **errp)
 880{
 881    struct slirp_config_str *config;
 882    char *vnet;
 883    int ret;
 884    const NetdevUserOptions *user;
 885    const char **dnssearch;
 886    bool ipv4 = true, ipv6 = true;
 887
 888    assert(netdev->type == NET_CLIENT_DRIVER_USER);
 889    user = &netdev->u.user;
 890
 891    if ((user->has_ipv6 && user->ipv6 && !user->has_ipv4) ||
 892        (user->has_ipv4 && !user->ipv4)) {
 893        ipv4 = 0;
 894    }
 895    if ((user->has_ipv4 && user->ipv4 && !user->has_ipv6) ||
 896        (user->has_ipv6 && !user->ipv6)) {
 897        ipv6 = 0;
 898    }
 899
 900    vnet = user->has_net ? g_strdup(user->net) :
 901           user->has_ip  ? g_strdup_printf("%s/24", user->ip) :
 902           NULL;
 903
 904    dnssearch = slirp_dnssearch(user->dnssearch);
 905
 906    /* all optional fields are initialized to "all bits zero" */
 907
 908    net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
 909    net_init_slirp_configs(user->guestfwd, 0);
 910
 911    ret = net_slirp_init(peer, "user", name, user->q_restrict,
 912                         ipv4, vnet, user->host,
 913                         ipv6, user->ipv6_prefix, user->ipv6_prefixlen,
 914                         user->ipv6_host, user->hostname, user->tftp,
 915                         user->bootfile, user->dhcpstart,
 916                         user->dns, user->ipv6_dns, user->smb,
 917                         user->smbserver, dnssearch, user->domainname,
 918                         user->tftp_server_name, errp);
 919
 920    while (slirp_configs) {
 921        config = slirp_configs;
 922        slirp_configs = config->next;
 923        g_free(config);
 924    }
 925
 926    g_free(vnet);
 927    g_free(dnssearch);
 928
 929    return ret;
 930}
 931