xref: /qemu/util/qemu-sockets.c (revision a6ba35b3be9d3d2874cd00930c954347e6be764c)
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