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#ifndef INET6_ADDRSTRLEN
30# define INET6_ADDRSTRLEN  46
31#endif
32
33static int sockets_debug = 0;
34static const int on=1, off=0;
35
36/* used temporarely until all users are converted to QemuOpts */
37static 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
70static 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
80int 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
172listen:
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
187int 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;
254EXIT:
255    sock_address_list_free(list);
256    return sock;
257}
258
259int 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;
360EXIT:
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 */
369static 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
443int 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
472int 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
486int 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
523err:
524    socket_close(sock);
525    return -1;
526}
527
528int 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 */
555int 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
584int 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
598int unix_listen_opts(QemuOpts *opts)
599{
600    fprintf(stderr, "unix sockets are not available on windows\n");
601    return -1;
602}
603
604int unix_connect_opts(QemuOpts *opts)
605{
606    fprintf(stderr, "unix sockets are not available on windows\n");
607    return -1;
608}
609
610int 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
616int 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
626static void socket_cleanup(void)
627{
628    WSACleanup();
629}
630#endif
631
632int 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