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