VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/slirp.c@ 1036

最後變更 在這個檔案從1036是 1036,由 vboxsync 提交於 18 年 前

Fixed Windows part of slirp, too.

  • 屬性 svn:eol-style 設為 native
檔案大小: 22.9 KB
 
1#include "slirp.h"
2#ifdef __OS2__
3# include <paths.h>
4#endif
5#ifdef VBOX
6# include <VBox/err.h>
7# include <iprt/assert.h>
8#endif
9
10#ifndef VBOX
11/* host address */
12struct in_addr our_addr;
13/* host dns address */
14struct in_addr dns_addr;
15/* host loopback address */
16struct in_addr loopback_addr;
17
18/* address for slirp virtual addresses */
19struct in_addr special_addr;
20/* virtual address alias for host */
21struct in_addr alias_addr;
22#endif /* !VBOX */
23
24#ifdef VBOX
25static const uint8_t special_ethaddr[6] = {
26#else /* !VBOX */
27const uint8_t special_ethaddr[6] = {
28#endif /* !VBOX */
29 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
30};
31
32#ifndef VBOX
33uint8_t client_ethaddr[6];
34
35int do_slowtimo;
36int link_up;
37struct timeval tt;
38FILE *lfd;
39struct ex_list *exec_list;
40#endif /* !VBOX */
41
42#ifndef VBOX
43/* XXX: suppress those select globals */
44fd_set *global_readfds, *global_writefds, *global_xfds;
45
46char slirp_hostname[33];
47#endif /* !VBOX */
48
49#ifdef _WIN32
50
51#ifdef VBOX
52static int get_dns_addr(PNATState pData, struct in_addr *pdns_addr)
53#else /* !VBOX */
54static int get_dns_addr(struct in_addr *pdns_addr)
55#endif /* !VBOX */
56{
57 FIXED_INFO *FixedInfo=NULL;
58 ULONG BufLen;
59 DWORD ret;
60 IP_ADDR_STRING *pIPAddr;
61 struct in_addr tmp_addr;
62
63 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
64 BufLen = sizeof(FIXED_INFO);
65
66 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
67 if (FixedInfo) {
68 GlobalFree(FixedInfo);
69 FixedInfo = NULL;
70 }
71 FixedInfo = GlobalAlloc(GPTR, BufLen);
72 }
73
74 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
75#ifndef VBOX
76 printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
77#else /* VBOX */
78 Log(("GetNetworkParams failed. ret = %08x\n", (u_int)ret ));
79#endif /* VBOX */
80 if (FixedInfo) {
81 GlobalFree(FixedInfo);
82 FixedInfo = NULL;
83 }
84 return -1;
85 }
86
87 pIPAddr = &(FixedInfo->DnsServerList);
88 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
89 *pdns_addr = tmp_addr;
90#ifndef VBOX
91#if 0
92 printf( "DNS Servers:\n" );
93 printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
94
95 pIPAddr = FixedInfo -> DnsServerList.Next;
96 while ( pIPAddr ) {
97 printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
98 pIPAddr = pIPAddr ->Next;
99 }
100#endif
101#else /* VBOX */
102 Log(("nat: DNS Servers:\n"));
103 Log(("nat: DNS Addr:%s\n", pIPAddr->IpAddress.String));
104
105 pIPAddr = FixedInfo -> DnsServerList.Next;
106 while ( pIPAddr ) {
107 Log(("nat: DNS Addr:%s\n", pIPAddr ->IpAddress.String));
108 pIPAddr = pIPAddr ->Next;
109 }
110#endif /* VBOX */
111 if (FixedInfo) {
112 GlobalFree(FixedInfo);
113 FixedInfo = NULL;
114 }
115 return 0;
116}
117
118#else
119
120#ifdef VBOX
121static int get_dns_addr(PNATState pData, struct in_addr *pdns_addr)
122#else /* !VBOX */
123static int get_dns_addr(struct in_addr *pdns_addr)
124#endif /* !VBOX */
125{
126 char buff[512];
127 char buff2[256];
128 FILE *f;
129 int found = 0;
130 struct in_addr tmp_addr;
131
132#ifdef __OS2__
133 /* Try various locations. */
134 char *etc = getenv("ETC");
135 f = NULL;
136 if (etc)
137 {
138 snprintf(buff, sizeof(buff), "%s/RESOLV2", etc);
139 f = fopen(buff, "rt");
140 }
141 if (!f) {
142 snprintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
143 f = fopen(buff, "rt");
144 }
145 if (!f) {
146 snprintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
147 f = fopen(buff, "rt");
148 }
149#else
150 f = fopen("/etc/resolv.conf", "r");
151#endif
152 if (!f)
153 return -1;
154
155#ifndef VBOX
156 lprint("IP address of your DNS(s): ");
157#else /* VBOX */
158 Log(("nat: IP address of your DNS(s): \n"));
159#endif /* VBOX */
160 while (fgets(buff, 512, f) != NULL) {
161 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
162 if (!inet_aton(buff2, &tmp_addr))
163 continue;
164 if (tmp_addr.s_addr == loopback_addr.s_addr)
165 tmp_addr = our_addr;
166 /* If it's the first one, set it to dns_addr */
167 if (!found)
168 *pdns_addr = tmp_addr;
169#ifndef VBOX
170 else
171 lprint(", ");
172#endif /* !VBOX */
173 if (++found > 3) {
174#ifndef VBOX
175 lprint("(more)");
176#else /* VBOX */
177 Log(("nat: (more)\n"));
178#endif /* VBOX */
179 break;
180 } else
181#ifndef VBOX
182 lprint("%s", inet_ntoa(tmp_addr));
183#else /* VBOX */
184 Log(("nat: %s\n", inet_ntoa(tmp_addr)));
185#endif /* VBOX */
186 }
187 }
188 fclose(f);
189 if (!found)
190 return -1;
191 return 0;
192}
193
194#endif
195
196#ifndef VBOX
197#ifdef _WIN32
198void slirp_cleanup(void)
199{
200 WSACleanup();
201}
202#endif
203#endif /* !VBOX (see slirp_term) */
204
205#ifndef VBOX
206void slirp_init(void)
207{
208 /* debug_init("/tmp/slirp.log", DEBUG_DEFAULT); */
209#else /* VBOX */
210/** Number of slirp users. Used for making sure init and term are only executed once. */
211int slirp_init(PNATState *ppData, const char *pszNetAddr, void *pvUser)
212{
213 PNATState pData = malloc(sizeof(NATState));
214 *ppData = pData;
215 if (!pData)
216 return VERR_NO_MEMORY;
217 memset(pData, '\0', sizeof(NATState));
218 pData->pvUser = pvUser;
219#endif /* VBOX */
220
221#ifdef _WIN32
222 {
223 WSADATA Data;
224 WSAStartup(MAKEWORD(2,0), &Data);
225#ifndef VBOX
226 atexit(slirp_cleanup);
227#endif /* !VBOX */
228 }
229#endif
230
231#ifdef VBOX
232 Assert(sizeof(struct ip) == 20);
233#endif /* VBOX */
234 link_up = 1;
235
236#ifdef VBOX
237 if_init(pData);
238 ip_init(pData);
239#else /* !VBOX */
240 if_init();
241 ip_init();
242#endif /* !VBOX */
243
244 /* Initialise mbufs *after* setting the MTU */
245#ifdef VBOX
246 m_init(pData);
247#else /* !VBOX */
248 m_init();
249#endif /* !VBOX */
250
251 /* set default addresses */
252 inet_aton("127.0.0.1", &loopback_addr);
253
254#ifdef VBOX
255 if (get_dns_addr(pData, &dns_addr) < 0) {
256#else /* !VBOX */
257 if (get_dns_addr(&dns_addr) < 0) {
258#endif /* !VBOX */
259#ifndef VBOX
260 dns_addr = loopback_addr;
261 fprintf (stderr, "Warning: No DNS servers found\n");
262#else
263 return VERR_NAT_DNS;
264#endif
265 }
266
267#ifdef VBOX
268 inet_aton(pszNetAddr, &special_addr);
269#else /* !VBOX */
270 inet_aton(CTL_SPECIAL, &special_addr);
271#endif /* !VBOX */
272 alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
273#ifdef VBOX
274 getouraddr(pData);
275 return VINF_SUCCESS;
276#else /* !VBOX */
277 getouraddr();
278#endif /* !VBOX */
279}
280
281#ifdef VBOX
282/**
283 * Marks the link as up, making it possible to establish new connections.
284 */
285void slirp_link_up(PNATState pData)
286{
287 link_up = 1;
288}
289
290/**
291 * Marks the link as down and cleans up the current connections.
292 */
293void slirp_link_down(PNATState pData)
294{
295 struct socket *so;
296
297 while ((so = tcb.so_next) != &tcb)
298 {
299 if (so->so_state & SS_NOFDREF || so->s == -1)
300 sofree(pData, so);
301 else
302 tcp_drop(pData, sototcpcb(so), 0);
303 }
304
305 while ((so = udb.so_next) != &udb)
306 udp_detach(pData, so);
307
308 link_up = 0;
309}
310
311/**
312 * Terminates the slirp component.
313 */
314void slirp_term(PNATState pData)
315{
316 slirp_link_down(pData);
317#ifdef WIN32
318 WSACleanup();
319#endif
320#ifdef LOG_ENABLED
321 Log(("\n"
322 "NAT statistics\n"
323 "--------------\n"
324 "\n"));
325 ipstats(pData);
326 tcpstats(pData);
327 udpstats(pData);
328 icmpstats(pData);
329 mbufstats(pData);
330 sockstats(pData);
331 Log(("\n"
332 "\n"
333 "\n"));
334#endif
335 free(pData);
336}
337#endif /* VBOX */
338
339
340#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
341#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
342#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
343
344/*
345 * curtime kept to an accuracy of 1ms
346 */
347#ifdef _WIN32
348#ifdef VBOX
349static void updtime(PNATState pData)
350#else /* !VBOX */
351static void updtime(void)
352#endif /* !VBOX */
353{
354 struct _timeb tb;
355
356 _ftime(&tb);
357 curtime = (u_int)tb.time * (u_int)1000;
358 curtime += (u_int)tb.millitm;
359}
360#else
361#ifdef VBOX
362static void updtime(PNATState pData)
363#else /* !VBOX */
364static void updtime(void)
365#endif /* !VBOX */
366{
367 gettimeofday(&tt, 0);
368
369 curtime = (u_int)tt.tv_sec * (u_int)1000;
370 curtime += (u_int)tt.tv_usec / (u_int)1000;
371
372 if ((tt.tv_usec % 1000) >= 500)
373 curtime++;
374}
375#endif
376
377#ifdef VBOX
378void slirp_select_fill(PNATState pData, int *pnfds,
379 fd_set *readfds, fd_set *writefds, fd_set *xfds)
380#else /* !VBOX */
381void slirp_select_fill(int *pnfds,
382 fd_set *readfds, fd_set *writefds, fd_set *xfds)
383#endif /* !VBOX */
384{
385 struct socket *so, *so_next;
386 struct timeval timeout;
387 int nfds;
388 int tmp_time;
389
390#ifndef VBOX
391 /* fail safe */
392 global_readfds = NULL;
393 global_writefds = NULL;
394 global_xfds = NULL;
395#endif /* !VBOX */
396
397 nfds = *pnfds;
398 /*
399 * First, TCP sockets
400 */
401 do_slowtimo = 0;
402 if (link_up) {
403 /*
404 * *_slowtimo needs calling if there are IP fragments
405 * in the fragment queue, or there are TCP connections active
406 */
407 do_slowtimo = ((tcb.so_next != &tcb) ||
408 ((struct ipasfrag *)&ipq != u32_to_ptr(ipq.next, struct ipasfrag *)));
409
410 for (so = tcb.so_next; so != &tcb; so = so_next) {
411 so_next = so->so_next;
412
413 /*
414 * See if we need a tcp_fasttimo
415 */
416 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
417 time_fasttimo = curtime; /* Flag when we want a fasttimo */
418
419 /*
420 * NOFDREF can include still connecting to local-host,
421 * newly socreated() sockets etc. Don't want to select these.
422 */
423 if (so->so_state & SS_NOFDREF || so->s == -1)
424 continue;
425
426 /*
427 * Set for reading sockets which are accepting
428 */
429 if (so->so_state & SS_FACCEPTCONN) {
430 FD_SET(so->s, readfds);
431 UPD_NFDS(so->s);
432 continue;
433 }
434
435 /*
436 * Set for writing sockets which are connecting
437 */
438 if (so->so_state & SS_ISFCONNECTING) {
439 FD_SET(so->s, writefds);
440 UPD_NFDS(so->s);
441 continue;
442 }
443
444 /*
445 * Set for writing if we are connected, can send more, and
446 * we have something to send
447 */
448 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
449 FD_SET(so->s, writefds);
450 UPD_NFDS(so->s);
451 }
452
453 /*
454 * Set for reading (and urgent data) if we are connected, can
455 * receive more, and we have room for it XXX /2 ?
456 */
457 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
458 FD_SET(so->s, readfds);
459 FD_SET(so->s, xfds);
460 UPD_NFDS(so->s);
461 }
462 }
463
464 /*
465 * UDP sockets
466 */
467 for (so = udb.so_next; so != &udb; so = so_next) {
468 so_next = so->so_next;
469
470 /*
471 * See if it's timed out
472 */
473 if (so->so_expire) {
474 if (so->so_expire <= curtime) {
475#ifdef VBOX
476 udp_detach(pData, so);
477#else /* !VBOX */
478 udp_detach(so);
479#endif /* !VBOX */
480 continue;
481 } else
482 do_slowtimo = 1; /* Let socket expire */
483 }
484
485 /*
486 * When UDP packets are received from over the
487 * link, they're sendto()'d straight away, so
488 * no need for setting for writing
489 * Limit the number of packets queued by this session
490 * to 4. Note that even though we try and limit this
491 * to 4 packets, the session could have more queued
492 * if the packets needed to be fragmented
493 * (XXX <= 4 ?)
494 */
495 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
496 FD_SET(so->s, readfds);
497 UPD_NFDS(so->s);
498 }
499 }
500 }
501
502 /*
503 * Setup timeout to use minimum CPU usage, especially when idle
504 */
505
506 /*
507 * First, see the timeout needed by *timo
508 */
509 timeout.tv_sec = 0;
510 timeout.tv_usec = -1;
511 /*
512 * If a slowtimo is needed, set timeout to 500ms from the last
513 * slow timeout. If a fast timeout is needed, set timeout within
514 * 200ms of when it was requested.
515 */
516 if (do_slowtimo) {
517 /* XXX + 10000 because some select()'s aren't that accurate */
518 timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
519 if (timeout.tv_usec < 0)
520 timeout.tv_usec = 0;
521 else if (timeout.tv_usec > 510000)
522 timeout.tv_usec = 510000;
523
524 /* Can only fasttimo if we also slowtimo */
525 if (time_fasttimo) {
526 tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
527 if (tmp_time < 0)
528 tmp_time = 0;
529
530 /* Choose the smallest of the 2 */
531 if (tmp_time < timeout.tv_usec)
532 timeout.tv_usec = (u_int)tmp_time;
533 }
534 }
535 *pnfds = nfds;
536}
537
538#ifdef VBOX
539void slirp_select_poll(PNATState pData, fd_set *readfds, fd_set *writefds, fd_set *xfds)
540#else /* !VBOX */
541void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
542#endif /* !VBOX */
543{
544 struct socket *so, *so_next;
545 int ret;
546
547#ifndef VBOX
548 global_readfds = readfds;
549 global_writefds = writefds;
550 global_xfds = xfds;
551#endif /* !VBOX */
552
553 /* Update time */
554#ifdef VBOX
555 updtime(pData);
556#else /* !VBOX */
557 updtime();
558#endif /* !VBOX */
559
560 /*
561 * See if anything has timed out
562 */
563 if (link_up) {
564 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
565#ifdef VBOX
566 tcp_fasttimo(pData);
567#else /* !VBOX */
568 tcp_fasttimo();
569#endif /* !VBOX */
570 time_fasttimo = 0;
571 }
572 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
573#ifdef VBOX
574 ip_slowtimo(pData);
575 tcp_slowtimo(pData);
576#else /* !VBOX */
577 ip_slowtimo();
578 tcp_slowtimo();
579#endif /* !VBOX */
580 last_slowtimo = curtime;
581 }
582 }
583
584 /*
585 * Check sockets
586 */
587 if (link_up) {
588 /*
589 * Check TCP sockets
590 */
591 for (so = tcb.so_next; so != &tcb; so = so_next) {
592 so_next = so->so_next;
593
594 /*
595 * FD_ISSET is meaningless on these sockets
596 * (and they can crash the program)
597 */
598 if (so->so_state & SS_NOFDREF || so->s == -1)
599 continue;
600
601 /*
602 * Check for URG data
603 * This will soread as well, so no need to
604 * test for readfds below if this succeeds
605 */
606 if (FD_ISSET(so->s, xfds))
607#ifdef VBOX
608 sorecvoob(pData, so);
609#else /* !VBOX */
610 sorecvoob(so);
611#endif /* !VBOX */
612 /*
613 * Check sockets for reading
614 */
615 else if (FD_ISSET(so->s, readfds)) {
616 /*
617 * Check for incoming connections
618 */
619 if (so->so_state & SS_FACCEPTCONN) {
620#ifdef VBOX
621 tcp_connect(pData, so);
622#else /* !VBOX */
623 tcp_connect(so);
624#endif /* !VBOX */
625 continue;
626 } /* else */
627#ifdef VBOX
628 ret = soread(pData, so);
629#else /* !VBOX */
630 ret = soread(so);
631#endif /* !VBOX */
632
633 /* Output it if we read something */
634 if (ret > 0)
635#ifdef VBOX
636 tcp_output(pData, sototcpcb(so));
637#else /* !VBOX */
638 tcp_output(sototcpcb(so));
639#endif /* !VBOX */
640 }
641
642 /*
643 * Check sockets for writing
644 */
645 if (FD_ISSET(so->s, writefds)) {
646 /*
647 * Check for non-blocking, still-connecting sockets
648 */
649 if (so->so_state & SS_ISFCONNECTING) {
650 /* Connected */
651 so->so_state &= ~SS_ISFCONNECTING;
652
653 ret = send(so->s, &ret, 0, 0);
654 if (ret < 0) {
655 /* XXXXX Must fix, zero bytes is a NOP */
656 if (errno == EAGAIN || errno == EWOULDBLOCK ||
657 errno == EINPROGRESS || errno == ENOTCONN)
658 continue;
659
660 /* else failed */
661 so->so_state = SS_NOFDREF;
662 }
663 /* else so->so_state &= ~SS_ISFCONNECTING; */
664
665 /*
666 * Continue tcp_input
667 */
668#ifdef VBOX
669 tcp_input(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
670#else /* !VBOX */
671 tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
672#endif /* !VBOX */
673 /* continue; */
674 } else
675#ifdef VBOX
676 ret = sowrite(pData, so);
677#else /* !VBOX */
678 ret = sowrite(so);
679#endif /* !VBOX */
680 /*
681 * XXXXX If we wrote something (a lot), there
682 * could be a need for a window update.
683 * In the worst case, the remote will send
684 * a window probe to get things going again
685 */
686 }
687
688 /*
689 * Probe a still-connecting, non-blocking socket
690 * to check if it's still alive
691 */
692#ifdef PROBE_CONN
693 if (so->so_state & SS_ISFCONNECTING) {
694 ret = recv(so->s, (char *)&ret, 0,0);
695
696 if (ret < 0) {
697 /* XXX */
698 if (errno == EAGAIN || errno == EWOULDBLOCK ||
699 errno == EINPROGRESS || errno == ENOTCONN)
700 continue; /* Still connecting, continue */
701
702 /* else failed */
703 so->so_state = SS_NOFDREF;
704
705 /* tcp_input will take care of it */
706 } else {
707 ret = send(so->s, &ret, 0,0);
708 if (ret < 0) {
709 /* XXX */
710 if (errno == EAGAIN || errno == EWOULDBLOCK ||
711 errno == EINPROGRESS || errno == ENOTCONN)
712 continue;
713 /* else failed */
714 so->so_state = SS_NOFDREF;
715 } else
716 so->so_state &= ~SS_ISFCONNECTING;
717
718 }
719 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
720 } /* SS_ISFCONNECTING */
721#endif
722 }
723
724 /*
725 * Now UDP sockets.
726 * Incoming packets are sent straight away, they're not buffered.
727 * Incoming UDP data isn't buffered either.
728 */
729 for (so = udb.so_next; so != &udb; so = so_next) {
730 so_next = so->so_next;
731
732 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
733#ifdef VBOX
734 sorecvfrom(pData, so);
735#else /* !VBOX */
736 sorecvfrom(so);
737#endif /* !VBOX */
738 }
739 }
740 }
741
742 /*
743 * See if we can start outputting
744 */
745 if (if_queued && link_up)
746#ifdef VBOX
747 if_start(pData);
748#else /* !VBOX */
749 if_start();
750#endif /* !VBOX */
751
752#ifndef VBOX
753 /* clear global file descriptor sets.
754 * these reside on the stack in vl.c
755 * so they're unusable if we're not in
756 * slirp_select_fill or slirp_select_poll.
757 */
758 global_readfds = NULL;
759 global_writefds = NULL;
760 global_xfds = NULL;
761#endif /* !VBOX */
762}
763
764#define ETH_ALEN 6
765#define ETH_HLEN 14
766
767#define ETH_P_IP 0x0800 /* Internet Protocol packet */
768#define ETH_P_ARP 0x0806 /* Address Resolution packet */
769
770#define ARPOP_REQUEST 1 /* ARP request */
771#define ARPOP_REPLY 2 /* ARP reply */
772
773struct ethhdr
774{
775 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
776 unsigned char h_source[ETH_ALEN]; /* source ether addr */
777 unsigned short h_proto; /* packet type ID field */
778};
779
780struct arphdr
781{
782 unsigned short ar_hrd; /* format of hardware address */
783 unsigned short ar_pro; /* format of protocol address */
784 unsigned char ar_hln; /* length of hardware address */
785 unsigned char ar_pln; /* length of protocol address */
786 unsigned short ar_op; /* ARP opcode (command) */
787
788 /*
789 * Ethernet looks like this : This bit is variable sized however...
790 */
791 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
792 unsigned char ar_sip[4]; /* sender IP address */
793 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
794 unsigned char ar_tip[4]; /* target IP address */
795};
796
797#ifdef VBOX
798static
799void arp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
800#else /* !VBOX */
801void arp_input(const uint8_t *pkt, int pkt_len)
802#endif /* !VBOX */
803{
804 struct ethhdr *eh = (struct ethhdr *)pkt;
805 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
806 uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
807 struct ethhdr *reh = (struct ethhdr *)arp_reply;
808 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
809 int ar_op;
810 struct ex_list *ex_ptr;
811
812 ar_op = ntohs(ah->ar_op);
813 switch(ar_op) {
814 case ARPOP_REQUEST:
815 if (!memcmp(ah->ar_tip, &special_addr, 3)) {
816 if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
817 goto arp_ok;
818 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
819 if (ex_ptr->ex_addr == ah->ar_tip[3])
820 goto arp_ok;
821 }
822 return;
823 arp_ok:
824 /* XXX: make an ARP request to have the client address */
825 memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
826
827 /* ARP request for alias/dns mac address */
828 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
829 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
830 reh->h_source[5] = ah->ar_tip[3];
831 reh->h_proto = htons(ETH_P_ARP);
832
833 rah->ar_hrd = htons(1);
834 rah->ar_pro = htons(ETH_P_IP);
835 rah->ar_hln = ETH_ALEN;
836 rah->ar_pln = 4;
837 rah->ar_op = htons(ARPOP_REPLY);
838 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
839 memcpy(rah->ar_sip, ah->ar_tip, 4);
840 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
841 memcpy(rah->ar_tip, ah->ar_sip, 4);
842#ifdef VBOX
843 slirp_output(pData->pvUser, arp_reply, sizeof(arp_reply));
844#else /* !VBOX */
845 slirp_output(arp_reply, sizeof(arp_reply));
846#endif /* !VBOX */
847 }
848 break;
849 default:
850 break;
851 }
852}
853
854#ifdef VBOX
855void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
856#else /* !VBOX */
857void slirp_input(const uint8_t *pkt, int pkt_len)
858#endif /* !VBOX */
859{
860 struct mbuf *m;
861 int proto;
862
863 if (pkt_len < ETH_HLEN)
864 return;
865
866 proto = ntohs(*(uint16_t *)(pkt + 12));
867 switch(proto) {
868 case ETH_P_ARP:
869#ifdef VBOX
870 arp_input(pData, pkt, pkt_len);
871#else /* !VBOX */
872 arp_input(pkt, pkt_len);
873#endif /* !VBOX */
874 break;
875 case ETH_P_IP:
876#ifdef VBOX
877 m = m_get(pData);
878#else /* !VBOX */
879 m = m_get();
880#endif /* !VBOX */
881 if (!m)
882 return;
883 /* Note: we add to align the IP header */
884 m->m_len = pkt_len + 2;
885 memcpy(m->m_data + 2, pkt, pkt_len);
886
887 m->m_data += 2 + ETH_HLEN;
888 m->m_len -= 2 + ETH_HLEN;
889
890#ifdef VBOX
891 ip_input(pData, m);
892#else /* !VBOX */
893 ip_input(m);
894#endif /* !VBOX */
895 break;
896 default:
897 break;
898 }
899}
900
901/* output the IP packet to the ethernet device */
902#ifdef VBOX
903void if_encap(PNATState pData, const uint8_t *ip_data, int ip_data_len)
904#else /* !VBOX */
905void if_encap(const uint8_t *ip_data, int ip_data_len)
906#endif /* !VBOX */
907{
908 uint8_t buf[1600];
909 struct ethhdr *eh = (struct ethhdr *)buf;
910
911 if (ip_data_len + ETH_HLEN > sizeof(buf))
912 return;
913
914 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
915 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
916 /* XXX: not correct */
917 eh->h_source[5] = CTL_ALIAS;
918 eh->h_proto = htons(ETH_P_IP);
919 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
920#ifdef VBOX
921 slirp_output(pData->pvUser, buf, ip_data_len + ETH_HLEN);
922#else /* !VBOX */
923 slirp_output(buf, ip_data_len + ETH_HLEN);
924#endif /* !VBOX */
925}
926
927int slirp_redir(PNATState pData, int is_udp, int host_port,
928 struct in_addr guest_addr, int guest_port)
929{
930 if (is_udp) {
931#ifdef VBOX
932 if (!udp_listen(pData, htons(host_port), guest_addr.s_addr,
933 htons(guest_port), 0))
934#else /* !VBOX */
935 if (!udp_listen(htons(host_port), guest_addr.s_addr,
936 htons(guest_port), 0))
937#endif /* !VBOX */
938 return -1;
939 } else {
940#ifdef VBOX
941 if (!solisten(pData, htons(host_port), guest_addr.s_addr,
942 htons(guest_port), 0))
943#else /* !VBOX */
944 if (!solisten(htons(host_port), guest_addr.s_addr,
945 htons(guest_port), 0))
946#endif /* !VBOX */
947 return -1;
948 }
949 return 0;
950}
951
952#ifdef VBOX
953int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
954 int guest_port)
955#else /* !VBOX */
956int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
957 int guest_port)
958#endif /* !VBOX */
959{
960 return add_exec(&exec_list, do_pty, (char *)args,
961 addr_low_byte, htons(guest_port));
962}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette