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 | int slirp_debug; |
33 | |
34 | /* Define to 1 if you want KEEPALIVE timers */ |
35 | bool slirp_do_keepalive; |
36 | |
37 | /* host loopback address */ |
38 | struct in_addr loopback_addr; |
39 | /* host loopback network mask */ |
40 | unsigned long loopback_mask; |
41 | |
42 | /* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */ |
43 | static const uint8_t special_ethaddr[ETH_ALEN] = { 0x52, 0x55, 0x00, |
44 | 0x00, 0x00, 0x00 }; |
45 | |
46 | unsigned curtime; |
47 | |
48 | static struct in_addr dns_addr; |
49 | #ifndef _WIN32 |
50 | static struct in6_addr dns6_addr; |
51 | #endif |
52 | static unsigned dns_addr_time; |
53 | #ifndef _WIN32 |
54 | static unsigned dns6_addr_time; |
55 | #endif |
56 | |
57 | #define TIMEOUT_FAST 2 /* milliseconds */ |
58 | #define TIMEOUT_SLOW 499 /* milliseconds */ |
59 | /* for the aging of certain requests like DNS */ |
60 | #define TIMEOUT_DEFAULT 1000 /* milliseconds */ |
61 | |
62 | #ifdef _WIN32 |
63 | |
64 | int get_dns_addr(struct in_addr *pdns_addr) |
65 | { |
66 | FIXED_INFO *FixedInfo = NULL; |
67 | ULONG BufLen; |
68 | DWORD ret; |
69 | IP_ADDR_STRING *pIPAddr; |
70 | struct in_addr tmp_addr; |
71 | |
72 | if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) { |
73 | *pdns_addr = dns_addr; |
74 | return 0; |
75 | } |
76 | |
77 | FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); |
78 | BufLen = sizeof(FIXED_INFO); |
79 | |
80 | if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { |
81 | if (FixedInfo) { |
82 | GlobalFree(FixedInfo); |
83 | FixedInfo = NULL; |
84 | } |
85 | FixedInfo = GlobalAlloc(GPTR, BufLen); |
86 | } |
87 | |
88 | if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { |
89 | printf("GetNetworkParams failed. ret = %08x\n" , (unsigned)ret); |
90 | if (FixedInfo) { |
91 | GlobalFree(FixedInfo); |
92 | FixedInfo = NULL; |
93 | } |
94 | return -1; |
95 | } |
96 | |
97 | pIPAddr = &(FixedInfo->DnsServerList); |
98 | inet_aton(pIPAddr->IpAddress.String, &tmp_addr); |
99 | *pdns_addr = tmp_addr; |
100 | dns_addr = tmp_addr; |
101 | dns_addr_time = curtime; |
102 | if (FixedInfo) { |
103 | GlobalFree(FixedInfo); |
104 | FixedInfo = NULL; |
105 | } |
106 | return 0; |
107 | } |
108 | |
109 | int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) |
110 | { |
111 | return -1; |
112 | } |
113 | |
114 | static void winsock_cleanup(void) |
115 | { |
116 | WSACleanup(); |
117 | } |
118 | |
119 | #else |
120 | |
121 | static int get_dns_addr_cached(void *pdns_addr, void *cached_addr, |
122 | socklen_t addrlen, struct stat *cached_stat, |
123 | unsigned *cached_time) |
124 | { |
125 | struct stat old_stat; |
126 | if (curtime - *cached_time < TIMEOUT_DEFAULT) { |
127 | memcpy(pdns_addr, cached_addr, addrlen); |
128 | return 0; |
129 | } |
130 | old_stat = *cached_stat; |
131 | if (stat("/etc/resolv.conf" , cached_stat) != 0) { |
132 | return -1; |
133 | } |
134 | if (cached_stat->st_dev == old_stat.st_dev && |
135 | cached_stat->st_ino == old_stat.st_ino && |
136 | cached_stat->st_size == old_stat.st_size && |
137 | cached_stat->st_mtime == old_stat.st_mtime) { |
138 | memcpy(pdns_addr, cached_addr, addrlen); |
139 | return 0; |
140 | } |
141 | return 1; |
142 | } |
143 | |
144 | static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr, |
145 | socklen_t addrlen, uint32_t *scope_id, |
146 | unsigned *cached_time) |
147 | { |
148 | char buff[512]; |
149 | char buff2[257]; |
150 | FILE *f; |
151 | int found = 0; |
152 | void *tmp_addr = alloca(addrlen); |
153 | unsigned if_index; |
154 | |
155 | f = fopen("/etc/resolv.conf" , "r" ); |
156 | if (!f) |
157 | return -1; |
158 | |
159 | DEBUG_MISC("IP address of your DNS(s):" ); |
160 | while (fgets(buff, 512, f) != NULL) { |
161 | if (sscanf(buff, "nameserver%*[ \t]%256s" , buff2) == 1) { |
162 | char *c = strchr(buff2, '%'); |
163 | if (c) { |
164 | if_index = if_nametoindex(c + 1); |
165 | *c = '\0'; |
166 | } else { |
167 | if_index = 0; |
168 | } |
169 | |
170 | if (!inet_pton(af, buff2, tmp_addr)) { |
171 | continue; |
172 | } |
173 | /* If it's the first one, set it to dns_addr */ |
174 | if (!found) { |
175 | memcpy(pdns_addr, tmp_addr, addrlen); |
176 | memcpy(cached_addr, tmp_addr, addrlen); |
177 | if (scope_id) { |
178 | *scope_id = if_index; |
179 | } |
180 | *cached_time = curtime; |
181 | } |
182 | |
183 | if (++found > 3) { |
184 | DEBUG_MISC(" (more)" ); |
185 | break; |
186 | } else if (slirp_debug & DBG_MISC) { |
187 | char s[INET6_ADDRSTRLEN]; |
188 | const char *res = inet_ntop(af, tmp_addr, s, sizeof(s)); |
189 | if (!res) { |
190 | res = " (string conversion error)" ; |
191 | } |
192 | DEBUG_MISC(" %s" , res); |
193 | } |
194 | } |
195 | } |
196 | fclose(f); |
197 | if (!found) |
198 | return -1; |
199 | return 0; |
200 | } |
201 | |
202 | int get_dns_addr(struct in_addr *pdns_addr) |
203 | { |
204 | static struct stat dns_addr_stat; |
205 | |
206 | if (dns_addr.s_addr != 0) { |
207 | int ret; |
208 | ret = get_dns_addr_cached(pdns_addr, &dns_addr, sizeof(dns_addr), |
209 | &dns_addr_stat, &dns_addr_time); |
210 | if (ret <= 0) { |
211 | return ret; |
212 | } |
213 | } |
214 | return get_dns_addr_resolv_conf(AF_INET, pdns_addr, &dns_addr, |
215 | sizeof(dns_addr), NULL, &dns_addr_time); |
216 | } |
217 | |
218 | int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) |
219 | { |
220 | static struct stat dns6_addr_stat; |
221 | |
222 | if (!in6_zero(&dns6_addr)) { |
223 | int ret; |
224 | ret = get_dns_addr_cached(pdns6_addr, &dns6_addr, sizeof(dns6_addr), |
225 | &dns6_addr_stat, &dns6_addr_time); |
226 | if (ret <= 0) { |
227 | return ret; |
228 | } |
229 | } |
230 | return get_dns_addr_resolv_conf(AF_INET6, pdns6_addr, &dns6_addr, |
231 | sizeof(dns6_addr), scope_id, |
232 | &dns6_addr_time); |
233 | } |
234 | |
235 | #endif |
236 | |
237 | static void slirp_init_once(void) |
238 | { |
239 | static int initialized; |
240 | const char *debug; |
241 | #ifdef _WIN32 |
242 | WSADATA Data; |
243 | #endif |
244 | |
245 | if (initialized) { |
246 | return; |
247 | } |
248 | initialized = 1; |
249 | |
250 | #ifdef _WIN32 |
251 | WSAStartup(MAKEWORD(2, 0), &Data); |
252 | atexit(winsock_cleanup); |
253 | #endif |
254 | |
255 | loopback_addr.s_addr = htonl(INADDR_LOOPBACK); |
256 | loopback_mask = htonl(IN_CLASSA_NET); |
257 | |
258 | debug = g_getenv("SLIRP_DEBUG" ); |
259 | if (debug) { |
260 | const GDebugKey keys[] = { |
261 | { "call" , DBG_CALL }, |
262 | { "misc" , DBG_MISC }, |
263 | { "error" , DBG_ERROR }, |
264 | { "tftp" , DBG_TFTP }, |
265 | }; |
266 | slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys)); |
267 | } |
268 | } |
269 | |
270 | Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork, |
271 | struct in_addr vnetmask, struct in_addr vhost, |
272 | bool in6_enabled, struct in6_addr vprefix_addr6, |
273 | uint8_t vprefix_len, struct in6_addr vhost6, |
274 | const char *vhostname, const char *tftp_server_name, |
275 | const char *tftp_path, const char *bootfile, |
276 | struct in_addr vdhcp_start, struct in_addr vnameserver, |
277 | struct in6_addr vnameserver6, const char **vdnssearch, |
278 | const char *vdomainname, const SlirpCb *callbacks, |
279 | void *opaque) |
280 | { |
281 | Slirp *slirp = g_malloc0(sizeof(Slirp)); |
282 | |
283 | slirp_init_once(); |
284 | |
285 | slirp->opaque = opaque; |
286 | slirp->cb = callbacks; |
287 | slirp->grand = g_rand_new(); |
288 | slirp->restricted = restricted; |
289 | |
290 | slirp->in_enabled = in_enabled; |
291 | slirp->in6_enabled = in6_enabled; |
292 | |
293 | if_init(slirp); |
294 | ip_init(slirp); |
295 | ip6_init(slirp); |
296 | |
297 | /* Initialise mbufs *after* setting the MTU */ |
298 | m_init(slirp); |
299 | |
300 | slirp->vnetwork_addr = vnetwork; |
301 | slirp->vnetwork_mask = vnetmask; |
302 | slirp->vhost_addr = vhost; |
303 | slirp->vprefix_addr6 = vprefix_addr6; |
304 | slirp->vprefix_len = vprefix_len; |
305 | slirp->vhost_addr6 = vhost6; |
306 | if (vhostname) { |
307 | slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname), |
308 | vhostname); |
309 | } |
310 | slirp->tftp_prefix = g_strdup(tftp_path); |
311 | slirp->bootp_filename = g_strdup(bootfile); |
312 | slirp->vdomainname = g_strdup(vdomainname); |
313 | slirp->vdhcp_startaddr = vdhcp_start; |
314 | slirp->vnameserver_addr = vnameserver; |
315 | slirp->vnameserver_addr6 = vnameserver6; |
316 | slirp->tftp_server_name = g_strdup(tftp_server_name); |
317 | |
318 | if (vdnssearch) { |
319 | translate_dnssearch(slirp, vdnssearch); |
320 | } |
321 | |
322 | return slirp; |
323 | } |
324 | |
325 | void slirp_cleanup(Slirp *slirp) |
326 | { |
327 | struct gfwd_list *e, *next; |
328 | |
329 | for (e = slirp->guestfwd_list; e; e = next) { |
330 | next = e->ex_next; |
331 | g_free(e->ex_exec); |
332 | g_free(e); |
333 | } |
334 | |
335 | ip_cleanup(slirp); |
336 | ip6_cleanup(slirp); |
337 | m_cleanup(slirp); |
338 | |
339 | g_rand_free(slirp->grand); |
340 | |
341 | g_free(slirp->vdnssearch); |
342 | g_free(slirp->tftp_prefix); |
343 | g_free(slirp->bootp_filename); |
344 | g_free(slirp->vdomainname); |
345 | g_free(slirp); |
346 | } |
347 | |
348 | #define CONN_CANFSEND(so) \ |
349 | (((so)->so_state & (SS_FCANTSENDMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED) |
350 | #define CONN_CANFRCV(so) \ |
351 | (((so)->so_state & (SS_FCANTRCVMORE | SS_ISFCONNECTED)) == SS_ISFCONNECTED) |
352 | |
353 | static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout) |
354 | { |
355 | uint32_t t; |
356 | |
357 | if (*timeout <= TIMEOUT_FAST) { |
358 | return; |
359 | } |
360 | |
361 | t = MIN(1000, *timeout); |
362 | |
363 | /* If we have tcp timeout with slirp, then we will fill @timeout with |
364 | * more precise value. |
365 | */ |
366 | if (slirp->time_fasttimo) { |
367 | *timeout = TIMEOUT_FAST; |
368 | return; |
369 | } |
370 | if (slirp->do_slowtimo) { |
371 | t = MIN(TIMEOUT_SLOW, t); |
372 | } |
373 | *timeout = t; |
374 | } |
375 | |
376 | void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout, |
377 | SlirpAddPollCb add_poll, void *opaque) |
378 | { |
379 | struct socket *so, *so_next; |
380 | |
381 | /* |
382 | * First, TCP sockets |
383 | */ |
384 | |
385 | /* |
386 | * *_slowtimo needs calling if there are IP fragments |
387 | * in the fragment queue, or there are TCP connections active |
388 | */ |
389 | slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) || |
390 | (&slirp->ipq.ip_link != slirp->ipq.ip_link.next)); |
391 | |
392 | for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { |
393 | int events = 0; |
394 | |
395 | so_next = so->so_next; |
396 | |
397 | so->pollfds_idx = -1; |
398 | |
399 | /* |
400 | * See if we need a tcp_fasttimo |
401 | */ |
402 | if (slirp->time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) { |
403 | slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */ |
404 | } |
405 | |
406 | /* |
407 | * NOFDREF can include still connecting to local-host, |
408 | * newly socreated() sockets etc. Don't want to select these. |
409 | */ |
410 | if (so->so_state & SS_NOFDREF || so->s == -1) { |
411 | continue; |
412 | } |
413 | |
414 | /* |
415 | * Set for reading sockets which are accepting |
416 | */ |
417 | if (so->so_state & SS_FACCEPTCONN) { |
418 | so->pollfds_idx = add_poll( |
419 | so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); |
420 | continue; |
421 | } |
422 | |
423 | /* |
424 | * Set for writing sockets which are connecting |
425 | */ |
426 | if (so->so_state & SS_ISFCONNECTING) { |
427 | so->pollfds_idx = |
428 | add_poll(so->s, SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque); |
429 | continue; |
430 | } |
431 | |
432 | /* |
433 | * Set for writing if we are connected, can send more, and |
434 | * we have something to send |
435 | */ |
436 | if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { |
437 | events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR; |
438 | } |
439 | |
440 | /* |
441 | * Set for reading (and urgent data) if we are connected, can |
442 | * receive more, and we have room for it XXX /2 ? |
443 | */ |
444 | if (CONN_CANFRCV(so) && |
445 | (so->so_snd.sb_cc < (so->so_snd.sb_datalen / 2))) { |
446 | events |= SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR | |
447 | SLIRP_POLL_PRI; |
448 | } |
449 | |
450 | if (events) { |
451 | so->pollfds_idx = add_poll(so->s, events, opaque); |
452 | } |
453 | } |
454 | |
455 | /* |
456 | * UDP sockets |
457 | */ |
458 | for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { |
459 | so_next = so->so_next; |
460 | |
461 | so->pollfds_idx = -1; |
462 | |
463 | /* |
464 | * See if it's timed out |
465 | */ |
466 | if (so->so_expire) { |
467 | if (so->so_expire <= curtime) { |
468 | udp_detach(so); |
469 | continue; |
470 | } else { |
471 | slirp->do_slowtimo = true; /* Let socket expire */ |
472 | } |
473 | } |
474 | |
475 | /* |
476 | * When UDP packets are received from over the |
477 | * link, they're sendto()'d straight away, so |
478 | * no need for setting for writing |
479 | * Limit the number of packets queued by this session |
480 | * to 4. Note that even though we try and limit this |
481 | * to 4 packets, the session could have more queued |
482 | * if the packets needed to be fragmented |
483 | * (XXX <= 4 ?) |
484 | */ |
485 | if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { |
486 | so->pollfds_idx = add_poll( |
487 | so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); |
488 | } |
489 | } |
490 | |
491 | /* |
492 | * ICMP sockets |
493 | */ |
494 | for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { |
495 | so_next = so->so_next; |
496 | |
497 | so->pollfds_idx = -1; |
498 | |
499 | /* |
500 | * See if it's timed out |
501 | */ |
502 | if (so->so_expire) { |
503 | if (so->so_expire <= curtime) { |
504 | icmp_detach(so); |
505 | continue; |
506 | } else { |
507 | slirp->do_slowtimo = true; /* Let socket expire */ |
508 | } |
509 | } |
510 | |
511 | if (so->so_state & SS_ISFCONNECTED) { |
512 | so->pollfds_idx = add_poll( |
513 | so->s, SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque); |
514 | } |
515 | } |
516 | |
517 | slirp_update_timeout(slirp, timeout); |
518 | } |
519 | |
520 | void slirp_pollfds_poll(Slirp *slirp, int select_error, |
521 | SlirpGetREventsCb get_revents, void *opaque) |
522 | { |
523 | struct socket *so, *so_next; |
524 | int ret; |
525 | |
526 | curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS; |
527 | |
528 | /* |
529 | * See if anything has timed out |
530 | */ |
531 | if (slirp->time_fasttimo && |
532 | ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) { |
533 | tcp_fasttimo(slirp); |
534 | slirp->time_fasttimo = 0; |
535 | } |
536 | if (slirp->do_slowtimo && |
537 | ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) { |
538 | ip_slowtimo(slirp); |
539 | tcp_slowtimo(slirp); |
540 | slirp->last_slowtimo = curtime; |
541 | } |
542 | |
543 | /* |
544 | * Check sockets |
545 | */ |
546 | if (!select_error) { |
547 | /* |
548 | * Check TCP sockets |
549 | */ |
550 | for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) { |
551 | int revents; |
552 | |
553 | so_next = so->so_next; |
554 | |
555 | revents = 0; |
556 | if (so->pollfds_idx != -1) { |
557 | revents = get_revents(so->pollfds_idx, opaque); |
558 | } |
559 | |
560 | if (so->so_state & SS_NOFDREF || so->s == -1) { |
561 | continue; |
562 | } |
563 | |
564 | /* |
565 | * Check for URG data |
566 | * This will soread as well, so no need to |
567 | * test for SLIRP_POLL_IN below if this succeeds |
568 | */ |
569 | if (revents & SLIRP_POLL_PRI) { |
570 | ret = sorecvoob(so); |
571 | if (ret < 0) { |
572 | /* Socket error might have resulted in the socket being |
573 | * removed, do not try to do anything more with it. */ |
574 | continue; |
575 | } |
576 | } |
577 | /* |
578 | * Check sockets for reading |
579 | */ |
580 | else if (revents & |
581 | (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) { |
582 | /* |
583 | * Check for incoming connections |
584 | */ |
585 | if (so->so_state & SS_FACCEPTCONN) { |
586 | tcp_connect(so); |
587 | continue; |
588 | } /* else */ |
589 | ret = soread(so); |
590 | |
591 | /* Output it if we read something */ |
592 | if (ret > 0) { |
593 | tcp_output(sototcpcb(so)); |
594 | } |
595 | if (ret < 0) { |
596 | /* Socket error might have resulted in the socket being |
597 | * removed, do not try to do anything more with it. */ |
598 | continue; |
599 | } |
600 | } |
601 | |
602 | /* |
603 | * Check sockets for writing |
604 | */ |
605 | if (!(so->so_state & SS_NOFDREF) && |
606 | (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) { |
607 | /* |
608 | * Check for non-blocking, still-connecting sockets |
609 | */ |
610 | if (so->so_state & SS_ISFCONNECTING) { |
611 | /* Connected */ |
612 | so->so_state &= ~SS_ISFCONNECTING; |
613 | |
614 | ret = send(so->s, (const void *)&ret, 0, 0); |
615 | if (ret < 0) { |
616 | /* XXXXX Must fix, zero bytes is a NOP */ |
617 | if (errno == EAGAIN || errno == EWOULDBLOCK || |
618 | errno == EINPROGRESS || errno == ENOTCONN) { |
619 | continue; |
620 | } |
621 | |
622 | /* else failed */ |
623 | so->so_state &= SS_PERSISTENT_MASK; |
624 | so->so_state |= SS_NOFDREF; |
625 | } |
626 | /* else so->so_state &= ~SS_ISFCONNECTING; */ |
627 | |
628 | /* |
629 | * Continue tcp_input |
630 | */ |
631 | tcp_input((struct mbuf *)NULL, sizeof(struct ip), so, |
632 | so->so_ffamily); |
633 | /* continue; */ |
634 | } else { |
635 | ret = sowrite(so); |
636 | if (ret > 0) { |
637 | /* Call tcp_output in case we need to send a window |
638 | * update to the guest, otherwise it will be stuck |
639 | * until it sends a window probe. */ |
640 | tcp_output(sototcpcb(so)); |
641 | } |
642 | } |
643 | } |
644 | } |
645 | |
646 | /* |
647 | * Now UDP sockets. |
648 | * Incoming packets are sent straight away, they're not buffered. |
649 | * Incoming UDP data isn't buffered either. |
650 | */ |
651 | for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) { |
652 | int revents; |
653 | |
654 | so_next = so->so_next; |
655 | |
656 | revents = 0; |
657 | if (so->pollfds_idx != -1) { |
658 | revents = get_revents(so->pollfds_idx, opaque); |
659 | } |
660 | |
661 | if (so->s != -1 && |
662 | (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) { |
663 | sorecvfrom(so); |
664 | } |
665 | } |
666 | |
667 | /* |
668 | * Check incoming ICMP relies. |
669 | */ |
670 | for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) { |
671 | int revents; |
672 | |
673 | so_next = so->so_next; |
674 | |
675 | revents = 0; |
676 | if (so->pollfds_idx != -1) { |
677 | revents = get_revents(so->pollfds_idx, opaque); |
678 | } |
679 | |
680 | if (so->s != -1 && |
681 | (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) { |
682 | icmp_receive(so); |
683 | } |
684 | } |
685 | } |
686 | |
687 | if_start(slirp); |
688 | } |
689 | |
690 | static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) |
691 | { |
692 | struct slirp_arphdr *ah = (struct slirp_arphdr *)(pkt + ETH_HLEN); |
693 | uint8_t arp_reply[MAX(ETH_HLEN + sizeof(struct slirp_arphdr), 64)]; |
694 | struct ethhdr *reh = (struct ethhdr *)arp_reply; |
695 | struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN); |
696 | int ar_op; |
697 | struct gfwd_list *ex_ptr; |
698 | |
699 | if (!slirp->in_enabled) { |
700 | return; |
701 | } |
702 | |
703 | ar_op = ntohs(ah->ar_op); |
704 | switch (ar_op) { |
705 | case ARPOP_REQUEST: |
706 | if (ah->ar_tip == ah->ar_sip) { |
707 | /* Gratuitous ARP */ |
708 | arp_table_add(slirp, ah->ar_sip, ah->ar_sha); |
709 | return; |
710 | } |
711 | |
712 | if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) == |
713 | slirp->vnetwork_addr.s_addr) { |
714 | if (ah->ar_tip == slirp->vnameserver_addr.s_addr || |
715 | ah->ar_tip == slirp->vhost_addr.s_addr) |
716 | goto arp_ok; |
717 | /* TODO: IPv6 */ |
718 | for (ex_ptr = slirp->guestfwd_list; ex_ptr; |
719 | ex_ptr = ex_ptr->ex_next) { |
720 | if (ex_ptr->ex_addr.s_addr == ah->ar_tip) |
721 | goto arp_ok; |
722 | } |
723 | return; |
724 | arp_ok: |
725 | memset(arp_reply, 0, sizeof(arp_reply)); |
726 | |
727 | arp_table_add(slirp, ah->ar_sip, ah->ar_sha); |
728 | |
729 | /* ARP request for alias/dns mac address */ |
730 | memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); |
731 | memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); |
732 | memcpy(&reh->h_source[2], &ah->ar_tip, 4); |
733 | reh->h_proto = htons(ETH_P_ARP); |
734 | |
735 | rah->ar_hrd = htons(1); |
736 | rah->ar_pro = htons(ETH_P_IP); |
737 | rah->ar_hln = ETH_ALEN; |
738 | rah->ar_pln = 4; |
739 | rah->ar_op = htons(ARPOP_REPLY); |
740 | memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); |
741 | rah->ar_sip = ah->ar_tip; |
742 | memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); |
743 | rah->ar_tip = ah->ar_sip; |
744 | slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply)); |
745 | } |
746 | break; |
747 | case ARPOP_REPLY: |
748 | arp_table_add(slirp, ah->ar_sip, ah->ar_sha); |
749 | break; |
750 | default: |
751 | break; |
752 | } |
753 | } |
754 | |
755 | void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) |
756 | { |
757 | struct mbuf *m; |
758 | int proto; |
759 | |
760 | if (pkt_len < ETH_HLEN) |
761 | return; |
762 | |
763 | proto = (((uint16_t)pkt[12]) << 8) + pkt[13]; |
764 | switch (proto) { |
765 | case ETH_P_ARP: |
766 | arp_input(slirp, pkt, pkt_len); |
767 | break; |
768 | case ETH_P_IP: |
769 | case ETH_P_IPV6: |
770 | m = m_get(slirp); |
771 | if (!m) |
772 | return; |
773 | /* Note: we add 2 to align the IP header on 4 bytes, |
774 | * and add the margin for the tcpiphdr overhead */ |
775 | if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) { |
776 | m_inc(m, pkt_len + TCPIPHDR_DELTA + 2); |
777 | } |
778 | m->m_len = pkt_len + TCPIPHDR_DELTA + 2; |
779 | memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len); |
780 | |
781 | m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN; |
782 | m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN; |
783 | |
784 | if (proto == ETH_P_IP) { |
785 | ip_input(m); |
786 | } else if (proto == ETH_P_IPV6) { |
787 | ip6_input(m); |
788 | } |
789 | break; |
790 | |
791 | case ETH_P_NCSI: |
792 | ncsi_input(slirp, pkt, pkt_len); |
793 | break; |
794 | |
795 | default: |
796 | break; |
797 | } |
798 | } |
799 | |
800 | /* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no |
801 | * packet should be sent, 0 if the packet must be re-queued, 2 if the packet |
802 | * is ready to go. |
803 | */ |
804 | static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, |
805 | uint8_t ethaddr[ETH_ALEN]) |
806 | { |
807 | const struct ip *iph = (const struct ip *)ifm->m_data; |
808 | |
809 | if (iph->ip_dst.s_addr == 0) { |
810 | /* 0.0.0.0 can not be a destination address, something went wrong, |
811 | * avoid making it worse */ |
812 | return 1; |
813 | } |
814 | if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) { |
815 | uint8_t arp_req[ETH_HLEN + sizeof(struct slirp_arphdr)]; |
816 | struct ethhdr *reh = (struct ethhdr *)arp_req; |
817 | struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_req + ETH_HLEN); |
818 | |
819 | if (!ifm->resolution_requested) { |
820 | /* If the client addr is not known, send an ARP request */ |
821 | memset(reh->h_dest, 0xff, ETH_ALEN); |
822 | memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4); |
823 | memcpy(&reh->h_source[2], &slirp->vhost_addr, 4); |
824 | reh->h_proto = htons(ETH_P_ARP); |
825 | rah->ar_hrd = htons(1); |
826 | rah->ar_pro = htons(ETH_P_IP); |
827 | rah->ar_hln = ETH_ALEN; |
828 | rah->ar_pln = 4; |
829 | rah->ar_op = htons(ARPOP_REQUEST); |
830 | |
831 | /* source hw addr */ |
832 | memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4); |
833 | memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4); |
834 | |
835 | /* source IP */ |
836 | rah->ar_sip = slirp->vhost_addr.s_addr; |
837 | |
838 | /* target hw addr (none) */ |
839 | memset(rah->ar_tha, 0, ETH_ALEN); |
840 | |
841 | /* target IP */ |
842 | rah->ar_tip = iph->ip_dst.s_addr; |
843 | slirp->client_ipaddr = iph->ip_dst; |
844 | slirp_send_packet_all(slirp, arp_req, sizeof(arp_req)); |
845 | ifm->resolution_requested = true; |
846 | |
847 | /* Expire request and drop outgoing packet after 1 second */ |
848 | ifm->expiration_date = |
849 | slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL; |
850 | } |
851 | return 0; |
852 | } else { |
853 | memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4); |
854 | /* XXX: not correct */ |
855 | memcpy(&eh->h_source[2], &slirp->vhost_addr, 4); |
856 | eh->h_proto = htons(ETH_P_IP); |
857 | |
858 | /* Send this */ |
859 | return 2; |
860 | } |
861 | } |
862 | |
863 | /* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no |
864 | * packet should be sent, 0 if the packet must be re-queued, 2 if the packet |
865 | * is ready to go. |
866 | */ |
867 | static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, |
868 | uint8_t ethaddr[ETH_ALEN]) |
869 | { |
870 | const struct ip6 *ip6h = mtod(ifm, const struct ip6 *); |
871 | if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) { |
872 | if (!ifm->resolution_requested) { |
873 | ndp_send_ns(slirp, ip6h->ip_dst); |
874 | ifm->resolution_requested = true; |
875 | ifm->expiration_date = |
876 | slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL; |
877 | } |
878 | return 0; |
879 | } else { |
880 | eh->h_proto = htons(ETH_P_IPV6); |
881 | in6_compute_ethaddr(ip6h->ip_src, eh->h_source); |
882 | |
883 | /* Send this */ |
884 | return 2; |
885 | } |
886 | } |
887 | |
888 | /* Output the IP packet to the ethernet device. Returns 0 if the packet must be |
889 | * re-queued. |
890 | */ |
891 | int if_encap(Slirp *slirp, struct mbuf *ifm) |
892 | { |
893 | uint8_t buf[1600]; |
894 | struct ethhdr *eh = (struct ethhdr *)buf; |
895 | uint8_t ethaddr[ETH_ALEN]; |
896 | const struct ip *iph = (const struct ip *)ifm->m_data; |
897 | int ret; |
898 | |
899 | if (ifm->m_len + ETH_HLEN > sizeof(buf)) { |
900 | return 1; |
901 | } |
902 | |
903 | switch (iph->ip_v) { |
904 | case IPVERSION: |
905 | ret = if_encap4(slirp, ifm, eh, ethaddr); |
906 | if (ret < 2) { |
907 | return ret; |
908 | } |
909 | break; |
910 | |
911 | case IP6VERSION: |
912 | ret = if_encap6(slirp, ifm, eh, ethaddr); |
913 | if (ret < 2) { |
914 | return ret; |
915 | } |
916 | break; |
917 | |
918 | default: |
919 | g_assert_not_reached(); |
920 | break; |
921 | } |
922 | |
923 | memcpy(eh->h_dest, ethaddr, ETH_ALEN); |
924 | DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x" , eh->h_source[0], |
925 | eh->h_source[1], eh->h_source[2], eh->h_source[3], |
926 | eh->h_source[4], eh->h_source[5]); |
927 | DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x" , eh->h_dest[0], |
928 | eh->h_dest[1], eh->h_dest[2], eh->h_dest[3], eh->h_dest[4], |
929 | eh->h_dest[5]); |
930 | memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len); |
931 | slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN); |
932 | return 1; |
933 | } |
934 | |
935 | /* Drop host forwarding rule, return 0 if found. */ |
936 | /* TODO: IPv6 */ |
937 | int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, |
938 | int host_port) |
939 | { |
940 | struct socket *so; |
941 | struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb); |
942 | struct sockaddr_in addr; |
943 | int port = htons(host_port); |
944 | socklen_t addr_len; |
945 | |
946 | for (so = head->so_next; so != head; so = so->so_next) { |
947 | addr_len = sizeof(addr); |
948 | if ((so->so_state & SS_HOSTFWD) && |
949 | getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 && |
950 | addr.sin_addr.s_addr == host_addr.s_addr && addr.sin_port == port) { |
951 | so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); |
952 | closesocket(so->s); |
953 | sofree(so); |
954 | return 0; |
955 | } |
956 | } |
957 | |
958 | return -1; |
959 | } |
960 | |
961 | /* TODO: IPv6 */ |
962 | int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, |
963 | int host_port, struct in_addr guest_addr, int guest_port) |
964 | { |
965 | if (!guest_addr.s_addr) { |
966 | guest_addr = slirp->vdhcp_startaddr; |
967 | } |
968 | if (is_udp) { |
969 | if (!udp_listen(slirp, host_addr.s_addr, htons(host_port), |
970 | guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) |
971 | return -1; |
972 | } else { |
973 | if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port), |
974 | guest_addr.s_addr, htons(guest_port), SS_HOSTFWD)) |
975 | return -1; |
976 | } |
977 | return 0; |
978 | } |
979 | |
980 | /* TODO: IPv6 */ |
981 | static bool check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, |
982 | int guest_port) |
983 | { |
984 | struct gfwd_list *tmp_ptr; |
985 | |
986 | if (!guest_addr->s_addr) { |
987 | guest_addr->s_addr = slirp->vnetwork_addr.s_addr | |
988 | (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr); |
989 | } |
990 | if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) != |
991 | slirp->vnetwork_addr.s_addr || |
992 | guest_addr->s_addr == slirp->vhost_addr.s_addr || |
993 | guest_addr->s_addr == slirp->vnameserver_addr.s_addr) { |
994 | return false; |
995 | } |
996 | |
997 | /* check if the port is "bound" */ |
998 | for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { |
999 | if (guest_port == tmp_ptr->ex_fport && |
1000 | guest_addr->s_addr == tmp_ptr->ex_addr.s_addr) |
1001 | return false; |
1002 | } |
1003 | |
1004 | return true; |
1005 | } |
1006 | |
1007 | int slirp_add_exec(Slirp *slirp, const char *cmdline, |
1008 | struct in_addr *guest_addr, int guest_port) |
1009 | { |
1010 | if (!check_guestfwd(slirp, guest_addr, guest_port)) { |
1011 | return -1; |
1012 | } |
1013 | |
1014 | add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port)); |
1015 | return 0; |
1016 | } |
1017 | |
1018 | int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque, |
1019 | struct in_addr *guest_addr, int guest_port) |
1020 | { |
1021 | if (!check_guestfwd(slirp, guest_addr, guest_port)) { |
1022 | return -1; |
1023 | } |
1024 | |
1025 | add_guestfwd(&slirp->guestfwd_list, write_cb, opaque, *guest_addr, |
1026 | htons(guest_port)); |
1027 | return 0; |
1028 | } |
1029 | |
1030 | ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags) |
1031 | { |
1032 | if (so->s == -1 && so->guestfwd) { |
1033 | /* XXX this blocks entire thread. Rewrite to use |
1034 | * qemu_chr_fe_write and background I/O callbacks */ |
1035 | so->guestfwd->write_cb(buf, len, so->guestfwd->opaque); |
1036 | return len; |
1037 | } |
1038 | |
1039 | if (so->s == -1) { |
1040 | /* |
1041 | * This should in theory not happen but it is hard to be |
1042 | * sure because some code paths will end up with so->s == -1 |
1043 | * on a failure but don't dispose of the struct socket. |
1044 | * Check specifically, so we don't pass -1 to send(). |
1045 | */ |
1046 | errno = EBADF; |
1047 | return -1; |
1048 | } |
1049 | |
1050 | return send(so->s, buf, len, flags); |
1051 | } |
1052 | |
1053 | struct socket *slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, |
1054 | int guest_port) |
1055 | { |
1056 | struct socket *so; |
1057 | |
1058 | /* TODO: IPv6 */ |
1059 | for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) { |
1060 | if (so->so_faddr.s_addr == guest_addr.s_addr && |
1061 | htons(so->so_fport) == guest_port) { |
1062 | return so; |
1063 | } |
1064 | } |
1065 | return NULL; |
1066 | } |
1067 | |
1068 | size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr, |
1069 | int guest_port) |
1070 | { |
1071 | struct iovec iov[2]; |
1072 | struct socket *so; |
1073 | |
1074 | so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); |
1075 | |
1076 | if (!so || so->so_state & SS_NOFDREF) { |
1077 | return 0; |
1078 | } |
1079 | |
1080 | if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen / 2)) { |
1081 | return 0; |
1082 | } |
1083 | |
1084 | return sopreprbuf(so, iov, NULL); |
1085 | } |
1086 | |
1087 | void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, |
1088 | const uint8_t *buf, int size) |
1089 | { |
1090 | int ret; |
1091 | struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port); |
1092 | |
1093 | if (!so) |
1094 | return; |
1095 | |
1096 | ret = soreadbuf(so, (const char *)buf, size); |
1097 | |
1098 | if (ret > 0) |
1099 | tcp_output(sototcpcb(so)); |
1100 | } |
1101 | |
1102 | void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len) |
1103 | { |
1104 | ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque); |
1105 | |
1106 | if (ret < 0) { |
1107 | g_critical("Failed to send packet, ret: %ld" , (long)ret); |
1108 | } else if (ret < len) { |
1109 | DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu" , (long)ret, |
1110 | (unsigned long)len); |
1111 | } |
1112 | } |
1113 | |