Statistics
| Branch: | Revision:

root / qemu-sockets.c @ b072a3c8

History | View | Annotate | Download (17.5 kB)

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
        { /* end if list */ }
56
    },
57
};
58

    
59
static int inet_getport(struct addrinfo *e)
60
{
61
    struct sockaddr_in *i4;
62
    struct sockaddr_in6 *i6;
63

    
64
    switch (e->ai_family) {
65
    case PF_INET6:
66
        i6 = (void*)e->ai_addr;
67
        return ntohs(i6->sin6_port);
68
    case PF_INET:
69
        i4 = (void*)e->ai_addr;
70
        return ntohs(i4->sin_port);
71
    default:
72
        return 0;
73
    }
74
}
75

    
76
static void inet_setport(struct addrinfo *e, int port)
77
{
78
    struct sockaddr_in *i4;
79
    struct sockaddr_in6 *i6;
80

    
81
    switch (e->ai_family) {
82
    case PF_INET6:
83
        i6 = (void*)e->ai_addr;
84
        i6->sin6_port = htons(port);
85
        break;
86
    case PF_INET:
87
        i4 = (void*)e->ai_addr;
88
        i4->sin_port = htons(port);
89
        break;
90
    }
91
}
92

    
93
const char *inet_strfamily(int family)
94
{
95
    switch (family) {
96
    case PF_INET6: return "ipv6";
97
    case PF_INET:  return "ipv4";
98
    case PF_UNIX:  return "unix";
99
    }
100
    return "unknown";
101
}
102

    
103
int inet_listen_opts(QemuOpts *opts, int port_offset)
104
{
105
    struct addrinfo ai,*res,*e;
106
    const char *addr;
107
    char port[33];
108
    char uaddr[INET6_ADDRSTRLEN+1];
109
    char uport[33];
110
    int slisten, rc, to, port_min, port_max, p;
111

    
112
    memset(&ai,0, sizeof(ai));
113
    ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
114
    ai.ai_family = PF_UNSPEC;
115
    ai.ai_socktype = SOCK_STREAM;
116

    
117
    if ((qemu_opt_get(opts, "host") == NULL) ||
118
        (qemu_opt_get(opts, "port") == NULL)) {
119
        fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
120
        return -1;
121
    }
122
    pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
123
    addr = qemu_opt_get(opts, "host");
124

    
125
    to = qemu_opt_get_number(opts, "to", 0);
126
    if (qemu_opt_get_bool(opts, "ipv4", 0))
127
        ai.ai_family = PF_INET;
128
    if (qemu_opt_get_bool(opts, "ipv6", 0))
129
        ai.ai_family = PF_INET6;
130

    
131
    /* lookup */
132
    if (port_offset)
133
        snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
134
    rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
135
    if (rc != 0) {
136
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
137
                gai_strerror(rc));
138
        return -1;
139
    }
140

    
141
    /* create socket + bind */
142
    for (e = res; e != NULL; e = e->ai_next) {
143
        getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
144
                        uaddr,INET6_ADDRSTRLEN,uport,32,
145
                        NI_NUMERICHOST | NI_NUMERICSERV);
146
        slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
147
        if (slisten < 0) {
148
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
149
                    inet_strfamily(e->ai_family), strerror(errno));
150
            continue;
151
        }
152

    
153
        setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
154
#ifdef IPV6_V6ONLY
155
        if (e->ai_family == PF_INET6) {
156
            /* listen on both ipv4 and ipv6 */
157
            setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
158
                sizeof(off));
159
        }
160
#endif
161

    
162
        port_min = inet_getport(e);
163
        port_max = to ? to + port_offset : port_min;
164
        for (p = port_min; p <= port_max; p++) {
165
            inet_setport(e, p);
166
            if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
167
                goto listen;
168
            }
169
            if (p == port_max) {
170
                fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
171
                        inet_strfamily(e->ai_family), uaddr, inet_getport(e),
172
                        strerror(errno));
173
            }
174
        }
175
        closesocket(slisten);
176
    }
177
    fprintf(stderr, "%s: FAILED\n", __FUNCTION__);
178
    freeaddrinfo(res);
179
    return -1;
180

    
181
listen:
182
    if (listen(slisten,1) != 0) {
183
        perror("listen");
184
        closesocket(slisten);
185
        freeaddrinfo(res);
186
        return -1;
187
    }
188
    snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
189
    qemu_opt_set(opts, "host", uaddr);
190
    qemu_opt_set(opts, "port", uport);
191
    qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
192
    qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
193
    freeaddrinfo(res);
194
    return slisten;
