|
|
1.1 ! root 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: #include "net/slirp.h" ! 25: ! 26: #include "config-host.h" ! 27: ! 28: #include "net.h" ! 29: #include "monitor.h" ! 30: #include "sysemu.h" ! 31: #include "qemu_socket.h" ! 32: #include "slirp/libslirp.h" ! 33: ! 34: static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) ! 35: { ! 36: const char *p, *p1; ! 37: int len; ! 38: p = *pp; ! 39: p1 = strchr(p, sep); ! 40: if (!p1) ! 41: return -1; ! 42: len = p1 - p; ! 43: p1++; ! 44: if (buf_size > 0) { ! 45: if (len > buf_size - 1) ! 46: len = buf_size - 1; ! 47: memcpy(buf, p, len); ! 48: buf[len] = '\0'; ! 49: } ! 50: *pp = p1; ! 51: return 0; ! 52: } ! 53: ! 54: /* slirp network adapter */ ! 55: ! 56: #define SLIRP_CFG_HOSTFWD 1 ! 57: #define SLIRP_CFG_LEGACY 2 ! 58: ! 59: struct slirp_config_str { ! 60: struct slirp_config_str *next; ! 61: int flags; ! 62: char str[1024]; ! 63: int legacy_format; ! 64: }; ! 65: ! 66: typedef struct SlirpState { ! 67: VLANClientState nc; ! 68: QTAILQ_ENTRY(SlirpState) entry; ! 69: Slirp *slirp; ! 70: #ifndef _WIN32 ! 71: char smb_dir[128]; ! 72: #endif ! 73: } SlirpState; ! 74: ! 75: static struct slirp_config_str *slirp_configs; ! 76: const char *legacy_tftp_prefix; ! 77: const char *legacy_bootp_filename; ! 78: static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = ! 79: QTAILQ_HEAD_INITIALIZER(slirp_stacks); ! 80: ! 81: static int slirp_hostfwd(SlirpState *s, const char *redir_str, ! 82: int legacy_format); ! 83: static int slirp_guestfwd(SlirpState *s, const char *config_str, ! 84: int legacy_format); ! 85: ! 86: #ifndef _WIN32 ! 87: static const char *legacy_smb_export; ! 88: ! 89: static int slirp_smb(SlirpState *s, const char *exported_dir, ! 90: struct in_addr vserver_addr); ! 91: static void slirp_smb_cleanup(SlirpState *s); ! 92: #else ! 93: static inline void slirp_smb_cleanup(SlirpState *s) { } ! 94: #endif ! 95: ! 96: int slirp_can_output(void *opaque) ! 97: { ! 98: SlirpState *s = opaque; ! 99: ! 100: return qemu_can_send_packet(&s->nc); ! 101: } ! 102: ! 103: void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) ! 104: { ! 105: SlirpState *s = opaque; ! 106: ! 107: qemu_send_packet(&s->nc, pkt, pkt_len); ! 108: } ! 109: ! 110: static ssize_t net_slirp_receive(VLANClientState *nc, const uint8_t *buf, size_t size) ! 111: { ! 112: SlirpState *s = DO_UPCAST(SlirpState, nc, nc); ! 113: ! 114: slirp_input(s->slirp, buf, size); ! 115: ! 116: return size; ! 117: } ! 118: ! 119: static void net_slirp_cleanup(VLANClientState *nc) ! 120: { ! 121: SlirpState *s = DO_UPCAST(SlirpState, nc, nc); ! 122: ! 123: slirp_cleanup(s->slirp); ! 124: slirp_smb_cleanup(s); ! 125: QTAILQ_REMOVE(&slirp_stacks, s, entry); ! 126: } ! 127: ! 128: static NetClientInfo net_slirp_info = { ! 129: .type = NET_CLIENT_TYPE_SLIRP, ! 130: .size = sizeof(SlirpState), ! 131: .receive = net_slirp_receive, ! 132: .cleanup = net_slirp_cleanup, ! 133: }; ! 134: ! 135: static int net_slirp_init(VLANState *vlan, const char *model, ! 136: const char *name, int restricted, ! 137: const char *vnetwork, const char *vhost, ! 138: const char *vhostname, const char *tftp_export, ! 139: const char *bootfile, const char *vdhcp_start, ! 140: const char *vnameserver, const char *smb_export, ! 141: const char *vsmbserver) ! 142: { ! 143: /* default settings according to historic slirp */ ! 144: struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ ! 145: struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ ! 146: struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ ! 147: struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ ! 148: struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ ! 149: #ifndef _WIN32 ! 150: struct in_addr smbsrv = { .s_addr = 0 }; ! 151: #endif ! 152: VLANClientState *nc; ! 153: SlirpState *s; ! 154: char buf[20]; ! 155: uint32_t addr; ! 156: int shift; ! 157: char *end; ! 158: struct slirp_config_str *config; ! 159: ! 160: if (!tftp_export) { ! 161: tftp_export = legacy_tftp_prefix; ! 162: } ! 163: if (!bootfile) { ! 164: bootfile = legacy_bootp_filename; ! 165: } ! 166: ! 167: if (vnetwork) { ! 168: if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { ! 169: if (!inet_aton(vnetwork, &net)) { ! 170: return -1; ! 171: } ! 172: addr = ntohl(net.s_addr); ! 173: if (!(addr & 0x80000000)) { ! 174: mask.s_addr = htonl(0xff000000); /* class A */ ! 175: } else if ((addr & 0xfff00000) == 0xac100000) { ! 176: mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ ! 177: } else if ((addr & 0xc0000000) == 0x80000000) { ! 178: mask.s_addr = htonl(0xffff0000); /* class B */ ! 179: } else if ((addr & 0xffff0000) == 0xc0a80000) { ! 180: mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ ! 181: } else if ((addr & 0xffff0000) == 0xc6120000) { ! 182: mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ ! 183: } else if ((addr & 0xe0000000) == 0xe0000000) { ! 184: mask.s_addr = htonl(0xffffff00); /* class C */ ! 185: } else { ! 186: mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ ! 187: } ! 188: } else { ! 189: if (!inet_aton(buf, &net)) { ! 190: return -1; ! 191: } ! 192: shift = strtol(vnetwork, &end, 10); ! 193: if (*end != '\0') { ! 194: if (!inet_aton(vnetwork, &mask)) { ! 195: return -1; ! 196: } ! 197: } else if (shift < 4 || shift > 32) { ! 198: return -1; ! 199: } else { ! 200: mask.s_addr = htonl(0xffffffff << (32 - shift)); ! 201: } ! 202: } ! 203: net.s_addr &= mask.s_addr; ! 204: host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); ! 205: dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); ! 206: dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); ! 207: } ! 208: ! 209: if (vhost && !inet_aton(vhost, &host)) { ! 210: return -1; ! 211: } ! 212: if ((host.s_addr & mask.s_addr) != net.s_addr) { ! 213: return -1; ! 214: } ! 215: ! 216: if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) { ! 217: return -1; ! 218: } ! 219: if ((dhcp.s_addr & mask.s_addr) != net.s_addr || ! 220: dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) { ! 221: return -1; ! 222: } ! 223: ! 224: if (vnameserver && !inet_aton(vnameserver, &dns)) { ! 225: return -1; ! 226: } ! 227: if ((dns.s_addr & mask.s_addr) != net.s_addr || ! 228: dns.s_addr == host.s_addr) { ! 229: return -1; ! 230: } ! 231: ! 232: #ifndef _WIN32 ! 233: if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { ! 234: return -1; ! 235: } ! 236: #endif ! 237: ! 238: nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name); ! 239: ! 240: snprintf(nc->info_str, sizeof(nc->info_str), ! 241: "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); ! 242: ! 243: s = DO_UPCAST(SlirpState, nc, nc); ! 244: ! 245: s->slirp = slirp_init(restricted, net, mask, host, vhostname, ! 246: tftp_export, bootfile, dhcp, dns, s); ! 247: QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); ! 248: ! 249: for (config = slirp_configs; config; config = config->next) { ! 250: if (config->flags & SLIRP_CFG_HOSTFWD) { ! 251: if (slirp_hostfwd(s, config->str, ! 252: config->flags & SLIRP_CFG_LEGACY) < 0) ! 253: goto error; ! 254: } else { ! 255: if (slirp_guestfwd(s, config->str, ! 256: config->flags & SLIRP_CFG_LEGACY) < 0) ! 257: goto error; ! 258: } ! 259: } ! 260: #ifndef _WIN32 ! 261: if (!smb_export) { ! 262: smb_export = legacy_smb_export; ! 263: } ! 264: if (smb_export) { ! 265: if (slirp_smb(s, smb_export, smbsrv) < 0) ! 266: goto error; ! 267: } ! 268: #endif ! 269: ! 270: return 0; ! 271: ! 272: error: ! 273: qemu_del_vlan_client(nc); ! 274: return -1; ! 275: } ! 276: ! 277: static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, ! 278: const char *stack) ! 279: { ! 280: ! 281: if (vlan) { ! 282: VLANClientState *nc; ! 283: nc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); ! 284: if (!nc) { ! 285: return NULL; ! 286: } ! 287: if (strcmp(nc->model, "user")) { ! 288: monitor_printf(mon, "invalid device specified\n"); ! 289: return NULL; ! 290: } ! 291: return DO_UPCAST(SlirpState, nc, nc); ! 292: } else { ! 293: if (QTAILQ_EMPTY(&slirp_stacks)) { ! 294: monitor_printf(mon, "user mode network stack not in use\n"); ! 295: return NULL; ! 296: } ! 297: return QTAILQ_FIRST(&slirp_stacks); ! 298: } ! 299: } ! 300: ! 301: void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) ! 302: { ! 303: struct in_addr host_addr = { .s_addr = INADDR_ANY }; ! 304: int host_port; ! 305: char buf[256] = ""; ! 306: const char *src_str, *p; ! 307: SlirpState *s; ! 308: int is_udp = 0; ! 309: int err; ! 310: const char *arg1 = qdict_get_str(qdict, "arg1"); ! 311: const char *arg2 = qdict_get_try_str(qdict, "arg2"); ! 312: const char *arg3 = qdict_get_try_str(qdict, "arg3"); ! 313: ! 314: if (arg2) { ! 315: s = slirp_lookup(mon, arg1, arg2); ! 316: src_str = arg3; ! 317: } else { ! 318: s = slirp_lookup(mon, NULL, NULL); ! 319: src_str = arg1; ! 320: } ! 321: if (!s) { ! 322: return; ! 323: } ! 324: ! 325: if (!src_str || !src_str[0]) ! 326: goto fail_syntax; ! 327: ! 328: p = src_str; ! 329: get_str_sep(buf, sizeof(buf), &p, ':'); ! 330: ! 331: if (!strcmp(buf, "tcp") || buf[0] == '\0') { ! 332: is_udp = 0; ! 333: } else if (!strcmp(buf, "udp")) { ! 334: is_udp = 1; ! 335: } else { ! 336: goto fail_syntax; ! 337: } ! 338: ! 339: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 340: goto fail_syntax; ! 341: } ! 342: if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { ! 343: goto fail_syntax; ! 344: } ! 345: ! 346: host_port = atoi(p); ! 347: ! 348: err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp, ! 349: host_addr, host_port); ! 350: ! 351: monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, ! 352: err ? "removed" : "not found"); ! 353: return; ! 354: ! 355: fail_syntax: ! 356: monitor_printf(mon, "invalid format\n"); ! 357: } ! 358: ! 359: static int slirp_hostfwd(SlirpState *s, const char *redir_str, ! 360: int legacy_format) ! 361: { ! 362: struct in_addr host_addr = { .s_addr = INADDR_ANY }; ! 363: struct in_addr guest_addr = { .s_addr = 0 }; ! 364: int host_port, guest_port; ! 365: const char *p; ! 366: char buf[256]; ! 367: int is_udp; ! 368: char *end; ! 369: ! 370: p = redir_str; ! 371: if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 372: goto fail_syntax; ! 373: } ! 374: if (!strcmp(buf, "tcp") || buf[0] == '\0') { ! 375: is_udp = 0; ! 376: } else if (!strcmp(buf, "udp")) { ! 377: is_udp = 1; ! 378: } else { ! 379: goto fail_syntax; ! 380: } ! 381: ! 382: if (!legacy_format) { ! 383: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 384: goto fail_syntax; ! 385: } ! 386: if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { ! 387: goto fail_syntax; ! 388: } ! 389: } ! 390: ! 391: if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) { ! 392: goto fail_syntax; ! 393: } ! 394: host_port = strtol(buf, &end, 0); ! 395: if (*end != '\0' || host_port < 1 || host_port > 65535) { ! 396: goto fail_syntax; ! 397: } ! 398: ! 399: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 400: goto fail_syntax; ! 401: } ! 402: if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { ! 403: goto fail_syntax; ! 404: } ! 405: ! 406: guest_port = strtol(p, &end, 0); ! 407: if (*end != '\0' || guest_port < 1 || guest_port > 65535) { ! 408: goto fail_syntax; ! 409: } ! 410: ! 411: if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, ! 412: guest_port) < 0) { ! 413: qemu_error("could not set up host forwarding rule '%s'\n", ! 414: redir_str); ! 415: return -1; ! 416: } ! 417: return 0; ! 418: ! 419: fail_syntax: ! 420: qemu_error("invalid host forwarding rule '%s'\n", redir_str); ! 421: return -1; ! 422: } ! 423: ! 424: void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) ! 425: { ! 426: const char *redir_str; ! 427: SlirpState *s; ! 428: const char *arg1 = qdict_get_str(qdict, "arg1"); ! 429: const char *arg2 = qdict_get_try_str(qdict, "arg2"); ! 430: const char *arg3 = qdict_get_try_str(qdict, "arg3"); ! 431: ! 432: if (arg2) { ! 433: s = slirp_lookup(mon, arg1, arg2); ! 434: redir_str = arg3; ! 435: } else { ! 436: s = slirp_lookup(mon, NULL, NULL); ! 437: redir_str = arg1; ! 438: } ! 439: if (s) { ! 440: slirp_hostfwd(s, redir_str, 0); ! 441: } ! 442: ! 443: } ! 444: ! 445: int net_slirp_redir(const char *redir_str) ! 446: { ! 447: struct slirp_config_str *config; ! 448: ! 449: if (QTAILQ_EMPTY(&slirp_stacks)) { ! 450: config = qemu_malloc(sizeof(*config)); ! 451: pstrcpy(config->str, sizeof(config->str), redir_str); ! 452: config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; ! 453: config->next = slirp_configs; ! 454: slirp_configs = config; ! 455: return 0; ! 456: } ! 457: ! 458: return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); ! 459: } ! 460: ! 461: #ifndef _WIN32 ! 462: ! 463: /* automatic user mode samba server configuration */ ! 464: static void slirp_smb_cleanup(SlirpState *s) ! 465: { ! 466: char cmd[128]; ! 467: ! 468: if (s->smb_dir[0] != '\0') { ! 469: snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); ! 470: system(cmd); ! 471: s->smb_dir[0] = '\0'; ! 472: } ! 473: } ! 474: ! 475: static int slirp_smb(SlirpState* s, const char *exported_dir, ! 476: struct in_addr vserver_addr) ! 477: { ! 478: static int instance; ! 479: char smb_conf[128]; ! 480: char smb_cmdline[128]; ! 481: FILE *f; ! 482: ! 483: snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", ! 484: (long)getpid(), instance++); ! 485: if (mkdir(s->smb_dir, 0700) < 0) { ! 486: qemu_error("could not create samba server dir '%s'\n", s->smb_dir); ! 487: return -1; ! 488: } ! 489: snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); ! 490: ! 491: f = fopen(smb_conf, "w"); ! 492: if (!f) { ! 493: slirp_smb_cleanup(s); ! 494: qemu_error("could not create samba server configuration file '%s'\n", ! 495: smb_conf); ! 496: return -1; ! 497: } ! 498: fprintf(f, ! 499: "[global]\n" ! 500: "private dir=%s\n" ! 501: "smb ports=0\n" ! 502: "socket address=127.0.0.1\n" ! 503: "pid directory=%s\n" ! 504: "lock directory=%s\n" ! 505: "log file=%s/log.smbd\n" ! 506: "smb passwd file=%s/smbpasswd\n" ! 507: "security = share\n" ! 508: "[qemu]\n" ! 509: "path=%s\n" ! 510: "read only=no\n" ! 511: "guest ok=yes\n", ! 512: s->smb_dir, ! 513: s->smb_dir, ! 514: s->smb_dir, ! 515: s->smb_dir, ! 516: s->smb_dir, ! 517: exported_dir ! 518: ); ! 519: fclose(f); ! 520: ! 521: snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", ! 522: SMBD_COMMAND, smb_conf); ! 523: ! 524: if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { ! 525: slirp_smb_cleanup(s); ! 526: qemu_error("conflicting/invalid smbserver address\n"); ! 527: return -1; ! 528: } ! 529: return 0; ! 530: } ! 531: ! 532: /* automatic user mode samba server configuration (legacy interface) */ ! 533: int net_slirp_smb(const char *exported_dir) ! 534: { ! 535: struct in_addr vserver_addr = { .s_addr = 0 }; ! 536: ! 537: if (legacy_smb_export) { ! 538: fprintf(stderr, "-smb given twice\n"); ! 539: return -1; ! 540: } ! 541: legacy_smb_export = exported_dir; ! 542: if (!QTAILQ_EMPTY(&slirp_stacks)) { ! 543: return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, ! 544: vserver_addr); ! 545: } ! 546: return 0; ! 547: } ! 548: ! 549: #endif /* !defined(_WIN32) */ ! 550: ! 551: struct GuestFwd { ! 552: CharDriverState *hd; ! 553: struct in_addr server; ! 554: int port; ! 555: Slirp *slirp; ! 556: }; ! 557: ! 558: static int guestfwd_can_read(void *opaque) ! 559: { ! 560: struct GuestFwd *fwd = opaque; ! 561: return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); ! 562: } ! 563: ! 564: static void guestfwd_read(void *opaque, const uint8_t *buf, int size) ! 565: { ! 566: struct GuestFwd *fwd = opaque; ! 567: slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); ! 568: } ! 569: ! 570: static int slirp_guestfwd(SlirpState *s, const char *config_str, ! 571: int legacy_format) ! 572: { ! 573: struct in_addr server = { .s_addr = 0 }; ! 574: struct GuestFwd *fwd; ! 575: const char *p; ! 576: char buf[128]; ! 577: char *end; ! 578: int port; ! 579: ! 580: p = config_str; ! 581: if (legacy_format) { ! 582: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 583: goto fail_syntax; ! 584: } ! 585: } else { ! 586: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 587: goto fail_syntax; ! 588: } ! 589: if (strcmp(buf, "tcp") && buf[0] != '\0') { ! 590: goto fail_syntax; ! 591: } ! 592: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { ! 593: goto fail_syntax; ! 594: } ! 595: if (buf[0] != '\0' && !inet_aton(buf, &server)) { ! 596: goto fail_syntax; ! 597: } ! 598: if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { ! 599: goto fail_syntax; ! 600: } ! 601: } ! 602: port = strtol(buf, &end, 10); ! 603: if (*end != '\0' || port < 1 || port > 65535) { ! 604: goto fail_syntax; ! 605: } ! 606: ! 607: fwd = qemu_malloc(sizeof(struct GuestFwd)); ! 608: snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); ! 609: fwd->hd = qemu_chr_open(buf, p, NULL); ! 610: if (!fwd->hd) { ! 611: qemu_error("could not open guest forwarding device '%s'\n", buf); ! 612: qemu_free(fwd); ! 613: return -1; ! 614: } ! 615: ! 616: if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { ! 617: qemu_error("conflicting/invalid host:port in guest forwarding " ! 618: "rule '%s'\n", config_str); ! 619: qemu_free(fwd); ! 620: return -1; ! 621: } ! 622: fwd->server = server; ! 623: fwd->port = port; ! 624: fwd->slirp = s->slirp; ! 625: ! 626: qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, ! 627: NULL, fwd); ! 628: return 0; ! 629: ! 630: fail_syntax: ! 631: qemu_error("invalid guest forwarding rule '%s'\n", config_str); ! 632: return -1; ! 633: } ! 634: ! 635: void do_info_usernet(Monitor *mon) ! 636: { ! 637: SlirpState *s; ! 638: ! 639: QTAILQ_FOREACH(s, &slirp_stacks, entry) { ! 640: monitor_printf(mon, "VLAN %d (%s):\n", ! 641: s->nc.vlan ? s->nc.vlan->id : -1, ! 642: s->nc.name); ! 643: slirp_connection_info(s->slirp, mon); ! 644: } ! 645: } ! 646: ! 647: static int net_init_slirp_configs(const char *name, const char *value, void *opaque) ! 648: { ! 649: struct slirp_config_str *config; ! 650: ! 651: if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { ! 652: return 0; ! 653: } ! 654: ! 655: config = qemu_mallocz(sizeof(*config)); ! 656: ! 657: pstrcpy(config->str, sizeof(config->str), value); ! 658: ! 659: if (!strcmp(name, "hostfwd")) { ! 660: config->flags = SLIRP_CFG_HOSTFWD; ! 661: } ! 662: ! 663: config->next = slirp_configs; ! 664: slirp_configs = config; ! 665: ! 666: return 0; ! 667: } ! 668: ! 669: int net_init_slirp(QemuOpts *opts, ! 670: Monitor *mon, ! 671: const char *name, ! 672: VLANState *vlan) ! 673: { ! 674: struct slirp_config_str *config; ! 675: const char *vhost; ! 676: const char *vhostname; ! 677: const char *vdhcp_start; ! 678: const char *vnamesrv; ! 679: const char *tftp_export; ! 680: const char *bootfile; ! 681: const char *smb_export; ! 682: const char *vsmbsrv; ! 683: char *vnet = NULL; ! 684: int restricted = 0; ! 685: int ret; ! 686: ! 687: vhost = qemu_opt_get(opts, "host"); ! 688: vhostname = qemu_opt_get(opts, "hostname"); ! 689: vdhcp_start = qemu_opt_get(opts, "dhcpstart"); ! 690: vnamesrv = qemu_opt_get(opts, "dns"); ! 691: tftp_export = qemu_opt_get(opts, "tftp"); ! 692: bootfile = qemu_opt_get(opts, "bootfile"); ! 693: smb_export = qemu_opt_get(opts, "smb"); ! 694: vsmbsrv = qemu_opt_get(opts, "smbserver"); ! 695: ! 696: if (qemu_opt_get(opts, "ip")) { ! 697: const char *ip = qemu_opt_get(opts, "ip"); ! 698: int l = strlen(ip) + strlen("/24") + 1; ! 699: ! 700: vnet = qemu_malloc(l); ! 701: ! 702: /* emulate legacy ip= parameter */ ! 703: pstrcpy(vnet, l, ip); ! 704: pstrcat(vnet, l, "/24"); ! 705: } ! 706: ! 707: if (qemu_opt_get(opts, "net")) { ! 708: if (vnet) { ! 709: qemu_free(vnet); ! 710: } ! 711: vnet = qemu_strdup(qemu_opt_get(opts, "net")); ! 712: } ! 713: ! 714: if (qemu_opt_get(opts, "restrict") && ! 715: qemu_opt_get(opts, "restrict")[0] == 'y') { ! 716: restricted = 1; ! 717: } ! 718: ! 719: qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); ! 720: ! 721: ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, ! 722: vhostname, tftp_export, bootfile, vdhcp_start, ! 723: vnamesrv, smb_export, vsmbsrv); ! 724: ! 725: while (slirp_configs) { ! 726: config = slirp_configs; ! 727: slirp_configs = config->next; ! 728: qemu_free(config); ! 729: } ! 730: ! 731: if (ret != -1 && vlan) { ! 732: vlan->nb_host_devs++; ! 733: } ! 734: ! 735: qemu_free(vnet); ! 736: ! 737: return ret; ! 738: } ! 739: ! 740: int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret) ! 741: { ! 742: if (strcmp(opts_list->name, "net") != 0 || ! 743: strncmp(optarg, "channel,", strlen("channel,")) != 0) { ! 744: return 0; ! 745: } ! 746: ! 747: /* handle legacy -net channel,port:chr */ ! 748: optarg += strlen("channel,"); ! 749: ! 750: if (QTAILQ_EMPTY(&slirp_stacks)) { ! 751: struct slirp_config_str *config; ! 752: ! 753: config = qemu_malloc(sizeof(*config)); ! 754: pstrcpy(config->str, sizeof(config->str), optarg); ! 755: config->flags = SLIRP_CFG_LEGACY; ! 756: config->next = slirp_configs; ! 757: slirp_configs = config; ! 758: *ret = 0; ! 759: } else { ! 760: *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); ! 761: } ! 762: ! 763: return 1; ! 764: } ! 765:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.