Statistics
| Branch: | Revision:

root / net / slirp.c @ 0834c9ea

History | View | Annotate | Download (21.3 kB)

1
/*
2
 * QEMU System Emulator
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "net/slirp.h"
25

    
26
#include "config-host.h"
27

    
28
#ifndef _WIN32
29
#include <pwd.h>
30
#include <sys/wait.h>
31
#endif
32
#include "net.h"
33
#include "net/hub.h"
34
#include "monitor.h"
35
#include "qemu_socket.h"
36
#include "slirp/libslirp.h"
37

    
38
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
39
{
40
    const char *p, *p1;
41
    int len;
42
    p = *pp;
43
    p1 = strchr(p, sep);
44
    if (!p1)
45
        return -1;
46
    len = p1 - p;
47
    p1++;
48
    if (buf_size > 0) {
49
        if (len > buf_size - 1)
50
            len = buf_size - 1;
51
        memcpy(buf, p, len);
52
        buf[len] = '\0';
53
    }
54
    *pp = p1;
55
    return 0;
56
}
57

    
58
/* slirp network adapter */
59

    
60
#define SLIRP_CFG_HOSTFWD 1
61
#define SLIRP_CFG_LEGACY  2
62

    
63
struct slirp_config_str {
64
    struct slirp_config_str *next;
65
    int flags;
66
    char str[1024];
67
    int legacy_format;
68
};
69

    
70
typedef struct SlirpState {
71
    NetClientState nc;
72
    QTAILQ_ENTRY(SlirpState) entry;
73
    Slirp *slirp;
74
#ifndef _WIN32
75
    char smb_dir[128];
76
#endif
77
} SlirpState;
78

    
79
static struct slirp_config_str *slirp_configs;
80
const char *legacy_tftp_prefix;
81
const char *legacy_bootp_filename;
82
static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
83
    QTAILQ_HEAD_INITIALIZER(slirp_stacks);
84

    
85
static int slirp_hostfwd(SlirpState *s, const char *redir_str,
86
                         int legacy_format);
87
static int slirp_guestfwd(SlirpState *s, const char *config_str,
88
                          int legacy_format);
89

    
90
#ifndef _WIN32
91
static const char *legacy_smb_export;
92

    
93
static int slirp_smb(SlirpState *s, const char *exported_dir,
94
                     struct in_addr vserver_addr);
95
static void slirp_smb_cleanup(SlirpState *s);
96
#else
97
static inline void slirp_smb_cleanup(SlirpState *s) { }
98
#endif
99

    
100
void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
101
{
102
    SlirpState *s = opaque;
103

    
104
    qemu_send_packet(&s->nc, pkt, pkt_len);
105
}
106

    
107
static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, size_t size)
108
{
109
    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
110

    
111
    slirp_input(s->slirp, buf, size);
112

    
113
    return size;
114
}
115

    
116
static void net_slirp_cleanup(NetClientState *nc)
117
{
118
    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
119

    
120
    slirp_cleanup(s->slirp);
121
    slirp_smb_cleanup(s);
122
    QTAILQ_REMOVE(&slirp_stacks, s, entry);
123
}
124

    
125
static NetClientInfo net_slirp_info = {
126
    .type = NET_CLIENT_OPTIONS_KIND_USER,
127
    .size = sizeof(SlirpState),
128
    .receive = net_slirp_receive,
129
    .cleanup = net_slirp_cleanup,
130
};
131

    
132
static int net_slirp_init(NetClientState *peer, const char *model,
133
                          const char *name, int restricted,
134
                          const char *vnetwork, const char *vhost,
135
                          const char *vhostname, const char *tftp_export,
136
                          const char *bootfile, const char *vdhcp_start,
137
                          const char *vnameserver, const char *smb_export,
138
                          const char *vsmbserver)
