copyright & license for qemu_sockets.c (Gerd Hoffman)
[qemu] / qemu-sockets.c
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
24 #ifndef AI_ADDRCONFIG
25 # define AI_ADDRCONFIG 0
26 #endif
27
28 static int sockets_debug = 0;
29 static const int on=1, off=0;
30
31 static int inet_getport(struct addrinfo *e)
32 {
33     struct sockaddr_in *i4;
34     struct sockaddr_in6 *i6;
35
36     switch (e->ai_family) {
37     case PF_INET6:
38         i6 = (void*)e->ai_addr;
39         return ntohs(i6->sin6_port);
40     case PF_INET:
41         i4 = (void*)e->ai_addr;
42         return ntohs(i4->sin_port);
43     default:
44         return 0;
45     }
46 }
47
48 static void inet_setport(struct addrinfo *e, int port)
49 {
50     struct sockaddr_in *i4;
51     struct sockaddr_in6 *i6;
52
53     switch (e->ai_family) {
54     case PF_INET6:
55         i6 = (void*)e->ai_addr;
56         i6->sin6_port = htons(port);
57         break;
58     case PF_INET:
59         i4 = (void*)e->ai_addr;
60         i4->sin_port = htons(port);
61         break;
62     }
63 }
64
65 static const char *inet_strfamily(int family)
66 {
67     switch (family) {
68     case PF_INET6: return "ipv6";
69     case PF_INET:  return "ipv4";
70     case PF_UNIX:  return "unix";
71     }
72     return "????";
73 }
74
75 static void inet_print_addrinfo(const char *tag, struct addrinfo *res)
76 {
77     struct addrinfo *e;
78     char uaddr[INET6_ADDRSTRLEN+1];
79     char uport[33];
80
81     for (e = res; e != NULL; e = e->ai_next) {
82         getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
83                     uaddr,INET6_ADDRSTRLEN,uport,32,
84                     NI_NUMERICHOST | NI_NUMERICSERV);
85         fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n",
86                 tag, inet_strfamily(e->ai_family), uaddr, uport);
87     }
88 }
89
90 int inet_listen(const char *str, char *ostr, int olen,
91                 int socktype, int port_offset)
92 {
93     struct addrinfo ai,*res,*e;
94     char addr[64];
95     char port[33];
96     char uaddr[INET6_ADDRSTRLEN+1];
97     char uport[33];
98     const char *opts, *h;
99     int slisten,rc,pos,to,try_next;
100
101     memset(&ai,0, sizeof(ai));
102     ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
103     ai.ai_family = PF_UNSPEC;
104     ai.ai_socktype = socktype;
105
106     /* parse address */
107     if (str[0] == ':') {
108         /* no host given */
109         strcpy(addr,"");
110         if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
111             fprintf(stderr, "%s: portonly parse error (%s)\n",
112                     __FUNCTION__, str);
113             return -1;
114         }
115     } else if (str[0] == '[') {
116         /* IPv6 addr */
117         if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
118             fprintf(stderr, "%s: ipv6 parse error (%s)\n",
119                     __FUNCTION__, str);
120             return -1;
121         }
122         ai.ai_family = PF_INET6;
123     } else if (isdigit(str[0])) {
124         /* IPv4 addr */
125         if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
126             fprintf(stderr, "%s: ipv4 parse error (%s)\n",
127                     __FUNCTION__, str);
128             return -1;
129         }
130         ai.ai_family = PF_INET;
131     } else {
132         /* hostname */
133         if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
134             fprintf(stderr, "%s: hostname parse error (%s)\n",
135                     __FUNCTION__, str);
136             return -1;
137         }
138     }
139
140     /* parse options */
141     opts = str + pos;
142     h = strstr(opts, ",to=");
143     to = h ? atoi(h+4) : 0;
144     if (strstr(opts, ",ipv4"))
145         ai.ai_family = PF_INET;
146     if (strstr(opts, ",ipv6"))
147         ai.ai_family = PF_INET6;
148
149     /* lookup */
150     if (port_offset)
151         snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
152     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
153     if (rc != 0) {
154         fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__,
155                 addr, port, gai_strerror(rc));
156         return -1;
157     }
158     if (sockets_debug)
159         inet_print_addrinfo(__FUNCTION__, res);
160
161     /* create socket + bind */
162     for (e = res; e != NULL; e = e->ai_next) {
163         getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
164                     uaddr,INET6_ADDRSTRLEN,uport,32,
165                     NI_NUMERICHOST | NI_NUMERICSERV);
166         slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
167         if (slisten < 0) {
168             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
169                     inet_strfamily(e->ai_family), strerror(errno));
170             continue;
171         }
172
173         setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
174 #ifdef IPV6_V6ONLY
175         if (e->ai_family == PF_INET6) {
176             /* listen on both ipv4 and ipv6 */
177             setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off));
178         }
179 #endif
180
181         for (;;) {
182             if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
183                 if (sockets_debug)
184                     fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
185                             inet_strfamily(e->ai_family), uaddr, inet_getport(e));
186                 goto listen;
187             }
188             try_next = to && (inet_getport(e) <= to + port_offset);
189             if (!try_next || sockets_debug)
190                 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
191                         inet_strfamily(e->ai_family), uaddr, inet_getport(e),
192                         strerror(errno));
193             if (try_next) {
194                 inet_setport(e, inet_getport(e) + 1);
195                 continue;
196             }
197             break;
198         }
199         closesocket(slisten);
200     }
201     fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
202     freeaddrinfo(res);
203     return -1;
204
205 listen:
206     if (listen(slisten,1) != 0) {
207         perror("listen");
208         closesocket(slisten);
209         return -1;
210     }
211     if (ostr) {
212         if (e->ai_family == PF_INET6) {
213             snprintf(ostr, olen, "[%s]:%d%s", uaddr,
214                      inet_getport(e) - port_offset, opts);
215         } else {
216             snprintf(ostr, olen, "%s:%d%s", uaddr,
217                      inet_getport(e) - port_offset, opts);
218         }
219     }
220     freeaddrinfo(res);
221     return slisten;
222 }
223
224 int inet_connect(const char *str, int socktype)
225 {
226     struct addrinfo ai,*res,*e;
227     char addr[64];
228     char port[33];
229     char uaddr[INET6_ADDRSTRLEN+1];
230     char uport[33];
231     int sock,rc;
232
233     memset(&ai,0, sizeof(ai));
234     ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
235     ai.ai_family = PF_UNSPEC;
236     ai.ai_socktype = socktype;
237
238     /* parse address */
239     if (str[0] == '[') {
240         /* IPv6 addr */
241         if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) {
242             fprintf(stderr, "%s: ipv6 parse error (%s)\n",
243                     __FUNCTION__, str);
244             return -1;
245         }
246         ai.ai_family = PF_INET6;
247     } else if (isdigit(str[0])) {
248         /* IPv4 addr */
249         if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) {
250             fprintf(stderr, "%s: ipv4 parse error (%s)\n",
251                     __FUNCTION__, str);
252             return -1;
253         }
254         ai.ai_family = PF_INET;
255     } else {
256         /* hostname */
257         if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) {
258             fprintf(stderr, "%s: hostname parse error (%s)\n",
259                     __FUNCTION__, str);
260             return -1;
261         }
262     }
263
264     /* parse options */
265     if (strstr(str, ",ipv4"))
266         ai.ai_family = PF_INET;
267     if (strstr(str, ",ipv6"))
268         ai.ai_family = PF_INET6;
269
270     /* lookup */
271     if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
272         fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc),
273                 addr, port);
274         return -1;
275     }
276     if (sockets_debug)
277         inet_print_addrinfo(__FUNCTION__, res);
278
279     for (e = res; e != NULL; e = e->ai_next) {
280         if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
281                         uaddr,INET6_ADDRSTRLEN,uport,32,
282                         NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
283             fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
284             continue;
285         }
286         sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol);
287         if (sock < 0) {
288             fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
289                     inet_strfamily(e->ai_family), strerror(errno));
290             continue;
291         }
292         setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
293
294         /* connect to peer */
295         if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
296             if (sockets_debug || NULL == e->ai_next)
297                 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
298                         inet_strfamily(e->ai_family),
299                         e->ai_canonname, uaddr, uport, strerror(errno));
300             closesocket(sock);
301             continue;
302         }
303         if (sockets_debug)
304             fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__,
305                     inet_strfamily(e->ai_family),
306                     e->ai_canonname, uaddr, uport);
307         freeaddrinfo(res);
308         return sock;
309     }
310     freeaddrinfo(res);
311     return -1;
312 }
313
314 #ifndef _WIN32
315
316 int unix_listen(const char *str, char *ostr, int olen)
317 {
318     struct sockaddr_un un;
319     char *path, *opts;
320     int sock, fd, len;
321
322     sock = socket(PF_UNIX, SOCK_STREAM, 0);
323     if (sock < 0) {
324         perror("socket(unix)");
325         return -1;
326     }
327
328     opts = strchr(str, ',');
329     if (opts) {
330         len = opts - str;
331         path = malloc(len+1);
332         snprintf(path, len+1, "%.*s", len, str);
333     } else
334         path = strdup(str);
335
336     memset(&un, 0, sizeof(un));
337     un.sun_family = AF_UNIX;
338     if (path && strlen(path)) {
339         snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
340     } else {
341         char *tmpdir = getenv("TMPDIR");
342         snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
343                  tmpdir ? tmpdir : "/tmp");
344         /*
345          * This dummy fd usage silences the mktemp() unsecure warning.
346          * Using mkstemp() doesn't make things more secure here
347          * though.  bind() complains about existing files, so we have
348          * to unlink first and thus re-open the race window.  The
349          * worst case possible is bind() failing, i.e. a DoS attack.
350          */
351         fd = mkstemp(un.sun_path); close(fd);
352     }
353     snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : "");
354
355     unlink(un.sun_path);
356     if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
357         fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
358         goto err;
359     }
360     if (listen(sock, 1) < 0) {
361         fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
362         goto err;
363     }
364
365     if (sockets_debug)
366         fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path);
367     free(path);
368     return sock;
369
370 err:
371     free(path);
372     closesocket(sock);
373     return -1;
374 }
375
376 int unix_connect(const char *path)
377 {
378     struct sockaddr_un un;
379     int sock;
380
381     sock = socket(PF_UNIX, SOCK_STREAM, 0);
382     if (sock < 0) {
383         perror("socket(unix)");
384         return -1;
385     }
386
387     memset(&un, 0, sizeof(un));
388     un.sun_family = AF_UNIX;
389     snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
390     if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
391         fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
392         return -1;
393     }
394
395     if (sockets_debug)
396         fprintf(stderr, "connect(unix:%s): OK\n", path);
397     return sock;
398 }
399
400 #else
401
402 int unix_listen(const char *path, char *ostr, int olen)
403 {
404     fprintf(stderr, "unix sockets are not available on windows\n");
405     return -1;
406 }
407
408 int unix_connect(const char *path)
409 {
410     fprintf(stderr, "unix sockets are not available on windows\n");
411     return -1;
412 }
413
414 #endif