• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
sock_address_strfamily(SockAddress * s)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 
inet_listen_opts(QemuOpts * opts,int port_offset)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 
inet_connect_opts(QemuOpts * opts)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 
inet_dgram_opts(QemuOpts * opts)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 */
inet_parse(QemuOpts * opts,const char * str)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 
inet_listen(const char * str,char * ostr,int olen,int socktype,int port_offset)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 
inet_connect(const char * str,int socktype)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 
unix_listen_opts(QemuOpts * opts)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 
unix_connect_opts(QemuOpts * opts)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 */
unix_listen(const char * str,char * ostr,int olen)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 
unix_connect(const char * path)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 
unix_listen_opts(QemuOpts * opts)598 int unix_listen_opts(QemuOpts *opts)
599 {
600     fprintf(stderr, "unix sockets are not available on windows\n");
601     return -1;
602 }
603 
unix_connect_opts(QemuOpts * opts)604 int unix_connect_opts(QemuOpts *opts)
605 {
606     fprintf(stderr, "unix sockets are not available on windows\n");
607     return -1;
608 }
609 
unix_listen(const char * path,char * ostr,int olen)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 
unix_connect(const char * path)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
socket_cleanup(void)626 static void socket_cleanup(void)
627 {
628     WSACleanup();
629 }
630 #endif
631 
socket_init(void)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