139
{
140
    /* default settings according to historic slirp */
141
    struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
142
    struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
143
    struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
144
    struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
145
    struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
146
#ifndef _WIN32
147
    struct in_addr smbsrv = { .s_addr = 0 };
148
#endif
149
    NetClientState *nc;
150
    SlirpState *s;
151
    char buf[20];
152
    uint32_t addr;
153
    int shift;
154
    char *end;
155
    struct slirp_config_str *config;
156

    
157
    if (!tftp_export) {
158
        tftp_export = legacy_tftp_prefix;
159
    }
160
    if (!bootfile) {
161
        bootfile = legacy_bootp_filename;
162
    }
163

    
164
    if (vnetwork) {
165
        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
166
            if (!inet_aton(vnetwork, &net)) {
167
                return -1;
168
            }
169
            addr = ntohl(net.s_addr);
170
            if (!(addr & 0x80000000)) {
171
                mask.s_addr = htonl(0xff000000); /* class A */
172
            } else if ((addr & 0xfff00000) == 0xac100000) {
173
                mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
174
            } else if ((addr & 0xc0000000) == 0x80000000) {
175
                mask.s_addr = htonl(0xffff0000); /* class B */
176
            } else if ((addr & 0xffff0000) == 0xc0a80000) {
177
                mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
178
            } else if ((addr & 0xffff0000) == 0xc6120000) {
179
                mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
180
            } else if ((addr & 0xe0000000) == 0xe0000000) {
181
                mask.s_addr = htonl(0xffffff00); /* class C */
182
            } else {
183
                mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
184
            }
185
        } else {
186
            if (!inet_aton(buf, &net)) {
187
                return -1;
188
            }
189
            shift = strtol(vnetwork, &end, 10);
190
            if (*end != '\0') {
191
                if (!inet_aton(vnetwork, &mask)) {
192
                    return -1;
193
                }
194
            } else if (shift < 4 || shift > 32) {
195
                return -1;
196
            } else {
197
                mask.s_addr = htonl(0xffffffff << (32 - shift));
198
            }
199
        }
200
        net.s_addr &= mask.s_addr;
201
        host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
202
        dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
203
        dns.s_addr  = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
204
    }
205

    
206
    if (vhost && !inet_aton(vhost, &host)) {
207
        return -1;
208
    }
209
    if ((host.s_addr & mask.s_addr) != net.s_addr) {
210
        return -1;
211
    }
212

    
213
    if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
214
        return -1;
215
    }
216
    if ((dhcp.s_addr & mask.s_addr) != net.s_addr ||
217
        dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
218
        return -1;
219
    }
220

    
221
    if (vnameserver && !inet_aton(vnameserver, &dns)) {
222
        return -1;
223
    }
224
    if ((dns.s_addr & mask.s_addr) != net.s_addr ||
225
        dns.s_addr == host.s_addr) {
226
        return -1;
227
    }
228

    
229
#ifndef _WIN32
230
    if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
231
        return -1;
232
    }
233
#endif
234

    
235
    nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
236

    
237
    snprintf(nc->info_str, sizeof(nc->info_str),
238
             "net=%s,restrict=%s", inet_ntoa(net),
239
             restricted ? "on" : "off");
240

    
241
    s = DO_UPCAST(SlirpState, nc, nc);
242

    
243
    s->slirp = slirp_init(restricted, net, mask, host, vhostname,
244
                          tftp_export, bootfile, dhcp, dns, s);
245
    QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
246

    
247
    for (config = slirp_configs; config; config = config->next) {
248
        if (config->flags & SLIRP_CFG_HOSTFWD) {
249
            if (slirp_hostfwd(s, config->str,
250
                              config->flags & SLIRP_CFG_LEGACY) < 0)
251
                goto error;
252
        } else {
253
            if (slirp_guestfwd(s, config->str,
254
                               config->flags & SLIRP_CFG_LEGACY) < 0)
255
                goto error;
256
        }
257
    }
258
#ifndef _WIN32
259
    if (!smb_export) {
260
        smb_export = legacy_smb_export;
261
    }
262
    if (smb_export) {
263
        if (slirp_smb(s, smb_export, smbsrv) < 0)
264
            goto error;
265
    }
266
#endif
267

    
268
    return 0;
269

    
270
error:
271
    qemu_del_net_client(nc);
272
    return -1;
273
}
274

    
275
static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
276
                                const char *stack)
277
{
278

    
279
    if (vlan) {
280
        NetClientState *nc;
281
        nc = net_hub_find_client_by_name(strtol(vlan, NULL, 0), stack);
282
        if (!nc) {
283
            return NULL;
284
        }
285
        if (strcmp(nc->model, "user")) {
286
            monitor_printf(mon, "invalid device specified\n");
287
            return NULL;
288
        }
289
        return DO_UPCAST(SlirpState, nc, nc);
290
    } else {
291
        if (QTAILQ_EMPTY(&slirp_stacks)) {
292
            monitor_printf(mon, "user mode network stack not in use\n");
293
            return NULL;
294
        }
295
        return QTAILQ_FIRST(&slirp_stacks);
296
    }
297
}
298

    
299
void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
300
{
301
    struct in_addr host_addr = { .s_addr = INADDR_ANY };
302
    int host_port;
303
    char buf[256];
304
    const char *src_str, *p;
305
    SlirpState *s;
306
    int is_udp = 0;
307
    int err;
308
    const char *arg1 = qdict_get_str(qdict, "arg1");
309
    const char *arg2 = qdict_get_try_str(qdict, "arg2");
310
    const char *arg3 = qdict_get_try_str(qdict, "arg3");
311

    
312
    if (arg2) {
313
        s = slirp_lookup(mon, arg1, arg2);
314
        src_str = arg3;
315
    } else {
316
        s = slirp_lookup(mon, NULL, NULL);
317
        src_str = arg1;
318
    }
319
    if (!s) {
320
        return;
321
    }
322

    
323
    p = src_str;
324
    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
325
        goto fail_syntax;
326
    }
