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