VirtualBox

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

最後變更 在這個檔案從22206是 22146,由 vboxsync 提交於 15 年 前

NAT: annoying assert

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

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