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