1 /* SPDX-License-Identifier: MIT */
2 /*
3 * libslirp glue
4 *
5 * Copyright (c) 2004-2008 Fabrice Bellard
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 #include "slirp.h"
26
27
28 #ifndef _WIN32
29 #include <net/if.h>
30 #endif
31
32 /* https://gitlab.freedesktop.org/slirp/libslirp/issues/18 */
33 #if defined(__NetBSD__) && defined(if_mtu)
34 #undef if_mtu
35 #endif
36
37 int slirp_debug;
38
39 /* Define to 1 if you want KEEPALIVE timers */
40 bool slirp_do_keepalive;
41
42 /* host loopback address */
43 struct in_addr loopback_addr;
44 /* host loopback network mask */
45 unsigned long loopback_mask;
46
47 /* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
48 static const uint8_t special_ethaddr[ETH_ALEN] = { 0x52, 0x55, 0x00,
49 0x00, 0x00, 0x00 };
50
51 unsigned curtime;
52
53 static struct in_addr dns_addr;
54 #ifndef _WIN32
55 static struct in6_addr dns6_addr;
56 #endif
57 static unsigned dns_addr_time;
58 #ifndef _WIN32
59 static unsigned dns6_addr_time;
60 #endif
61
62 #define TIMEOUT_FAST 2 /* milliseconds */
63 #define TIMEOUT_SLOW 499 /* milliseconds */
64 /* for the aging of certain requests like DNS */
65 #define TIMEOUT_DEFAULT 1000 /* milliseconds */
66
67 #if defined(_WIN32)
68
get_dns_addr(struct in_addr * pdns_addr)69 int get_dns_addr(struct in_addr *pdns_addr)
70 {
71 FIXED_INFO *FixedInfo = NULL;
72 ULONG BufLen;
73 DWORD ret;
74 IP_ADDR_STRING *pIPAddr;
75 struct in_addr tmp_addr;
76
77 if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
78 *pdns_addr = dns_addr;
79 return 0;
80 }
81
82 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
83 BufLen = sizeof(FIXED_INFO);
84
85 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
86 if (FixedInfo) {
87 GlobalFree(FixedInfo);
88 FixedInfo = NULL;
89 }
90 FixedInfo = GlobalAlloc(GPTR, BufLen);
91 }
92
93 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
94 printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret);
95 if (FixedInfo) {
96 GlobalFree(FixedInfo);
97 FixedInfo = NULL;
98 }
99 return -1;
100 }
101
102 pIPAddr = &(FixedInfo->DnsServerList);
103 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
104 *pdns_addr = tmp_addr;
105 dns_addr = tmp_addr;
106 dns_addr_time = curtime;
107 if (FixedInfo) {
108 GlobalFree(FixedInfo);
109 FixedInfo = NULL;
110 }
111 return 0;
112 }
113
get_dns6_addr(struct in6_addr * pdns6_addr,uint32_t * scope_id)114 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
115 {
116 return -1;
117 }
118
winsock_cleanup(void)119 static void winsock_cleanup(void)
120 {
121 WSACleanup();
122 }
123
124 #elif defined(__APPLE__)
125
126 #include <resolv.h>
127
get_dns_addr_cached(void * pdns_addr,void * cached_addr,socklen_t addrlen,unsigned * cached_time)128 static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
129 socklen_t addrlen, unsigned *cached_time)
130 {
131 if (curtime - *cached_time < TIMEOUT_DEFAULT) {
132 memcpy(pdns_addr, cached_addr, addrlen);
133 return 0;
134 }
135 return 1;
136 }
137
get_dns_addr_libresolv(int af,void * pdns_addr,void * cached_addr,socklen_t addrlen,uint32_t * scope_id,unsigned * cached_time)138 static int get_dns_addr_libresolv(int af, void *pdns_addr, void *cached_addr,
139 socklen_t addrlen, uint32_t *scope_id,
140 unsigned *cached_time)
141 {
142 struct __res_state state;
143 union res_sockaddr_union servers[NI_MAXSERV];
144 int count;
145 int found;
146
147 if (res_ninit(&state) != 0) {
148 return -1;
149 }
150
151 count = res_getservers(&state, servers, NI_MAXSERV);
152 found = 0;
153 DEBUG_MISC("IP address of your DNS(s):");
154 for (int i = 0; i < count; i++) {
155 if (af == servers[i].sin.sin_family) {
156 found++;
157 }
158
159 // we use the first found entry
160 if (found == 1) {
161 memcpy(pdns_addr, &servers[i].sin.sin_addr, addrlen);
162 memcpy(cached_addr, &servers[i].sin.sin_addr, addrlen);
163 if (scope_id) {
164 *scope_id = 0;
165 }
166 *cached_time = curtime;
167 }
168
169 if (found > 3) {
170 DEBUG_MISC(" (more)");
171 break;
172 } else if (slirp_debug & DBG_MISC) {
173 char s[INET6_ADDRSTRLEN];
174 const char *res = inet_ntop(servers[i].sin.sin_family,
175 &servers[i].sin.sin_addr,
176 s,
177 sizeof(s));
178 if (!res) {
179 res = " (string conversion error)";
180 }
181 DEBUG_MISC(" %s", res);
182 }
183 }
184
185 res_nclose(&state);
186 if (!found)
187 return -1;
188 return 0;
189 }
190
get_dns_addr(struct in_addr * pdns_addr)191 int get_dns_addr(struct in_addr *pdns_addr)
192 {
193 if (dns_addr.s_addr != 0) {
194 int ret;
195 ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr),
196 &dns_addr_time);
197 if (ret <= 0) {
198 return ret;
199 }
200 }
201 return get_dns_addr_libresolv(AF_INET, pdns_addr, &dns_addr,
202 sizeof(dns_addr), NULL, &dns_addr_time);
203 }
204
get_dns6_addr(struct in6_addr * pdns6_addr,uint32_t * scope_id)205 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
206 {
207 if (!in6_zero(&dns6_addr)) {
208 int ret;
209 ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr),
210 &dns6_addr_time);
211 if (ret <= 0) {
212 return ret;
213 }
214 }
215 return get_dns_addr_libresolv(AF_INET6, pdns6_addr, &dns6_addr,
216 sizeof(dns6_addr), scope_id, &dns6_addr_time);
217 }
218
219 #else // !defined(_WIN32) && !defined(__APPLE__)
220
221 #if defined(__HAIKU__)
222 #define RESOLV_CONF_PATH "/boot/system/settings/network/resolv.conf"
223 #else
224 #define RESOLV_CONF_PATH "/etc/resolv.conf"
225 #endif
226
get_dns_addr_cached(void * pdns_addr,void * cached_addr,socklen_t addrlen,struct stat * cached_stat,unsigned * cached_time)227 static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
228 socklen_t addrlen, struct stat *cached_stat,
229 unsigned *cached_time)
230 {
231 struct stat old_stat;
232 if (curtime - *cached_time < TIMEOUT_DEFAULT) {
233 memcpy(pdns_addr, cached_addr, addrlen);
234 return 0;
235 }
236 old_stat = *cached_stat;
237 if (stat(RESOLV_CONF_PATH, cached_stat) != 0) {
238 return -1;
239 }
240 if (cached_stat->st_dev == old_stat.st_dev &&
241 cached_stat->st_ino == old_stat.st_ino &&
242 cached_stat->st_size == old_stat.st_size &&
243 cached_stat->st_mtime == old_stat.st_mtime) {
244 memcpy(pdns_addr, cached_addr, addrlen);
245 return 0;
246 }
247 return 1;
248 }
249
get_dns_addr_resolv_conf(int af,void * pdns_addr,void * cached_addr,socklen_t addrlen,uint32_t * scope_id,unsigned * cached_time)250 static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
251 socklen_t addrlen, uint32_t *scope_id,
252 unsigned *cached_time)
253 {
254 char buff[512];
255 char buff2[257];
256 FILE *f;
257 int found = 0;
258 union {
259 struct in_addr dns_addr;
260 struct in6_addr dns6_addr;
261 } tmp_addr;
262 unsigned if_index;
263
264 assert(sizeof(tmp_addr) >= addrlen);
265 f = fopen(RESOLV_CONF_PATH, "r");
266 if (!f)
267 return -1;
268
269 DEBUG_MISC("IP address of your DNS(s):");
270 while (fgets(buff, 512, f) != NULL) {
271 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
272 char *c = strchr(buff2, '%');
273 if (c) {
274 if_index = if_nametoindex(c + 1);
275 *c = '\0';
276 } else {
277 if_index = 0;
278 }
279
280 if (!inet_pton(af, buff2, &tmp_addr)) {
281 continue;
282 }
283 /* If it's the first one, set it to dns_addr */
284 if (!found) {
285 memcpy(pdns_addr, &tmp_addr, addrlen);
286 memcpy(cached_addr, &tmp_addr, addrlen);
287 if (scope_id) {
288 *scope_id = if_index;
289 }
290 *cached_time = curtime;
291 }
292
293 if (++found > 3) {
294 DEBUG_MISC(" (more)");
295 break;
296 } else if (slirp_debug & DBG_MISC) {
297 char s[INET6_ADDRSTRLEN];
298 const char *res = inet_ntop(af, &tmp_addr, s, sizeof(s));
299 if (!res) {
300 res = " (string conversion error)";
301 }
302 DEBUG_MISC(" %s", res);
303 }
304 }
305 }
306 fclose(f);
307 if (!found)
308 return -1;
309 return 0;
310 }
311
get_dns_addr(struct in_addr * pdns_addr)312 int get_dns_addr(struct in_addr *pdns_addr)
313 {
314 static struct stat dns_addr_stat;
315
316 if (dns_addr.s_addr != 0) {
317 int ret;
318 ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr),
319 &dns_addr_stat, &dns_addr_time);
320 if (ret <= 0) {
321 return ret;
322 }
323 }
324 return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr,
325 sizeof(dns_addr), NULL, &dns_addr_time);
326 }
327
get_dns6_addr(struct in6_addr * pdns6_addr,uint32_t * scope_id)328 int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id)
329 {
330 static struct stat dns6_addr_stat;
331
332 if (!in6_zero(&dns6_addr)) {
333 int ret;
334 ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr),
335 &dns6_addr_stat, &dns6_addr_time);
336 if (ret <= 0) {
337 return ret;
338 }
339 }
340 return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr,
341 sizeof(dns6_addr), scope_id,
342 &dns6_addr_time);
343 }
344
345 #endif
346
slirp_init_once(void)347 static void slirp_init_once(void)
348 {
349 static int initialized;
350 const char *debug;
351 #ifdef _WIN32
352 WSADATA Data;
353 #endif
354
355 if (initialized) {
356 return;
357 }
358 initialized = 1;
359
360 #ifdef _WIN32
361 WSAStartup(MAKEWORD(2, 0), &Data);
362 atexit(winsock_cleanup);
363 #endif
364
365 loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
366 loopback_mask = htonl(IN_CLASSA_NET);
367
368 debug = g_getenv("SLIRP_DEBUG");
369 if (debug) {
370 const GDebugKey keys[] = {
371 { "call", DBG_CALL },
372 { "misc", DBG_MISC },
373 { "error", DBG_ERROR },
374 { "tftp", DBG_TFTP },
375 { "verbose_call", DBG_VERBOSE_CALL },
376 };
377 slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
378 }
379 }
380
slirp_new(const SlirpConfig * cfg,const SlirpCb * callbacks,void * opaque)381 Slirp *slirp_new(const SlirpConfig *cfg, const SlirpCb *callbacks, void *opaque)
382 {
383 Slirp *slirp;
384
385 g_return_val_if_fail(cfg != NULL, NULL);
386 g_return_val_if_fail(cfg->version >= SLIRP_CONFIG_VERSION_MIN, NULL);
387 g_return_val_if_fail(cfg->version <= SLIRP_CONFIG_VERSION_MAX, NULL);
388 g_return_val_if_fail(cfg->if_mtu >= IF_MTU_MIN || cfg->if_mtu == 0, NULL);
389 g_return_val_if_fail(cfg->if_mtu <= IF_MTU_MAX, NULL);
390 g_return_val_if_fail(cfg->if_mru >= IF_MRU_MIN || cfg->if_mru == 0, NULL);
391 g_return_val_if_fail(cfg->if_mru <= IF_MRU_MAX, NULL);
392 g_return_val_if_fail(!cfg->bootfile ||
393 (strlen(cfg->bootfile) <
394 G_SIZEOF_MEMBER(struct bootp_t, bp_file)), NULL);
395
396 slirp = g_malloc0(sizeof(Slirp));
397
398 slirp_init_once();
399
400 slirp->opaque = opaque;
401 slirp->cb = callbacks;
402 slirp->grand = g_rand_new();
403 slirp->restricted = cfg->restricted;
404
405 slirp->in_enabled = cfg->in_enabled;
406 slirp->in6_enabled = cfg->in6_enabled;
407
408 if_init(slirp);
409 ip_init(slirp);
410 ip6_init(slirp);
411
412 m_init(slirp);
413
414 slirp->vnetwork_addr = cfg->vnetwork;
415 slirp->vnetwork_mask = cfg->vnetmask;
416 slirp->vhost_addr = cfg->vhost;
417 slirp->vprefix_addr6 = cfg->vprefix_addr6;
418 slirp->vprefix_len = cfg->vprefix_len;
419 slirp->vhost_addr6 = cfg->vhost6;
420 if (cfg->vhostname) {
421 slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
422 cfg->vhostname);
423 }
424 slirp->tftp_prefix = g_strdup(cfg->tftp_path);
425 slirp->bootp_filename = g_strdup(cfg->bootfile);
426 slirp->vdomainname = g_strdup(cfg->vdomainname);
427 slirp->vdhcp_startaddr = cfg->vdhcp_start;
428 slirp->vnameserver_addr = cfg->vnameserver;
429 slirp->vnameserver_addr6 = cfg->vnameserver6;
430 slirp->tftp_server_name = g_strdup(cfg->tftp_server_name);
431
432 if (cfg->vdnssearch) {
433 translate_dnssearch(slirp, cfg->vdnssearch);
434 }
435 slirp->if_mtu = cfg->if_mtu == 0 ? IF_MTU_DEFAULT : cfg->if_mtu;
436 slirp->if_mru = cfg->if_mru == 0 ? IF_MRU_DEFAULT : cfg->if_mru;
437 slirp->disable_host_loopback = cfg->disable_host_loopback;
438 slirp->enable_emu = cfg->enable_emu;
439
440 if (cfg->version >= 2) {
441 slirp->outbound_addr = cfg->outbound_addr;
442 slirp->outbound_addr6 = cfg->outbound_addr6;
443 } else {
444 slirp->outbound_addr = NULL;
445 slirp->outbound_addr6 = NULL;
446 }
447
448 if (cfg->version >= 3) {
449 slirp->disable_dns = cfg->disable_dns;
450 } else {
451 slirp->disable_dns = false;
452 }
453
454 return slirp;
455 }
456
slirp_init(int restricted,bool in_enabled,struct in_addr vnetwork,struct in_addr vnetmask,struct in_addr vhost,bool in6_enabled,struct in6_addr vprefix_addr6,uint8_t vprefix_len,struct in6_addr vhost6,const char * vhostname,const char * tftp_server_name,const char * tftp_path,const char * bootfile,struct in_addr vdhcp_start,struct in_addr vnameserver,struct in6_addr vnameserver6,const char ** vdnssearch,const char * vdomainname,const SlirpCb * callbacks,void * opaque)457 Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
458 struct in_addr vnetmask, struct in_addr vhost,
459 bool in6_enabled, struct in6_addr vprefix_addr6,
460 uint8_t vprefix_len, struct in6_addr vhost6,
461 const char *vhostname, const char *tftp_server_name,
462 const char *tftp_path, const char *bootfile,
463 struct in_addr vdhcp_start, struct in_addr vnameserver,
464 struct in6_addr vnameserver6, const char **vdnssearch,
465 const char *vdomainname, const SlirpCb *callbacks,
466 void *opaque)
467 {
468 SlirpConfig cfg;
469 memset(&cfg, 0, sizeof(cfg));
470 cfg.version = 1;
471 cfg.restricted = restricted;
472 cfg.in_enabled = in_enabled;
473 cfg.vnetwork = vnetwork;
474 cfg.vnetmask = vnetmask;
475 cfg.vhost = vhost;
476 cfg.in6_enabled = in6_enabled;
477 cfg.vprefix_addr6 = vprefix_addr6;
478 cfg.vprefix_len = vprefix_len;
479 cfg.vhost6 = vhost6;
480 cfg.vhostname = vhostname;
481 cfg.tftp_server_name = tftp_server_name;
482 cfg.tftp_path = tftp_path;
483 cfg.bootfile = bootfile;
484 cfg.vdhcp_start = vdhcp_start;
485 cfg.vnameserver = vnameserver;
486 cfg.vnameserver6 = vnameserver6;
487 cfg.vdnssearch = vdnssearch;
488 cfg.vdomainname = vdomainname;
489 return slirp_new(&cfg, callbacks, opaque);
490 }
491
slirp_cleanup(Slirp * slirp)492 void slirp_cleanup(Slirp *slirp)
493 {
494 struct gfwd_list *e, *next;
495
496 for (e = slirp->guestfwd_list; e; e = next) {
497 next = e->ex_next;
498 g_free(e->ex_exec);
499 g_free(e->ex_unix);
500 g_free(e);
501 }
502
503 ip_cleanup(slirp);
504 ip6_cleanup(slirp);
505 m_cleanup(slirp);
506
507 g_rand_free(slirp->grand);
508
509 g_free(slirp->vdnssearch);
510 g_free(slirp->tftp_prefix);
511 g_free(slirp->bootp_filename);
512 g_free(slirp->vdomainname);
513 g_free(slirp);
514 }
515
516 #define CONN_CANFSEND(so) \
517 (((so)->so_state & (SS_FCANTSENDMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED)
518 #define CONN_CANFRCV(so) \
519 (((so)->so_state & (SS_FCANTRCVMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED)
520
slirp_update_timeout(Slirp * slirp,uint32_t * timeout)521 static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
522 {
523 uint32_t t;
524
525 if (*timeout <= TIMEOUT_FAST) {
526 return;
527 }
528
529 t = MIN(1000, *timeout);
530
531 /* If we have tcp timeout with slirp, then we will fill @timeout with
532 * more precise value.
533 */
534 if (slirp->time_fasttimo) {
535 *timeout = TIMEOUT_FAST;
536 return;
537 }
538 if (slirp->do_slowtimo) {
539 t = MIN(TIMEOUT_SLOW, t);
540 }
541 *timeout = t;
542 }
543
slirp_pollfds_fill(Slirp * slirp,uint32_t * timeout,SlirpAddPollCb add_poll,void * opaque)544 void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
545 SlirpAddPollCb add_poll, void *opaque)
546 {
547 struct socket *so, *so_next;
548
549 /*
550 * First, TCP sockets
551 */
552
553 /*
554 * *_slowtimo needs calling if there are IP fragments
555 * in the fragment queue, or there are TCP connections active
556 */
557 slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
558 (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
559
560 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
561 int events = 0;
562
563 so_next = so->so_next;
564
565 so->pollfds_idx = -1;
566
567 /*
568 * See if we need a tcp_fasttimo
569 */
570 if (slirp->time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) {
571 slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
572 }
573
574 /*
575 * NOFDREF can include still connecting to local-host,
576 * newly socreated() sockets etc. Don't want to select these.
577 */
578 if (so->so_state & SS_NOFDREF || so->s == -1) {
579 continue;
580 }
581
582 /*
583 * Set for reading sockets which are accepting
584 */
585 if (so->so_state & SS_FACCEPTCONN) {
586 so->pollfds_idx = add_poll(
587 so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
588 continue;
589 }
590
591 /*
592 * Set for writing sockets which are connecting
593 */
594 if (so->so_state & SS_ISFCONNECTING) {
595 so->pollfds_idx =
596 add_poll(so->s, SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque);
597 continue;
598 }
599
600 /*
601 * Set for writing if we are connected, can send more, and
602 * we have something to send
603 */
604 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
605 events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR;
606 }
607
608 /*
609 * Set for reading (and urgent data) if we are connected, can
610 * receive more, and we have room for it XXX /2 ?
611 */
612 if (CONN_CANFRCV(so) &&
613 (so->so_snd.sb_cc < (so->so_snd.sb_datalen / 2))) {
614 events |= SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR |
615 SLIRP_POLL_PRI;
616 }
617
618 if (events) {
619 so->pollfds_idx = add_poll(so->s, events, opaque);
620 }
621 }
622
623 /*
624 * UDP sockets
625 */
626 for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
627 so_next = so->so_next;
628
629 so->pollfds_idx = -1;
630
631 /*
632 * See if it's timed out
633 */
634 if (so->so_expire) {
635 if (so->so_expire <= curtime) {
636 udp_detach(so);
637 continue;
638 } else {
639 slirp->do_slowtimo = true; /* Let socket expire */
640 }
641 }
642
643 /*
644 * When UDP packets are received from over the
645 * link, they're sendto()'d straight away, so
646 * no need for setting for writing
647 * Limit the number of packets queued by this session
648 * to 4. Note that even though we try and limit this
649 * to 4 packets, the session could have more queued
650 * if the packets needed to be fragmented
651 * (XXX <= 4 ?)
652 */
653 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
654 so->pollfds_idx = add_poll(
655 so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
656 }
657 }
658
659 /*
660 * ICMP sockets
661 */
662 for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
663 so_next = so->so_next;
664
665 so->pollfds_idx = -1;
666
667 /*
668 * See if it's timed out
669 */
670 if (so->so_expire) {
671 if (so->so_expire <= curtime) {
672 icmp_detach(so);
673 continue;
674 } else {
675 slirp->do_slowtimo = true; /* Let socket expire */
676 }
677 }
678
679 if (so->so_state & SS_ISFCONNECTED) {
680 so->pollfds_idx = add_poll(
681 so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
682 }
683 }
684
685 slirp_update_timeout(slirp, timeout);
686 }
687
slirp_pollfds_poll(Slirp * slirp,int select_error,SlirpGetREventsCb get_revents,void * opaque)688 void slirp_pollfds_poll(Slirp *slirp, int select_error,
689 SlirpGetREventsCb get_revents, void *opaque)
690 {
691 struct socket *so, *so_next;
692 int ret;
693
694 curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS;
695
696 /*
697 * See if anything has timed out
698 */
699 if (slirp->time_fasttimo &&
700 ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
701 tcp_fasttimo(slirp);
702 slirp->time_fasttimo = 0;
703 }
704 if (slirp->do_slowtimo &&
705 ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
706 ip_slowtimo(slirp);
707 tcp_slowtimo(slirp);
708 slirp->last_slowtimo = curtime;
709 }
710
711 /*
712 * Check sockets
713 */
714 if (!select_error) {
715 /*
716 * Check TCP sockets
717 */
718 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
719 int revents;
720
721 so_next = so->so_next;
722
723 revents = 0;
724 if (so->pollfds_idx != -1) {
725 revents = get_revents(so->pollfds_idx, opaque);
726 }
727
728 if (so->so_state & SS_NOFDREF || so->s == -1) {
729 continue;
730 }
731
732 #ifndef __APPLE__
733 /*
734 * Check for URG data
735 * This will soread as well, so no need to
736 * test for SLIRP_POLL_IN below if this succeeds.
737 *
738 * This is however disabled on MacOS, which apparently always
739 * reports data as PRI when it is the last data of the
740 * connection. We would then report it out of band, which the guest
741 * would most probably not be ready for.
742 */
743 if (revents & SLIRP_POLL_PRI) {
744 ret = sorecvoob(so);
745 if (ret < 0) {
746 /* Socket error might have resulted in the socket being
747 * removed, do not try to do anything more with it. */
748 continue;
749 }
750 }
751 /*
752 * Check sockets for reading
753 */
754 else
755 #endif
756 if (revents &
757 (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR | SLIRP_POLL_PRI)) {
758 /*
759 * Check for incoming connections
760 */
761 if (so->so_state & SS_FACCEPTCONN) {
762 tcp_connect(so);
763 continue;
764 } /* else */
765 ret = soread(so);
766
767 /* Output it if we read something */
768 if (ret > 0) {
769 tcp_output(sototcpcb(so));
770 }
771 if (ret < 0) {
772 /* Socket error might have resulted in the socket being
773 * removed, do not try to do anything more with it. */
774 continue;
775 }
776 }
777
778 /*
779 * Check sockets for writing
780 */
781 if (!(so->so_state & SS_NOFDREF) &&
782 (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) {
783 /*
784 * Check for non-blocking, still-connecting sockets
785 */
786 if (so->so_state & SS_ISFCONNECTING) {
787 /* Connected */
788 so->so_state &= ~SS_ISFCONNECTING;
789
790 ret = send(so->s, (const void *)&ret, 0, 0);
791 if (ret < 0) {
792 /* XXXXX Must fix, zero bytes is a NOP */
793 if (errno == EAGAIN || errno == EWOULDBLOCK ||
794 errno == EINPROGRESS || errno == ENOTCONN) {
795 continue;
796 }
797
798 /* else failed */
799 so->so_state &= SS_PERSISTENT_MASK;
800 so->so_state |= SS_NOFDREF;
801 }
802 /* else so->so_state &= ~SS_ISFCONNECTING; */
803
804 /*
805 * Continue tcp_input
806 */
807 tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
808 so->so_ffamily);
809 /* continue; */
810 } else {
811 ret = sowrite(so);
812 if (ret > 0) {
813 /* Call tcp_output in case we need to send a window
814 * update to the guest, otherwise it will be stuck
815 * until it sends a window probe. */
816 tcp_output(sototcpcb(so));
817 }
818 }
819 }
820 }
821
822 /*
823 * Now UDP sockets.
824 * Incoming packets are sent straight away, they're not buffered.
825 * Incoming UDP data isn't buffered either.
826 */
827 for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
828 int revents;
829
830 so_next = so->so_next;
831
832 revents = 0;
833 if (so->pollfds_idx != -1) {
834 revents = get_revents(so->pollfds_idx, opaque);
835 }
836
837 if (so->s != -1 &&
838 (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
839 sorecvfrom(so);
840 }
841 }
842
843 /*
844 * Check incoming ICMP relies.
845 */
846 for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
847 int revents;
848
849 so_next = so->so_next;
850
851 revents = 0;
852 if (so->pollfds_idx != -1) {
853 revents = get_revents(so->pollfds_idx, opaque);
854 }
855
856 if (so->s != -1 &&
857 (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
858 icmp_receive(so);
859 }
860 }
861 }
862
863 if_start(slirp);
864 }
865
arp_input(Slirp * slirp,const uint8_t * pkt,int pkt_len)866 static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
867 {
868 const struct slirp_arphdr *ah =
869 (const struct slirp_arphdr *)(pkt + ETH_HLEN);
870 uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)];
871 struct ethhdr *reh = (struct ethhdr *)arp_reply;
872 struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN);
873 int ar_op;
874 struct gfwd_list *ex_ptr;
875
876 if (!slirp->in_enabled) {
877 return;
878 }
879
880 if (pkt_len < ETH_HLEN + sizeof(struct slirp_arphdr)) {
881 return; /* packet too short */
882 }
883
884 ar_op = ntohs(ah->ar_op);
885 switch (ar_op) {
886 case ARPOP_REQUEST:
887 if (ah->ar_tip == ah->ar_sip) {
888 /* Gratuitous ARP */
889 arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
890 return;
891 }
892
893 if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
894 slirp->vnetwork_addr.s_addr) {
895 if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
896 ah->ar_tip == slirp->vhost_addr.s_addr)
897 goto arp_ok;
898 /* TODO: IPv6 */
899 for (ex_ptr = slirp->guestfwd_list; ex_ptr;
900 ex_ptr = ex_ptr->ex_next) {
901 if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
902 goto arp_ok;
903 }
904 return;
905 arp_ok:
906 memset(arp_reply, 0, sizeof(arp_reply));
907
908 arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
909
910 /* ARP request for alias/dns mac address */
911 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
912 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
913 memcpy(&reh->h_source[2], &ah->ar_tip, 4);
914 reh->h_proto = htons(ETH_P_ARP);
915
916 rah->ar_hrd = htons(1);
917 rah->ar_pro = htons(ETH_P_IP);
918 rah->ar_hln = ETH_ALEN;
919 rah->ar_pln = 4;
920 rah->ar_op = htons(ARPOP_REPLY);
921 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
922 rah->ar_sip = ah->ar_tip;
923 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
924 rah->ar_tip = ah->ar_sip;
925 slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply));
926 }
927 break;
928 case ARPOP_REPLY:
929 arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
930 break;
931 default:
932 break;
933 }
934 }
935
slirp_input(Slirp * slirp,const uint8_t * pkt,int pkt_len)936 void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
937 {
938 struct mbuf *m;
939 int proto;
940
941 if (pkt_len < ETH_HLEN)
942 return;
943
944 proto = (((uint16_t)pkt[12]) << 8) + pkt[13];
945 switch (proto) {
946 case ETH_P_ARP:
947 arp_input(slirp, pkt, pkt_len);
948 break;
949 case ETH_P_IP:
950 case ETH_P_IPV6:
951 m = m_get(slirp);
952 if (!m)
953 return;
954 /* Note: we add 2 to align the IP header on 4 bytes,
955 * and add the margin for the tcpiphdr overhead */
956 if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
957 m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
958 }
959 m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
960 memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
961
962 m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
963 m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
964
965 if (proto == ETH_P_IP) {
966 ip_input(m);
967 } else if (proto == ETH_P_IPV6) {
968 ip6_input(m);
969 }
970 break;
971
972 case ETH_P_NCSI:
973 ncsi_input(slirp, pkt, pkt_len);
974 break;
975
976 default:
977 break;
978 }
979 }
980
981 /* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
982 * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
983 * is ready to go.
984 */
if_encap4(Slirp * slirp,struct mbuf * ifm,struct ethhdr * eh,uint8_t ethaddr[ETH_ALEN])985 static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
986 uint8_t ethaddr[ETH_ALEN])
987 {
988 const struct ip *iph = (const struct ip *)ifm->m_data;
989
990 if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
991 uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)];
992 struct ethhdr *reh = (struct ethhdr *)arp_req;
993 struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN);
994
995 if (!ifm->resolution_requested) {
996 /* If the client addr is not known, send an ARP request */
997 memset(reh->h_dest, 0xff, ETH_ALEN);
998 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
999 memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
1000 reh->h_proto = htons(ETH_P_ARP);
1001 rah->ar_hrd = htons(1);
1002 rah->ar_pro = htons(ETH_P_IP);
1003 rah->ar_hln = ETH_ALEN;
1004 rah->ar_pln = 4;
1005 rah->ar_op = htons(ARPOP_REQUEST);
1006
1007 /* source hw addr */
1008 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
1009 memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
1010
1011 /* source IP */
1012 rah->ar_sip = slirp->vhost_addr.s_addr;
1013
1014 /* target hw addr (none) */
1015 memset(rah->ar_tha, 0, ETH_ALEN);
1016
1017 /* target IP */
1018 rah->ar_tip = iph->ip_dst.s_addr;
1019 slirp->client_ipaddr = iph->ip_dst;
1020 slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
1021 ifm->resolution_requested = true;
1022
1023 /* Expire request and drop outgoing packet after 1 second */
1024 ifm->expiration_date =
1025 slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
1026 }
1027 return 0;
1028 } else {
1029 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
1030 /* XXX: not correct */
1031 memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
1032 eh->h_proto = htons(ETH_P_IP);
1033
1034 /* Send this */
1035 return 2;
1036 }
1037 }
1038
1039 /* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
1040 * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
1041 * is ready to go.
1042 */
if_encap6(Slirp * slirp,struct mbuf * ifm,struct ethhdr * eh,uint8_t ethaddr[ETH_ALEN])1043 static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
1044 uint8_t ethaddr[ETH_ALEN])
1045 {
1046 const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
1047 if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
1048 if (!ifm->resolution_requested) {
1049 ndp_send_ns(slirp, ip6h->ip_dst);
1050 ifm->resolution_requested = true;
1051 ifm->expiration_date =
1052 slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
1053 }
1054 return 0;
1055 } else {
1056 eh->h_proto = htons(ETH_P_IPV6);
1057 in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
1058
1059 /* Send this */
1060 return 2;
1061 }
1062 }
1063
1064 /* Output the IP packet to the ethernet device. Returns 0 if the packet must be
1065 * re-queued.
1066 */
if_encap(Slirp * slirp,struct mbuf * ifm)1067 int if_encap(Slirp *slirp, struct mbuf *ifm)
1068 {
1069 uint8_t buf[IF_MTU_MAX + 100];
1070 struct ethhdr *eh = (struct ethhdr *)buf;
1071 uint8_t ethaddr[ETH_ALEN];
1072 const struct ip *iph = (const struct ip *)ifm->m_data;
1073 int ret;
1074 char ethaddr_str[ETH_ADDRSTRLEN];
1075
1076 if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
1077 return 1;
1078 }
1079
1080 switch (iph->ip_v) {
1081 case IPVERSION:
1082 ret = if_encap4(slirp, ifm, eh, ethaddr);
1083 if (ret < 2) {
1084 return ret;
1085 }
1086 break;
1087
1088 case IP6VERSION:
1089 ret = if_encap6(slirp, ifm, eh, ethaddr);
1090 if (ret < 2) {
1091 return ret;
1092 }
1093 break;
1094
1095 default:
1096 g_assert_not_reached();
1097 }
1098
1099 memcpy(eh->h_dest, ethaddr, ETH_ALEN);
1100 DEBUG_ARG("src = %s", slirp_ether_ntoa(eh->h_source, ethaddr_str,
1101 sizeof(ethaddr_str)));
1102 DEBUG_ARG("dst = %s", slirp_ether_ntoa(eh->h_dest, ethaddr_str,
1103 sizeof(ethaddr_str)));
1104 memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
1105 slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
1106 return 1;
1107 }
1108
1109 /* Drop host forwarding rule, return 0 if found. */
slirp_remove_hostfwd(Slirp * slirp,int is_udp,struct in_addr host_addr,int host_port)1110 int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
1111 int host_port)
1112 {
1113 struct socket *so;
1114 struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
1115 struct sockaddr_in addr;
1116 int port = htons(host_port);
1117 socklen_t addr_len;
1118
1119 for (so = head->so_next; so != head; so = so->so_next) {
1120 addr_len = sizeof(addr);
1121 if ((so->so_state & SS_HOSTFWD) &&
1122 getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
1123 addr_len == sizeof(addr) &&
1124 addr.sin_family == AF_INET &&
1125 addr.sin_addr.s_addr == host_addr.s_addr &&
1126 addr.sin_port == port) {
1127 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
1128 closesocket(so->s);
1129 sofree(so);
1130 return 0;
1131 }
1132 }
1133
1134 return -1;
1135 }
1136
slirp_add_hostfwd(Slirp * slirp,int is_udp,struct in_addr host_addr,int host_port,struct in_addr guest_addr,int guest_port)1137 int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
1138 int host_port, struct in_addr guest_addr, int guest_port)
1139 {
1140 if (!guest_addr.s_addr) {
1141 guest_addr = slirp->vdhcp_startaddr;
1142 }
1143 if (is_udp) {
1144 if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
1145 guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
1146 return -1;
1147 } else {
1148 if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
1149 guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
1150 return -1;
1151 }
1152 return 0;
1153 }
1154
slirp_remove_hostxfwd(Slirp * slirp,const struct sockaddr * haddr,socklen_t haddrlen,int flags)1155 int slirp_remove_hostxfwd(Slirp *slirp,
1156 const struct sockaddr *haddr, socklen_t haddrlen,
1157 int flags)
1158 {
1159 struct socket *so;
1160 struct socket *head = (flags & SLIRP_HOSTFWD_UDP ? &slirp->udb : &slirp->tcb);
1161 struct sockaddr_storage addr;
1162 socklen_t addr_len;
1163
1164 for (so = head->so_next; so != head; so = so->so_next) {
1165 addr_len = sizeof(addr);
1166 if ((so->so_state & SS_HOSTFWD) &&
1167 getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
1168 sockaddr_equal(&addr, (const struct sockaddr_storage *) haddr)) {
1169 so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
1170 closesocket(so->s);
1171 sofree(so);
1172 return 0;
1173 }
1174 }
1175
1176 return -1;
1177 }
1178
slirp_add_hostxfwd(Slirp * slirp,const struct sockaddr * haddr,socklen_t haddrlen,const struct sockaddr * gaddr,socklen_t gaddrlen,int flags)1179 int slirp_add_hostxfwd(Slirp *slirp,
1180 const struct sockaddr *haddr, socklen_t haddrlen,
1181 const struct sockaddr *gaddr, socklen_t gaddrlen,
1182 int flags)
1183 {
1184 struct sockaddr_in gdhcp_addr;
1185 int fwd_flags = SS_HOSTFWD;
1186
1187 if (flags & SLIRP_HOSTFWD_V6ONLY)
1188 fwd_flags |= SS_HOSTFWD_V6ONLY;
1189
1190 if (gaddr->sa_family == AF_INET) {
1191 const struct sockaddr_in *gaddr_in = (const struct sockaddr_in *) gaddr;
1192
1193 if (gaddrlen < sizeof(struct sockaddr_in)) {
1194 errno = EINVAL;
1195 return -1;
1196 }
1197
1198 if (!gaddr_in->sin_addr.s_addr) {
1199 gdhcp_addr = *gaddr_in;
1200 gdhcp_addr.sin_addr = slirp->vdhcp_startaddr;
1201 gaddr = (struct sockaddr *) &gdhcp_addr;
1202 gaddrlen = sizeof(gdhcp_addr);
1203 }
1204 } else {
1205 if (gaddrlen < sizeof(struct sockaddr_in6)) {
1206 errno = EINVAL;
1207 return -1;
1208 }
1209
1210 /*
1211 * Libslirp currently only provides a stateless DHCPv6 server, thus
1212 * we can't translate "addr-any" to the guest here. Instead, we defer
1213 * performing the translation to when it's needed. See
1214 * soassign_guest_addr_if_needed().
1215 */
1216 }
1217
1218 if (flags & SLIRP_HOSTFWD_UDP) {
1219 if (!udpx_listen(slirp, haddr, haddrlen,
1220 gaddr, gaddrlen,
1221 fwd_flags))
1222 return -1;
1223 } else {
1224 if (!tcpx_listen(slirp, haddr, haddrlen,
1225 gaddr, gaddrlen,
1226 fwd_flags))
1227 return -1;
1228 }
1229 return 0;
1230 }
1231
1232 /* TODO: IPv6 */
check_guestfwd(Slirp * slirp,struct in_addr * guest_addr,int guest_port)1233 static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr,
1234 int guest_port)
1235 {
1236 struct gfwd_list *tmp_ptr;
1237
1238 if (!guest_addr->s_addr) {
1239 guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
1240 (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
1241 }
1242 if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
1243 slirp->vnetwork_addr.s_addr ||
1244 guest_addr->s_addr == slirp->vhost_addr.s_addr ||
1245 guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
1246 return false;
1247 }
1248
1249 /* check if the port is "bound" */
1250 for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
1251 if (guest_port == tmp_ptr->ex_fport &&
1252 guest_addr->s_addr == tmp_ptr->ex_addr.s_addr)
1253 return false;
1254 }
1255
1256 return true;
1257 }
1258
slirp_add_exec(Slirp * slirp,const char * cmdline,struct in_addr * guest_addr,int guest_port)1259 int slirp_add_exec(Slirp *slirp, const char *cmdline,
1260 struct in_addr *guest_addr, int guest_port)
1261 {
1262 if (!check_guestfwd(slirp, guest_addr, guest_port)) {
1263 return -1;
1264 }
1265
1266 add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
1267 return 0;
1268 }
1269
slirp_add_unix(Slirp * slirp,const char * unixsock,struct in_addr * guest_addr,int guest_port)1270 int slirp_add_unix(Slirp *slirp, const char *unixsock,
1271 struct in_addr *guest_addr, int guest_port)
1272 {
1273 #ifdef G_OS_UNIX
1274 if (!check_guestfwd(slirp, guest_addr, guest_port)) {
1275 return -1;
1276 }
1277
1278 add_unix(&slirp->guestfwd_list, unixsock, *guest_addr, htons(guest_port));
1279 return 0;
1280 #else
1281 g_warn_if_reached();
1282 return -1;
1283 #endif
1284 }
1285
slirp_add_guestfwd(Slirp * slirp,SlirpWriteCb write_cb,void * opaque,struct in_addr * guest_addr,int guest_port)1286 int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
1287 struct in_addr *guest_addr, int guest_port)
1288 {
1289 if (!check_guestfwd(slirp, guest_addr, guest_port)) {
1290 return -1;
1291 }
1292
1293 add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr,
1294 htons(guest_port));
1295 return 0;
1296 }
1297
slirp_remove_guestfwd(Slirp * slirp,struct in_addr guest_addr,int guest_port)1298 int slirp_remove_guestfwd(Slirp *slirp, struct in_addr guest_addr,
1299 int guest_port)
1300 {
1301 return remove_guestfwd(&slirp->guestfwd_list, guest_addr,
1302 htons(guest_port));
1303 }
1304
slirp_send(struct socket * so,const void * buf,size_t len,int flags)1305 ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
1306 {
1307 if (so->s == -1 && so->guestfwd) {
1308 /* XXX this blocks entire thread. Rewrite to use
1309 * qemu_chr_fe_write and background I/O callbacks */
1310 so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
1311 return len;
1312 }
1313
1314 if (so->s == -1) {
1315 /*
1316 * This should in theory not happen but it is hard to be
1317 * sure because some code paths will end up with so->s == -1
1318 * on a failure but don't dispose of the struct socket.
1319 * Check specifically, so we don't pass -1 to send().
1320 */
1321 errno = EBADF;
1322 return -1;
1323 }
1324
1325 return send(so->s, buf, len, flags);
1326 }
1327
slirp_find_ctl_socket(Slirp * slirp,struct in_addr guest_addr,int guest_port)1328 struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr,
1329 int guest_port)
1330 {
1331 struct socket *so;
1332
1333 /* TODO: IPv6 */
1334 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
1335 if (so->so_faddr.s_addr == guest_addr.s_addr &&
1336 htons(so->so_fport) == guest_port) {
1337 return so;
1338 }
1339 }
1340 return NULL;
1341 }
1342
slirp_socket_can_recv(Slirp * slirp,struct in_addr guest_addr,int guest_port)1343 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
1344 int guest_port)
1345 {
1346 struct iovec iov[2];
1347 struct socket *so;
1348
1349 so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
1350
1351 if (!so || so->so_state & SS_NOFDREF) {
1352 return 0;
1353 }
1354
1355 if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen / 2)) {
1356 return 0;
1357 }
1358
1359 return sopreprbuf(so, iov, NULL);
1360 }
1361
slirp_socket_recv(Slirp * slirp,struct in_addr guest_addr,int guest_port,const uint8_t * buf,int size)1362 void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
1363 const uint8_t *buf, int size)
1364 {
1365 int ret;
1366 struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
1367
1368 if (!so)
1369 return;
1370
1371 ret = soreadbuf(so, (const char *)buf, size);
1372
1373 if (ret > 0)
1374 tcp_output(sototcpcb(so));
1375 }
1376
slirp_send_packet_all(Slirp * slirp,const void * buf,size_t len)1377 void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len)
1378 {
1379 ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque);
1380
1381 if (ret < 0) {
1382 g_critical("Failed to send packet, ret: %ld", (long)ret);
1383 } else if (ret < len) {
1384 DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu", (long)ret,
1385 (unsigned long)len);
1386 }
1387 }
1388