327

    
328
    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
329
        is_udp = 0;
330
    } else if (!strcmp(buf, "udp")) {
331
        is_udp = 1;
332
    } else {
333
        goto fail_syntax;
334
    }
335

    
336
    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
337
        goto fail_syntax;
338
    }
339
    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
340
        goto fail_syntax;
341
    }
342

    
343
    host_port = atoi(p);
344

    
345
    err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
346
                               host_addr, host_port);
347

    
348
    monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
349
                   err ? "not found" : "removed");
350
    return;
351

    
352
 fail_syntax:
353
    monitor_printf(mon, "invalid format\n");
354
}
355

    
356
static int slirp_hostfwd(SlirpState *s, const char *redir_str,
357
                         int legacy_format)
358
{
359
    struct in_addr host_addr = { .s_addr = INADDR_ANY };
360
    struct in_addr guest_addr = { .s_addr = 0 };
361
    int host_port, guest_port;
362
    const char *p;
363
    char buf[256];
364
    int is_udp;
365
    char *end;
366

    
367
    p = redir_str;
368
    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
369
        goto fail_syntax;
370
    }
371
    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
372
        is_udp = 0;
373
    } else if (!strcmp(buf, "udp")) {
374
        is_udp = 1;
375
    } else {
376
        goto fail_syntax;
377
    }
378

    
379
    if (!legacy_format) {
380
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
381
            goto fail_syntax;
382
        }
383
        if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
384
            goto fail_syntax;
385
        }
386
    }
387

    
388
    if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
389
        goto fail_syntax;
390
    }
391
    host_port = strtol(buf, &end, 0);
392
    if (*end != '\0' || host_port < 1 || host_port > 65535) {
393
        goto fail_syntax;
394
    }
395

    
396
    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
397
        goto fail_syntax;
398
    }
399
    if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
400
        goto fail_syntax;
401
    }
402

    
403
    guest_port = strtol(p, &end, 0);
404
    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
405
        goto fail_syntax;
406
    }
407

    
408
    if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
409
                          guest_port) < 0) {
410
        error_report("could not set up host forwarding rule '%s'",
411
                     redir_str);
412
        return -1;
413
    }
414
    return 0;
415

    
416
 fail_syntax:
417
    error_report("invalid host forwarding rule '%s'", redir_str);
418
    return -1;
419
}
420

    
421
void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict)
422
{
423
    const char *redir_str;
424
    SlirpState *s;
425
    const char *arg1 = qdict_get_str(qdict, "arg1");
426
    const char *arg2 = qdict_get_try_str(qdict, "arg2");
427
    const char *arg3 = qdict_get_try_str(qdict, "arg3");
428

    
429
    if (arg2) {
430
        s = slirp_lookup(mon, arg1, arg2);
431
        redir_str = arg3;
432
    } else {
433
        s = slirp_lookup(mon, NULL, NULL);
434
        redir_str = arg1;
435
    }
436
    if (s) {
437
        slirp_hostfwd(s, redir_str, 0);
438
    }
439

    
440
}
441

    
442
int net_slirp_redir(const char *redir_str)
443
{
444
    struct slirp_config_str *config;
445

    
446
    if (QTAILQ_EMPTY(&slirp_stacks)) {
447
        config = g_malloc(sizeof(*config));
448
        pstrcpy(config->str, sizeof(config->str), redir_str);
449
        config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
450
        config->next = slirp_configs;
451
        slirp_configs = config;
452
        return 0;
453
    }
454

    
455
    return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1);
