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