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 static int sockets_debug = 0;
     30 static const int on=1, off=0;
     31 
     32 static const char *sock_address_strfamily(SockAddress *s)
     33 {
     34     switch (sock_address_get_family(s)) {
     35     case SOCKET_IN6:   return "ipv6";
     36     case SOCKET_INET:  return "ipv4";
     37     case SOCKET_UNIX:  return "unix";
     38     default:           return "????";
     39     }
     40 }
     41 
     42 int inet_listen(const char *str, char *ostr, int olen,
     43                 SocketType socktype, int port_offset)
     44 {
     45     SockAddress**  list;
     46     SockAddress*   e;
     47     unsigned       flags = SOCKET_LIST_PASSIVE;
     48     char addr[64];
     49     char port[33];
     50     char uaddr[256+1];
     51     const char *opts, *h;
     52     int slisten,pos,to,try_next,nn;
     53 
     54     /* parse address */
     55     if (str[0] == ':') {
     56         /* no host given */
     57         addr[0] = '\0';
     58         if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
     59             fprintf(stderr, "%s: portonly parse error (%s)\n",
     60                     __FUNCTION__, str);
     61             return -1;
     62         }
     63     } else if (str[0] == '[') {
     64         /* IPv6 addr */
     65         if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
     66             fprintf(stderr, "%s: ipv6 parse error (%s)\n",
     67                     __FUNCTION__, str);
     68             return -1;
     69         }
     70         flags |= SOCKET_LIST_FORCE_IN6;
     71     } else if (qemu_isdigit(str[0])) {
     72         /* IPv4 addr */
     73         if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
     74             fprintf(stderr, "%s: ipv4 parse error (%s)\n",
     75                     __FUNCTION__, str);
     76             return -1;
     77         }
     78         flags |= SOCKET_LIST_FORCE_INET;
     79     } else {
     80         /* hostname */
     81         if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
     82             fprintf(stderr, "%s: hostname parse error (%s)\n",
     83                     __FUNCTION__, str);
     84             return -1;
     85         }
     86     }
     87 
     88     /* parse options */
     89     opts = str + pos;
     90     h = strstr(opts, ",to=");
     91     to = h ? atoi(h+4) : 0;
     92     if (strstr(opts, ",ipv4")) {
     93         flags &= ~SOCKET_LIST_FORCE_IN6;
     94         flags |= SOCKET_LIST_FORCE_INET;
     95     }
     96     if (strstr(opts, ",ipv6")) {
     97         flags &= SOCKET_LIST_FORCE_INET;
     98         flags |= SOCKET_LIST_FORCE_IN6;
     99     }
    100 
    101     /* lookup */
    102     if (port_offset)
    103         snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
    104 
    105     list = sock_address_list_create( strlen(addr) ? addr : NULL,
    106                                        port,
    107                                        flags );
    108     if (list == NULL) {
    109         fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
    110                 addr, port, errno_str);
    111         return -1;
    112     }
    113 
    114     /* create socket + bind */
    115     for (nn = 0; list[nn] != NULL; nn++) {
    116         SocketFamily  family;
    117 
    118         e      = list[nn];
    119         family = sock_address_get_family(e);
    120         slisten = socket_create(family, socktype);
    121         if (slisten < 0) {
    122             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
    123                     sock_address_strfamily(e), errno_str);
    124             continue;
    125         }
    126 
    127         socket_set_xreuseaddr(slisten);
    128 #ifdef IPV6_V6ONLY
    129         /* listen on both ipv4 and ipv6 */
    130         if (family == PF_INET6) {
    131             socket_set_ipv6only(slisten);
    132         }
    133 #endif
    134 
    135         for (;;) {
    136             if (socket_bind(slisten, e) == 0) {
    137                 if (sockets_debug)
    138                     fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
    139                         sock_address_strfamily(e), uaddr, sock_address_get_port(e));
    140                 goto listen;
    141             }
    142             socket_close(slisten);
    143             try_next = to && (sock_address_get_port(e) <= to + port_offset);
    144             if (!try_next || sockets_debug)
    145                 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
    146                         sock_address_strfamily(e), uaddr, sock_address_get_port(e),
    147                         strerror(errno));
    148             if (try_next) {
    149                 sock_address_set_port(e, sock_address_get_port(e) + 1);
    150                 continue;
    151             }
    152             break;
    153         }
    154     }
    155     sock_address_list_free(list);
    156     fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
    157     return -1;
    158 
    159 listen:
    160     if (socket_listen(slisten,1) != 0) {
    161         perror("listen");
    162         socket_close(slisten);
    163         return -1;
    164     }
    165     if (ostr) {
    166         if (flags & SOCKET_LIST_FORCE_IN6) {
    167             snprintf(ostr, olen, "[%s]:%d%s", uaddr,
    168                      sock_address_get_port(e) - port_offset, opts);
    169         } else {
    170             snprintf(ostr, olen, "%s:%d%s", uaddr,
    171                      sock_address_get_port(e) - port_offset, opts);
    172         }
    173     }
    174     sock_address_list_free(list);
    175     return slisten;
    176 }
    177 
    178 int inet_connect(const char *str, SocketType socktype)
    179 {
    180     SockAddress**  list;
    181     SockAddress*   e;
    182     unsigned       flags = 0;
    183     char addr[64];
    184     char port[33];
    185     int sock, nn;
    186 
    187     /* parse address */
    188     if (str[0] == '[') {
    189         /* IPv6 addr */
    190         if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
    191             fprintf(stderr, "%s: ipv6 parse error (%s)\n",
    192                     __FUNCTION__, str);
    193             return -1;
    194         }
    195         flags |= SOCKET_LIST_FORCE_IN6;
    196     } else if (qemu_isdigit(str[0])) {
    197         /* IPv4 addr */
    198         if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
    199             fprintf(stderr, "%s: ipv4 parse error (%s)\n",
    200                     __FUNCTION__, str);
    201             return -1;
    202         }
    203         flags |= SOCKET_LIST_FORCE_INET;
    204     } else {
    205         /* hostname */
    206         if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
    207             fprintf(stderr, "%s: hostname parse error (%s)\n",
    208                     __FUNCTION__, str);
    209             return -1;
    210         }
    211     }
    212 
    213     /* parse options */
    214     if (strstr(str, ",ipv4")) {
    215         flags &= SOCKET_LIST_FORCE_IN6;
    216         flags |= SOCKET_LIST_FORCE_INET;
    217     }
    218     if (strstr(str, ",ipv6")) {
    219         flags &= SOCKET_LIST_FORCE_INET;
    220         flags |= SOCKET_LIST_FORCE_IN6;
    221     }
    222 
    223     /* lookup */
    224     list = sock_address_list_create(addr, port, flags);
    225     if (list == NULL) {
    226         fprintf(stderr,"getaddrinfo(%s,%s): %s\n",
    227                 addr, port, errno_str);
    228         return -1;
    229     }
    230 
    231     for (nn = 0; list[nn] != NULL; nn++) {
    232         e     = list[nn];
    233         sock = socket_create(sock_address_get_family(e), socktype);
    234         if (sock < 0) {
    235             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
    236             sock_address_strfamily(e), errno_str);
    237             continue;
    238         }
    239         socket_set_xreuseaddr(sock);
    240 
    241         /* connect to peer */
    242         if (socket_connect(sock,e) < 0) {
    243             if (sockets_debug)
    244                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
    245                         sock_address_strfamily(e),
    246                         sock_address_to_string(e), addr, port, strerror(errno));
    247             socket_close(sock);
    248             continue;
    249         }
    250         if (sockets_debug)
    251             fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
    252                         sock_address_strfamily(e),
    253                         sock_address_to_string(e), addr, port);
    254 
    255         goto EXIT;
    256     }
    257     sock = -1;
    258 EXIT:
    259     sock_address_list_free(list);
    260     return sock;
    261 }
    262 
    263 #ifndef _WIN32
    264 
    265 int unix_listen(const char *str, char *ostr, int olen)
    266 {
    267     SockAddress  un;
    268     char         unpath[PATH_MAX];
    269     char *path, *upath, *opts;
    270     int sock, fd, len;
    271 
    272     opts = strchr(str, ',');
    273     if (opts) {
    274         len = opts - str;
    275         path = qemu_malloc(len+1);
    276         snprintf(path, len+1, "%.*s", len, str);
    277     } else
    278         path = qemu_strdup(str);
    279 
    280     if (path || strlen(path) > 0) {
    281         upath = path;
    282     } else {
    283         char *tmpdir = getenv("TMPDIR");
    284         snprintf(unpath, sizeof(unpath), "%s/qemu-socket-XXXXXX",
    285                  tmpdir ? tmpdir : "/tmp");
    286         /*
    287          * This dummy fd usage silences the mktemp() unsecure warning.
    288          * Using mkstemp() doesn't make things more secure here
    289          * though.  bind() complains about existing files, so we have
    290          * to unlink first and thus re-open the race window.  The
    291          * worst case possible is bind() failing, i.e. a DoS attack.
    292          */
    293         fd = mkstemp(unpath); close(fd);
    294         upath = unpath;
    295     }
    296     snprintf(ostr, olen, "%s%s", path, opts ? opts : "");
    297 
    298     sock = socket_unix_server(upath, SOCKET_STREAM);
    299     sock_address_done(&un);
    300 
    301     if (sock < 0) {
    302         fprintf(stderr, "bind(unix:%s): %s\n", upath, errno_str);
    303         goto err;
    304     }
    305 
    306     if (sockets_debug)
    307         fprintf(stderr, "bind(unix:%s): OK\n", upath);
    308 
    309     qemu_free(path);
    310     return sock;
    311 
    312 err:
    313     qemu_free(path);
    314     socket_close(sock);
    315     return -1;
    316 }
    317 
    318 int unix_connect(const char *path)
    319 {
    320     SockAddress  un;
    321     int ret, sock;
    322 
    323     sock = socket_create_unix(SOCKET_STREAM);
    324     if (sock < 0) {
    325         perror("socket(unix)");
    326         return -1;
    327     }
    328 
    329     sock_address_init_unix(&un, path);
    330     ret = socket_connect(sock, &un);
    331     sock_address_done(&un);
    332     if (ret < 0) {
    333         fprintf(stderr, "connect(unix:%s): %s\n", path, errno_str);
    334         return -1;
    335     }
    336 
    337 
    338     if (sockets_debug)
    339         fprintf(stderr, "connect(unix:%s): OK\n", path);
    340     return sock;
    341 }
    342 
    343 #else
    344 
    345 int unix_listen(const char *path, char *ostr, int olen)
    346 {
    347     fprintf(stderr, "unix sockets are not available on windows\n");
    348     return -1;
    349 }
    350 
    351 int unix_connect(const char *path)
    352 {
    353     fprintf(stderr, "unix sockets are not available on windows\n");
    354     return -1;
    355 }
    356 
    357 #endif
    358