]> git.proxmox.com Git - mirror_qemu.git/blame - net/slirp.c
slirp: replace qemu_set_nonblock()
[mirror_qemu.git] / net / slirp.c
CommitLineData
68ac40d2
MM
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 */
452fcdbc 24
2744d920 25#include "qemu/osdep.h"
2addc8fb 26#include "qemu/log.h"
68ac40d2
MM
27#include "net/slirp.h"
28
68ac40d2 29
28b150bf 30#ifndef _WIN32
1cb1c5d1 31#include <pwd.h>
28b150bf
BS
32#include <sys/wait.h>
33#endif
1422e32d 34#include "net/net.h"
a245fc18
PB
35#include "clients.h"
36#include "hub.h"
83c9089e 37#include "monitor/monitor.h"
d49b6836 38#include "qemu/error-report.h"
1de7afc9 39#include "qemu/sockets.h"
68ac40d2 40#include "slirp/libslirp.h"
4d43a603 41#include "chardev/char-fe.h"
f6c2e66a 42#include "sysemu/sysemu.h"
f348b6d1 43#include "qemu/cutils.h"
32a6ebec 44#include "qapi/error.h"
452fcdbc 45#include "qapi/qmp/qdict.h"
e05ae1d9 46#include "util.h"
68ac40d2
MM
47
48static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
49{
50 const char *p, *p1;
51 int len;
52 p = *pp;
53 p1 = strchr(p, sep);
54 if (!p1)
55 return -1;
56 len = p1 - p;
57 p1++;
58 if (buf_size > 0) {
59 if (len > buf_size - 1)
60 len = buf_size - 1;
61 memcpy(buf, p, len);
62 buf[len] = '\0';
63 }
64 *pp = p1;
65 return 0;
66}
67
68/* slirp network adapter */
69
70#define SLIRP_CFG_HOSTFWD 1
68ac40d2
MM
71
72struct slirp_config_str {
73 struct slirp_config_str *next;
74 int flags;
75 char str[1024];
68ac40d2
MM
76};
77
8d45a3b9
MAL
78struct GuestFwd {
79 CharBackend hd;
80 struct in_addr server;
81 int port;
82 Slirp *slirp;
83};
84
68ac40d2 85typedef struct SlirpState {
4e68f7a0 86 NetClientState nc;
68ac40d2 87 QTAILQ_ENTRY(SlirpState) entry;
68ac40d2 88 Slirp *slirp;
f6c2e66a 89 Notifier exit_notifier;
68ac40d2 90#ifndef _WIN32
f95cc8b6 91 gchar *smb_dir;
68ac40d2 92#endif
8d45a3b9 93 GSList *fwd;
68ac40d2
MM
94} SlirpState;
95
96static struct slirp_config_str *slirp_configs;
b58deb34 97static QTAILQ_HEAD(, SlirpState) slirp_stacks =
68ac40d2
MM
98 QTAILQ_HEAD_INITIALIZER(slirp_stacks);
99
d18572dd
TH
100static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp);
101static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp);
68ac40d2
MM
102
103#ifndef _WIN32
68ac40d2 104static int slirp_smb(SlirpState *s, const char *exported_dir,
5c843af2 105 struct in_addr vserver_addr, Error **errp);
68ac40d2
MM
106static void slirp_smb_cleanup(SlirpState *s);
107#else
108static inline void slirp_smb_cleanup(SlirpState *s) { }
109#endif
110
62c1d2c4 111static void net_slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
68ac40d2
MM
112{
113 SlirpState *s = opaque;
114
ce20b5be 115 qemu_send_packet(&s->nc, pkt, pkt_len);
68ac40d2
MM
116}
117
4e68f7a0 118static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, size_t size)
68ac40d2 119{
ce20b5be 120 SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
68ac40d2
MM
121
122 slirp_input(s->slirp, buf, size);
123
124 return size;
125}
126
f6c2e66a
PB
127static void slirp_smb_exit(Notifier *n, void *data)
128{
129 SlirpState *s = container_of(n, SlirpState, exit_notifier);
130 slirp_smb_cleanup(s);
131}
132
8d45a3b9
MAL
133static void slirp_free_fwd(gpointer data)
134{
135 struct GuestFwd *fwd = data;
136
137 qemu_chr_fe_deinit(&fwd->hd, true);
138 g_free(data);
139}
140
4e68f7a0 141static void net_slirp_cleanup(NetClientState *nc)
68ac40d2 142{
ce20b5be 143 SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
68ac40d2 144
8d45a3b9 145 g_slist_free_full(s->fwd, slirp_free_fwd);
68ac40d2 146 slirp_cleanup(s->slirp);
67f3280c
MAL
147 if (s->exit_notifier.notify) {
148 qemu_remove_exit_notifier(&s->exit_notifier);
149 }
68ac40d2
MM
150 slirp_smb_cleanup(s);
151 QTAILQ_REMOVE(&slirp_stacks, s, entry);
68ac40d2
MM
152}
153
ce20b5be 154static NetClientInfo net_slirp_info = {
f394b2e2 155 .type = NET_CLIENT_DRIVER_USER,
ce20b5be
MM
156 .size = sizeof(SlirpState),
157 .receive = net_slirp_receive,
158 .cleanup = net_slirp_cleanup,
159};
160
2addc8fb
MAL
161static void net_slirp_guest_error(const char *msg)
162{
163 qemu_log_mask(LOG_GUEST_ERROR, "%s", msg);
164}
165
e6dbff3f
MAL
166static int64_t net_slirp_clock_get_ns(void)
167{
168 return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
169}
170
07abf6d4
MAL
171static void *net_slirp_timer_new(SlirpTimerCb cb, void *opaque)
172{
173 return timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
174 SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
175 cb, opaque);
176}
177
178static void net_slirp_timer_free(void *timer)
179{
180 timer_del(timer);
181 timer_free(timer);
182}
183
184static void net_slirp_timer_mod(void *timer, int64_t expire_timer)
185{
186 timer_mod(timer, expire_timer);
187}
188
848c7092
MAL
189static void net_slirp_register_poll_fd(int fd)
190{
191 qemu_fd_register(fd);
192}
193
d846b927
MAL
194static const SlirpCb slirp_cb = {
195 .output = net_slirp_output,
2addc8fb 196 .guest_error = net_slirp_guest_error,
e6dbff3f 197 .clock_get_ns = net_slirp_clock_get_ns,
07abf6d4
MAL
198 .timer_new = net_slirp_timer_new,
199 .timer_free = net_slirp_timer_free,
200 .timer_mod = net_slirp_timer_mod,
848c7092 201 .register_poll_fd = net_slirp_register_poll_fd,
d846b927
MAL
202};
203
4e68f7a0 204static int net_slirp_init(NetClientState *peer, const char *model,
68ac40d2 205 const char *name, int restricted,
0b11c036
ST
206 bool ipv4, const char *vnetwork, const char *vhost,
207 bool ipv6, const char *vprefix6, int vprefix6_len,
7aac531e 208 const char *vhost6,
68ac40d2
MM
209 const char *vhostname, const char *tftp_export,
210 const char *bootfile, const char *vdhcp_start,
7aac531e
YB
211 const char *vnameserver, const char *vnameserver6,
212 const char *smb_export, const char *vsmbserver,
f18d1375 213 const char **dnssearch, const char *vdomainname,
0fca92b9 214 const char *tftp_server_name,
f18d1375 215 Error **errp)
68ac40d2
MM
216{
217 /* default settings according to historic slirp */
218 struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
219 struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
220 struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
221 struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
222 struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
7aac531e
YB
223 struct in6_addr ip6_prefix;
224 struct in6_addr ip6_host;
225 struct in6_addr ip6_dns;
68ac40d2
MM
226#ifndef _WIN32
227 struct in_addr smbsrv = { .s_addr = 0 };
228#endif
4e68f7a0 229 NetClientState *nc;
68ac40d2
MM
230 SlirpState *s;
231 char buf[20];
232 uint32_t addr;
233 int shift;
234 char *end;
235 struct slirp_config_str *config;
236
0b11c036 237 if (!ipv4 && (vnetwork || vhost || vnameserver)) {
5c843af2 238 error_setg(errp, "IPv4 disabled but netmask/host/dns provided");
0b11c036
ST
239 return -1;
240 }
241
242 if (!ipv6 && (vprefix6 || vhost6 || vnameserver6)) {
5c843af2 243 error_setg(errp, "IPv6 disabled but prefix/host6/dns6 provided");
0b11c036
ST
244 return -1;
245 }
246
247 if (!ipv4 && !ipv6) {
248 /* It doesn't make sense to disable both */
5c843af2 249 error_setg(errp, "IPv4 and IPv6 disabled");
0b11c036
ST
250 return -1;
251 }
252
68ac40d2
MM
253 if (vnetwork) {
254 if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
255 if (!inet_aton(vnetwork, &net)) {
5c843af2 256 error_setg(errp, "Failed to parse netmask");
68ac40d2
MM
257 return -1;
258 }
259 addr = ntohl(net.s_addr);
260 if (!(addr & 0x80000000)) {
261 mask.s_addr = htonl(0xff000000); /* class A */
262 } else if ((addr & 0xfff00000) == 0xac100000) {
263 mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
264 } else if ((addr & 0xc0000000) == 0x80000000) {
265 mask.s_addr = htonl(0xffff0000); /* class B */
266 } else if ((addr & 0xffff0000) == 0xc0a80000) {
267 mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
268 } else if ((addr & 0xffff0000) == 0xc6120000) {
269 mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
270 } else if ((addr & 0xe0000000) == 0xe0000000) {
271 mask.s_addr = htonl(0xffffff00); /* class C */
272 } else {
273 mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
274 }
275 } else {
276 if (!inet_aton(buf, &net)) {
5c843af2 277 error_setg(errp, "Failed to parse netmask");
68ac40d2
MM
278 return -1;
279 }
280 shift = strtol(vnetwork, &end, 10);
281 if (*end != '\0') {
282 if (!inet_aton(vnetwork, &mask)) {
5c843af2
HP
283 error_setg(errp,
284 "Failed to parse netmask (trailing chars)");
68ac40d2
MM
285 return -1;
286 }
287 } else if (shift < 4 || shift > 32) {
5c843af2
HP
288 error_setg(errp,
289 "Invalid netmask provided (must be in range 4-32)");
68ac40d2
MM
290 return -1;
291 } else {
292 mask.s_addr = htonl(0xffffffff << (32 - shift));
293 }
294 }
295 net.s_addr &= mask.s_addr;
296 host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
297 dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
298 dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
299 }
300
301 if (vhost && !inet_aton(vhost, &host)) {
5c843af2 302 error_setg(errp, "Failed to parse host");
68ac40d2
MM
303 return -1;
304 }
305 if ((host.s_addr & mask.s_addr) != net.s_addr) {
5c843af2 306 error_setg(errp, "Host doesn't belong to network");
68ac40d2
MM
307 return -1;
308 }
309
68756ba8 310 if (vnameserver && !inet_aton(vnameserver, &dns)) {
5c843af2 311 error_setg(errp, "Failed to parse DNS");
68ac40d2
MM
312 return -1;
313 }
5c843af2
HP
314 if ((dns.s_addr & mask.s_addr) != net.s_addr) {
315 error_setg(errp, "DNS doesn't belong to network");
316 return -1;
317 }
318 if (dns.s_addr == host.s_addr) {
319 error_setg(errp, "DNS must be different from host");
68ac40d2
MM
320 return -1;
321 }
322
68756ba8 323 if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
5c843af2 324 error_setg(errp, "Failed to parse DHCP start address");
68ac40d2
MM
325 return -1;
326 }
5c843af2
HP
327 if ((dhcp.s_addr & mask.s_addr) != net.s_addr) {
328 error_setg(errp, "DHCP doesn't belong to network");
329 return -1;
330 }
331 if (dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
332 error_setg(errp, "DNS must be different from host and DNS");
68ac40d2
MM
333 return -1;
334 }
335
336#ifndef _WIN32
337 if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
5c843af2 338 error_setg(errp, "Failed to parse SMB address");
68ac40d2
MM
339 return -1;
340 }
341#endif
342
7aac531e
YB
343 if (!vprefix6) {
344 vprefix6 = "fec0::";
345 }
346 if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
5c843af2 347 error_setg(errp, "Failed to parse IPv6 prefix");
7aac531e
YB
348 return -1;
349 }
7aac531e
YB
350
351 if (!vprefix6_len) {
352 vprefix6_len = 64;
353 }
354 if (vprefix6_len < 0 || vprefix6_len > 126) {
5c843af2
HP
355 error_setg(errp,
356 "Invalid prefix provided (prefix len must be in range 0-126");
7aac531e
YB
357 return -1;
358 }
359
360 if (vhost6) {
7aac531e 361 if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
5c843af2 362 error_setg(errp, "Failed to parse IPv6 host");
7aac531e
YB
363 return -1;
364 }
365 if (!in6_equal_net(&ip6_prefix, &ip6_host, vprefix6_len)) {
5c843af2 366 error_setg(errp, "IPv6 Host doesn't belong to network");
7aac531e
YB
367 return -1;
368 }
7aac531e
YB
369 } else {
370 ip6_host = ip6_prefix;
371 ip6_host.s6_addr[15] |= 2;
372 }
373
374 if (vnameserver6) {
7aac531e 375 if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
5c843af2 376 error_setg(errp, "Failed to parse IPv6 DNS");
7aac531e
YB
377 return -1;
378 }
379 if (!in6_equal_net(&ip6_prefix, &ip6_dns, vprefix6_len)) {
5c843af2 380 error_setg(errp, "IPv6 DNS doesn't belong to network");
7aac531e
YB
381 return -1;
382 }
7aac531e
YB
383 } else {
384 ip6_dns = ip6_prefix;
385 ip6_dns.s6_addr[15] |= 3;
386 }
387
f18d1375
BD
388 if (vdomainname && !*vdomainname) {
389 error_setg(errp, "'domainname' parameter cannot be empty");
390 return -1;
391 }
392
6e157a03
FZ
393 if (vdomainname && strlen(vdomainname) > 255) {
394 error_setg(errp, "'domainname' parameter cannot exceed 255 bytes");
395 return -1;
396 }
397
398 if (vhostname && strlen(vhostname) > 255) {
399 error_setg(errp, "'vhostname' parameter cannot exceed 255 bytes");
400 return -1;
401 }
7aac531e 402
0fca92b9
FZ
403 if (tftp_server_name && strlen(tftp_server_name) > 255) {
404 error_setg(errp, "'tftp-server-name' parameter cannot exceed 255 bytes");
405 return -1;
406 }
407
ab5f3f84 408 nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
ce20b5be
MM
409
410 snprintf(nc->info_str, sizeof(nc->info_str),
c54ed5bc
JK
411 "net=%s,restrict=%s", inet_ntoa(net),
412 restricted ? "on" : "off");
ce20b5be
MM
413
414 s = DO_UPCAST(SlirpState, nc, nc);
415
0b11c036
ST
416 s->slirp = slirp_init(restricted, ipv4, net, mask, host,
417 ipv6, ip6_prefix, vprefix6_len, ip6_host,
0fca92b9
FZ
418 vhostname, tftp_server_name,
419 tftp_export, bootfile, dhcp,
62c1d2c4 420 dns, ip6_dns, dnssearch, vdomainname,
d846b927 421 &slirp_cb, s);
68ac40d2
MM
422 QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
423
424 for (config = slirp_configs; config; config = config->next) {
425 if (config->flags & SLIRP_CFG_HOSTFWD) {
d18572dd 426 if (slirp_hostfwd(s, config->str, errp) < 0) {
ce20b5be 427 goto error;
5c843af2 428 }
68ac40d2 429 } else {
d18572dd 430 if (slirp_guestfwd(s, config->str, errp) < 0) {
ce20b5be 431 goto error;
5c843af2 432 }
68ac40d2
MM
433 }
434 }
435#ifndef _WIN32
68ac40d2 436 if (smb_export) {
5c843af2 437 if (slirp_smb(s, smb_export, smbsrv, errp) < 0) {
ce20b5be 438 goto error;
5c843af2 439 }
68ac40d2
MM
440 }
441#endif
442
f6c2e66a
PB
443 s->exit_notifier.notify = slirp_smb_exit;
444 qemu_add_exit_notifier(&s->exit_notifier);
68ac40d2 445 return 0;
ce20b5be
MM
446
447error:
b20c6b9e 448 qemu_del_net_client(nc);
ce20b5be 449 return -1;
68ac40d2
MM
450}
451
93653066
TH
452static SlirpState *slirp_lookup(Monitor *mon, const char *hub_id,
453 const char *name)
68ac40d2 454{
93653066 455 if (name) {
4e68f7a0 456 NetClientState *nc;
93653066
TH
457 if (hub_id) {
458 nc = net_hub_find_client_by_name(strtol(hub_id, NULL, 0), name);
459 if (!nc) {
442da403 460 monitor_printf(mon, "unrecognized (hub-id, stackname) pair\n");
93653066
TH
461 return NULL;
462 }
68cb29ea
TH
463 warn_report("Using 'hub-id' is deprecated, specify the netdev id "
464 "directly instead");
93653066
TH
465 } else {
466 nc = qemu_find_netdev(name);
467 if (!nc) {
468 monitor_printf(mon, "unrecognized netdev id '%s'\n", name);
469 return NULL;
470 }
68ac40d2 471 }
ce20b5be 472 if (strcmp(nc->model, "user")) {
68ac40d2
MM
473 monitor_printf(mon, "invalid device specified\n");
474 return NULL;
475 }
ce20b5be 476 return DO_UPCAST(SlirpState, nc, nc);
68ac40d2
MM
477 } else {
478 if (QTAILQ_EMPTY(&slirp_stacks)) {
479 monitor_printf(mon, "user mode network stack not in use\n");
480 return NULL;
481 }
482 return QTAILQ_FIRST(&slirp_stacks);
483 }
484}
485
3e5a50d6 486void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
68ac40d2
MM
487{
488 struct in_addr host_addr = { .s_addr = INADDR_ANY };
489 int host_port;
e30e5eb6 490 char buf[256];
68ac40d2
MM
491 const char *src_str, *p;
492 SlirpState *s;
493 int is_udp = 0;
494 int err;
495 const char *arg1 = qdict_get_str(qdict, "arg1");
496 const char *arg2 = qdict_get_try_str(qdict, "arg2");
497 const char *arg3 = qdict_get_try_str(qdict, "arg3");
498
93653066 499 if (arg3) {
68ac40d2
MM
500 s = slirp_lookup(mon, arg1, arg2);
501 src_str = arg3;
93653066
TH
502 } else if (arg2) {
503 s = slirp_lookup(mon, NULL, arg1);
504 src_str = arg2;
68ac40d2
MM
505 } else {
506 s = slirp_lookup(mon, NULL, NULL);
507 src_str = arg1;
508 }
509 if (!s) {
510 return;
511 }
512
68ac40d2 513 p = src_str;
e30e5eb6
MA
514 if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
515 goto fail_syntax;
516 }
68ac40d2
MM
517
518 if (!strcmp(buf, "tcp") || buf[0] == '\0') {
519 is_udp = 0;
520 } else if (!strcmp(buf, "udp")) {
521 is_udp = 1;
522 } else {
523 goto fail_syntax;
524 }
525
526 if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
527 goto fail_syntax;
528 }
529 if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
530 goto fail_syntax;
531 }
532
1fb3f7f2
NA
533 if (qemu_strtoi(p, NULL, 10, &host_port)) {
534 goto fail_syntax;
535 }
68ac40d2 536
70381662 537 err = slirp_remove_hostfwd(s->slirp, is_udp, host_addr, host_port);
68ac40d2
MM
538
539 monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
b15ba6c9 540 err ? "not found" : "removed");
68ac40d2
MM
541 return;
542
543 fail_syntax:
544 monitor_printf(mon, "invalid format\n");
545}
546
d18572dd 547static int slirp_hostfwd(SlirpState *s, const char *redir_str, Error **errp)
68ac40d2
MM
548{
549 struct in_addr host_addr = { .s_addr = INADDR_ANY };
550 struct in_addr guest_addr = { .s_addr = 0 };
551 int host_port, guest_port;
552 const char *p;
553 char buf[256];
554 int is_udp;
555 char *end;
0e7e4fb0 556 const char *fail_reason = "Unknown reason";
68ac40d2
MM
557
558 p = redir_str;
559 if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
0e7e4fb0 560 fail_reason = "No : separators";
68ac40d2
MM
561 goto fail_syntax;
562 }
563 if (!strcmp(buf, "tcp") || buf[0] == '\0') {
564 is_udp = 0;
565 } else if (!strcmp(buf, "udp")) {
566 is_udp = 1;
567 } else {
0e7e4fb0 568 fail_reason = "Bad protocol name";
68ac40d2
MM
569 goto fail_syntax;
570 }
571
d18572dd
TH
572 if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
573 fail_reason = "Missing : separator";
574 goto fail_syntax;
575 }
576 if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
577 fail_reason = "Bad host address";
578 goto fail_syntax;
68ac40d2
MM
579 }
580
d18572dd 581 if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
0e7e4fb0 582 fail_reason = "Bad host port separator";
68ac40d2
MM
583 goto fail_syntax;
584 }
585 host_port = strtol(buf, &end, 0);
0bed71ed 586 if (*end != '\0' || host_port < 0 || host_port > 65535) {
0e7e4fb0 587 fail_reason = "Bad host port";
68ac40d2
MM
588 goto fail_syntax;
589 }
590
591 if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
0e7e4fb0 592 fail_reason = "Missing guest address";
68ac40d2
MM
593 goto fail_syntax;
594 }
595 if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
0e7e4fb0 596 fail_reason = "Bad guest address";
68ac40d2
MM
597 goto fail_syntax;
598 }
599
600 guest_port = strtol(p, &end, 0);
601 if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
0e7e4fb0 602 fail_reason = "Bad guest port";
68ac40d2
MM
603 goto fail_syntax;
604 }
605
606 if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
607 guest_port) < 0) {
5c843af2
HP
608 error_setg(errp, "Could not set up host forwarding rule '%s'",
609 redir_str);
68ac40d2
MM
610 return -1;
611 }
612 return 0;
613
614 fail_syntax:
0e7e4fb0
DDAG
615 error_setg(errp, "Invalid host forwarding rule '%s' (%s)", redir_str,
616 fail_reason);
68ac40d2
MM
617 return -1;
618}
619
3e5a50d6 620void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
68ac40d2
MM
621{
622 const char *redir_str;
623 SlirpState *s;
624 const char *arg1 = qdict_get_str(qdict, "arg1");
625 const char *arg2 = qdict_get_try_str(qdict, "arg2");
626 const char *arg3 = qdict_get_try_str(qdict, "arg3");
627
93653066 628 if (arg3) {
68ac40d2
MM
629 s = slirp_lookup(mon, arg1, arg2);
630 redir_str = arg3;
93653066
TH
631 } else if (arg2) {
632 s = slirp_lookup(mon, NULL, arg1);
633 redir_str = arg2;
68ac40d2
MM
634 } else {
635 s = slirp_lookup(mon, NULL, NULL);
636 redir_str = arg1;
637 }
638 if (s) {
5c843af2 639 Error *err = NULL;
d18572dd 640 if (slirp_hostfwd(s, redir_str, &err) < 0) {
5c843af2
HP
641 error_report_err(err);
642 }
68ac40d2
MM
643 }
644
645}
646
68ac40d2
MM
647#ifndef _WIN32
648
649/* automatic user mode samba server configuration */
650static void slirp_smb_cleanup(SlirpState *s)
651{
5a01e99f 652 int ret;
68ac40d2 653
f95cc8b6
DDAG
654 if (s->smb_dir) {
655 gchar *cmd = g_strdup_printf("rm -rf %s", s->smb_dir);
5a01e99f 656 ret = system(cmd);
24ac07de 657 if (ret == -1 || !WIFEXITED(ret)) {
1ecda02b 658 error_report("'%s' failed.", cmd);
5a01e99f 659 } else if (WEXITSTATUS(ret)) {
1ecda02b
MA
660 error_report("'%s' failed. Error code: %d",
661 cmd, WEXITSTATUS(ret));
5a01e99f 662 }
f95cc8b6
DDAG
663 g_free(cmd);
664 g_free(s->smb_dir);
665 s->smb_dir = NULL;
68ac40d2
MM
666 }
667}
668
669static int slirp_smb(SlirpState* s, const char *exported_dir,
5c843af2 670 struct in_addr vserver_addr, Error **errp)
68ac40d2 671{
f95cc8b6
DDAG
672 char *smb_conf;
673 char *smb_cmdline;
1cb1c5d1 674 struct passwd *passwd;
68ac40d2
MM
675 FILE *f;
676
1cb1c5d1
JK
677 passwd = getpwuid(geteuid());
678 if (!passwd) {
5c843af2 679 error_setg(errp, "Failed to retrieve user name");
1cb1c5d1
JK
680 return -1;
681 }
682
927d811b 683 if (access(CONFIG_SMBD_COMMAND, F_OK)) {
5c843af2
HP
684 error_setg(errp, "Could not find '%s', please install it",
685 CONFIG_SMBD_COMMAND);
927d811b
DH
686 return -1;
687 }
688
689 if (access(exported_dir, R_OK | X_OK)) {
5c843af2
HP
690 error_setg(errp, "Error accessing shared directory '%s': %s",
691 exported_dir, strerror(errno));
927d811b
DH
692 return -1;
693 }
694
f95cc8b6
DDAG
695 s->smb_dir = g_dir_make_tmp("qemu-smb.XXXXXX", NULL);
696 if (!s->smb_dir) {
5c843af2 697 error_setg(errp, "Could not create samba server dir");
68ac40d2
MM
698 return -1;
699 }
f95cc8b6 700 smb_conf = g_strdup_printf("%s/%s", s->smb_dir, "smb.conf");
68ac40d2
MM
701
702 f = fopen(smb_conf, "w");
703 if (!f) {
704 slirp_smb_cleanup(s);
5c843af2
HP
705 error_setg(errp,
706 "Could not create samba server configuration file '%s'",
707 smb_conf);
f95cc8b6 708 g_free(smb_conf);
68ac40d2
MM
709 return -1;
710 }
711 fprintf(f,
712 "[global]\n"
713 "private dir=%s\n"
7912d04b
PW
714 "interfaces=127.0.0.1\n"
715 "bind interfaces only=yes\n"
68ac40d2
MM
716 "pid directory=%s\n"
717 "lock directory=%s\n"
276eda57 718 "state directory=%s\n"
7912d04b 719 "cache directory=%s\n"
b87b8a8b 720 "ncalrpc dir=%s/ncalrpc\n"
68ac40d2
MM
721 "log file=%s/log.smbd\n"
722 "smb passwd file=%s/smbpasswd\n"
c2804ee6
MB
723 "security = user\n"
724 "map to guest = Bad User\n"
7912d04b
PW
725 "load printers = no\n"
726 "printing = bsd\n"
727 "disable spoolss = yes\n"
728 "usershare max shares = 0\n"
68ac40d2
MM
729 "[qemu]\n"
730 "path=%s\n"
731 "read only=no\n"
1cb1c5d1
JK
732 "guest ok=yes\n"
733 "force user=%s\n",
68ac40d2
MM
734 s->smb_dir,
735 s->smb_dir,
736 s->smb_dir,
737 s->smb_dir,
738 s->smb_dir,
276eda57 739 s->smb_dir,
b87b8a8b 740 s->smb_dir,
7912d04b 741 s->smb_dir,
1cb1c5d1
JK
742 exported_dir,
743 passwd->pw_name
68ac40d2
MM
744 );
745 fclose(f);
746
f95cc8b6 747 smb_cmdline = g_strdup_printf("%s -l %s -s %s",
44d8d2b2 748 CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf);
f95cc8b6 749 g_free(smb_conf);
68ac40d2 750
44b4ff24
MAL
751 if (slirp_add_exec(s->slirp, smb_cmdline, &vserver_addr, 139) < 0 ||
752 slirp_add_exec(s->slirp, smb_cmdline, &vserver_addr, 445) < 0) {
68ac40d2 753 slirp_smb_cleanup(s);
f95cc8b6 754 g_free(smb_cmdline);
5c843af2 755 error_setg(errp, "Conflicting/invalid smbserver address");
68ac40d2
MM
756 return -1;
757 }
f95cc8b6 758 g_free(smb_cmdline);
68ac40d2
MM
759 return 0;
760}
761
68ac40d2
MM
762#endif /* !defined(_WIN32) */
763
68ac40d2
MM
764static int guestfwd_can_read(void *opaque)
765{
766 struct GuestFwd *fwd = opaque;
767 return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
768}
769
770static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
771{
772 struct GuestFwd *fwd = opaque;
773 slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
774}
775
44b4ff24
MAL
776static int guestfwd_write(const void *buf, size_t len, void *chr)
777{
778 return qemu_chr_fe_write_all(chr, buf, len);
779}
780
d18572dd 781static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
68ac40d2
MM
782{
783 struct in_addr server = { .s_addr = 0 };
784 struct GuestFwd *fwd;
785 const char *p;
786 char buf[128];
787 char *end;
788 int port;
789
790 p = config_str;
d18572dd
TH
791 if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
792 goto fail_syntax;
793 }
794 if (strcmp(buf, "tcp") && buf[0] != '\0') {
795 goto fail_syntax;
796 }
797 if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
798 goto fail_syntax;
799 }
800 if (buf[0] != '\0' && !inet_aton(buf, &server)) {
801 goto fail_syntax;
802 }
803 if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
804 goto fail_syntax;
68ac40d2
MM
805 }
806 port = strtol(buf, &end, 10);
807 if (*end != '\0' || port < 1 || port > 65535) {
808 goto fail_syntax;
809 }
810
a9899996 811 snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
68ac40d2 812
3624730a 813 if (g_str_has_prefix(p, "cmd:")) {
44b4ff24 814 if (slirp_add_exec(s->slirp, &p[4], &server, port) < 0) {
5c843af2
HP
815 error_setg(errp, "Conflicting/invalid host:port in guest "
816 "forwarding rule '%s'", config_str);
b412eb61
AG
817 return -1;
818 }
819 } else {
32a6ebec 820 Error *err = NULL;
95e30b2a
MAL
821 /*
822 * FIXME: sure we want to support implicit
823 * muxed monitors here?
824 */
825 Chardev *chr = qemu_chr_new_mux_mon(buf, p);
32a6ebec
MAL
826
827 if (!chr) {
5c843af2
HP
828 error_setg(errp, "Could not open guest forwarding device '%s'",
829 buf);
32a6ebec
MAL
830 return -1;
831 }
832
833 fwd = g_new(struct GuestFwd, 1);
834 qemu_chr_fe_init(&fwd->hd, chr, &err);
835 if (err) {
5c843af2 836 error_propagate(errp, err);
8e207c32 837 object_unparent(OBJECT(chr));
b412eb61
AG
838 g_free(fwd);
839 return -1;
840 }
68ac40d2 841
44b4ff24
MAL
842 if (slirp_add_guestfwd(s->slirp, guestfwd_write, &fwd->hd,
843 &server, port) < 0) {
5c843af2
HP
844 error_setg(errp, "Conflicting/invalid host:port in guest "
845 "forwarding rule '%s'", config_str);
8e207c32 846 qemu_chr_fe_deinit(&fwd->hd, true);
b412eb61
AG
847 g_free(fwd);
848 return -1;
849 }
850 fwd->server = server;
851 fwd->port = port;
852 fwd->slirp = s->slirp;
853
5345fdb4 854 qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
81517ba3 855 NULL, NULL, fwd, NULL, true);
8d45a3b9 856 s->fwd = g_slist_append(s->fwd, fwd);
b412eb61 857 }
68ac40d2
MM
858 return 0;
859
860 fail_syntax:
5c843af2 861 error_setg(errp, "Invalid guest forwarding rule '%s'", config_str);
68ac40d2
MM
862 return -1;
863}
864
1ce6be24 865void hmp_info_usernet(Monitor *mon, const QDict *qdict)
68ac40d2
MM
866{
867 SlirpState *s;
868
869 QTAILQ_FOREACH(s, &slirp_stacks, entry) {
90d87a33 870 int id;
442da403 871 bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0;
b7f43bf2
MAL
872 char *info = slirp_connection_info(s->slirp);
873 monitor_printf(mon, "Hub %d (%s):\n%s",
442da403 874 got_hub_id ? id : -1,
b7f43bf2
MAL
875 s->nc.name, info);
876 g_free(info);
68ac40d2
MM
877 }
878}
879
094f15c5
LE
880static void
881net_init_slirp_configs(const StringList *fwd, int flags)
68ac40d2 882{
094f15c5
LE
883 while (fwd) {
884 struct slirp_config_str *config;
68ac40d2 885
094f15c5
LE
886 config = g_malloc0(sizeof(*config));
887 pstrcpy(config->str, sizeof(config->str), fwd->value->str);
888 config->flags = flags;
889 config->next = slirp_configs;
890 slirp_configs = config;
68ac40d2 891
094f15c5 892 fwd = fwd->next;
68ac40d2 893 }
68ac40d2
MM
894}
895
63d2960b
KS
896static const char **slirp_dnssearch(const StringList *dnsname)
897{
898 const StringList *c = dnsname;
899 size_t i = 0, num_opts = 0;
900 const char **ret;
901
902 while (c) {
903 num_opts++;
904 c = c->next;
905 }
906
907 if (num_opts == 0) {
908 return NULL;
909 }
910
911 ret = g_malloc((num_opts + 1) * sizeof(*ret));
912 c = dnsname;
913 while (c) {
914 ret[i++] = c->value->str;
915 c = c->next;
916 }
917 ret[i] = NULL;
918 return ret;
919}
920
cebea510 921int net_init_slirp(const Netdev *netdev, const char *name,
a30ecde6 922 NetClientState *peer, Error **errp)
68ac40d2
MM
923{
924 struct slirp_config_str *config;
094f15c5 925 char *vnet;
68ac40d2 926 int ret;
094f15c5 927 const NetdevUserOptions *user;
63d2960b 928 const char **dnssearch;
0b11c036 929 bool ipv4 = true, ipv6 = true;
68ac40d2 930
f394b2e2
EB
931 assert(netdev->type == NET_CLIENT_DRIVER_USER);
932 user = &netdev->u.user;
68ac40d2 933
0b11c036
ST
934 if ((user->has_ipv6 && user->ipv6 && !user->has_ipv4) ||
935 (user->has_ipv4 && !user->ipv4)) {
936 ipv4 = 0;
937 }
938 if ((user->has_ipv4 && user->ipv4 && !user->has_ipv6) ||
939 (user->has_ipv6 && !user->ipv6)) {
940 ipv6 = 0;
941 }
942
094f15c5
LE
943 vnet = user->has_net ? g_strdup(user->net) :
944 user->has_ip ? g_strdup_printf("%s/24", user->ip) :
945 NULL;
68ac40d2 946
63d2960b
KS
947 dnssearch = slirp_dnssearch(user->dnssearch);
948
094f15c5 949 /* all optional fields are initialized to "all bits zero" */
68ac40d2 950
094f15c5
LE
951 net_init_slirp_configs(user->hostfwd, SLIRP_CFG_HOSTFWD);
952 net_init_slirp_configs(user->guestfwd, 0);
68ac40d2 953
0b11c036
ST
954 ret = net_slirp_init(peer, "user", name, user->q_restrict,
955 ipv4, vnet, user->host,
956 ipv6, user->ipv6_prefix, user->ipv6_prefixlen,
d8eb3864 957 user->ipv6_host, user->hostname, user->tftp,
7aac531e 958 user->bootfile, user->dhcpstart,
d8eb3864 959 user->dns, user->ipv6_dns, user->smb,
0fca92b9
FZ
960 user->smbserver, dnssearch, user->domainname,
961 user->tftp_server_name, errp);
68ac40d2
MM
962
963 while (slirp_configs) {
964 config = slirp_configs;
965 slirp_configs = config->next;
7267c094 966 g_free(config);
68ac40d2
MM
967 }
968
7267c094 969 g_free(vnet);
63d2960b 970 g_free(dnssearch);
68ac40d2
MM
971
972 return ret;
973}