195
}
196

    
197
int inet_connect_opts(QemuOpts *opts)
198
{
199
    struct addrinfo ai,*res,*e;
200
    const char *addr;
201
    const char *port;
202
    char uaddr[INET6_ADDRSTRLEN+1];
203
    char uport[33];
204
    int sock,rc;
205

    
206
    memset(&ai,0, sizeof(ai));
207
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
208
    ai.ai_family = PF_UNSPEC;
209
    ai.ai_socktype = SOCK_STREAM;
210

    
211
    addr = qemu_opt_get(opts, "host");
212
    port = qemu_opt_get(opts, "port");
213
    if (addr == NULL || port == NULL) {
214
        fprintf(stderr, "inet_connect: host and/or port not specified\n");
215
        return -1;
216
    }
217

    
218
    if (qemu_opt_get_bool(opts, "ipv4", 0))
219
        ai.ai_family = PF_INET;
220
    if (qemu_opt_get_bool(opts, "ipv6", 0))
221
        ai.ai_family = PF_INET6;
222

    
223
    /* lookup */
224
    if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
225
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
226
                gai_strerror(rc));
227
        return -1;
228
    }
229

    
230
    for (e = res; e != NULL; e = e->ai_next) {
231
        if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
232
                            uaddr,INET6_ADDRSTRLEN,uport,32,
233
                            NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
234
            fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__);
235
            continue;
236
        }
237
        sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
238
        if (sock < 0) {
239
            fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
240
            inet_strfamily(e->ai_family), strerror(errno));
241
            continue;
242
        }
243
        setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
244

    
245
        /* connect to peer */
246
        if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
247
            if (NULL == e->ai_next)
248
                fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
249
                        inet_strfamily(e->ai_family),
250
                        e->ai_canonname, uaddr, uport, strerror(errno));
251
            closesocket(sock);
252
            continue;
253
        }
254
        freeaddrinfo(res);
255
        return sock;
256
    }
257
    freeaddrinfo(res);
258
    return -1;
259
}
260

    
261
int inet_dgram_opts(QemuOpts *opts)
262
{
263
    struct addrinfo ai, *peer = NULL, *local = NULL;
264
    const char *addr;
265
    const char *port;
266
    char uaddr[INET6_ADDRSTRLEN+1];
267
    char uport[33];
268
    int sock = -1, rc;
269

    
270
    /* lookup peer addr */
271
    memset(&ai,0, sizeof(ai));
272
    ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
273
    ai.ai_family = PF_UNSPEC;
274
    ai.ai_socktype = SOCK_DGRAM;
275

    
276
    addr = qemu_opt_get(opts, "host");
277
    port = qemu_opt_get(opts, "port");
278
    if (addr == NULL || strlen(addr) == 0) {
279
        addr = "localhost";
280
    }
281
    if (port == NULL || strlen(port) == 0) {
282
        fprintf(stderr, "inet_dgram: port not specified\n");
283
        return -1;
284
    }
285

    
286
    if (qemu_opt_get_bool(opts, "ipv4", 0))
287
        ai.ai_family = PF_INET;
288
    if (qemu_opt_get_bool(opts, "ipv6", 0))
289
        ai.ai_family = PF_INET6;
290

    
291
    if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
292
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
293
                gai_strerror(rc));
294
        return -1;
295
    }
296

    
297
    /* lookup local addr */
298
    memset(&ai,0, sizeof(ai));
299
    ai.ai_flags = AI_PASSIVE;
300
    ai.ai_family = peer->ai_family;
301
    ai.ai_socktype = SOCK_DGRAM;
302

    
303
    addr = qemu_opt_get(opts, "localaddr");
304
    port = qemu_opt_get(opts, "localport");
305
    if (addr == NULL || strlen(addr) == 0) {
306
        addr = NULL;
307
    }
308
    if (!port || strlen(port) == 0)
309
        port = "0";
310

    
311
    if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
312
        fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
313
                gai_strerror(rc));
314
        return -1;
315
    }
316

    
317
    /* create socket */
318
    sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
319
    if (sock < 0) {
320
        fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
321
                inet_strfamily(peer->ai_family), strerror(errno));
322
        goto err;
323
    }
324
    setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
325

    
326
    /* bind socket */
327
    if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen,
328
                    uaddr,INET6_ADDRSTRLEN,uport,32,
329
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
330
        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
331
        goto err;
332
    }
333
    if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
334
        fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__,
335
                inet_strfamily(local->ai_family), uaddr, inet_getport(local));
336
        goto err;
337
    }
338

    
339
    /* connect to peer */
340
    if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen,