456
}
457

    
458
#ifndef _WIN32
459

    
460
/* automatic user mode samba server configuration */
461
static void slirp_smb_cleanup(SlirpState *s)
462
{
463
    char cmd[128];
464
    int ret;
465

    
466
    if (s->smb_dir[0] != '\0') {
467
        snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
468
        ret = system(cmd);
469
        if (ret == -1 || !WIFEXITED(ret)) {
470
            error_report("'%s' failed.", cmd);
471
        } else if (WEXITSTATUS(ret)) {
472
            error_report("'%s' failed. Error code: %d",
473
                         cmd, WEXITSTATUS(ret));
474
        }
475
        s->smb_dir[0] = '\0';
476
    }
477
}
478

    
479
static int slirp_smb(SlirpState* s, const char *exported_dir,
480
                     struct in_addr vserver_addr)
481
{
482
    static int instance;
483
    char smb_conf[128];
484
    char smb_cmdline[128];
485
    struct passwd *passwd;
486
    FILE *f;
487

    
488
    passwd = getpwuid(geteuid());
489
    if (!passwd) {
490
        error_report("failed to retrieve user name");
491
        return -1;
492
    }
493

    
494
    if (access(CONFIG_SMBD_COMMAND, F_OK)) {
495
        error_report("could not find '%s', please install it",
496
                     CONFIG_SMBD_COMMAND);
497
        return -1;
498
    }
499

    
500
    if (access(exported_dir, R_OK | X_OK)) {
501
        error_report("error accessing shared directory '%s': %s",
502
                     exported_dir, strerror(errno));
503
        return -1;
504
    }
505

    
506
    snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
507
             (long)getpid(), instance++);
508
    if (mkdir(s->smb_dir, 0700) < 0) {
509
        error_report("could not create samba server dir '%s'", s->smb_dir);
510
        return -1;
511
    }
512
    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
513

    
514
    f = fopen(smb_conf, "w");
515
    if (!f) {
516
        slirp_smb_cleanup(s);
517
        error_report("could not create samba server configuration file '%s'",
518
                     smb_conf);
519
        return -1;
520
    }
521
    fprintf(f,
522
            "[global]\n"
523
            "private dir=%s\n"
524
            "socket address=127.0.0.1\n"
525
            "pid directory=%s\n"
526
            "lock directory=%s\n"
527
            "state directory=%s\n"
528
            "log file=%s/log.smbd\n"
529
            "smb passwd file=%s/smbpasswd\n"
530
            "security = share\n"
531
            "[qemu]\n"
532
            "path=%s\n"
533
            "read only=no\n"
534
            "guest ok=yes\n"
535
            "force user=%s\n",
536
            s->smb_dir,
537
            s->smb_dir,
538
            s->smb_dir,
539
            s->smb_dir,
540
            s->smb_dir,
541
            s->smb_dir,
542
            exported_dir,
543
            passwd->pw_name
544
            );
545
    fclose(f);
546

    
547
    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
548
             CONFIG_SMBD_COMMAND, smb_conf);
549

    
550
    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
551
        slirp_smb_cleanup(s);
552
        error_report("conflicting/invalid smbserver address");
553
        return -1;
554
    }
555
    return 0;
556
}
557

    
558
/* automatic user mode samba server configuration (legacy interface) */
559
int net_slirp_smb(const char *exported_dir)
560
{
561
    struct in_addr vserver_addr = { .s_addr = 0 };
562

    
563
    if (legacy_smb_export) {
564
        fprintf(stderr, "-smb given twice\n");
565
        return -1;
566
    }
567
    legacy_smb_export = exported_dir;
568
    if (!QTAILQ_EMPTY(&slirp_stacks)) {
569
        return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
570
                         vserver_addr);
571
    }
572
    return 0;
573
}
574

    
575
#endif /* !defined(_WIN32) */
576

    
577
struct GuestFwd {
578
    CharDriverState *hd;
579
    struct in_addr server;
580
    int port;
581
    Slirp *slirp;
582
};
583

    
584
static int guestfwd_can_read(void *opaque)
585
{
586
    struct GuestFwd *fwd = opaque;
587
    return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
588
}
589

    
590
static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
591
{
592
    struct GuestFwd *fwd = opaque;
593
    slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
594
}
595

    
596
static int slirp_guestfwd(SlirpState *s, const char *config_str,
597
                          int legacy_format)
598
{
599
    struct in_addr server = { .s_addr = 0 };
600
    struct GuestFwd *fwd;
601
    const char *p;
602
    char buf[128];
603
    char *end;
604
    int port;
605

    
606
    p = config_str;
607
    if (legacy_format) {
608
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
609
            goto fail_syntax;
610
        }
611
    } else {
612
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
613
            goto fail_syntax;
614
        }
615
        if (strcmp(buf, "tcp") && buf[0] != '\0') {
616
            goto fail_syntax;
617
        }
618
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
619
            goto fail_syntax;
