VirtualBox

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

Last change on this file since 18872 was 18872, checked in by vboxsync, 16 years ago

slirp.c: empty strings still takes at least 1 byte of heap, don't leak it. Also, deal with RTUtf16ToUtf8 failure (it will set suffix to NULL) the same way as empty DNS strings.

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

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