1 /* 2 * inet and unix socket functions for qemu 3 * 4 * (c) 2008 Gerd Hoffmann <kraxel@redhat.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; under version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <ctype.h> 19 #include <errno.h> 20 #include <unistd.h> 21 22 #include "qemu_socket.h" 23 #include "qemu-common.h" /* for qemu_isdigit */ 24 25 #ifndef AI_ADDRCONFIG 26 # define AI_ADDRCONFIG 0 27 #endif 28 29 static int sockets_debug = 0; 30 static const int on=1, off=0; 31 32 /* used temporarely until all users are converted to QemuOpts */ 33 static QemuOptsList dummy_opts = { 34 .name = "dummy", 35 .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head), 36 .desc = { 37 { 38 .name = "path", 39 .type = QEMU_OPT_STRING, 40 },{ 41 .name = "host", 42 .type = QEMU_OPT_STRING, 43 },{ 44 .name = "port", 45 .type = QEMU_OPT_STRING, 46 },{ 47 .name = "to", 48 .type = QEMU_OPT_NUMBER, 49 },{ 50 .name = "ipv4", 51 .type = QEMU_OPT_BOOL, 52 },{ 53 .name = "ipv6", 54 .type = QEMU_OPT_BOOL, 55 }, 56 { /* end if list */ } 57 }, 58 }; 59 60 static int inet_getport(struct addrinfo *e) 61 { 62 struct sockaddr_in *i4; 63 struct sockaddr_in6 *i6; 64 65 switch (e->ai_family) { 66 case PF_INET6: 67 i6 = (void*)e->ai_addr; 68 return ntohs(i6->sin6_port); 69 case PF_INET: 70 i4 = (void*)e->ai_addr; 71 return ntohs(i4->sin_port); 72 default: 73 return 0; 74 } 75 } 76 77 static void inet_setport(struct addrinfo *e, int port) 78 { 79 struct sockaddr_in *i4; 80 struct sockaddr_in6 *i6; 81 82 switch (e->ai_family) { 83 case PF_INET6: 84 i6 = (void*)e->ai_addr; 85 i6->sin6_port = htons(port); 86 break; 87 case PF_INET: 88 i4 = (void*)e->ai_addr; 89 i4->sin_port = htons(port); 90 break; 91 } 92 } 93 94 const char *inet_strfamily(int family) 95 { 96 switch (family) { 97 case PF_INET6: return "ipv6"; 98 case PF_INET: return "ipv4"; 99 case PF_UNIX: return "unix"; 100 } 101 return "unknown"; 102 } 103 104 static void inet_print_addrinfo(const char *tag, struct addrinfo *res) 105 { 106 struct addrinfo *e; 107 char uaddr[INET6_ADDRSTRLEN+1]; 108 char uport[33]; 109 110 for (e = res; e != NULL; e = e->ai_next) { 111 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 112 uaddr,INET6_ADDRSTRLEN,uport,32, 113 NI_NUMERICHOST | NI_NUMERICSERV); 114 fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", 115 tag, inet_strfamily(e->ai_family), uaddr, uport); 116 } 117 } 118 119 int inet_listen_opts(QemuOpts *opts, int port_offset) 120 { 121 struct addrinfo ai,*res,*e; 122 const char *addr; 123 char port[33]; 124 char uaddr[INET6_ADDRSTRLEN+1]; 125 char uport[33]; 126 int slisten,rc,to,try_next; 127 128 memset(&ai,0, sizeof(ai)); 129 ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; 130 ai.ai_family = PF_UNSPEC; 131 ai.ai_socktype = SOCK_STREAM; 132 133 if ((qemu_opt_get(opts, "host") == NULL) || 134 (qemu_opt_get(opts, "port") == NULL)) { 135 fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__); 136 return -1; 137 } 138 pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port")); 139 addr = qemu_opt_get(opts, "host"); 140 141 to = qemu_opt_get_number(opts, "to", 0); 142 if (qemu_opt_get_bool(opts, "ipv4", 0)) 143 ai.ai_family = PF_INET; 144 if (qemu_opt_get_bool(opts, "ipv6", 0)) 145 ai.ai_family = PF_INET6; 146 147 /* lookup */ 148 if (port_offset) 149 snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); 150 rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); 151 if (rc != 0) { 152 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 153 gai_strerror(rc)); 154 return -1; 155 } 156 if (sockets_debug) 157 inet_print_addrinfo(__FUNCTION__, res); 158 159 /* create socket + bind */ 160 for (e = res; e != NULL; e = e->ai_next) { 161 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 162 uaddr,INET6_ADDRSTRLEN,uport,32, 163 NI_NUMERICHOST | NI_NUMERICSERV); 164 slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); 165 if (slisten < 0) { 166 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 167 inet_strfamily(e->ai_family), strerror(errno)); 168 continue; 169 } 170 171 setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 172 #ifdef IPV6_V6ONLY 173 if (e->ai_family == PF_INET6) { 174 /* listen on both ipv4 and ipv6 */ 175 setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, 176 sizeof(off)); 177 } 178 #endif 179 180 for (;;) { 181 if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { 182 if (sockets_debug) 183 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 184 inet_strfamily(e->ai_family), uaddr, inet_getport(e)); 185 goto listen; 186 } 187 try_next = to && (inet_getport(e) <= to + port_offset); 188 if (!try_next || sockets_debug) 189 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, 190 inet_strfamily(e->ai_family), uaddr, inet_getport(e), 191 strerror(errno)); 192 if (try_next) { 193 inet_setport(e, inet_getport(e) + 1); 194 continue; 195 } 196 break; 197 } 198 closesocket(slisten); 199 } 200 fprintf(stderr, "%s: FAILED\n", __FUNCTION__); 201 freeaddrinfo(res); 202 return -1; 203 204 listen: 205 if (listen(slisten,1) != 0) { 206 perror("listen"); 207 closesocket(slisten); 208 freeaddrinfo(res); 209 return -1; 210 } 211 snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset); 212 qemu_opt_set(opts, "host", uaddr); 213 qemu_opt_set(opts, "port", uport); 214 qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off"); 215 qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off"); 216 freeaddrinfo(res); 217 return slisten; 218 } 219 220 int inet_connect_opts(QemuOpts *opts) 221 { 222 struct addrinfo ai,*res,*e; 223 const char *addr; 224 const char *port; 225 char uaddr[INET6_ADDRSTRLEN+1]; 226 char uport[33]; 227 int sock,rc; 228 229 memset(&ai,0, sizeof(ai)); 230 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 231 ai.ai_family = PF_UNSPEC; 232 ai.ai_socktype = SOCK_STREAM; 233 234 addr = qemu_opt_get(opts, "host"); 235 port = qemu_opt_get(opts, "port"); 236 if (addr == NULL || port == NULL) { 237 fprintf(stderr, "inet_connect: host and/or port not specified\n"); 238 return -1; 239 } 240 241 if (qemu_opt_get_bool(opts, "ipv4", 0)) 242 ai.ai_family = PF_INET; 243 if (qemu_opt_get_bool(opts, "ipv6", 0)) 244 ai.ai_family = PF_INET6; 245 246 /* lookup */ 247 if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { 248 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 249 gai_strerror(rc)); 250 return -1; 251 } 252 if (sockets_debug) 253 inet_print_addrinfo(__FUNCTION__, res); 254 255 for (e = res; e != NULL; e = e->ai_next) { 256 if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 257 uaddr,INET6_ADDRSTRLEN,uport,32, 258 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 259 fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); 260 continue; 261 } 262 sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); 263 if (sock < 0) { 264 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 265 inet_strfamily(e->ai_family), strerror(errno)); 266 continue; 267 } 268 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 269 270 /* connect to peer */ 271 if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { 272 if (sockets_debug || NULL == e->ai_next) 273 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 274 inet_strfamily(e->ai_family), 275 e->ai_canonname, uaddr, uport, strerror(errno)); 276 closesocket(sock); 277 continue; 278 } 279 if (sockets_debug) 280 fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, 281 inet_strfamily(e->ai_family), 282 e->ai_canonname, uaddr, uport); 283 freeaddrinfo(res); 284 return sock; 285 } 286 freeaddrinfo(res); 287 return -1; 288 } 289 290 int inet_dgram_opts(QemuOpts *opts) 291 { 292 struct addrinfo ai, *peer = NULL, *local = NULL; 293 const char *addr; 294 const char *port; 295 char uaddr[INET6_ADDRSTRLEN+1]; 296 char uport[33]; 297 int sock = -1, rc; 298 299 /* lookup peer addr */ 300 memset(&ai,0, sizeof(ai)); 301 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 302 ai.ai_family = PF_UNSPEC; 303 ai.ai_socktype = SOCK_DGRAM; 304 305 addr = qemu_opt_get(opts, "host"); 306 port = qemu_opt_get(opts, "port"); 307 if (addr == NULL || strlen(addr) == 0) { 308 addr = "localhost"; 309 } 310 if (port == NULL || strlen(port) == 0) { 311 fprintf(stderr, "inet_dgram: port not specified\n"); 312 return -1; 313 } 314 315 if (qemu_opt_get_bool(opts, "ipv4", 0)) 316 ai.ai_family = PF_INET; 317 if (qemu_opt_get_bool(opts, "ipv6", 0)) 318 ai.ai_family = PF_INET6; 319 320 if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { 321 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 322 gai_strerror(rc)); 323 return -1; 324 } 325 if (sockets_debug) { 326 fprintf(stderr, "%s: peer (%s:%s)\n", __FUNCTION__, addr, port); 327 inet_print_addrinfo(__FUNCTION__, peer); 328 } 329 330 /* lookup local addr */ 331 memset(&ai,0, sizeof(ai)); 332 ai.ai_flags = AI_PASSIVE; 333 ai.ai_family = peer->ai_family; 334 ai.ai_socktype = SOCK_DGRAM; 335 336 addr = qemu_opt_get(opts, "localaddr"); 337 port = qemu_opt_get(opts, "localport"); 338 if (addr == NULL || strlen(addr) == 0) { 339 addr = NULL; 340 } 341 if (!port || strlen(port) == 0) 342 port = "0"; 343 344 if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { 345 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, 346 gai_strerror(rc)); 347 return -1; 348 } 349 if (sockets_debug) { 350 fprintf(stderr, "%s: local (%s:%s)\n", __FUNCTION__, addr, port); 351 inet_print_addrinfo(__FUNCTION__, local); 352 } 353 354 /* create socket */ 355 sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); 356 if (sock < 0) { 357 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 358 inet_strfamily(peer->ai_family), strerror(errno)); 359 goto err; 360 } 361 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 362 363 /* bind socket */ 364 if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen, 365 uaddr,INET6_ADDRSTRLEN,uport,32, 366 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 367 fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); 368 goto err; 369 } 370 if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { 371 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 372 inet_strfamily(local->ai_family), uaddr, inet_getport(local)); 373 goto err; 374 } 375 376 /* connect to peer */ 377 if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen, 378 uaddr, INET6_ADDRSTRLEN, uport, 32, 379 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 380 fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); 381 goto err; 382 } 383 if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { 384 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 385 inet_strfamily(peer->ai_family), 386 peer->ai_canonname, uaddr, uport, strerror(errno)); 387 goto err; 388 } 389 390 freeaddrinfo(local); 391 freeaddrinfo(peer); 392 return sock; 393 394 err: 395 if (-1 != sock) 396 closesocket(sock); 397 if (local) 398 freeaddrinfo(local); 399 if (peer) 400 freeaddrinfo(peer); 401 return -1; 402 } 403 404 /* compatibility wrapper */ 405 static int inet_parse(QemuOpts *opts, const char *str) 406 { 407 const char *optstr, *h; 408 char addr[64]; 409 char port[33]; 410 int pos; 411 412 /* parse address */ 413 if (str[0] == ':') { 414 /* no host given */ 415 addr[0] = '\0'; 416 if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { 417 fprintf(stderr, "%s: portonly parse error (%s)\n", 418 __FUNCTION__, str); 419 return -1; 420 } 421 } else if (str[0] == '[') { 422 /* IPv6 addr */ 423 if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { 424 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 425 __FUNCTION__, str); 426 return -1; 427 } 428 qemu_opt_set(opts, "ipv6", "on"); 429 } else if (qemu_isdigit(str[0])) { 430 /* IPv4 addr */ 431 if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { 432 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 433 __FUNCTION__, str); 434 return -1; 435 } 436 qemu_opt_set(opts, "ipv4", "on"); 437 } else { 438 /* hostname */ 439 if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { 440 fprintf(stderr, "%s: hostname parse error (%s)\n", 441 __FUNCTION__, str); 442 return -1; 443 } 444 } 445 qemu_opt_set(opts, "host", addr); 446 qemu_opt_set(opts, "port", port); 447 448 /* parse options */ 449 optstr = str + pos; 450 h = strstr(optstr, ",to="); 451 if (h) 452 qemu_opt_set(opts, "to", h+4); 453 if (strstr(optstr, ",ipv4")) 454 qemu_opt_set(opts, "ipv4", "on"); 455 if (strstr(optstr, ",ipv6")) 456 qemu_opt_set(opts, "ipv6", "on"); 457 return 0; 458 } 459 460 int inet_listen(const char *str, char *ostr, int olen, 461 int socktype, int port_offset) 462 { 463 QemuOpts *opts; 464 char *optstr; 465 int sock = -1; 466 467 opts = qemu_opts_create(&dummy_opts, NULL, 0); 468 if (inet_parse(opts, str) == 0) { 469 sock = inet_listen_opts(opts, port_offset); 470 if (sock != -1 && ostr) { 471 optstr = strchr(str, ','); 472 if (qemu_opt_get_bool(opts, "ipv6", 0)) { 473 snprintf(ostr, olen, "[%s]:%s%s", 474 qemu_opt_get(opts, "host"), 475 qemu_opt_get(opts, "port"), 476 optstr ? optstr : ""); 477 } else { 478 snprintf(ostr, olen, "%s:%s%s", 479 qemu_opt_get(opts, "host"), 480 qemu_opt_get(opts, "port"), 481 optstr ? optstr : ""); 482 } 483 } 484 } 485 qemu_opts_del(opts); 486 return sock; 487 } 488 489 int inet_connect(const char *str, int socktype) 490 { 491 QemuOpts *opts; 492 int sock = -1; 493 494 opts = qemu_opts_create(&dummy_opts, NULL, 0); 495 if (inet_parse(opts, str) == 0) 496 sock = inet_connect_opts(opts); 497 qemu_opts_del(opts); 498 return sock; 499 } 500 501 #ifndef _WIN32 502 503 int unix_listen_opts(QemuOpts *opts) 504 { 505 struct sockaddr_un un; 506 const char *path = qemu_opt_get(opts, "path"); 507 int sock, fd; 508 509 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 510 if (sock < 0) { 511 perror("socket(unix)"); 512 return -1; 513 } 514 515 memset(&un, 0, sizeof(un)); 516 un.sun_family = AF_UNIX; 517 if (path && strlen(path)) { 518 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 519 } else { 520 char *tmpdir = getenv("TMPDIR"); 521 snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", 522 tmpdir ? tmpdir : "/tmp"); 523 /* 524 * This dummy fd usage silences the mktemp() unsecure warning. 525 * Using mkstemp() doesn't make things more secure here 526 * though. bind() complains about existing files, so we have 527 * to unlink first and thus re-open the race window. The 528 * worst case possible is bind() failing, i.e. a DoS attack. 529 */ 530 fd = mkstemp(un.sun_path); close(fd); 531 qemu_opt_set(opts, "path", un.sun_path); 532 } 533 534 unlink(un.sun_path); 535 if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 536 fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); 537 goto err; 538 } 539 if (listen(sock, 1) < 0) { 540 fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); 541 goto err; 542 } 543 544 if (sockets_debug) 545 fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); 546 return sock; 547 548 err: 549 closesocket(sock); 550 return -1; 551 } 552 553 int unix_connect_opts(QemuOpts *opts) 554 { 555 struct sockaddr_un un; 556 const char *path = qemu_opt_get(opts, "path"); 557 int sock; 558 559 if (NULL == path) { 560 fprintf(stderr, "unix connect: no path specified\n"); 561 return -1; 562 } 563 564 sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); 565 if (sock < 0) { 566 perror("socket(unix)"); 567 return -1; 568 } 569 570 memset(&un, 0, sizeof(un)); 571 un.sun_family = AF_UNIX; 572 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 573 if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 574 fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); 575 return -1; 576 } 577 578 if (sockets_debug) 579 fprintf(stderr, "connect(unix:%s): OK\n", path); 580 return sock; 581 } 582 583 /* compatibility wrapper */ 584 int unix_listen(const char *str, char *ostr, int olen) 585 { 586 QemuOpts *opts; 587 char *path, *optstr; 588 int sock, len; 589 590 opts = qemu_opts_create(&dummy_opts, NULL, 0); 591 592 optstr = strchr(str, ','); 593 if (optstr) { 594 len = optstr - str; 595 if (len) { 596 path = qemu_malloc(len+1); 597 snprintf(path, len+1, "%.*s", len, str); 598 qemu_opt_set(opts, "path", path); 599 qemu_free(path); 600 } 601 } else { 602 qemu_opt_set(opts, "path", str); 603 } 604 605 sock = unix_listen_opts(opts); 606 607 if (sock != -1 && ostr) 608 snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : ""); 609 qemu_opts_del(opts); 610 return sock; 611 } 612 613 int unix_connect(const char *path) 614 { 615 QemuOpts *opts; 616 int sock; 617 618 opts = qemu_opts_create(&dummy_opts, NULL, 0); 619 qemu_opt_set(opts, "path", path); 620 sock = unix_connect_opts(opts); 621 qemu_opts_del(opts); 622 return sock; 623 } 624 625 #else 626 627 int unix_listen_opts(QemuOpts *opts) 628 { 629 fprintf(stderr, "unix sockets are not available on windows\n"); 630 return -1; 631 } 632 633 int unix_connect_opts(QemuOpts *opts) 634 { 635 fprintf(stderr, "unix sockets are not available on windows\n"); 636 return -1; 637 } 638 639 int unix_listen(const char *path, char *ostr, int olen) 640 { 641 fprintf(stderr, "unix sockets are not available on windows\n"); 642 return -1; 643 } 644 645 int unix_connect(const char *path) 646 { 647 fprintf(stderr, "unix sockets are not available on windows\n"); 648 return -1; 649 } 650 651 #endif 652 653 #ifdef _WIN32 654 static void socket_cleanup(void) 655 { 656 WSACleanup(); 657 } 658 #endif 659 660 int socket_init(void) 661 { 662 #ifdef _WIN32 663 WSADATA Data; 664 int ret, err; 665 666 ret = WSAStartup(MAKEWORD(2,2), &Data); 667 if (ret != 0) { 668 err = WSAGetLastError(); 669 fprintf(stderr, "WSAStartup: %d\n", err); 670 return -1; 671 } 672 atexit(socket_cleanup); 673 #endif 674 return 0; 675 } 676