VirtualBox

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

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

slirp.c: leaks in get_dns_addr_domain (hope I fixed it right).

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

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