620
        }
621
        if (buf[0] != '\0' && !inet_aton(buf, &server)) {
622
            goto fail_syntax;
623
        }
624
        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
625
            goto fail_syntax;
626
        }
627
    }
628
    port = strtol(buf, &end, 10);
629
    if (*end != '\0' || port < 1 || port > 65535) {
630
        goto fail_syntax;
631
    }
632

    
633
    fwd = g_malloc(sizeof(struct GuestFwd));
634
    snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
635

    
636
    if ((strlen(p) > 4) && !strncmp(p, "cmd:", 4)) {
637
        if (slirp_add_exec(s->slirp, 0, &p[4], &server, port) < 0) {
638
            error_report("conflicting/invalid host:port in guest forwarding "
639
                         "rule '%s'", config_str);
640
            g_free(fwd);
641
            return -1;
642
        }
643
    } else {
644
        fwd->hd = qemu_chr_new(buf, p, NULL);
645
        if (!fwd->hd) {
646
            error_report("could not open guest forwarding device '%s'", buf);
647
            g_free(fwd);
648
            return -1;
649
        }
650

    
651
        if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
652
            error_report("conflicting/invalid host:port in guest forwarding "
653
                         "rule '%s'", config_str);
654
            g_free(fwd);
655
            return -1;
656
        }
657
        fwd->server = server;
658
        fwd->port = port;
659
        fwd->slirp = s->slirp;
660

    
661
        qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
662
                              NULL, fwd);
663
    }
664
    return 0;
665

    
666
 fail_syntax:
667
    error_report("invalid guest forwarding rule '%s'", config_str);
668
    return -1;
669
}
670

    
671
void do_info_usernet(Monitor *mon)
672
{
673
    SlirpState *s;
674

    
675
    QTAILQ_FOREACH(s, &slirp_stacks, entry) {
676
        int id;
677
        bool got_vlan_id = net_hub_id_for_client(&s->nc, &id) == 0;
678
        monitor_printf(mon, "VLAN %d (%s):\n",
679
                       got_vlan_id ? id : -1,
680
                       s->nc.name);
681
        slirp_connection_info(s->slirp, mon);
682
    }
683
}
684

    
685
static void
686
net_init_slirp_configs(const StringList *fwd, int flags)
687
{
688
    while (fwd) {
689
        struct slirp_config_str *config;
690

    
691
        config = g_malloc0(sizeof(*config));
692
        pstrcpy(config->str, sizeof(config->str), fwd->value->str);
693
        config->flags = flags;
694
        config->next = slirp_configs;
695
        slirp_configs = config;
696

    
697
        fwd = fwd->next;
698
    }
699
}
700

    
701
int net_init_slirp(const NetClientOptions *opts, const char *name,
702
                   NetClientState *peer)
703
{
704
    struct slirp_config_str *config;
705
    char *vnet;
706
    int ret;
707
    const NetdevUserOptions *user;
708

    
709
    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_USER);
710
    user = opts->user;
711

    
712
    vnet = user->has_net ? g_strdup(user->net) :
713
           user->has_ip  ? g_strdup_printf("%s/24", user->ip) :
714
           NULL;
715

    
716
    /* all optional fields are initialized to "all bits zero" */
717

    
718
    net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
719
    net_init_slirp_configs(user->guestfwd, 0);
720

    
721
    ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet,
722
                         user->host, user->hostname, user->tftp,
723
                         user->bootfile, user->dhcpstart, user->dns, user->smb,
724
                         user->smbserver);
725

    
726
    while (slirp_configs) {
727
        config = slirp_configs;
728
        slirp_configs = config->next;
729
        g_free(config);
730
    }
731

    
732
    g_free(vnet);
733

    
734
    return ret;
735
}
736

    
737
int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
738
{
739
    if (strcmp(opts_list->name, "net") != 0 ||
740
        strncmp(optarg, "channel,", strlen("channel,")) != 0) {
741
        return 0;
742
    }
743

    
744
    /* handle legacy -net channel,port:chr */
745
    optarg += strlen("channel,");
746

    
747
    if (QTAILQ_EMPTY(&slirp_stacks)) {
748
        struct slirp_config_str *config;
749

    
750
        config = g_malloc(sizeof(*config));
751
        pstrcpy(config->str, sizeof(config->str), optarg);
752
        config->flags = SLIRP_CFG_LEGACY;
753
        config->next = slirp_configs;
754
        slirp_configs = config;
755
        *ret = 0;
756
    } else {
757
        *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
758
    }
759

    
760
    return 1;
761
}
762