VirtualBox

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

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

NAT: Backed r51387

  • 屬性 svn:eol-style 設為 native
檔案大小: 55.7 KB
 
1#include "slirp.h"
2#ifdef RT_OS_OS2
3# include <paths.h>
4#endif
5
6#include <VBox/err.h>
7#include <VBox/pdmdrv.h>
8#include <iprt/assert.h>
9#ifndef RT_OS_WINDOWS
10# include <sys/ioctl.h>
11# include <poll.h>
12#else
13# include <Winnls.h>
14# define _WINSOCK2API_
15# include <IPHlpApi.h>
16#endif
17#include <alias.h>
18#define COUNTERS_INIT
19#include "counters.h"
20
21#if !defined(RT_OS_WINDOWS)
22
23# define DO_ENGAGE_EVENT1(so, fdset, label) \
24 do { \
25 if( so->so_poll_index != -1 \
26 && so->s == polls[so->so_poll_index].fd) { \
27 polls[so->so_poll_index].events |= N_(fdset ## _poll); \
28 break; /* out of this loop */ \
29 } \
30 AssertRelease(poll_index < (nfds)); \
31 AssertRelease(poll_index >= 0 && poll_index < (nfds)); \
32 polls[poll_index].fd = (so)->s; \
33 (so)->so_poll_index = poll_index; \
34 polls[poll_index].events = N_(fdset ## _poll); \
35 polls[poll_index].revents = 0; \
36 poll_index++; \
37 } while(0)
38
39
40# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
41 do { \
42 if( so->so_poll_index != -1 \
43 && so->s == polls[so->so_poll_index].fd) { \
44 polls[so->so_poll_index].events |= \
45 N_(fdset1 ## _poll) | N_(fdset1 ## _poll); \
46 break; /* out of this loop */ \
47 } \
48 AssertRelease(poll_index < (nfds)); \
49 polls[poll_index].fd = (so)->s; \
50 (so)->so_poll_index = poll_index; \
51 polls[poll_index].events = \
52 N_(fdset1 ## _poll) | N_(fdset1 ## _poll); \
53 poll_index++; \
54 } while(0)
55
56# define DO_POLL_EVENTS(rc, error, so, events, label) do {} while (0)
57
58# define DO_CHECK_FD_SET(so, events, fdset) ( ((so)->so_poll_index != -1) \
59 && ((so)->so_poll_index <= ndfs) \
60 && ((so)->s == polls[so->so_poll_index].fd) \
61 && (polls[(so)->so_poll_index].revents & N_(fdset ## _poll)))
62# define DO_UNIX_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset) /*specific for Unix API */
63# define DO_WIN_CHECK_FD_SET(so, events, fdset ) 0 /* specific for Windows Winsock API */
64
65# ifndef RT_OS_WINDOWS
66
67# ifndef RT_OS_LINUX
68# define readfds_poll (POLLRDNORM)
69# define writefds_poll (POLLWRNORM)
70# define xfds_poll (POLLRDBAND|POLLWRBAND|POLLPRI)
71# else
72# define readfds_poll (POLLIN)
73# define writefds_poll (POLLOUT)
74# define xfds_poll (POLLPRI)
75# endif
76# define rderr_poll (POLLERR)
77# define rdhup_poll (POLLHUP)
78# define nval_poll (POLLNVAL)
79
80# define ICMP_ENGAGE_EVENT(so, fdset) \
81 do { \
82 if (pData->icmp_socket.s != -1) \
83 DO_ENGAGE_EVENT1((so), fdset, ICMP); \
84 } while (0)
85# else /* !RT_OS_WINDOWS */
86# define DO_WIN_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset)
87# define ICMP_ENGAGE_EVENT(so, fdset) do {} while(0)
88#endif /* RT_OS_WINDOWS */
89
90#else /* defined(RT_OS_WINDOWS) */
91
92/*
93 * On Windows, we will be notified by IcmpSendEcho2() when the response arrives.
94 * So no call to WSAEventSelect necessary.
95 */
96# define ICMP_ENGAGE_EVENT(so, fdset) do {} while(0)
97
98# define DO_ENGAGE_EVENT1(so, fdset1, label) \
99 do { \
100 rc = WSAEventSelect((so)->s, VBOX_SOCKET_EVENT, FD_ALL_EVENTS); \
101 if (rc == SOCKET_ERROR) \
102 { \
103 /* This should not happen */ \
104 error = WSAGetLastError(); \
105 LogRel(("WSAEventSelect (" #label ") error %d (so=%x, socket=%s, event=%x)\n", \
106 error, (so), (so)->s, VBOX_SOCKET_EVENT)); \
107 } \
108 } while(0); \
109 CONTINUE(label)
110
111# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
112 DO_ENGAGE_EVENT1((so), (fdset1), label)
113
114# define DO_POLL_EVENTS(rc, error, so, events, label) \
115 (rc) = WSAEnumNetworkEvents((so)->s, VBOX_SOCKET_EVENT, (events)); \
116 if ((rc) == SOCKET_ERROR) \
117 { \
118 (error) = WSAGetLastError(); \
119 LogRel(("WSAEnumNetworkEvents " #label " error %d\n", (error))); \
120 CONTINUE(label); \
121 }
122
123# define acceptds_win FD_ACCEPT
124# define acceptds_win_bit FD_ACCEPT_BIT
125
126# define readfds_win FD_READ
127# define readfds_win_bit FD_READ_BIT
128
129# define writefds_win FD_WRITE
130# define writefds_win_bit FD_WRITE_BIT
131
132# define xfds_win FD_OOB
133# define xfds_win_bit FD_OOB_BIT
134
135# define DO_CHECK_FD_SET(so, events, fdset) \
136 (((events).lNetworkEvents & fdset ## _win) && ((events).iErrorCode[fdset ## _win_bit] == 0))
137
138# define DO_WIN_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset)
139# define DO_UNIX_CHECK_FD_SET(so, events, fdset ) 1 /*specific for Unix API */
140
141#endif /* defined(RT_OS_WINDOWS) */
142
143#define TCP_ENGAGE_EVENT1(so, fdset) \
144 DO_ENGAGE_EVENT1((so), fdset, tcp)
145
146#define TCP_ENGAGE_EVENT2(so, fdset1, fdset2) \
147 DO_ENGAGE_EVENT2((so), fdset1, fdset2, tcp)
148
149#define UDP_ENGAGE_EVENT(so, fdset) \
150 DO_ENGAGE_EVENT1((so), fdset, udp)
151
152#define POLL_TCP_EVENTS(rc, error, so, events) \
153 DO_POLL_EVENTS((rc), (error), (so), (events), tcp)
154
155#define POLL_UDP_EVENTS(rc, error, so, events) \
156 DO_POLL_EVENTS((rc), (error), (so), (events), udp)
157
158#define CHECK_FD_SET(so, events, set) \
159 (DO_CHECK_FD_SET((so), (events), set))
160
161#define WIN_CHECK_FD_SET(so, events, set) \
162 (DO_WIN_CHECK_FD_SET((so), (events), set))
163#define UNIX_CHECK_FD_SET(so, events, set) \
164 (DO_UNIX_CHECK_FD_SET(so, events, set))
165
166/*
167 * Loging macros
168 */
169#if VBOX_WITH_DEBUG_NAT_SOCKETS
170# if defined(RT_OS_WINDOWS)
171# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
172 do { \
173 LogRel((" " #proto " %R[natsock] %R[natwinnetevents]\n", (so), (winevent))); \
174 } while (0)
175# else /* RT_OS_WINDOWS */
176# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
177 do { \
178 LogRel((" " #proto " %R[natsock] %s %s %s er: %s, %s, %s\n", (so), \
179 CHECK_FD_SET(so, ign ,r_fdset) ? "READ":"", \
180 CHECK_FD_SET(so, ign, w_fdset) ? "WRITE":"", \
181 CHECK_FD_SET(so, ign, x_fdset) ? "OOB":"", \
182 CHECK_FD_SET(so, ign, rderr) ? "RDERR":"", \
183 CHECK_FD_SET(so, ign, rdhup) ? "RDHUP":"", \
184 CHECK_FD_SET(so, ign, nval) ? "RDNVAL":"")); \
185 } while (0)
186# endif /* !RT_OS_WINDOWS */
187#else /* VBOX_WITH_DEBUG_NAT_SOCKETS */
188# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) do {} while (0)
189#endif /* !VBOX_WITH_DEBUG_NAT_SOCKETS */
190
191#define LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) DO_LOG_NAT_SOCK((so), proto, (winevent), r_fdset, w_fdset, x_fdset)
192
193static void acivate_port_forwarding(PNATState, struct ethhdr *);
194static uint32_t find_guest_ip(PNATState, uint8_t *);
195
196static const uint8_t special_ethaddr[6] =
197{
198 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
199};
200
201static const uint8_t broadcast_ethaddr[6] =
202{
203 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
204};
205
206const uint8_t zerro_ethaddr[6] =
207{
208 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
209};
210
211#ifdef RT_OS_WINDOWS
212static int get_dns_addr_domain(PNATState pData, bool fVerbose,
213 struct in_addr *pdns_addr,
214 const char **ppszDomain)
215{
216 /* Get amount of memory required for operation */
217 ULONG flags = GAA_FLAG_INCLUDE_PREFIX; /*GAA_FLAG_INCLUDE_ALL_INTERFACES;*/ /* all interfaces registered in NDIS */
218 PIP_ADAPTER_ADDRESSES addresses = NULL;
219 PIP_ADAPTER_ADDRESSES addr = NULL;
220 PIP_ADAPTER_DNS_SERVER_ADDRESS dns = NULL;
221 ULONG size = 0;
222 int wlen = 0;
223 char *suffix;
224 struct dns_entry *da = NULL;
225 struct dns_domain_entry *dd = NULL;
226 ULONG ret = ERROR_SUCCESS;
227
228 /* @todo add SKIPing flags to get only required information */
229
230 ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, addresses, &size);
231 if (ret != ERROR_BUFFER_OVERFLOW)
232 {
233 LogRel(("NAT: error %lu occurred on capacity detection operation\n", ret));
234 return -1;
235 }
236
237 if (size == 0)
238 {
239 LogRel(("NAT: Win socket API returns non capacity\n"));
240 return -1;
241 }
242
243 addresses = RTMemAllocZ(size);
244 if (addresses == NULL)
245 {
246 LogRel(("NAT: No memory available \n"));
247 return -1;
248 }
249
250 ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, addresses, &size);
251 if (ret != ERROR_SUCCESS)
252 {
253 LogRel(("NAT: error %lu occurred on fetching adapters info\n", ret));
254 RTMemFree(addresses);
255 return -1;
256 }
257 addr = addresses;
258 while(addr != NULL)
259 {
260 int found;
261 if (addr->OperStatus != IfOperStatusUp)
262 goto next;
263 dns = addr->FirstDnsServerAddress;
264 while (dns != NULL)
265 {
266 struct sockaddr *saddr = dns->Address.lpSockaddr;
267 if (saddr->sa_family != AF_INET)
268 goto next_dns;
269 /* add dns server to list */
270 da = RTMemAllocZ(sizeof(struct dns_entry));
271 if (da == NULL)
272 {
273 LogRel(("NAT: Can't allocate buffer for DNS entry\n"));
274 RTMemFree(addresses);
275 return VERR_NO_MEMORY;
276 }
277 LogRel(("NAT: adding %R[IP4] to DNS server list\n", &((struct sockaddr_in *)saddr)->sin_addr));
278 if ((((struct sockaddr_in *)saddr)->sin_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET)) {
279 da->de_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
280 }
281 else
282 {
283 da->de_addr.s_addr = ((struct sockaddr_in *)saddr)->sin_addr.s_addr;
284 }
285 TAILQ_INSERT_HEAD(&pData->dns_list_head, da, de_list);
286
287 if (addr->DnsSuffix == NULL)
288 goto next_dns;
289
290 /*uniq*/
291 RTUtf16ToUtf8(addr->DnsSuffix, &suffix);
292
293 if (!suffix || strlen(suffix) == 0) {
294 RTStrFree(suffix);
295 goto next_dns;
296 }
297
298 found = 0;
299 LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
300 {
301 if ( dd->dd_pszDomain != NULL
302 && strcmp(dd->dd_pszDomain, suffix) == 0)
303 {
304 found = 1;
305 RTStrFree(suffix);
306 break;
307 }
308 }
309 if (found == 0)
310 {
311 dd = RTMemAllocZ(sizeof(struct dns_domain_entry));
312 if (dd == NULL)
313 {
314 LogRel(("NAT: not enough memory\n"));
315 RTStrFree(suffix);
316 RTMemFree(addresses);
317 return VERR_NO_MEMORY;
318 }
319 dd->dd_pszDomain = suffix;
320 LogRel(("NAT: adding domain name %s to search list\n", dd->dd_pszDomain));
321 LIST_INSERT_HEAD(&pData->dns_domain_list_head, dd, dd_list);
322 }
323 next_dns:
324 dns = dns->Next;
325 }
326 next:
327 addr = addr->Next;
328 }
329 RTMemFree(addresses);
330 return 0;
331}
332
333#else /* !RT_OS_WINDOWS */
334
335static int get_dns_addr_domain(PNATState pData, bool fVerbose,
336 struct in_addr *pdns_addr,
337 const char **ppszDomain)
338{
339 char buff[512];
340 char buff2[256];
341 FILE *f = NULL;
342 int found = 0;
343 struct in_addr tmp_addr;
344
345#ifdef RT_OS_OS2
346 /* Try various locations. */
347 char *etc = getenv("ETC");
348 if (etc)
349 {
350 snprintf(buff, sizeof(buff), "%s/RESOLV2", etc);
351 f = fopen(buff, "rt");
352 }
353 if (!f)
354 {
355 snprintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
356 f = fopen(buff, "rt");
357 }
358 if (!f)
359 {
360 snprintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
361 f = fopen(buff, "rt");
362 }
363#else
364#ifndef DEBUG_vvl
365 f = fopen("/etc/resolv.conf", "r");
366#else
367 char *home = getenv("HOME");
368 snprintf(buff, sizeof(buff), "%s/resolv.conf", home);
369 f = fopen(buff, "r");
370 if (f != NULL)
371 {
372 Log(("NAT: DNS we're using %s\n", buff));
373 }
374 else
375 {
376 f = fopen("/etc/resolv.conf", "r");
377 Log(("NAT: DNS we're using %s\n", buff));
378 }
379#endif
380#endif
381 if (!f)
382 return -1;
383
384 if (ppszDomain)
385 *ppszDomain = NULL;
386 Log(("nat: DNS Servers:\n"));
387 while (fgets(buff, 512, f) != NULL)
388 {
389 struct dns_entry *da = NULL;
390 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1)
391 {
392 if (!inet_aton(buff2, &tmp_addr))
393 continue;
394 /*localhost mask */
395 da = RTMemAllocZ(sizeof (struct dns_entry));
396 if (da == NULL)
397 {
398 LogRel(("can't alloc memory for DNS entry\n"));
399 return -1;
400 }
401 /*check */
402 da->de_addr.s_addr = tmp_addr.s_addr;
403 if ((da->de_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET)) {
404 da->de_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
405 }
406 TAILQ_INSERT_HEAD(&pData->dns_list_head, da, de_list);
407 found++;
408 }
409 if ((!strncmp(buff, "domain", 6) || !strncmp(buff, "search", 6)))
410 {
411 char *tok;
412 char *saveptr;
413 struct dns_domain_entry *dd = NULL;
414 int found = 0;
415 tok = strtok_r(&buff[6], " \t\n", &saveptr);
416 LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
417 {
418 if( tok != NULL
419 && strcmp(tok, dd->dd_pszDomain) == 0)
420 {
421 found = 1;
422 break;
423 }
424 }
425 if (tok != NULL && found == 0) {
426 dd = RTMemAllocZ(sizeof(struct dns_domain_entry));
427 if (dd == NULL)
428 {
429 LogRel(("NAT: not enought memory to add domain list\n"));
430 return VERR_NO_MEMORY;
431 }
432 dd->dd_pszDomain = RTStrDup(tok);
433 LogRel(("NAT: adding domain name %s to search list\n", dd->dd_pszDomain));
434 LIST_INSERT_HEAD(&pData->dns_domain_list_head, dd, dd_list);
435 }
436 }
437 }
438 fclose(f);
439 if (!found)
440 return -1;
441 return 0;
442}
443
444#endif
445
446static int slirp_init_dns_list(PNATState pData)
447{
448 TAILQ_INIT(&pData->dns_list_head);
449 LIST_INIT(&pData->dns_domain_list_head);
450 return get_dns_addr_domain(pData, true, NULL, NULL);
451}
452
453static void slirp_release_dns_list(PNATState pData)
454{
455 struct dns_entry *de = NULL;
456 struct dns_domain_entry *dd = NULL;
457 while(!TAILQ_EMPTY(&pData->dns_list_head)) {
458 de = TAILQ_FIRST(&pData->dns_list_head);
459 TAILQ_REMOVE(&pData->dns_list_head, de, de_list);
460 RTMemFree(de);
461 }
462 while(!LIST_EMPTY(&pData->dns_domain_list_head)) {
463 dd = LIST_FIRST(&pData->dns_domain_list_head);
464 LIST_REMOVE(dd, dd_list);
465 if (dd->dd_pszDomain != NULL)
466 RTStrFree(dd->dd_pszDomain);
467 RTMemFree(dd);
468 }
469}
470
471int get_dns_addr(PNATState pData, struct in_addr *pdns_addr)
472{
473 return get_dns_addr_domain(pData, false, pdns_addr, NULL);
474}
475
476#ifndef VBOX_WITH_NAT_SERVICE
477int slirp_init(PNATState *ppData, const char *pszNetAddr, uint32_t u32Netmask,
478 bool fPassDomain, void *pvUser)
479#else
480int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
481 bool fPassDomain, void *pvUser)
482#endif
483{
484 int fNATfailed = 0;
485 int rc;
486 PNATState pData = RTMemAllocZ(sizeof(NATState));
487 *ppData = pData;
488 if (!pData)
489 return VERR_NO_MEMORY;
490 if (u32Netmask & 0x1f)
491 /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
492 return VERR_INVALID_PARAMETER;
493 pData->fPassDomain = fPassDomain;
494 pData->pvUser = pvUser;
495 pData->netmask = u32Netmask;
496
497 /* sockets & TCP defaults */
498 pData->socket_rcv = 64 * _1K;
499 pData->socket_snd = 64 * _1K;
500 tcp_sndspace = 64 * _1K;
501 tcp_rcvspace = 64 * _1K;
502
503#ifdef RT_OS_WINDOWS
504 {
505 WSADATA Data;
506 WSAStartup(MAKEWORD(2, 0), &Data);
507 }
508 pData->phEvents[VBOX_SOCKET_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
509#endif
510#ifdef VBOX_WITH_SLIRP_MT
511 QSOCKET_LOCK_CREATE(tcb);
512 QSOCKET_LOCK_CREATE(udb);
513 rc = RTReqCreateQueue(&pData->pReqQueue);
514 AssertReleaseRC(rc);
515#endif
516
517 link_up = 1;
518
519 debug_init();
520 if_init(pData);
521 ip_init(pData);
522 icmp_init(pData);
523
524 /* Initialise mbufs *after* setting the MTU */
525 m_init(pData);
526
527#ifndef VBOX_WITH_NAT_SERVICE
528 inet_aton(pszNetAddr, &special_addr);
529#else
530 special_addr.s_addr = u32NetAddr;
531#endif
532 pData->slirp_ethaddr = &special_ethaddr[0];
533 alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
534 /* @todo: add ability to configure this staff */
535
536 /* set default addresses */
537 inet_aton("127.0.0.1", &loopback_addr);
538 if (slirp_init_dns_list(pData) < 0)
539 fNATfailed = 1;
540
541 dnsproxy_init(pData);
542
543 getouraddr(pData);
544 {
545 int flags = 0;
546 struct in_addr proxy_addr;
547 pData->proxy_alias = LibAliasInit(pData, NULL);
548 if (pData->proxy_alias == NULL)
549 {
550 LogRel(("NAT: LibAlias default rule wasn't initialized\n"));
551 AssertMsgFailed(("NAT: LibAlias default rule wasn't initialized\n"));
552 }
553 flags = LibAliasSetMode(pData->proxy_alias, 0, 0);
554 flags |= PKT_ALIAS_LOG; /* set logging */
555 flags = LibAliasSetMode(pData->proxy_alias, flags, ~0);
556 proxy_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
557 LibAliasSetAddress(pData->proxy_alias, proxy_addr);
558 ftp_alias_load(pData);
559 nbt_alias_load(pData);
560 }
561 return fNATfailed ? VINF_NAT_DNS : VINF_SUCCESS;
562}
563
564/**
565 * Register statistics.
566 */
567void slirp_register_statistics(PNATState pData, PPDMDRVINS pDrvIns)
568{
569#ifdef VBOX_WITH_STATISTICS
570# define PROFILE_COUNTER(name, dsc) REGISTER_COUNTER(name, pData, STAMTYPE_PROFILE, STAMUNIT_TICKS_PER_CALL, dsc)
571# define COUNTING_COUNTER(name, dsc) REGISTER_COUNTER(name, pData, STAMTYPE_COUNTER, STAMUNIT_COUNT, dsc)
572
573# include "counters.h"
574
575# undef COUNTER
576/** @todo register statistics for the variables dumped by:
577 * ipstats(pData); tcpstats(pData); udpstats(pData); icmpstats(pData);
578 * mbufstats(pData); sockstats(pData); */
579#endif /* VBOX_WITH_STATISTICS */
580}
581
582/**
583 * Deregister statistics.
584 */
585void slirp_deregister_statistics(PNATState pData, PPDMDRVINS pDrvIns)
586{
587#ifdef VBOX_WITH_STATISTICS
588# define PROFILE_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pData)
589# define COUNTING_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pData)
590
591# include "counters.h"
592#endif /* VBOX_WITH_STATISTICS */
593}
594
595/**
596 * Marks the link as up, making it possible to establish new connections.
597 */
598void slirp_link_up(PNATState pData)
599{
600 link_up = 1;
601}
602
603/**
604 * Marks the link as down and cleans up the current connections.
605 */
606void slirp_link_down(PNATState pData)
607{
608 struct socket *so;
609
610 while ((so = tcb.so_next) != &tcb)
611 {
612 if (so->so_state & SS_NOFDREF || so->s == -1)
613 sofree(pData, so);
614 else
615 tcp_drop(pData, sototcpcb(so), 0);
616 }
617
618 while ((so = udb.so_next) != &udb)
619 udp_detach(pData, so);
620
621 link_up = 0;
622}
623
624/**
625 * Terminates the slirp component.
626 */
627void slirp_term(PNATState pData)
628{
629#ifdef RT_OS_WINDOWS
630 pData->pfIcmpCloseHandle(pData->icmp_socket.sh);
631 FreeLibrary(pData->hmIcmpLibrary);
632 RTMemFree(pData->pvIcmpBuffer);
633#else
634 closesocket(pData->icmp_socket.s);
635#endif
636
637 slirp_link_down(pData);
638 slirp_release_dns_list(pData);
639 ftp_alias_unload(pData);
640 nbt_alias_unload(pData);
641 while(!LIST_EMPTY(&instancehead)) {
642 struct libalias *la = LIST_FIRST(&instancehead);
643 /* libalias do all clean up */
644 LibAliasUninit(la);
645 }
646#ifdef RT_OS_WINDOWS
647 WSACleanup();
648#endif
649#ifdef LOG_ENABLED
650 Log(("\n"
651 "NAT statistics\n"
652 "--------------\n"
653 "\n"));
654 ipstats(pData);
655 tcpstats(pData);
656 udpstats(pData);
657 icmpstats(pData);
658 mbufstats(pData);
659 sockstats(pData);
660 Log(("\n"
661 "\n"
662 "\n"));
663#endif
664 RTMemFree(pData);
665}
666
667
668#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
669#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
670
671/*
672 * curtime kept to an accuracy of 1ms
673 */
674static void updtime(PNATState pData)
675{
676#ifdef RT_OS_WINDOWS
677 struct _timeb tb;
678
679 _ftime(&tb);
680 curtime = (u_int)tb.time * (u_int)1000;
681 curtime += (u_int)tb.millitm;
682#else
683 gettimeofday(&tt, 0);
684
685 curtime = (u_int)tt.tv_sec * (u_int)1000;
686 curtime += (u_int)tt.tv_usec / (u_int)1000;
687
688 if ((tt.tv_usec % 1000) >= 500)
689 curtime++;
690#endif
691}
692
693#ifdef RT_OS_WINDOWS
694void slirp_select_fill(PNATState pData, int *pnfds)
695#else /* RT_OS_WINDOWS */
696void slirp_select_fill(PNATState pData, int *pnfds, struct pollfd *polls)
697#endif /* !RT_OS_WINDOWS */
698{
699 struct socket *so, *so_next;
700 int nfds;
701#if defined(RT_OS_WINDOWS)
702 int rc;
703 int error;
704#else
705 int poll_index = 0;
706#endif
707 int i;
708
709 STAM_PROFILE_START(&pData->StatFill, a);
710
711 nfds = *pnfds;
712
713 /*
714 * First, TCP sockets
715 */
716 do_slowtimo = 0;
717 if (!link_up)
718 goto done;
719 /*
720 * *_slowtimo needs calling if there are IP fragments
721 * in the fragment queue, or there are TCP connections active
722 */
723 /* XXX:
724 * triggering of fragment expiration should be the same but use new macroses
725 */
726 do_slowtimo = (tcb.so_next != &tcb);
727 if (!do_slowtimo)
728 {
729 for (i = 0; i < IPREASS_NHASH; i++)
730 {
731 if (!TAILQ_EMPTY(&ipq[i]))
732 {
733 do_slowtimo = 1;
734 break;
735 }
736 }
737 }
738 ICMP_ENGAGE_EVENT(&pData->icmp_socket, readfds);
739
740 STAM_COUNTER_RESET(&pData->StatTCP);
741 STAM_COUNTER_RESET(&pData->StatTCPHot);
742
743 QSOCKET_FOREACH(so, so_next, tcp)
744 /* { */
745#if !defined(RT_OS_WINDOWS)
746 so->so_poll_index = -1;
747#endif
748 STAM_COUNTER_INC(&pData->StatTCP);
749
750 /*
751 * See if we need a tcp_fasttimo
752 */
753 if ( time_fasttimo == 0
754 && so->so_tcpcb != NULL
755 && so->so_tcpcb->t_flags & TF_DELACK)
756 time_fasttimo = curtime; /* Flag when we want a fasttimo */
757
758 /*
759 * NOFDREF can include still connecting to local-host,
760 * newly socreated() sockets etc. Don't want to select these.
761 */
762 if (so->so_state & SS_NOFDREF || so->s == -1)
763 CONTINUE(tcp);
764
765 /*
766 * Set for reading sockets which are accepting
767 */
768 if (so->so_state & SS_FACCEPTCONN)
769 {
770 STAM_COUNTER_INC(&pData->StatTCPHot);
771 TCP_ENGAGE_EVENT1(so, readfds);
772 CONTINUE(tcp);
773 }
774
775 /*
776 * Set for writing sockets which are connecting
777 */
778 if (so->so_state & SS_ISFCONNECTING)
779 {
780 Log2(("connecting %R[natsock] engaged\n",so));
781 STAM_COUNTER_INC(&pData->StatTCPHot);
782 TCP_ENGAGE_EVENT1(so, writefds);
783 }
784
785 /*
786 * Set for writing if we are connected, can send more, and
787 * we have something to send
788 */
789 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc)
790 {
791 STAM_COUNTER_INC(&pData->StatTCPHot);
792 TCP_ENGAGE_EVENT1(so, writefds);
793 }
794
795 /*
796 * Set for reading (and urgent data) if we are connected, can
797 * receive more, and we have room for it XXX /2 ?
798 */
799 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2)))
800 {
801 STAM_COUNTER_INC(&pData->StatTCPHot);
802 TCP_ENGAGE_EVENT2(so, readfds, xfds);
803 }
804 LOOP_LABEL(tcp, so, so_next);
805 }
806
807 /*
808 * UDP sockets
809 */
810 STAM_COUNTER_RESET(&pData->StatUDP);
811 STAM_COUNTER_RESET(&pData->StatUDPHot);
812
813 QSOCKET_FOREACH(so, so_next, udp)
814 /* { */
815
816 STAM_COUNTER_INC(&pData->StatUDP);
817#if !defined(RT_OS_WINDOWS)
818 so->so_poll_index = -1;
819#endif
820
821 /*
822 * See if it's timed out
823 */
824 if (so->so_expire)
825 {
826 if (so->so_expire <= curtime)
827 {
828 Log2(("NAT: %R[natsock] expired\n", so));
829 if (so->so_timeout != NULL)
830 {
831 so->so_timeout(pData, so, so->so_timeout_arg);
832 }
833#ifdef VBOX_WITH_SLIRP_MT
834 /* we need so_next for continue our cycle*/
835 so_next = so->so_next;
836#endif
837 UDP_DETACH(pData, so, so_next);
838 CONTINUE_NO_UNLOCK(udp);
839 }
840 else
841 do_slowtimo = 1; /* Let socket expire */
842 }
843
844 /*
845 * When UDP packets are received from over the link, they're
846 * sendto()'d straight away, so no need for setting for writing
847 * Limit the number of packets queued by this session to 4.
848 * Note that even though we try and limit this to 4 packets,
849 * the session could have more queued if the packets needed
850 * to be fragmented.
851 *
852 * (XXX <= 4 ?)
853 */
854 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4)
855 {
856 STAM_COUNTER_INC(&pData->StatUDPHot);
857 UDP_ENGAGE_EVENT(so, readfds);
858 }
859 LOOP_LABEL(udp, so, so_next);
860 }
861done:
862
863#if defined(RT_OS_WINDOWS)
864 *pnfds = VBOX_EVENT_COUNT;
865#else /* RT_OS_WINDOWS */
866 AssertRelease(poll_index <= *pnfds);
867 *pnfds = poll_index;
868#endif /* !RT_OS_WINDOWS */
869
870 STAM_PROFILE_STOP(&pData->StatFill, a);
871}
872
873#if defined(RT_OS_WINDOWS)
874void slirp_select_poll(PNATState pData, int fTimeout, int fIcmp)
875#else /* RT_OS_WINDOWS */
876void slirp_select_poll(PNATState pData, struct pollfd *polls, int ndfs)
877#endif /* !RT_OS_WINDOWS */
878{
879 struct socket *so, *so_next;
880 int ret;
881#if defined(RT_OS_WINDOWS)
882 WSANETWORKEVENTS NetworkEvents;
883 int rc;
884 int error;
885#else
886 int poll_index = 0;
887#endif
888
889 STAM_PROFILE_START(&pData->StatPoll, a);
890
891 /* Update time */
892 updtime(pData);
893
894 /*
895 * See if anything has timed out
896 */
897 if (link_up)
898 {
899 if (time_fasttimo && ((curtime - time_fasttimo) >= 2))
900 {
901 STAM_PROFILE_START(&pData->StatFastTimer, a);
902 tcp_fasttimo(pData);
903 time_fasttimo = 0;
904 STAM_PROFILE_STOP(&pData->StatFastTimer, a);
905 }
906 if (do_slowtimo && ((curtime - last_slowtimo) >= 499))
907 {
908 STAM_PROFILE_START(&pData->StatSlowTimer, a);
909 ip_slowtimo(pData);
910 tcp_slowtimo(pData);
911 last_slowtimo = curtime;
912 STAM_PROFILE_STOP(&pData->StatSlowTimer, a);
913 }
914 }
915#if defined(RT_OS_WINDOWS)
916 if (fTimeout)
917 return; /* only timer update */
918#endif
919
920 /*
921 * Check sockets
922 */
923 if (!link_up)
924 goto done;
925#if defined(RT_OS_WINDOWS)
926 /*XXX: before renaming please make see define
927 * fIcmp in slirp_state.h
928 */
929 if (fIcmp)
930 sorecvfrom(pData, &pData->icmp_socket);
931#else
932 if ( (pData->icmp_socket.s != -1)
933 && CHECK_FD_SET(&pData->icmp_socket, ignored, readfds))
934 sorecvfrom(pData, &pData->icmp_socket);
935#endif
936 /*
937 * Check TCP sockets
938 */
939 QSOCKET_FOREACH(so, so_next, tcp)
940 /* { */
941
942#ifdef VBOX_WITH_SLIRP_MT
943 if ( so->so_state & SS_NOFDREF
944 && so->so_deleted == 1)
945 {
946 struct socket *son, *sop = NULL;
947 QSOCKET_LOCK(tcb);
948 if (so->so_next != NULL)
949 {
950 if (so->so_next != &tcb)
951 SOCKET_LOCK(so->so_next);
952 son = so->so_next;
953 }
954 if ( so->so_prev != &tcb
955 && so->so_prev != NULL)
956 {
957 SOCKET_LOCK(so->so_prev);
958 sop = so->so_prev;
959 }
960 QSOCKET_UNLOCK(tcb);
961 remque(pData, so);
962 NSOCK_DEC();
963 SOCKET_UNLOCK(so);
964 SOCKET_LOCK_DESTROY(so);
965 RTMemFree(so);
966 so_next = son;
967 if (sop != NULL)
968 SOCKET_UNLOCK(sop);
969 CONTINUE_NO_UNLOCK(tcp);
970 }
971#endif
972 /*
973 * FD_ISSET is meaningless on these sockets
974 * (and they can crash the program)
975 */
976 if (so->so_state & SS_NOFDREF || so->s == -1)
977 CONTINUE(tcp);
978
979 POLL_TCP_EVENTS(rc, error, so, &NetworkEvents);
980
981 LOG_NAT_SOCK(so, TCP, &NetworkEvents, readfds, writefds, xfds);
982
983
984 /*
985 * Check for URG data
986 * This will soread as well, so no need to
987 * test for readfds below if this succeeds
988 */
989
990 /* out-of-band data */
991 if (CHECK_FD_SET(so, NetworkEvents, xfds))
992 {
993 sorecvoob(pData, so);
994 }
995
996 /*
997 * Check sockets for reading
998 */
999 else if ( CHECK_FD_SET(so, NetworkEvents, readfds)
1000 || WIN_CHECK_FD_SET(so, NetworkEvents, acceptds))
1001 {
1002 /*
1003 * Check for incoming connections
1004 */
1005 if (so->so_state & SS_FACCEPTCONN)
1006 {
1007 TCP_CONNECT(pData, so);
1008#if defined(RT_OS_WINDOWS)
1009 if (!(NetworkEvents.lNetworkEvents & FD_CLOSE))
1010#endif
1011 CONTINUE(tcp);
1012 }
1013
1014 ret = soread(pData, so);
1015 /* Output it if we read something */
1016 if (RT_LIKELY(ret > 0))
1017 TCP_OUTPUT(pData, sototcpcb(so));
1018 }
1019
1020#if defined(RT_OS_WINDOWS)
1021 /*
1022 * Check for FD_CLOSE events.
1023 * in some cases once FD_CLOSE engaged on socket it could be flashed latter (for some reasons)
1024 */
1025 if ( (NetworkEvents.lNetworkEvents & FD_CLOSE)
1026 || (so->so_close == 1))
1027 {
1028 so->so_close = 1; /* mark it */
1029 /*
1030 * drain the socket
1031 */
1032 for (;;)
1033 {
1034 ret = soread(pData, so);
1035 if (ret > 0)
1036 TCP_OUTPUT(pData, sototcpcb(so));
1037 else
1038 break;
1039 }
1040 CONTINUE(tcp);
1041 }
1042#endif
1043
1044 /*
1045 * Check sockets for writing
1046 */
1047 if (CHECK_FD_SET(so, NetworkEvents, writefds))
1048 {
1049 /*
1050 * Check for non-blocking, still-connecting sockets
1051 */
1052 if (so->so_state & SS_ISFCONNECTING)
1053 {
1054 Log2(("connecting %R[natsock] catched\n", so));
1055 /* Connected */
1056 so->so_state &= ~SS_ISFCONNECTING;
1057
1058 /*
1059 * This should be probably guarded by PROBE_CONN too. Anyway,
1060 * we disable it on OS/2 because the below send call returns
1061 * EFAULT which causes the opened TCP socket to close right
1062 * after it has been opened and connected.
1063 */
1064#ifndef RT_OS_OS2
1065 ret = send(so->s, (const char *)&ret, 0, 0);
1066 if (ret < 0)
1067 {
1068 /* XXXXX Must fix, zero bytes is a NOP */
1069 if ( errno == EAGAIN
1070 || errno == EWOULDBLOCK
1071 || errno == EINPROGRESS
1072 || errno == ENOTCONN)
1073 CONTINUE(tcp);
1074
1075 /* else failed */
1076 so->so_state = SS_NOFDREF;
1077 }
1078 /* else so->so_state &= ~SS_ISFCONNECTING; */
1079#endif
1080
1081 /*
1082 * Continue tcp_input
1083 */
1084 TCP_INPUT(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
1085 /* continue; */
1086 }
1087 else
1088 SOWRITE(ret, pData, so);
1089 /*
1090 * XXX If we wrote something (a lot), there could be the need
1091 * for a window update. In the worst case, the remote will send
1092 * a window probe to get things going again.
1093 */
1094 }
1095
1096 /*
1097 * Probe a still-connecting, non-blocking socket
1098 * to check if it's still alive
1099 */
1100#ifdef PROBE_CONN
1101 if (so->so_state & SS_ISFCONNECTING)
1102 {
1103 ret = recv(so->s, (char *)&ret, 0, 0);
1104
1105 if (ret < 0)
1106 {
1107 /* XXX */
1108 if ( errno == EAGAIN
1109 || errno == EWOULDBLOCK
1110 || errno == EINPROGRESS
1111 || errno == ENOTCONN)
1112 {
1113 CONTINUE(tcp); /* Still connecting, continue */
1114 }
1115
1116 /* else failed */
1117 so->so_state = SS_NOFDREF;
1118
1119 /* tcp_input will take care of it */
1120 }
1121 else
1122 {
1123 ret = send(so->s, &ret, 0, 0);
1124 if (ret < 0)
1125 {
1126 /* XXX */
1127 if ( errno == EAGAIN
1128 || errno == EWOULDBLOCK
1129 || errno == EINPROGRESS
1130 || errno == ENOTCONN)
1131 {
1132 CONTINUE(tcp);
1133 }
1134 /* else failed */
1135 so->so_state = SS_NOFDREF;
1136 }
1137 else
1138 so->so_state &= ~SS_ISFCONNECTING;
1139
1140 }
1141 TCP_INPUT((struct mbuf *)NULL, sizeof(struct ip),so);
1142 } /* SS_ISFCONNECTING */
1143#endif
1144#ifndef RT_OS_WINDOWS
1145 if ( UNIX_CHECK_FD_SET(so, NetworkEvents, rdhup)
1146 || UNIX_CHECK_FD_SET(so, NetworkEvents, rderr))
1147 {
1148 int err;
1149 int inq, outq;
1150 int status;
1151 socklen_t optlen = sizeof(int);
1152 inq = outq = 0;
1153 status = getsockopt(so->s, SOL_SOCKET, SO_ERROR, &err, &optlen);
1154 if (status != 0)
1155 Log(("NAT: can't get error status from %R[natsock]\n", so));
1156#ifndef RT_OS_SOLARIS
1157 status = ioctl(so->s, FIONREAD, &inq); /* tcp(7) recommends SIOCINQ which is Linux specific */
1158 if (status != 0 || status != EINVAL)
1159 {
1160 /* EINVAL returned if socket in listen state tcp(7)*/
1161 Log(("NAT: can't get depth of IN queue status from %R[natsock]\n", so));
1162 }
1163 status = ioctl(so->s, TIOCOUTQ, &outq); /* SIOCOUTQ see previous comment */
1164 if (status != 0)
1165 Log(("NAT: can't get depth of OUT queue from %R[natsock]\n", so));
1166#else
1167 /*
1168 * Solaris has bit different ioctl commands and its handlings
1169 * hint: streamio(7) I_NREAD
1170 */
1171#endif
1172 if ( so->so_state & SS_ISFCONNECTING
1173 || UNIX_CHECK_FD_SET(so, NetworkEvents, readfds))
1174 {
1175 /**
1176 * Check if we need here take care about gracefull connection
1177 * @todo try with proxy server
1178 */
1179 if (UNIX_CHECK_FD_SET(so, NetworkEvents, readfds))
1180 {
1181 /*
1182 * Never meet inq != 0 or outq != 0, anyway let it stay for a while
1183 * in case it happens we'll able to detect it.
1184 * Give TCP/IP stack wait or expire the socket.
1185 */
1186 Log(("NAT: %R[natsock] err(%d:%s) s(in:%d,out:%d)happens on read I/O, "
1187 "other side close connection \n", so, err, strerror(err), inq, outq));
1188 CONTINUE(tcp);
1189 }
1190 goto tcp_input_close;
1191 }
1192 if ( !UNIX_CHECK_FD_SET(so, NetworkEvents, readfds)
1193 && !UNIX_CHECK_FD_SET(so, NetworkEvents, writefds)
1194 && !UNIX_CHECK_FD_SET(so, NetworkEvents, xfds))
1195 {
1196 Log(("NAT: system expires the socket %R[natsock] err(%d:%s) s(in:%d,out:%d) happens on non-I/O. ",
1197 so, err, strerror(err), inq, outq));
1198 goto tcp_input_close;
1199 }
1200 Log(("NAT: %R[natsock] we've met(%d:%s) s(in:%d, out:%d) unhandled combination hup (%d) "
1201 "rederr(%d) on (r:%d, w:%d, x:%d)\n",
1202 so, err, strerror(err),
1203 inq, outq,
1204 UNIX_CHECK_FD_SET(so, ign, rdhup),
1205 UNIX_CHECK_FD_SET(so, ign, rderr),
1206 UNIX_CHECK_FD_SET(so, ign, readfds),
1207 UNIX_CHECK_FD_SET(so, ign, writefds),
1208 UNIX_CHECK_FD_SET(so, ign, xfds)));
1209 /*
1210 * Give OS's TCP/IP stack a chance to resolve an issue or expire the socket.
1211 */
1212 CONTINUE(tcp);
1213tcp_input_close:
1214 so->so_state = SS_NOFDREF; /*cause connection valid tcp connection termination and socket closing */
1215 TCP_INPUT(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
1216 CONTINUE(tcp);
1217 }
1218#endif
1219 LOOP_LABEL(tcp, so, so_next);
1220 }
1221
1222 /*
1223 * Now UDP sockets.
1224 * Incoming packets are sent straight away, they're not buffered.
1225 * Incoming UDP data isn't buffered either.
1226 */
1227 QSOCKET_FOREACH(so, so_next, udp)
1228 /* { */
1229#ifdef VBOX_WITH_SLIRP_MT
1230 if ( so->so_state & SS_NOFDREF
1231 && so->so_deleted == 1)
1232 {
1233 struct socket *son, *sop = NULL;
1234 QSOCKET_LOCK(udb);
1235 if (so->so_next != NULL)
1236 {
1237 if (so->so_next != &udb)
1238 SOCKET_LOCK(so->so_next);
1239 son = so->so_next;
1240 }
1241 if ( so->so_prev != &udb
1242 && so->so_prev != NULL)
1243 {
1244 SOCKET_LOCK(so->so_prev);
1245 sop = so->so_prev;
1246 }
1247 QSOCKET_UNLOCK(udb);
1248 remque(pData, so);
1249 NSOCK_DEC();
1250 SOCKET_UNLOCK(so);
1251 SOCKET_LOCK_DESTROY(so);
1252 RTMemFree(so);
1253 so_next = son;
1254 if (sop != NULL)
1255 SOCKET_UNLOCK(sop);
1256 CONTINUE_NO_UNLOCK(udp);
1257 }
1258#endif
1259 POLL_UDP_EVENTS(rc, error, so, &NetworkEvents);
1260
1261 LOG_NAT_SOCK(so, UDP, &NetworkEvents, readfds, writefds, xfds);
1262
1263 if (so->s != -1 && CHECK_FD_SET(so, NetworkEvents, readfds))
1264 {
1265 SORECVFROM(pData, so);
1266 }
1267 LOOP_LABEL(udp, so, so_next);
1268 }
1269
1270done:
1271#ifndef VBOX_WITH_SLIRP_MT
1272 /*
1273 * See if we can start outputting
1274 */
1275 if (if_queued && link_up)
1276 if_start(pData);
1277#endif
1278
1279 STAM_PROFILE_STOP(&pData->StatPoll, a);
1280}
1281
1282
1283struct arphdr
1284{
1285 unsigned short ar_hrd; /* format of hardware address */
1286 unsigned short ar_pro; /* format of protocol address */
1287 unsigned char ar_hln; /* length of hardware address */
1288 unsigned char ar_pln; /* length of protocol address */
1289 unsigned short ar_op; /* ARP opcode (command) */
1290
1291 /*
1292 * Ethernet looks like this : This bit is variable sized however...
1293 */
1294 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
1295 unsigned char ar_sip[4]; /* sender IP address */
1296 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
1297 unsigned char ar_tip[4]; /* target IP address */
1298};
1299AssertCompileSize(struct arphdr, 28);
1300
1301static void arp_input(PNATState pData, struct mbuf *m)
1302{
1303 struct ethhdr *eh;
1304 struct ethhdr *reh;
1305 struct arphdr *ah;
1306 struct arphdr *rah;
1307 int ar_op;
1308 struct ex_list *ex_ptr;
1309 uint32_t htip;
1310 uint32_t tip;
1311 struct mbuf *mr;
1312 eh = mtod(m, struct ethhdr *);
1313 ah = (struct arphdr *)&eh[1];
1314 htip = ntohl(*(uint32_t*)ah->ar_tip);
1315 tip = *(uint32_t*)ah->ar_tip;
1316
1317 mr = m_get(pData);
1318
1319 reh = mtod(mr, struct ethhdr *);
1320 memcpy(reh->h_source, eh->h_source, ETH_ALEN); /* XXX: if_encap will swap src and dst*/
1321 Log4(("NAT: arp:%R[ether]->%R[ether]\n",
1322 reh->h_source, reh->h_dest));
1323 Log4(("NAT: arp: %R[IP4]\n", &tip));
1324
1325 mr->m_data += if_maxlinkhdr;
1326 mr->m_len = sizeof(struct arphdr);
1327 rah = mtod(mr, struct arphdr *);
1328
1329 ar_op = ntohs(ah->ar_op);
1330 switch(ar_op)
1331 {
1332 case ARPOP_REQUEST:
1333#ifdef VBOX_WITH_NAT_SERVICE
1334 if (tip == special_addr.s_addr) goto arp_ok;
1335#endif
1336 if ((htip & pData->netmask) == ntohl(special_addr.s_addr))
1337 {
1338 if ( CTL_CHECK(htip, CTL_DNS)
1339 || CTL_CHECK(htip, CTL_ALIAS)
1340 || CTL_CHECK(htip, CTL_TFTP))
1341 goto arp_ok;
1342 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
1343 {
1344 if ((htip & ~pData->netmask) == ex_ptr->ex_addr)
1345 {
1346 goto arp_ok;
1347 }
1348 }
1349 return;
1350 arp_ok:
1351 rah->ar_hrd = htons(1);
1352 rah->ar_pro = htons(ETH_P_IP);
1353 rah->ar_hln = ETH_ALEN;
1354 rah->ar_pln = 4;
1355 rah->ar_op = htons(ARPOP_REPLY);
1356 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN);
1357
1358 switch (htip & ~pData->netmask)
1359 {
1360 case CTL_DNS:
1361 case CTL_ALIAS:
1362 rah->ar_sha[5] = (uint8_t)(htip & ~pData->netmask);
1363 break;
1364 default:;
1365 }
1366
1367 memcpy(rah->ar_sip, ah->ar_tip, 4);
1368 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
1369 memcpy(rah->ar_tip, ah->ar_sip, 4);
1370 if_encap(pData, ETH_P_ARP, mr);
1371 m_free(pData, m);
1372 }
1373 break;
1374 default:
1375 break;
1376 }
1377}
1378
1379void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
1380{
1381 struct mbuf *m;
1382 int proto;
1383 static bool fWarnedIpv6;
1384 struct ethhdr *eh = (struct ethhdr*)pkt;
1385
1386 Log2(("NAT: slirp_input %d\n", pkt_len));
1387 if (pkt_len < ETH_HLEN)
1388 {
1389 LogRel(("NAT: packet having size %d has been ingnored\n", pkt_len));
1390 return;
1391 }
1392 Log4(("NAT: in:%R[ether]->%R[ether]\n", &eh->h_source, &eh->h_dest));
1393
1394 if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) == 0)
1395 {
1396 /* @todo vasily: add ether logging routine in debug.c */
1397 Log(("NAT: packet was addressed to other MAC\n"));
1398 RTMemFree((void *)pkt);
1399 return;
1400 }
1401
1402 m = m_get(pData);
1403 if (!m)
1404 {
1405 LogRel(("NAT: can't allocate new mbuf\n"));
1406 return;
1407 }
1408
1409 /* Note: we add to align the IP header */
1410
1411 if (M_FREEROOM(m) < pkt_len)
1412 m_inc(m, pkt_len);
1413
1414 m->m_len = pkt_len ;
1415 memcpy(m->m_data, pkt, pkt_len);
1416
1417 if (pData->port_forwarding_activated == 0)
1418 acivate_port_forwarding(pData, mtod(m, struct ethhdr *));
1419
1420 proto = ntohs(*(uint16_t *)(pkt + 12));
1421 switch(proto)
1422 {
1423 case ETH_P_ARP:
1424 arp_input(pData, m);
1425 break;
1426 case ETH_P_IP:
1427 /* Update time. Important if the network is very quiet, as otherwise
1428 * the first outgoing connection gets an incorrect timestamp. */
1429 updtime(pData);
1430 m_adj(m, ETH_HLEN);
1431 ip_input(pData, m);
1432 break;
1433 case ETH_P_IPV6:
1434 m_free(pData, m);
1435 if (!fWarnedIpv6)
1436 {
1437 LogRel(("NAT: IPv6 not supported\n"));
1438 fWarnedIpv6 = true;
1439 }
1440 break;
1441 default:
1442 Log(("NAT: Unsupported protocol %x\n", proto));
1443 m_free(pData, m);
1444 break;
1445 }
1446 RTMemFree((void *)pkt);
1447}
1448
1449/* output the IP packet to the ethernet device */
1450void if_encap(PNATState pData, uint16_t eth_proto, struct mbuf *m)
1451{
1452 struct ethhdr *eh;
1453 uint8_t *buf = NULL;
1454 STAM_PROFILE_START(&pData->StatIF_encap, a);
1455
1456 m->m_data -= if_maxlinkhdr;
1457 m->m_len += ETH_HLEN;
1458 eh = mtod(m, struct ethhdr *);
1459
1460 if(MBUF_HEAD(m) != m->m_data)
1461 {
1462 LogRel(("NAT: ethernet detects corruption of the packet"));
1463 AssertMsgFailed(("!!Ethernet frame corrupted!!"));
1464 }
1465
1466 if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) != 0)
1467 {
1468 memcpy(eh->h_dest, eh->h_source, ETH_ALEN);
1469 memcpy(eh->h_source, special_ethaddr, ETH_ALEN);
1470 Assert(memcmp(eh->h_dest, special_ethaddr, ETH_ALEN) != 0);
1471 if (memcmp(eh->h_dest, zerro_ethaddr, ETH_ALEN) == 0)
1472 {
1473 /* don't do anything */
1474 goto done;
1475 }
1476 }
1477 buf = RTMemAlloc(1600);
1478 if (buf == NULL)
1479 {
1480 LogRel(("NAT: Can't alloc memory for outgoing buffer\n"));
1481 goto done;
1482 }
1483 eh->h_proto = htons(eth_proto);
1484 memcpy(buf, mtod(m, uint8_t *), m->m_len);
1485 slirp_output(pData->pvUser, NULL, buf, m->m_len);
1486done:
1487 STAM_PROFILE_STOP(&pData->StatIF_encap, a);
1488 m_free(pData, m);
1489}
1490
1491/**
1492 * Still we're using dhcp server leasing to map ether to IP
1493 * @todo see rt_lookup_in_cache
1494 */
1495static uint32_t find_guest_ip(PNATState pData, uint8_t *eth_addr)
1496{
1497 int i;
1498 if (memcmp(eth_addr, zerro_ethaddr, ETH_ALEN) == 0
1499 || memcmp(eth_addr, broadcast_ethaddr, ETH_ALEN) == 0)
1500 goto done;
1501 for (i = 0; i < NB_ADDR; i++)
1502 {
1503 if ( bootp_clients[i].allocated
1504 && memcmp(bootp_clients[i].macaddr, eth_addr, ETH_ALEN) == 0)
1505 return bootp_clients[i].addr.s_addr;
1506 }
1507done:
1508 return INADDR_ANY;
1509}
1510
1511/**
1512 * We need check if we've activated port forwarding
1513 * for specific machine ... that of course relates to
1514 * service mode
1515 * @todo finish this for service case
1516 */
1517static void acivate_port_forwarding(PNATState pData, struct ethhdr *ethdr)
1518{
1519 struct port_forward_rule *rule = NULL;
1520
1521 pData->port_forwarding_activated = 1;
1522 /* check mac here */
1523 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
1524 {
1525 struct socket *so;
1526 struct alias_link *link;
1527 struct libalias *lib;
1528 int flags;
1529 struct sockaddr sa;
1530 struct sockaddr_in *psin;
1531 socklen_t socketlen;
1532 struct in_addr alias;
1533 int rc;
1534 uint32_t guest_addr; /* need to understand if we already give address to guest */
1535
1536 if (rule->activated)
1537 continue; /*already activated */
1538#ifdef VBOX_WITH_NAT_SERVICE
1539 if (memcmp(rule->mac_address, ethdr->h_source, ETH_ALEN) != 0)
1540 continue; /*not right mac, @todo: it'd be better do the list port forwarding per mac */
1541 guest_addr = find_guest_ip(pData, ethdr->h_source);
1542#else
1543 if (memcmp(client_ethaddr, ethdr->h_source, ETH_ALEN) != 0)
1544 continue;
1545 guest_addr = find_guest_ip(pData, ethdr->h_source);
1546#endif
1547 if (guest_addr == INADDR_ANY)
1548 {
1549 /* the address wasn't granted */
1550 pData->port_forwarding_activated = 0;
1551 return;
1552 }
1553#if defined(DEBUG_vvl) && !defined(VBOX_WITH_NAT_SERVICE)
1554 Assert(rule->guest_addr.s_addr == guest_addr);
1555#endif
1556
1557 LogRel(("NAT: set redirect %s hp:%d gp:%d\n", (rule->proto == IPPROTO_UDP?"UDP":"TCP"),
1558 rule->host_port, rule->guest_port));
1559 if (rule->proto == IPPROTO_UDP)
1560 {
1561 so = udp_listen(pData, rule->bind_ip.s_addr, htons(rule->host_port), guest_addr,
1562 htons(rule->guest_port), 0);
1563 }
1564 else
1565 {
1566 so = solisten(pData, rule->bind_ip.s_addr, htons(rule->host_port), guest_addr,
1567 htons(rule->guest_port), 0);
1568 }
1569 if (so == NULL)
1570 {
1571 LogRel(("NAT: failed redirect %s hp:%d gp:%d\n", (rule->proto == IPPROTO_UDP?"UDP":"TCP"),
1572 rule->host_port, rule->guest_port));
1573 goto remove_port_forwarding;
1574 }
1575
1576 psin = (struct sockaddr_in *)&sa;
1577 psin->sin_family = AF_INET;
1578 psin->sin_port = 0;
1579 psin->sin_addr.s_addr = INADDR_ANY;
1580 socketlen = sizeof(struct sockaddr);
1581
1582 rc = getsockname(so->s, &sa, &socketlen);
1583 if (rc < 0 || sa.sa_family != AF_INET)
1584 {
1585 LogRel(("NAT: failed redirect %s hp:%d gp:%d\n", (rule->proto == IPPROTO_UDP?"UDP":"TCP"),
1586 rule->host_port, rule->guest_port));
1587 goto remove_port_forwarding;
1588 }
1589
1590 psin = (struct sockaddr_in *)&sa;
1591
1592 lib = LibAliasInit(pData, NULL);
1593 flags = LibAliasSetMode(lib, 0, 0);
1594 flags |= PKT_ALIAS_LOG; /* set logging */
1595 flags |= PKT_ALIAS_REVERSE; /* set logging */
1596 flags = LibAliasSetMode(lib, flags, ~0);
1597
1598 alias.s_addr = htonl(ntohl(guest_addr) | CTL_ALIAS);
1599 link = LibAliasRedirectPort(lib, psin->sin_addr, htons(rule->host_port),
1600 alias, htons(rule->guest_port),
1601 special_addr, -1, /* not very clear for now*/
1602 rule->proto);
1603 if (link == NULL)
1604 {
1605 LogRel(("NAT: failed redirect %s hp:%d gp:%d\n", (rule->proto == IPPROTO_UDP?"UDP":"TCP"),
1606 rule->host_port, rule->guest_port));
1607 goto remove_port_forwarding;
1608 }
1609 so->so_la = lib;
1610 rule->activated = 1;
1611 continue;
1612 remove_port_forwarding:
1613 LIST_REMOVE(rule, list);
1614 RTMemFree(rule);
1615 }
1616}
1617
1618/**
1619 * Changes in 3.1 instead of opening new socket do the following:
1620 * gain more information:
1621 * 1. bind IP
1622 * 2. host port
1623 * 3. guest port
1624 * 4. proto
1625 * 5. guest MAC address
1626 * the guest's MAC address is rather important for service, but we easily
1627 * could get it from VM configuration in DrvNAT or Service, the idea is activating
1628 * corresponding port-forwarding
1629 */
1630int slirp_redir(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1631 struct in_addr guest_addr, int guest_port, const uint8_t *ethaddr)
1632{
1633 struct port_forward_rule *rule = NULL;
1634 Assert(memcmp(ethaddr, zerro_ethaddr, ETH_ALEN) == 0);
1635 rule = RTMemAllocZ(sizeof(struct port_forward_rule));
1636 if (rule == NULL)
1637 return 1;
1638 rule->proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
1639 rule->host_port = host_port;
1640 rule->guest_port = guest_port;
1641#ifndef VBOX_WITH_NAT_SERVICE
1642 rule->guest_addr.s_addr = guest_addr.s_addr;
1643#endif
1644 rule->bind_ip.s_addr = host_addr.s_addr;
1645 memcpy(rule->mac_address, ethaddr, ETH_ALEN);
1646 /* @todo add mac address */
1647 LIST_INSERT_HEAD(&pData->port_forward_rule_head, rule, list);
1648 return 0;
1649}
1650
1651int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
1652 int guest_port)
1653{
1654 return add_exec(&exec_list, do_pty, (char *)args,
1655 addr_low_byte, htons(guest_port));
1656}
1657
1658void slirp_set_ethaddr(PNATState pData, const uint8_t *ethaddr)
1659{
1660#ifndef VBOX_WITH_NAT_SERVICE
1661 memcpy(client_ethaddr, ethaddr, ETH_ALEN);
1662#endif
1663}
1664
1665#if defined(RT_OS_WINDOWS)
1666HANDLE *slirp_get_events(PNATState pData)
1667{
1668 return pData->phEvents;
1669}
1670void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index)
1671{
1672 pData->phEvents[index] = hEvent;
1673}
1674#endif
1675
1676unsigned int slirp_get_timeout_ms(PNATState pData)
1677{
1678 if (link_up)
1679 {
1680 if (time_fasttimo)
1681 return 2;
1682 if (do_slowtimo)
1683 return 500; /* see PR_SLOWHZ */
1684 }
1685 return 0;
1686}
1687
1688#ifndef RT_OS_WINDOWS
1689int slirp_get_nsock(PNATState pData)
1690{
1691 return pData->nsock;
1692}
1693#endif
1694
1695/*
1696 * this function called from NAT thread
1697 */
1698void slirp_post_sent(PNATState pData, void *pvArg)
1699{
1700 struct socket *so = 0;
1701 struct tcpcb *tp = 0;
1702 struct mbuf *m = (struct mbuf *)pvArg;
1703 m_free(pData, m);
1704}
1705#ifdef VBOX_WITH_SLIRP_MT
1706void slirp_process_queue(PNATState pData)
1707{
1708 RTReqProcess(pData->pReqQueue, RT_INDEFINITE_WAIT);
1709}
1710void *slirp_get_queue(PNATState pData)
1711{
1712 return pData->pReqQueue;
1713}
1714#endif
1715
1716void slirp_set_dhcp_TFTP_prefix(PNATState pData, const char *tftpPrefix)
1717{
1718 Log2(("tftp_prefix:%s\n", tftpPrefix));
1719 tftp_prefix = tftpPrefix;
1720}
1721
1722void slirp_set_dhcp_TFTP_bootfile(PNATState pData, const char *bootFile)
1723{
1724 Log2(("bootFile:%s\n", bootFile));
1725 bootp_filename = bootFile;
1726}
1727
1728void slirp_set_dhcp_next_server(PNATState pData, const char *next_server)
1729{
1730 Log2(("next_server:%s\n", next_server));
1731 if (next_server == NULL)
1732 pData->tftp_server.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_TFTP);
1733 else
1734 inet_aton(next_server, &pData->tftp_server);
1735}
1736
1737int slirp_set_binding_address(PNATState pData, char *addr)
1738{
1739 if (addr == NULL || (inet_aton(addr, &pData->bindIP) == 0))
1740 {
1741 pData->bindIP.s_addr = INADDR_ANY;
1742 return 1;
1743 }
1744 return 0;
1745}
1746
1747void slirp_set_dhcp_dns_proxy(PNATState pData, bool fDNSProxy)
1748{
1749 Log2(("NAT: DNS proxy switched %s\n", (fDNSProxy ? "on" : "off")));
1750 pData->use_dns_proxy = fDNSProxy;
1751}
1752
1753#define CHECK_ARG(name, val, lim_min, lim_max) \
1754do { \
1755 if ((val) < (lim_min) || (val) > (lim_max)) \
1756 { \
1757 LogRel(("NAT: (" #name ":%d) has been ignored, " \
1758 "because out of range (%d, %d)\n", (val), (lim_min), (lim_max))); \
1759 return; \
1760 } \
1761 else \
1762 { \
1763 LogRel(("NAT: (" #name ":%d)\n", (val))); \
1764 } \
1765} while (0)
1766
1767/* don't allow user set less 8kB and more than 1M values */
1768#define _8K_1M_CHECK_ARG(name, val) CHECK_ARG(name, (val), 8, 1024)
1769void slirp_set_rcvbuf(PNATState pData, int kilobytes)
1770{
1771 _8K_1M_CHECK_ARG("SOCKET_RCVBUF", kilobytes);
1772 pData->socket_rcv = kilobytes;
1773}
1774void slirp_set_sndbuf(PNATState pData, int kilobytes)
1775{
1776 _8K_1M_CHECK_ARG("SOCKET_SNDBUF", kilobytes);
1777 pData->socket_snd = kilobytes * _1K;
1778}
1779void slirp_set_tcp_rcvspace(PNATState pData, int kilobytes)
1780{
1781 _8K_1M_CHECK_ARG("TCP_RCVSPACE", kilobytes);
1782 tcp_rcvspace = kilobytes * _1K;
1783}
1784void slirp_set_tcp_sndspace(PNATState pData, int kilobytes)
1785{
1786 _8K_1M_CHECK_ARG("TCP_SNDSPACE", kilobytes);
1787 tcp_sndspace = kilobytes * _1K;
1788}
1789
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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