341
                    uaddr, INET6_ADDRSTRLEN, uport, 32,
342
                    NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
343
        fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__);
344
        goto err;
345
    }
346
    if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
347
        fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
348
                inet_strfamily(peer->ai_family),
349
                peer->ai_canonname, uaddr, uport, strerror(errno));
350
        goto err;
351
    }
352

    
353
    freeaddrinfo(local);
354
    freeaddrinfo(peer);
355
    return sock;
356

    
357
err:
358
    if (-1 != sock)
359
        closesocket(sock);
360
    if (local)
361
        freeaddrinfo(local);
362
    if (peer)
363
        freeaddrinfo(peer);
364
    return -1;
365
}
366

    
367
/* compatibility wrapper */
368
static int inet_parse(QemuOpts *opts, const char *str)
369
{
370
    const char *optstr, *h;
371
    char addr[64];
372
    char port[33];
373
    int pos;
374

    
375
    /* parse address */
376
    if (str[0] == ':') {
377
        /* no host given */
378
        addr[0] = '\0';
379
        if (1 != sscanf(str,":%32[^,]%n",port,&pos)) {
380
            fprintf(stderr, "%s: portonly parse error (%s)\n",
381
                    __FUNCTION__, str);
382
            return -1;
383
        }
384
    } else if (str[0] == '[') {
385
        /* IPv6 addr */
386
        if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) {
387
            fprintf(stderr, "%s: ipv6 parse error (%s)\n",
388
                    __FUNCTION__, str);
389
            return -1;
390
        }
391
        qemu_opt_set(opts, "ipv6", "on");
392
    } else if (qemu_isdigit(str[0])) {
393
        /* IPv4 addr */
394
        if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
395
            fprintf(stderr, "%s: ipv4 parse error (%s)\n",
396
                    __FUNCTION__, str);
397
            return -1;
398
        }
399
        qemu_opt_set(opts, "ipv4", "on");
400
    } else {
401
        /* hostname */
402
        if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
403
            fprintf(stderr, "%s: hostname parse error (%s)\n",
404
                    __FUNCTION__, str);
405
            return -1;
406
        }
407
    }
408
    qemu_opt_set(opts, "host", addr);
409
    qemu_opt_set(opts, "port", port);
410

    
411
    /* parse options */
412
    optstr = str + pos;
413
    h = strstr(optstr, ",to=");
414
    if (h)
415
        qemu_opt_set(opts, "to", h+4);
416
    if (strstr(optstr, ",ipv4"))
417
        qemu_opt_set(opts, "ipv4", "on");
418
    if (strstr(optstr, ",ipv6"))
419
        qemu_opt_set(opts, "ipv6", "on");
420
    return 0;
421
}
422

    
423
int inet_listen(const char *str, char *ostr, int olen,
424
                int socktype, int port_offset)
425
{
426
    QemuOpts *opts;
427
    char *optstr;
428
    int sock = -1;
429

    
430
    opts = qemu_opts_create(&dummy_opts, NULL, 0);
431
    if (inet_parse(opts, str) == 0) {
432
        sock = inet_listen_opts(opts, port_offset);
433
        if (sock != -1 && ostr) {
434
            optstr = strchr(str, ',');
435
            if (qemu_opt_get_bool(opts, "ipv6", 0)) {
436
                snprintf(ostr, olen, "[%s]:%s%s",
437
                         qemu_opt_get(opts, "host"),
438
                         qemu_opt_get(opts, "port"),
439
                         optstr ? optstr : "");
440
            } else {
441
                snprintf(ostr, olen, "%s:%s%s",
442
                         qemu_opt_get(opts, "host"),
443
                         qemu_opt_get(opts, "port"),
444
                         optstr ? optstr : "");
445
            }
446
        }
447
    }
448
    qemu_opts_del(opts);
449
    return sock;
450
}
451

    
452
int inet_connect(const char *str, int socktype)
453
{
454
    QemuOpts *opts;
455
    int sock = -1;
456

    
457
    opts = qemu_opts_create(&dummy_opts, NULL, 0);
458
    if (inet_parse(opts, str) == 0)
459
        sock = inet_connect_opts(opts);
460
    qemu_opts_del(opts);
461
    return sock;
462
}
463

    
464
#ifndef _WIN32
465

    
466
int unix_listen_opts(QemuOpts *opts)
467
{
468
    struct sockaddr_un un;
469
    const char *path = qemu_opt_get(opts, "path");
470
    int sock, fd;
471

    
472
    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
473
    if (sock < 0) {
474
        perror("socket(unix)");
475
        return -1;
476
    }
477

    
478
    memset(&un, 0, sizeof(un));
479
    un.sun_family = AF_UNIX;
480
    if (path && strlen(path)) {
481
        snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
482
    } else {
483
        char *tmpdir = getenv("TMPDIR");
484
        snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
485
                 tmpdir ? tmpdir : "/tmp");
486
        /*
487
         * This dummy fd usage silences the mktemp() unsecure warning.
488
         * Using mkstemp() doesn't make things more secure here
489
         * though.  bind() complains about existing files, so we have
490
         * to unlink first and thus re-open the race window.  The
491
         * worst case possible is bind() failing, i.e. a DoS attack.
492
         */
493
        fd = mkstemp(un.sun_path); close(fd);
494
        qemu_opt_set(opts, "path", un.sun_path);
495
    }
496

    
497
    unlink(un.sun_path);
498
    if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
499
        fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno));
500
        goto err;
501
    }
502
    if (listen(sock, 1) < 0) {
503
        fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno));
504
        goto err;
505
    }
506

    
507
    return sock;
508

    
509
err:
510
    closesocket(sock);
511
    return -1;
512
}
513

    
514
int unix_connect_opts(QemuOpts *opts)
515
{
516
    struct sockaddr_un un;
517
    const char *path = qemu_opt_get(opts, "path");
518
    int sock;
519

    
520
    if (NULL == path) {
521
        fprintf(stderr, "unix connect: no path specified\n");
522
        return -1;
523
    }
524

    
525
    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
526
    if (sock < 0) {
527
        perror("socket(unix)");
528
        return -1;
529
    }
530

    
531
    memset(&un, 0, sizeof(un));
532
    un.sun_family = AF_UNIX;
533
    snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
534
    if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
535
        fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
536
        close(sock);
537
        return -1;
538
    }
539

    
540
    return sock;
541
}
542

    
543
/* compatibility wrapper */
544
int unix_listen(const char *str, char *ostr, int olen)
545
{
546
    QemuOpts *opts;
547
    char *path, *optstr;
548
    int sock, len;
549

    
550
    opts = qemu_opts_create(&dummy_opts, NULL, 0);
551

    
552
    optstr = strchr(str, ',');
553
    if (optstr) {
554
        len = optstr - str;
555
        if (len) {
556
            path = g_malloc(len+1);
557
            snprintf(path, len+1, "%.*s", len, str);
558
            qemu_opt_set(opts, "path", path);
559
            g_free(path);
560
        }
561
    } else {
562
        qemu_opt_set(opts, "path", str);
563
    }
564

    
565
    sock = unix_listen_opts(opts);
566

    
567
    if (sock != -1 && ostr)
568
        snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
569
    qemu_opts_del(opts);
570
    return sock;
571
}
572

    
573
int unix_connect(const char *path)
574
{
575
    QemuOpts *opts;
576
    int sock;
577

    
578
    opts = qemu_opts_create(&dummy_opts, NULL, 0);
579
    qemu_opt_set(opts, "path", path);
580
    sock = unix_connect_opts(opts);
581
    qemu_opts_del(opts);
582
    return sock;
583
}
584

    
585
#else
586

    
587
int unix_listen_opts(QemuOpts *opts)
588
{
589
    fprintf(stderr, "unix sockets are not available on windows\n");
590
    errno = ENOTSUP;
591
    return -1;
592
}
593

    
594
int unix_connect_opts(QemuOpts *opts)
595
{
596
    fprintf(stderr, "unix sockets are not available on windows\n");
597
    errno = ENOTSUP;
598
    return -1;
599
}
600

    
601
int unix_listen(const char *path, char *ostr, int olen)
602
{
603
    fprintf(stderr, "unix sockets are not available on windows\n");
604
    errno = ENOTSUP;
605
    return -1;
606
}
607

    
608
int unix_connect(const char *path)
609
{
610
    fprintf(stderr, "unix sockets are not available on windows\n");
611
    errno = ENOTSUP;
612
    return -1;
613
}
614

    
615
#endif
616

    
617
#ifdef _WIN32
618
static void socket_cleanup(void)
619
{
620
    WSACleanup();
621
}
622
#endif
623

    
624
int socket_init(void)
625
{
626
#ifdef _WIN32
627
    WSADATA Data;
628
    int ret, err;
629

    
630
    ret = WSAStartup(MAKEWORD(2,2), &Data);
631
    if (ret != 0) {
632
        err = WSAGetLastError();
633
        fprintf(stderr, "WSAStartup: %d\n", err);
634
        return -1;
635
    }
636
    atexit(socket_cleanup);
637
#endif
638
    return 0;
639
}