VirtualBox

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

Last change on this file since 39248 was 39248, checked in by vboxsync, 13 years ago

Runtime: new guest OS type for Solaris 11
Frontends/VirtualBox: add new patterns for Solaris 11 guest OS type, reuse the icon
Frontends/VBoxManage: more details for "list ostypes"
Main/xml: make guest OS type in config file an arbitrary string (still validated/mapped in the old way in the settings code), remove hardcoded limit of 8 network adapters
Main/Global: move list of valid guest OS types into a single place, add function to get the network adapter limit for each chipset type
Main/Console+Machine+Snapshot+NetworkAdapter+Appliance+VirtualBox+Guest+SystemProperties: consistently use the appropriate network adapter limit so that ICH9 chipset can use 36 network adapters, adapt to cleaned up guest OS type handling, remove leftover rendundant guest OS mapping, whitespace
Network/NAT: release log message cosmetics, allow unlimited number of instances, fix maxconn clamping
Network/PCNet+VirtioNet+E1000: allow unlimited number of instances

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.6 KB
Line 
1/* $Id: slirp.c 39248 2011-11-09 12:29:53Z vboxsync $ */
2/** @file
3 * NAT - slirp glue.
4 */
5
6/*
7 * Copyright (C) 2006-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * libslirp glue
22 *
23 * Copyright (c) 2004-2008 Fabrice Bellard
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a copy
26 * of this software and associated documentation files (the "Software"), to deal
27 * in the Software without restriction, including without limitation the rights
28 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the Software is
30 * furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 * THE SOFTWARE.
42 */
43
44#include "slirp.h"
45#ifdef RT_OS_OS2
46# include <paths.h>
47#endif
48
49#include <VBox/err.h>
50#include <VBox/vmm/pdmdrv.h>
51#include <iprt/assert.h>
52#include <iprt/file.h>
53#ifndef RT_OS_WINDOWS
54# include <sys/ioctl.h>
55# include <poll.h>
56#else
57# include <Winnls.h>
58# define _WINSOCK2API_
59# include <IPHlpApi.h>
60#endif
61#include <alias.h>
62
63#ifndef RT_OS_WINDOWS
64
65# define DO_ENGAGE_EVENT1(so, fdset, label) \
66 do { \
67 if ( so->so_poll_index != -1 \
68 && so->s == polls[so->so_poll_index].fd) \
69 { \
70 polls[so->so_poll_index].events |= N_(fdset ## _poll); \
71 break; \
72 } \
73 AssertRelease(poll_index < (nfds)); \
74 AssertRelease(poll_index >= 0 && poll_index < (nfds)); \
75 polls[poll_index].fd = (so)->s; \
76 (so)->so_poll_index = poll_index; \
77 polls[poll_index].events = N_(fdset ## _poll); \
78 polls[poll_index].revents = 0; \
79 poll_index++; \
80 } while (0)
81
82# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
83 do { \
84 if ( so->so_poll_index != -1 \
85 && so->s == polls[so->so_poll_index].fd) \
86 { \
87 polls[so->so_poll_index].events |= \
88 N_(fdset1 ## _poll) | N_(fdset2 ## _poll); \
89 break; \
90 } \
91 AssertRelease(poll_index < (nfds)); \
92 polls[poll_index].fd = (so)->s; \
93 (so)->so_poll_index = poll_index; \
94 polls[poll_index].events = \
95 N_(fdset1 ## _poll) | N_(fdset2 ## _poll); \
96 poll_index++; \
97 } while (0)
98
99# define DO_POLL_EVENTS(rc, error, so, events, label) do {} while (0)
100
101/*
102 * DO_CHECK_FD_SET is used in dumping events on socket, including POLLNVAL.
103 * gcc warns about attempts to log POLLNVAL so construction in a last to lines
104 * used to catch POLLNVAL while logging and return false in case of error while
105 * normal usage.
106 */
107# define DO_CHECK_FD_SET(so, events, fdset) \
108 ( ((so)->so_poll_index != -1) \
109 && ((so)->so_poll_index <= ndfs) \
110 && ((so)->s == polls[so->so_poll_index].fd) \
111 && (polls[(so)->so_poll_index].revents & N_(fdset ## _poll)) \
112 && ( N_(fdset ## _poll) == POLLNVAL \
113 || !(polls[(so)->so_poll_index].revents & POLLNVAL)))
114
115 /* specific for Unix API */
116# define DO_UNIX_CHECK_FD_SET(so, events, fdset) DO_CHECK_FD_SET((so), (events), fdset)
117 /* specific for Windows Winsock API */
118# define DO_WIN_CHECK_FD_SET(so, events, fdset) 0
119
120# ifndef RT_OS_LINUX
121# define readfds_poll (POLLRDNORM)
122# define writefds_poll (POLLWRNORM)
123# else
124# define readfds_poll (POLLIN)
125# define writefds_poll (POLLOUT)
126# endif
127# define xfds_poll (POLLPRI)
128# define closefds_poll (POLLHUP)
129# define rderr_poll (POLLERR)
130# define rdhup_poll (POLLHUP)
131# define nval_poll (POLLNVAL)
132
133# define ICMP_ENGAGE_EVENT(so, fdset) \
134 do { \
135 if (pData->icmp_socket.s != -1) \
136 DO_ENGAGE_EVENT1((so), fdset, ICMP); \
137 } while (0)
138
139#else /* RT_OS_WINDOWS */
140
141/*
142 * On Windows, we will be notified by IcmpSendEcho2() when the response arrives.
143 * So no call to WSAEventSelect necessary.
144 */
145# define ICMP_ENGAGE_EVENT(so, fdset) do {} while (0)
146
147/*
148 * On Windows we use FD_ALL_EVENTS to ensure that we don't miss any event.
149 */
150# define DO_ENGAGE_EVENT1(so, fdset1, label) \
151 do { \
152 rc = WSAEventSelect((so)->s, VBOX_SOCKET_EVENT, FD_ALL_EVENTS); \
153 if (rc == SOCKET_ERROR) \
154 { \
155 /* This should not happen */ \
156 error = WSAGetLastError(); \
157 LogRel(("WSAEventSelect (" #label ") error %d (so=%x, socket=%s, event=%x)\n", \
158 error, (so), (so)->s, VBOX_SOCKET_EVENT)); \
159 } \
160 } while (0); \
161 CONTINUE(label)
162
163# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
164 DO_ENGAGE_EVENT1((so), (fdset1), label)
165
166# define DO_POLL_EVENTS(rc, error, so, events, label) \
167 (rc) = WSAEnumNetworkEvents((so)->s, VBOX_SOCKET_EVENT, (events)); \
168 if ((rc) == SOCKET_ERROR) \
169 { \
170 (error) = WSAGetLastError(); \
171 LogRel(("WSAEnumNetworkEvents " #label " error %d\n", (error))); \
172 CONTINUE(label); \
173 }
174
175# define acceptds_win FD_ACCEPT
176# define acceptds_win_bit FD_ACCEPT_BIT
177# define readfds_win FD_READ
178# define readfds_win_bit FD_READ_BIT
179# define writefds_win FD_WRITE
180# define writefds_win_bit FD_WRITE_BIT
181# define xfds_win FD_OOB
182# define xfds_win_bit FD_OOB_BIT
183# define closefds_win FD_CLOSE
184# define closefds_win_bit FD_CLOSE_BIT
185# define connectfds_win FD_CONNECT
186# define connectfds_win_bit FD_CONNECT_BIT
187
188# define closefds_win FD_CLOSE
189# define closefds_win_bit FD_CLOSE_BIT
190
191# define DO_CHECK_FD_SET(so, events, fdset) \
192 (((events).lNetworkEvents & fdset ## _win) && ((events).iErrorCode[fdset ## _win_bit] == 0))
193
194# define DO_WIN_CHECK_FD_SET(so, events, fdset) DO_CHECK_FD_SET((so), (events), fdset)
195# define DO_UNIX_CHECK_FD_SET(so, events, fdset) 1 /*specific for Unix API */
196
197#endif /* RT_OS_WINDOWS */
198
199#define TCP_ENGAGE_EVENT1(so, fdset) \
200 DO_ENGAGE_EVENT1((so), fdset, tcp)
201
202#define TCP_ENGAGE_EVENT2(so, fdset1, fdset2) \
203 DO_ENGAGE_EVENT2((so), fdset1, fdset2, tcp)
204
205#ifdef RT_OS_WINDOWS
206# define WIN_TCP_ENGAGE_EVENT2(so, fdset, fdset2) TCP_ENGAGE_EVENT2(so, fdset1, fdset2)
207#else
208# define WIN_TCP_ENGAGE_EVENT2(so, fdset, fdset2) do{}while(0)
209#endif
210
211#define UDP_ENGAGE_EVENT(so, fdset) \
212 DO_ENGAGE_EVENT1((so), fdset, udp)
213
214#define POLL_TCP_EVENTS(rc, error, so, events) \
215 DO_POLL_EVENTS((rc), (error), (so), (events), tcp)
216
217#define POLL_UDP_EVENTS(rc, error, so, events) \
218 DO_POLL_EVENTS((rc), (error), (so), (events), udp)
219
220#define CHECK_FD_SET(so, events, set) \
221 (DO_CHECK_FD_SET((so), (events), set))
222
223#define WIN_CHECK_FD_SET(so, events, set) \
224 (DO_WIN_CHECK_FD_SET((so), (events), set))
225
226#define UNIX_CHECK_FD_SET(so, events, set) \
227 (DO_UNIX_CHECK_FD_SET(so, events, set))
228
229/*
230 * Loging macros
231 */
232#if VBOX_WITH_DEBUG_NAT_SOCKETS
233# if defined(RT_OS_WINDOWS)
234# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
235 do { \
236 LogRel((" " #proto " %R[natsock] %R[natwinnetevents]\n", (so), (winevent))); \
237 } while (0)
238# else /* !RT_OS_WINDOWS */
239# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
240 do { \
241 LogRel((" " #proto " %R[natsock] %s %s %s er: %s, %s, %s\n", (so), \
242 CHECK_FD_SET(so, ign ,r_fdset) ? "READ":"", \
243 CHECK_FD_SET(so, ign, w_fdset) ? "WRITE":"", \
244 CHECK_FD_SET(so, ign, x_fdset) ? "OOB":"", \
245 CHECK_FD_SET(so, ign, rderr) ? "RDERR":"", \
246 CHECK_FD_SET(so, ign, rdhup) ? "RDHUP":"", \
247 CHECK_FD_SET(so, ign, nval) ? "RDNVAL":"")); \
248 } while (0)
249# endif /* !RT_OS_WINDOWS */
250#else /* !VBOX_WITH_DEBUG_NAT_SOCKETS */
251# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) do {} while (0)
252#endif /* !VBOX_WITH_DEBUG_NAT_SOCKETS */
253
254#define LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
255 DO_LOG_NAT_SOCK((so), proto, (winevent), r_fdset, w_fdset, x_fdset)
256
257static void activate_port_forwarding(PNATState, const uint8_t *pEther);
258
259static const uint8_t special_ethaddr[6] =
260{
261 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
262};
263
264static const uint8_t broadcast_ethaddr[6] =
265{
266 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
267};
268
269const uint8_t zerro_ethaddr[6] =
270{
271 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
272};
273
274#ifdef RT_OS_WINDOWS
275static int get_dns_addr_domain(PNATState pData,
276 const char **ppszDomain)
277{
278 ULONG flags = GAA_FLAG_INCLUDE_PREFIX; /*GAA_FLAG_INCLUDE_ALL_INTERFACES;*/ /* all interfaces registered in NDIS */
279 PIP_ADAPTER_ADDRESSES pAdapterAddr = NULL;
280 PIP_ADAPTER_ADDRESSES pAddr = NULL;
281 PIP_ADAPTER_DNS_SERVER_ADDRESS pDnsAddr = NULL;
282 ULONG size;
283 int wlen = 0;
284 char *pszSuffix;
285 struct dns_domain_entry *pDomain = NULL;
286 ULONG ret = ERROR_SUCCESS;
287
288 /* @todo add SKIPing flags to get only required information */
289
290 /* determine size of buffer */
291 size = 0;
292 ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
293 if (ret != ERROR_BUFFER_OVERFLOW)
294 {
295 Log(("NAT: error %lu occurred on capacity detection operation\n", ret));
296 return -1;
297 }
298 if (size == 0)
299 {
300 Log(("NAT: Win socket API returns non capacity\n"));
301 return -1;
302 }
303
304 pAdapterAddr = RTMemAllocZ(size);
305 if (!pAdapterAddr)
306 {
307 Log(("NAT: No memory available\n"));
308 return -1;
309 }
310 ret = pData->pfGetAdaptersAddresses(AF_INET, 0, NULL /* reserved */, pAdapterAddr, &size);
311 if (ret != ERROR_SUCCESS)
312 {
313 Log(("NAT: error %lu occurred on fetching adapters info\n", ret));
314 RTMemFree(pAdapterAddr);
315 return -1;
316 }
317
318 for (pAddr = pAdapterAddr; pAddr != NULL; pAddr = pAddr->Next)
319 {
320 int found;
321 if (pAddr->OperStatus != IfOperStatusUp)
322 continue;
323
324 for (pDnsAddr = pAddr->FirstDnsServerAddress; pDnsAddr != NULL; pDnsAddr = pDnsAddr->Next)
325 {
326 struct sockaddr *SockAddr = pDnsAddr->Address.lpSockaddr;
327 struct in_addr InAddr;
328 struct dns_entry *pDns;
329
330 if (SockAddr->sa_family != AF_INET)
331 continue;
332
333 InAddr = ((struct sockaddr_in *)SockAddr)->sin_addr;
334
335 /* add dns server to list */
336 pDns = RTMemAllocZ(sizeof(struct dns_entry));
337 if (!pDns)
338 {
339 Log(("NAT: Can't allocate buffer for DNS entry\n"));
340 RTMemFree(pAdapterAddr);
341 return VERR_NO_MEMORY;
342 }
343
344 Log(("NAT: adding %RTnaipv4 to DNS server list\n", InAddr));
345 if ((InAddr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_N2H_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET))
346 pDns->de_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
347 else
348 pDns->de_addr.s_addr = InAddr.s_addr;
349
350 TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
351
352 if (pAddr->DnsSuffix == NULL)
353 continue;
354
355 /* uniq */
356 RTUtf16ToUtf8(pAddr->DnsSuffix, &pszSuffix);
357 if (!pszSuffix || strlen(pszSuffix) == 0)
358 {
359 RTStrFree(pszSuffix);
360 continue;
361 }
362
363 found = 0;
364 LIST_FOREACH(pDomain, &pData->pDomainList, dd_list)
365 {
366 if ( pDomain->dd_pszDomain != NULL
367 && strcmp(pDomain->dd_pszDomain, pszSuffix) == 0)
368 {
369 found = 1;
370 RTStrFree(pszSuffix);
371 break;
372 }
373 }
374 if (!found)
375 {
376 pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
377 if (!pDomain)
378 {
379 Log(("NAT: not enough memory\n"));
380 RTStrFree(pszSuffix);
381 RTMemFree(pAdapterAddr);
382 return VERR_NO_MEMORY;
383 }
384 pDomain->dd_pszDomain = pszSuffix;
385 Log(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
386 LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
387 }
388 }
389 }
390 RTMemFree(pAdapterAddr);
391 return 0;
392}
393
394#else /* !RT_OS_WINDOWS */
395
396static int RTFileGets(RTFILE File, void *pvBuf, size_t cbBufSize, size_t *pcbRead)
397{
398 size_t cbRead;
399 char bTest;
400 int rc = VERR_NO_MEMORY;
401 char *pu8Buf = (char *)pvBuf;
402 *pcbRead = 0;
403
404 while ( RT_SUCCESS(rc = RTFileRead(File, &bTest, 1, &cbRead))
405 && (pu8Buf - (char *)pvBuf) < cbBufSize)
406 {
407 if (cbRead == 0)
408 return VERR_EOF;
409
410 if (bTest == '\r' || bTest == '\n')
411 {
412 *pu8Buf = 0;
413 return VINF_SUCCESS;
414 }
415 *pu8Buf = bTest;
416 pu8Buf++;
417 (*pcbRead)++;
418 }
419 return rc;
420}
421
422static int get_dns_addr_domain(PNATState pData, const char **ppszDomain)
423{
424 char buff[512];
425 char buff2[256];
426 RTFILE f;
427 int cNameserversFound = 0;
428 bool fWarnTooManyDnsServers = false;
429 struct in_addr tmp_addr;
430 int rc;
431 size_t bytes;
432
433# ifdef RT_OS_OS2
434 /* Try various locations. */
435 char *etc = getenv("ETC");
436 if (etc)
437 {
438 RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", etc);
439 rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
440 }
441 if (RT_FAILURE(rc))
442 {
443 RTStrmPrintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
444 rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
445 }
446 if (RT_FAILURE(rc))
447 {
448 RTStrmPrintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
449 rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
450 }
451# else /* !RT_OS_OS2 */
452# ifndef DEBUG_vvl
453 rc = RTFileOpen(&f, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
454# else
455 char *home = getenv("HOME");
456 RTStrPrintf(buff, sizeof(buff), "%s/resolv.conf", home);
457 rc = RTFileOpen(&f, buff, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
458 if (RT_SUCCESS(rc))
459 {
460 Log(("NAT: DNS we're using %s\n", buff));
461 }
462 else
463 {
464 rc = RTFileOpen(&f, "/etc/resolv.conf", RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
465 Log(("NAT: DNS we're using %s\n", buff));
466 }
467# endif
468# endif /* !RT_OS_OS2 */
469 if (RT_FAILURE(rc))
470 return -1;
471
472 if (ppszDomain)
473 *ppszDomain = NULL;
474
475 Log(("NAT: DNS Servers:\n"));
476 while ( RT_SUCCESS(rc = RTFileGets(f, buff, sizeof(buff), &bytes))
477 && rc != VERR_EOF)
478 {
479 struct dns_entry *pDns = NULL;
480 if ( cNameserversFound == 4
481 && !fWarnTooManyDnsServers
482 && sscanf(buff, "nameserver%*[ \t]%255s", buff2) == 1)
483 {
484 fWarnTooManyDnsServers = true;
485 LogRel(("NAT: too many nameservers registered.\n"));
486 }
487 if ( sscanf(buff, "nameserver%*[ \t]%255s", buff2) == 1
488 && cNameserversFound < 4) /* Unix doesn't accept more than 4 name servers*/
489 {
490 if (!inet_aton(buff2, &tmp_addr))
491 continue;
492
493 /* localhost mask */
494 pDns = RTMemAllocZ(sizeof (struct dns_entry));
495 if (!pDns)
496 {
497 Log(("can't alloc memory for DNS entry\n"));
498 return -1;
499 }
500
501 /* check */
502 pDns->de_addr.s_addr = tmp_addr.s_addr;
503 if ((pDns->de_addr.s_addr & RT_H2N_U32_C(IN_CLASSA_NET)) == RT_N2H_U32_C(INADDR_LOOPBACK & IN_CLASSA_NET))
504 {
505 pDns->de_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
506 }
507 TAILQ_INSERT_HEAD(&pData->pDnsList, pDns, de_list);
508 cNameserversFound++;
509 }
510 if ((!strncmp(buff, "domain", 6) || !strncmp(buff, "search", 6)))
511 {
512 char *tok;
513 char *saveptr;
514 struct dns_domain_entry *pDomain = NULL;
515 int fFoundDomain = 0;
516 tok = strtok_r(&buff[6], " \t\n", &saveptr);
517 LIST_FOREACH(pDomain, &pData->pDomainList, dd_list)
518 {
519 if ( tok != NULL
520 && strcmp(tok, pDomain->dd_pszDomain) == 0)
521 {
522 fFoundDomain = 1;
523 break;
524 }
525 }
526 if (tok != NULL && !fFoundDomain)
527 {
528 pDomain = RTMemAllocZ(sizeof(struct dns_domain_entry));
529 if (!pDomain)
530 {
531 Log(("NAT: not enought memory to add domain list\n"));
532 return VERR_NO_MEMORY;
533 }
534 pDomain->dd_pszDomain = RTStrDup(tok);
535 Log(("NAT: adding domain name %s to search list\n", pDomain->dd_pszDomain));
536 LIST_INSERT_HEAD(&pData->pDomainList, pDomain, dd_list);
537 }
538 }
539 }
540 RTFileClose(f);
541 if (!cNameserversFound)
542 return -1;
543 return 0;
544}
545
546#endif /* !RT_OS_WINDOWS */
547
548int slirp_init_dns_list(PNATState pData)
549{
550 TAILQ_INIT(&pData->pDnsList);
551 LIST_INIT(&pData->pDomainList);
552 return get_dns_addr_domain(pData, NULL);
553}
554
555void slirp_release_dns_list(PNATState pData)
556{
557 struct dns_entry *pDns = NULL;
558 struct dns_domain_entry *pDomain = NULL;
559
560 while (!TAILQ_EMPTY(&pData->pDnsList))
561 {
562 pDns = TAILQ_FIRST(&pData->pDnsList);
563 TAILQ_REMOVE(&pData->pDnsList, pDns, de_list);
564 RTMemFree(pDns);
565 }
566
567 while (!LIST_EMPTY(&pData->pDomainList))
568 {
569 pDomain = LIST_FIRST(&pData->pDomainList);
570 LIST_REMOVE(pDomain, dd_list);
571 if (pDomain->dd_pszDomain != NULL)
572 RTStrFree(pDomain->dd_pszDomain);
573 RTMemFree(pDomain);
574 }
575}
576
577int get_dns_addr(PNATState pData)
578{
579 return get_dns_addr_domain(pData, NULL);
580}
581
582int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
583 bool fPassDomain, bool fUseHostResolver, int i32AliasMode,
584 int iIcmpCacheLimit, void *pvUser)
585{
586 int fNATfailed = 0;
587 int rc;
588 PNATState pData;
589 if (u32Netmask & 0x1f)
590 /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
591 return VERR_INVALID_PARAMETER;
592 pData = RTMemAllocZ(RT_ALIGN_Z(sizeof(NATState), sizeof(uint64_t)));
593 *ppData = pData;
594 if (!pData)
595 return VERR_NO_MEMORY;
596 pData->fPassDomain = !fUseHostResolver ? fPassDomain : false;
597 pData->fUseHostResolver = fUseHostResolver;
598 pData->pvUser = pvUser;
599 pData->netmask = u32Netmask;
600
601 /* sockets & TCP defaults */
602 pData->socket_rcv = 64 * _1K;
603 pData->socket_snd = 64 * _1K;
604 tcp_sndspace = 64 * _1K;
605 tcp_rcvspace = 64 * _1K;
606 pData->soMaxConn = 1; /* historical value */
607
608#ifdef RT_OS_WINDOWS
609 {
610 WSADATA Data;
611 WSAStartup(MAKEWORD(2, 0), &Data);
612 }
613 pData->phEvents[VBOX_SOCKET_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
614#endif
615#ifdef VBOX_WITH_SLIRP_MT
616 QSOCKET_LOCK_CREATE(tcb);
617 QSOCKET_LOCK_CREATE(udb);
618 rc = RTReqCreateQueue(&pData->pReqQueue);
619 AssertReleaseRC(rc);
620#endif
621
622 link_up = 1;
623
624 rc = bootp_dhcp_init(pData);
625 if (RT_FAILURE(rc))
626 {
627 Log(("NAT: DHCP server initialization failed\n"));
628 RTMemFree(pData);
629 *ppData = NULL;
630 return rc;
631 }
632 debug_init();
633 if_init(pData);
634 ip_init(pData);
635 icmp_init(pData, iIcmpCacheLimit);
636
637 /* Initialise mbufs *after* setting the MTU */
638 mbuf_init(pData);
639
640 pData->special_addr.s_addr = u32NetAddr;
641 pData->slirp_ethaddr = &special_ethaddr[0];
642 alias_addr.s_addr = pData->special_addr.s_addr | RT_H2N_U32_C(CTL_ALIAS);
643 /* @todo: add ability to configure this staff */
644
645 /* set default addresses */
646 inet_aton("127.0.0.1", &loopback_addr);
647 if (!pData->fUseHostResolver)
648 {
649 if (slirp_init_dns_list(pData) < 0)
650 fNATfailed = 1;
651
652 dnsproxy_init(pData);
653 }
654 if (i32AliasMode & ~(PKT_ALIAS_LOG|PKT_ALIAS_SAME_PORTS|PKT_ALIAS_PROXY_ONLY))
655 {
656 Log(("NAT: alias mode %x is ignored\n", i32AliasMode));
657 i32AliasMode = 0;
658 }
659 pData->i32AliasMode = i32AliasMode;
660 getouraddr(pData);
661 {
662 int flags = 0;
663 struct in_addr proxy_addr;
664 pData->proxy_alias = LibAliasInit(pData, NULL);
665 if (pData->proxy_alias == NULL)
666 {
667 Log(("NAT: LibAlias default rule wasn't initialized\n"));
668 AssertMsgFailed(("NAT: LibAlias default rule wasn't initialized\n"));
669 }
670 flags = LibAliasSetMode(pData->proxy_alias, 0, 0);
671#ifndef NO_FW_PUNCH
672 flags |= PKT_ALIAS_PUNCH_FW;
673#endif
674 flags |= pData->i32AliasMode; /* do transparent proxying */
675 flags = LibAliasSetMode(pData->proxy_alias, flags, ~0);
676 proxy_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
677 LibAliasSetAddress(pData->proxy_alias, proxy_addr);
678 ftp_alias_load(pData);
679 nbt_alias_load(pData);
680 if (pData->fUseHostResolver)
681 dns_alias_load(pData);
682 }
683 return fNATfailed ? VINF_NAT_DNS : VINF_SUCCESS;
684}
685
686/**
687 * Register statistics.
688 */
689void slirp_register_statistics(PNATState pData, PPDMDRVINS pDrvIns)
690{
691#ifdef VBOX_WITH_STATISTICS
692# define PROFILE_COUNTER(name, dsc) REGISTER_COUNTER(name, pData, STAMTYPE_PROFILE, STAMUNIT_TICKS_PER_CALL, dsc)
693# define COUNTING_COUNTER(name, dsc) REGISTER_COUNTER(name, pData, STAMTYPE_COUNTER, STAMUNIT_COUNT, dsc)
694# include "counters.h"
695# undef COUNTER
696/** @todo register statistics for the variables dumped by:
697 * ipstats(pData); tcpstats(pData); udpstats(pData); icmpstats(pData);
698 * mbufstats(pData); sockstats(pData); */
699#endif /* VBOX_WITH_STATISTICS */
700}
701
702/**
703 * Deregister statistics.
704 */
705void slirp_deregister_statistics(PNATState pData, PPDMDRVINS pDrvIns)
706{
707 if (pData == NULL)
708 return;
709#ifdef VBOX_WITH_STATISTICS
710# define PROFILE_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pData)
711# define COUNTING_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pData)
712# include "counters.h"
713#endif /* VBOX_WITH_STATISTICS */
714}
715
716/**
717 * Marks the link as up, making it possible to establish new connections.
718 */
719void slirp_link_up(PNATState pData)
720{
721 struct arp_cache_entry *ac;
722 link_up = 1;
723
724 if (LIST_EMPTY(&pData->arp_cache))
725 return;
726
727 LIST_FOREACH(ac, &pData->arp_cache, list)
728 {
729 activate_port_forwarding(pData, ac->ether);
730 }
731}
732
733/**
734 * Marks the link as down and cleans up the current connections.
735 */
736void slirp_link_down(PNATState pData)
737{
738 struct socket *so;
739 struct port_forward_rule *rule;
740
741 while ((so = tcb.so_next) != &tcb)
742 {
743 if (so->so_state & SS_NOFDREF || so->s == -1)
744 sofree(pData, so);
745 else
746 tcp_drop(pData, sototcpcb(so), 0);
747 }
748
749 while ((so = udb.so_next) != &udb)
750 udp_detach(pData, so);
751
752 /*
753 * Clear the active state of port-forwarding rules to force
754 * re-setup on restoration of communications.
755 */
756 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
757 {
758 rule->activated = 0;
759 }
760 pData->cRedirectionsActive = 0;
761
762 link_up = 0;
763}
764
765/**
766 * Terminates the slirp component.
767 */
768void slirp_term(PNATState pData)
769{
770 if (pData == NULL)
771 return;
772 icmp_finit(pData);
773
774 slirp_link_down(pData);
775 slirp_release_dns_list(pData);
776 ftp_alias_unload(pData);
777 nbt_alias_unload(pData);
778 if (pData->fUseHostResolver)
779 dns_alias_unload(pData);
780 while (!LIST_EMPTY(&instancehead))
781 {
782 struct libalias *la = LIST_FIRST(&instancehead);
783 /* libalias do all clean up */
784 LibAliasUninit(la);
785 }
786 while (!LIST_EMPTY(&pData->arp_cache))
787 {
788 struct arp_cache_entry *ac = LIST_FIRST(&pData->arp_cache);
789 LIST_REMOVE(ac, list);
790 RTMemFree(ac);
791 }
792 bootp_dhcp_fini(pData);
793 m_fini(pData);
794#ifdef RT_OS_WINDOWS
795 WSACleanup();
796#endif
797#ifndef VBOX_WITH_SLIRP_BSD_SBUF
798#ifdef LOG_ENABLED
799 Log(("\n"
800 "NAT statistics\n"
801 "--------------\n"
802 "\n"));
803 ipstats(pData);
804 tcpstats(pData);
805 udpstats(pData);
806 icmpstats(pData);
807 mbufstats(pData);
808 sockstats(pData);
809 Log(("\n"
810 "\n"
811 "\n"));
812#endif
813#endif
814 RTMemFree(pData);
815}
816
817
818#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
819#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
820
821/*
822 * curtime kept to an accuracy of 1ms
823 */
824static void updtime(PNATState pData)
825{
826#ifdef RT_OS_WINDOWS
827 struct _timeb tb;
828
829 _ftime(&tb);
830 curtime = (u_int)tb.time * (u_int)1000;
831 curtime += (u_int)tb.millitm;
832#else
833 gettimeofday(&tt, 0);
834
835 curtime = (u_int)tt.tv_sec * (u_int)1000;
836 curtime += (u_int)tt.tv_usec / (u_int)1000;
837
838 if ((tt.tv_usec % 1000) >= 500)
839 curtime++;
840#endif
841}
842
843#ifdef RT_OS_WINDOWS
844void slirp_select_fill(PNATState pData, int *pnfds)
845#else /* RT_OS_WINDOWS */
846void slirp_select_fill(PNATState pData, int *pnfds, struct pollfd *polls)
847#endif /* !RT_OS_WINDOWS */
848{
849 struct socket *so, *so_next;
850 int nfds;
851#if defined(RT_OS_WINDOWS)
852 int rc;
853 int error;
854#else
855 int poll_index = 0;
856#endif
857 int i;
858
859 STAM_PROFILE_START(&pData->StatFill, a);
860
861 nfds = *pnfds;
862
863 /*
864 * First, TCP sockets
865 */
866 do_slowtimo = 0;
867 if (!link_up)
868 goto done;
869
870 /*
871 * *_slowtimo needs calling if there are IP fragments
872 * in the fragment queue, or there are TCP connections active
873 */
874 /* XXX:
875 * triggering of fragment expiration should be the same but use new macroses
876 */
877 do_slowtimo = (tcb.so_next != &tcb);
878 if (!do_slowtimo)
879 {
880 for (i = 0; i < IPREASS_NHASH; i++)
881 {
882 if (!TAILQ_EMPTY(&ipq[i]))
883 {
884 do_slowtimo = 1;
885 break;
886 }
887 }
888 }
889 /* always add the ICMP socket */
890#ifndef RT_OS_WINDOWS
891 pData->icmp_socket.so_poll_index = -1;
892#endif
893 ICMP_ENGAGE_EVENT(&pData->icmp_socket, readfds);
894
895 STAM_COUNTER_RESET(&pData->StatTCP);
896 STAM_COUNTER_RESET(&pData->StatTCPHot);
897
898 QSOCKET_FOREACH(so, so_next, tcp)
899 /* { */
900#if !defined(RT_OS_WINDOWS)
901 so->so_poll_index = -1;
902#endif
903 STAM_COUNTER_INC(&pData->StatTCP);
904
905 /*
906 * See if we need a tcp_fasttimo
907 */
908 if ( time_fasttimo == 0
909 && so->so_tcpcb != NULL
910 && so->so_tcpcb->t_flags & TF_DELACK)
911 {
912 time_fasttimo = curtime; /* Flag when we want a fasttimo */
913 }
914
915 /*
916 * NOFDREF can include still connecting to local-host,
917 * newly socreated() sockets etc. Don't want to select these.
918 */
919 if (so->so_state & SS_NOFDREF || so->s == -1)
920 CONTINUE(tcp);
921
922 /*
923 * Set for reading sockets which are accepting
924 */
925 if (so->so_state & SS_FACCEPTCONN)
926 {
927 STAM_COUNTER_INC(&pData->StatTCPHot);
928 TCP_ENGAGE_EVENT1(so, readfds);
929 CONTINUE(tcp);
930 }
931
932 /*
933 * Set for writing sockets which are connecting
934 */
935 if (so->so_state & SS_ISFCONNECTING)
936 {
937 Log2(("connecting %R[natsock] engaged\n",so));
938 STAM_COUNTER_INC(&pData->StatTCPHot);
939#ifdef RT_OS_WINDOWS
940 WIN_TCP_ENGAGE_EVENT2(so, writefds, connectfds);
941#else
942 TCP_ENGAGE_EVENT1(so, writefds);
943#endif
944 }
945
946 /*
947 * Set for writing if we are connected, can send more, and
948 * we have something to send
949 */
950 if (CONN_CANFSEND(so) && SBUF_LEN(&so->so_rcv))
951 {
952 STAM_COUNTER_INC(&pData->StatTCPHot);
953 TCP_ENGAGE_EVENT1(so, writefds);
954 }
955
956 /*
957 * Set for reading (and urgent data) if we are connected, can
958 * receive more, and we have room for it XXX /2 ?
959 */
960 /* @todo: vvl - check which predicat here will be more useful here in rerm of new sbufs. */
961 if ( CONN_CANFRCV(so)
962 && (SBUF_LEN(&so->so_snd) < (SBUF_SIZE(&so->so_snd)/2))
963#ifdef RT_OS_WINDOWS
964 && !(so->so_state & SS_ISFCONNECTING)
965#endif
966 )
967 {
968 STAM_COUNTER_INC(&pData->StatTCPHot);
969 TCP_ENGAGE_EVENT2(so, readfds, xfds);
970 }
971 LOOP_LABEL(tcp, so, so_next);
972 }
973
974 /*
975 * UDP sockets
976 */
977 STAM_COUNTER_RESET(&pData->StatUDP);
978 STAM_COUNTER_RESET(&pData->StatUDPHot);
979
980 QSOCKET_FOREACH(so, so_next, udp)
981 /* { */
982
983 STAM_COUNTER_INC(&pData->StatUDP);
984#if !defined(RT_OS_WINDOWS)
985 so->so_poll_index = -1;
986#endif
987
988 /*
989 * See if it's timed out
990 */
991 if (so->so_expire)
992 {
993 if (so->so_expire <= curtime)
994 {
995 Log2(("NAT: %R[natsock] expired\n", so));
996 if (so->so_timeout != NULL)
997 {
998 so->so_timeout(pData, so, so->so_timeout_arg);
999 }
1000#ifdef VBOX_WITH_SLIRP_MT
1001 /* we need so_next for continue our cycle*/
1002 so_next = so->so_next;
1003#endif
1004 UDP_DETACH(pData, so, so_next);
1005 CONTINUE_NO_UNLOCK(udp);
1006 }
1007 }
1008
1009 /*
1010 * When UDP packets are received from over the link, they're
1011 * sendto()'d straight away, so no need for setting for writing
1012 * Limit the number of packets queued by this session to 4.
1013 * Note that even though we try and limit this to 4 packets,
1014 * the session could have more queued if the packets needed
1015 * to be fragmented.
1016 *
1017 * (XXX <= 4 ?)
1018 */
1019 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4)
1020 {
1021 STAM_COUNTER_INC(&pData->StatUDPHot);
1022 UDP_ENGAGE_EVENT(so, readfds);
1023 }
1024 LOOP_LABEL(udp, so, so_next);
1025 }
1026done:
1027
1028#if defined(RT_OS_WINDOWS)
1029 *pnfds = VBOX_EVENT_COUNT;
1030#else /* RT_OS_WINDOWS */
1031 AssertRelease(poll_index <= *pnfds);
1032 *pnfds = poll_index;
1033#endif /* !RT_OS_WINDOWS */
1034
1035 STAM_PROFILE_STOP(&pData->StatFill, a);
1036}
1037
1038
1039static bool slirpConnectOrWrite(PNATState pData, struct socket *so, bool fConnectOnly)
1040{
1041 int ret;
1042 LogFlowFunc(("ENTER: so:%R[natsock], fConnectOnly:%RTbool\n", so, fConnectOnly));
1043 /*
1044 * Check for non-blocking, still-connecting sockets
1045 */
1046 if (so->so_state & SS_ISFCONNECTING)
1047 {
1048 Log2(("connecting %R[natsock] catched\n", so));
1049 /* Connected */
1050 so->so_state &= ~SS_ISFCONNECTING;
1051
1052 /*
1053 * This should be probably guarded by PROBE_CONN too. Anyway,
1054 * we disable it on OS/2 because the below send call returns
1055 * EFAULT which causes the opened TCP socket to close right
1056 * after it has been opened and connected.
1057 */
1058#ifndef RT_OS_OS2
1059 ret = send(so->s, (const char *)&ret, 0, 0);
1060 if (ret < 0)
1061 {
1062 /* XXXXX Must fix, zero bytes is a NOP */
1063 if ( errno == EAGAIN
1064 || errno == EWOULDBLOCK
1065 || errno == EINPROGRESS
1066 || errno == ENOTCONN)
1067 {
1068 LogFlowFunc(("LEAVE: true"));
1069 return false;
1070 }
1071
1072 /* else failed */
1073 so->so_state = SS_NOFDREF;
1074 }
1075 /* else so->so_state &= ~SS_ISFCONNECTING; */
1076#endif
1077
1078 /*
1079 * Continue tcp_input
1080 */
1081 TCP_INPUT(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
1082 /* continue; */
1083 }
1084 else if (!fConnectOnly)
1085 SOWRITE(ret, pData, so);
1086 /*
1087 * XXX If we wrote something (a lot), there could be the need
1088 * for a window update. In the worst case, the remote will send
1089 * a window probe to get things going again.
1090 */
1091 LogFlowFunc(("LEAVE: true"));
1092 return true;
1093}
1094
1095#if defined(RT_OS_WINDOWS)
1096void slirp_select_poll(PNATState pData, int fTimeout, int fIcmp)
1097#else /* RT_OS_WINDOWS */
1098void slirp_select_poll(PNATState pData, struct pollfd *polls, int ndfs)
1099#endif /* !RT_OS_WINDOWS */
1100{
1101 struct socket *so, *so_next;
1102 int ret;
1103#if defined(RT_OS_WINDOWS)
1104 WSANETWORKEVENTS NetworkEvents;
1105 int rc;
1106 int error;
1107#endif
1108
1109 STAM_PROFILE_START(&pData->StatPoll, a);
1110
1111 /* Update time */
1112 updtime(pData);
1113
1114 /*
1115 * See if anything has timed out
1116 */
1117 if (link_up)
1118 {
1119 if (time_fasttimo && ((curtime - time_fasttimo) >= 2))
1120 {
1121 STAM_PROFILE_START(&pData->StatFastTimer, b);
1122 tcp_fasttimo(pData);
1123 time_fasttimo = 0;
1124 STAM_PROFILE_STOP(&pData->StatFastTimer, b);
1125 }
1126 if (do_slowtimo && ((curtime - last_slowtimo) >= 499))
1127 {
1128 STAM_PROFILE_START(&pData->StatSlowTimer, c);
1129 ip_slowtimo(pData);
1130 tcp_slowtimo(pData);
1131 last_slowtimo = curtime;
1132 STAM_PROFILE_STOP(&pData->StatSlowTimer, c);
1133 }
1134 }
1135#if defined(RT_OS_WINDOWS)
1136 if (fTimeout)
1137 return; /* only timer update */
1138#endif
1139
1140 /*
1141 * Check sockets
1142 */
1143 if (!link_up)
1144 goto done;
1145#if defined(RT_OS_WINDOWS)
1146 /*XXX: before renaming please make see define
1147 * fIcmp in slirp_state.h
1148 */
1149 if (fIcmp)
1150 sorecvfrom(pData, &pData->icmp_socket);
1151#else
1152 if ( (pData->icmp_socket.s != -1)
1153 && CHECK_FD_SET(&pData->icmp_socket, ignored, readfds))
1154 sorecvfrom(pData, &pData->icmp_socket);
1155#endif
1156 /*
1157 * Check TCP sockets
1158 */
1159 QSOCKET_FOREACH(so, so_next, tcp)
1160 /* { */
1161
1162#ifdef VBOX_WITH_SLIRP_MT
1163 if ( so->so_state & SS_NOFDREF
1164 && so->so_deleted == 1)
1165 {
1166 struct socket *son, *sop = NULL;
1167 QSOCKET_LOCK(tcb);
1168 if (so->so_next != NULL)
1169 {
1170 if (so->so_next != &tcb)
1171 SOCKET_LOCK(so->so_next);
1172 son = so->so_next;
1173 }
1174 if ( so->so_prev != &tcb
1175 && so->so_prev != NULL)
1176 {
1177 SOCKET_LOCK(so->so_prev);
1178 sop = so->so_prev;
1179 }
1180 QSOCKET_UNLOCK(tcb);
1181 remque(pData, so);
1182 NSOCK_DEC();
1183 SOCKET_UNLOCK(so);
1184 SOCKET_LOCK_DESTROY(so);
1185 RTMemFree(so);
1186 so_next = son;
1187 if (sop != NULL)
1188 SOCKET_UNLOCK(sop);
1189 CONTINUE_NO_UNLOCK(tcp);
1190 }
1191#endif
1192 /*
1193 * FD_ISSET is meaningless on these sockets
1194 * (and they can crash the program)
1195 */
1196 if (so->so_state & SS_NOFDREF || so->s == -1)
1197 CONTINUE(tcp);
1198
1199 POLL_TCP_EVENTS(rc, error, so, &NetworkEvents);
1200
1201 LOG_NAT_SOCK(so, TCP, &NetworkEvents, readfds, writefds, xfds);
1202
1203
1204 /*
1205 * Check for URG data
1206 * This will soread as well, so no need to
1207 * test for readfds below if this succeeds
1208 */
1209
1210 /* out-of-band data */
1211 if ( CHECK_FD_SET(so, NetworkEvents, xfds)
1212#ifdef RT_OS_DARWIN
1213 /* Darwin and probably BSD hosts generates POLLPRI|POLLHUP event on receiving TCP.flags.{ACK|URG|FIN} this
1214 * combination on other Unixs hosts doesn't enter to this branch
1215 */
1216 && !CHECK_FD_SET(so, NetworkEvents, closefds)
1217#endif
1218#ifdef RT_OS_WINDOWS
1219 /**
1220 * In some cases FD_CLOSE comes with FD_OOB, that confuse tcp processing.
1221 */
1222 && !WIN_CHECK_FD_SET(so, NetworkEvents, closefds)
1223#endif
1224 )
1225 {
1226 sorecvoob(pData, so);
1227 }
1228
1229 /*
1230 * Check sockets for reading
1231 */
1232 else if ( CHECK_FD_SET(so, NetworkEvents, readfds)
1233 || WIN_CHECK_FD_SET(so, NetworkEvents, acceptds))
1234 {
1235
1236#ifdef RT_OS_WINDOWS
1237 if (WIN_CHECK_FD_SET(so, NetworkEvents, connectfds))
1238 {
1239 /* Finish connection first */
1240 /* should we ignore return value? */
1241 bool fRet = slirpConnectOrWrite(pData, so, true);
1242 LogFunc(("fRet:%RTbool\n", fRet));
1243 }
1244#endif
1245 /*
1246 * Check for incoming connections
1247 */
1248 if (so->so_state & SS_FACCEPTCONN)
1249 {
1250 TCP_CONNECT(pData, so);
1251 if (!CHECK_FD_SET(so, NetworkEvents, closefds))
1252 CONTINUE(tcp);
1253 }
1254
1255 ret = soread(pData, so);
1256 /* Output it if we read something */
1257 if (RT_LIKELY(ret > 0))
1258 TCP_OUTPUT(pData, sototcpcb(so));
1259 }
1260
1261 /*
1262 * Check for FD_CLOSE events.
1263 * in some cases once FD_CLOSE engaged on socket it could be flashed latter (for some reasons)
1264 */
1265 if ( CHECK_FD_SET(so, NetworkEvents, closefds)
1266 || (so->so_close == 1))
1267 {
1268 /*
1269 * drain the socket
1270 */
1271 for (;;)
1272 {
1273 ret = soread(pData, so);
1274 if (ret > 0)
1275 TCP_OUTPUT(pData, sototcpcb(so));
1276 else
1277 {
1278 Log2(("%R[natsock] errno %d (%s)\n", so, errno, strerror(errno)));
1279 break;
1280 }
1281 }
1282 /* mark the socket for termination _after_ it was drained */
1283 so->so_close = 1;
1284 /* No idea about Windows but on Posix, POLLHUP means that we can't send more.
1285 * Actually in the specific error scenario, POLLERR is set as well. */
1286#ifndef RT_OS_WINDOWS
1287 if (CHECK_FD_SET(so, NetworkEvents, rderr))
1288 sofcantsendmore(so);
1289#endif
1290 CONTINUE(tcp);
1291 }
1292
1293 /*
1294 * Check sockets for writing
1295 */
1296 if ( CHECK_FD_SET(so, NetworkEvents, writefds)
1297#ifdef RT_OS_WINDOWS
1298 || WIN_CHECK_FD_SET(so, NetworkEvents, connectfds)
1299#endif
1300 )
1301 {
1302 if(!slirpConnectOrWrite(pData, so, false))
1303 CONTINUE(tcp);
1304 }
1305
1306 /*
1307 * Probe a still-connecting, non-blocking socket
1308 * to check if it's still alive
1309 */
1310#ifdef PROBE_CONN
1311 if (so->so_state & SS_ISFCONNECTING)
1312 {
1313 ret = recv(so->s, (char *)&ret, 0, 0);
1314
1315 if (ret < 0)
1316 {
1317 /* XXX */
1318 if ( errno == EAGAIN
1319 || errno == EWOULDBLOCK
1320 || errno == EINPROGRESS
1321 || errno == ENOTCONN)
1322 {
1323 CONTINUE(tcp); /* Still connecting, continue */
1324 }
1325
1326 /* else failed */
1327 so->so_state = SS_NOFDREF;
1328
1329 /* tcp_input will take care of it */
1330 }
1331 else
1332 {
1333 ret = send(so->s, &ret, 0, 0);
1334 if (ret < 0)
1335 {
1336 /* XXX */
1337 if ( errno == EAGAIN
1338 || errno == EWOULDBLOCK
1339 || errno == EINPROGRESS
1340 || errno == ENOTCONN)
1341 {
1342 CONTINUE(tcp);
1343 }
1344 /* else failed */
1345 so->so_state = SS_NOFDREF;
1346 }
1347 else
1348 so->so_state &= ~SS_ISFCONNECTING;
1349
1350 }
1351 TCP_INPUT((struct mbuf *)NULL, sizeof(struct ip),so);
1352 } /* SS_ISFCONNECTING */
1353#endif
1354 LOOP_LABEL(tcp, so, so_next);
1355 }
1356
1357 /*
1358 * Now UDP sockets.
1359 * Incoming packets are sent straight away, they're not buffered.
1360 * Incoming UDP data isn't buffered either.
1361 */
1362 QSOCKET_FOREACH(so, so_next, udp)
1363 /* { */
1364#ifdef VBOX_WITH_SLIRP_MT
1365 if ( so->so_state & SS_NOFDREF
1366 && so->so_deleted == 1)
1367 {
1368 struct socket *son, *sop = NULL;
1369 QSOCKET_LOCK(udb);
1370 if (so->so_next != NULL)
1371 {
1372 if (so->so_next != &udb)
1373 SOCKET_LOCK(so->so_next);
1374 son = so->so_next;
1375 }
1376 if ( so->so_prev != &udb
1377 && so->so_prev != NULL)
1378 {
1379 SOCKET_LOCK(so->so_prev);
1380 sop = so->so_prev;
1381 }
1382 QSOCKET_UNLOCK(udb);
1383 remque(pData, so);
1384 NSOCK_DEC();
1385 SOCKET_UNLOCK(so);
1386 SOCKET_LOCK_DESTROY(so);
1387 RTMemFree(so);
1388 so_next = son;
1389 if (sop != NULL)
1390 SOCKET_UNLOCK(sop);
1391 CONTINUE_NO_UNLOCK(udp);
1392 }
1393#endif
1394 POLL_UDP_EVENTS(rc, error, so, &NetworkEvents);
1395
1396 LOG_NAT_SOCK(so, UDP, &NetworkEvents, readfds, writefds, xfds);
1397
1398 if (so->s != -1 && CHECK_FD_SET(so, NetworkEvents, readfds))
1399 {
1400 SORECVFROM(pData, so);
1401 }
1402 LOOP_LABEL(udp, so, so_next);
1403 }
1404
1405done:
1406
1407 STAM_PROFILE_STOP(&pData->StatPoll, a);
1408}
1409
1410
1411struct arphdr
1412{
1413 unsigned short ar_hrd; /* format of hardware address */
1414 unsigned short ar_pro; /* format of protocol address */
1415 unsigned char ar_hln; /* length of hardware address */
1416 unsigned char ar_pln; /* length of protocol address */
1417 unsigned short ar_op; /* ARP opcode (command) */
1418
1419 /*
1420 * Ethernet looks like this : This bit is variable sized however...
1421 */
1422 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
1423 unsigned char ar_sip[4]; /* sender IP address */
1424 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
1425 unsigned char ar_tip[4]; /* target IP address */
1426};
1427AssertCompileSize(struct arphdr, 28);
1428
1429/**
1430 * @note This function will free m!
1431 */
1432static void arp_input(PNATState pData, struct mbuf *m)
1433{
1434 struct ethhdr *eh;
1435 struct ethhdr *reh;
1436 struct arphdr *ah;
1437 struct arphdr *rah;
1438 int ar_op;
1439 uint32_t htip;
1440 uint32_t tip;
1441 struct mbuf *mr;
1442 eh = mtod(m, struct ethhdr *);
1443 ah = (struct arphdr *)&eh[1];
1444 htip = RT_N2H_U32(*(uint32_t*)ah->ar_tip);
1445 tip = *(uint32_t*)ah->ar_tip;
1446
1447 ar_op = RT_N2H_U16(ah->ar_op);
1448
1449 switch (ar_op)
1450 {
1451 case ARPOP_REQUEST:
1452 mr = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
1453 if (!mr)
1454 break;
1455 reh = mtod(mr, struct ethhdr *);
1456 mr->m_data += ETH_HLEN;
1457 rah = mtod(mr, struct arphdr *);
1458 mr->m_len = sizeof(struct arphdr);
1459 memcpy(reh->h_source, eh->h_source, ETH_ALEN); /* XXX: if_encap will swap src and dst*/
1460 if ( 0
1461#ifdef VBOX_WITH_NAT_SERVICE
1462 || (tip == pData->special_addr.s_addr)
1463#endif
1464 || ( ((htip & pData->netmask) == RT_N2H_U32(pData->special_addr.s_addr))
1465 && ( CTL_CHECK(htip, CTL_DNS)
1466 || CTL_CHECK(htip, CTL_ALIAS)
1467 || CTL_CHECK(htip, CTL_TFTP))
1468 )
1469 )
1470 {
1471 rah->ar_hrd = RT_H2N_U16_C(1);
1472 rah->ar_pro = RT_H2N_U16_C(ETH_P_IP);
1473 rah->ar_hln = ETH_ALEN;
1474 rah->ar_pln = 4;
1475 rah->ar_op = RT_H2N_U16_C(ARPOP_REPLY);
1476 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN);
1477
1478 switch (htip & ~pData->netmask)
1479 {
1480 case CTL_DNS:
1481 case CTL_ALIAS:
1482 case CTL_TFTP:
1483 if (!slirpMbufTagService(pData, mr, (uint8_t)(htip & ~pData->netmask)))
1484 {
1485 static bool fTagErrorReported;
1486 if (!fTagErrorReported)
1487 {
1488 LogRel(("NAT: couldn't add the tag(PACKET_SERVICE:%d) to mbuf:%p\n",
1489 (uint8_t)(htip & ~pData->netmask), m));
1490 fTagErrorReported = true;
1491 }
1492 }
1493 rah->ar_sha[5] = (uint8_t)(htip & ~pData->netmask);
1494 break;
1495 default:;
1496 }
1497
1498 memcpy(rah->ar_sip, ah->ar_tip, 4);
1499 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
1500 memcpy(rah->ar_tip, ah->ar_sip, 4);
1501 if_encap(pData, ETH_P_ARP, mr, ETH_ENCAP_URG);
1502 }
1503 else
1504 m_freem(pData, mr);
1505
1506 /* Gratuitous ARP */
1507 if ( *(uint32_t *)ah->ar_sip == *(uint32_t *)ah->ar_tip
1508 && memcmp(ah->ar_tha, broadcast_ethaddr, ETH_ALEN) == 0
1509 && memcmp(eh->h_dest, broadcast_ethaddr, ETH_ALEN) == 0)
1510 {
1511 /* We've received an announce about address assignment,
1512 * let's do an ARP cache update
1513 */
1514 static bool fGratuitousArpReported;
1515 if (!fGratuitousArpReported)
1516 {
1517 LogRel(("NAT: Gratuitous ARP [IP:%RTnaipv4, ether:%RTmac]\n",
1518 ah->ar_sip, ah->ar_sha));
1519 fGratuitousArpReported = true;
1520 }
1521 slirp_arp_cache_update_or_add(pData, *(uint32_t *)ah->ar_sip, &ah->ar_sha[0]);
1522 }
1523 break;
1524
1525 case ARPOP_REPLY:
1526 slirp_arp_cache_update_or_add(pData, *(uint32_t *)ah->ar_sip, &ah->ar_sha[0]);
1527 break;
1528
1529 default:
1530 break;
1531 }
1532
1533 m_freem(pData, m);
1534}
1535
1536/**
1537 * Feed a packet into the slirp engine.
1538 *
1539 * @param m Data buffer, m_len is not valid.
1540 * @param cbBuf The length of the data in m.
1541 */
1542void slirp_input(PNATState pData, struct mbuf *m, size_t cbBuf)
1543{
1544 int proto;
1545 static bool fWarnedIpv6;
1546 struct ethhdr *eh;
1547 uint8_t au8Ether[ETH_ALEN];
1548
1549 m->m_len = cbBuf;
1550 if (cbBuf < ETH_HLEN)
1551 {
1552 Log(("NAT: packet having size %d has been ignored\n", m->m_len));
1553 m_freem(pData, m);
1554 return;
1555 }
1556 eh = mtod(m, struct ethhdr *);
1557 proto = RT_N2H_U16(eh->h_proto);
1558
1559 memcpy(au8Ether, eh->h_source, ETH_ALEN);
1560
1561 switch(proto)
1562 {
1563 case ETH_P_ARP:
1564 arp_input(pData, m);
1565 break;
1566
1567 case ETH_P_IP:
1568 /* Update time. Important if the network is very quiet, as otherwise
1569 * the first outgoing connection gets an incorrect timestamp. */
1570 updtime(pData);
1571 m_adj(m, ETH_HLEN);
1572 M_ASSERTPKTHDR(m);
1573 m->m_pkthdr.header = mtod(m, void *);
1574 ip_input(pData, m);
1575 break;
1576
1577 case ETH_P_IPV6:
1578 m_freem(pData, m);
1579 if (!fWarnedIpv6)
1580 {
1581 LogRel(("NAT: IPv6 not supported\n"));
1582 fWarnedIpv6 = true;
1583 }
1584 break;
1585
1586 default:
1587 Log(("NAT: Unsupported protocol %x\n", proto));
1588 m_freem(pData, m);
1589 break;
1590 }
1591
1592 if (pData->cRedirectionsActive != pData->cRedirectionsStored)
1593 activate_port_forwarding(pData, au8Ether);
1594}
1595
1596/**
1597 * Output the IP packet to the ethernet device.
1598 *
1599 * @note This function will free m!
1600 */
1601void if_encap(PNATState pData, uint16_t eth_proto, struct mbuf *m, int flags)
1602{
1603 struct ethhdr *eh;
1604 uint8_t *mbuf = NULL;
1605 size_t mlen = 0;
1606 STAM_PROFILE_START(&pData->StatIF_encap, a);
1607 LogFlowFunc(("ENTER: pData:%p, eth_proto:%RX16, m:%p, flags:%d\n",
1608 pData, eth_proto, m, flags));
1609
1610 M_ASSERTPKTHDR(m);
1611 m->m_data -= ETH_HLEN;
1612 m->m_len += ETH_HLEN;
1613 eh = mtod(m, struct ethhdr *);
1614 mlen = m->m_len;
1615
1616 if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) != 0)
1617 {
1618 struct m_tag *t = m_tag_first(m);
1619 uint8_t u8ServiceId = CTL_ALIAS;
1620 memcpy(eh->h_dest, eh->h_source, ETH_ALEN);
1621 memcpy(eh->h_source, special_ethaddr, ETH_ALEN);
1622 Assert(memcmp(eh->h_dest, special_ethaddr, ETH_ALEN) != 0);
1623 if (memcmp(eh->h_dest, zerro_ethaddr, ETH_ALEN) == 0)
1624 {
1625 /* don't do anything */
1626 m_freem(pData, m);
1627 goto done;
1628 }
1629 if ( t
1630 && (t = m_tag_find(m, PACKET_SERVICE, NULL)))
1631 {
1632 Assert(t);
1633 u8ServiceId = *(uint8_t *)&t[1];
1634 }
1635 eh->h_source[5] = u8ServiceId;
1636 }
1637 /*
1638 * we're processing the chain, that isn't not expected.
1639 */
1640 Assert((!m->m_next));
1641 if (m->m_next)
1642 {
1643 Log(("NAT: if_encap's recived the chain, dropping...\n"));
1644 m_freem(pData, m);
1645 goto done;
1646 }
1647 mbuf = mtod(m, uint8_t *);
1648 eh->h_proto = RT_H2N_U16(eth_proto);
1649 LogFunc(("eh(dst:%RTmac, src:%RTmac)\n", eh->h_dest, eh->h_source));
1650 if (flags & ETH_ENCAP_URG)
1651 slirp_urg_output(pData->pvUser, m, mbuf, mlen);
1652 else
1653 slirp_output(pData->pvUser, m, mbuf, mlen);
1654done:
1655 STAM_PROFILE_STOP(&pData->StatIF_encap, a);
1656 LogFlowFuncLeave();
1657}
1658
1659/**
1660 * Still we're using dhcp server leasing to map ether to IP
1661 * @todo see rt_lookup_in_cache
1662 */
1663static uint32_t find_guest_ip(PNATState pData, const uint8_t *eth_addr)
1664{
1665 uint32_t ip = INADDR_ANY;
1666 int rc;
1667
1668 if (eth_addr == NULL)
1669 return INADDR_ANY;
1670
1671 if ( memcmp(eth_addr, zerro_ethaddr, ETH_ALEN) == 0
1672 || memcmp(eth_addr, broadcast_ethaddr, ETH_ALEN) == 0)
1673 return INADDR_ANY;
1674
1675 rc = slirp_arp_lookup_ip_by_ether(pData, eth_addr, &ip);
1676 if (RT_SUCCESS(rc))
1677 return ip;
1678
1679 bootp_cache_lookup_ip_by_ether(pData, eth_addr, &ip);
1680 /* ignore return code, ip will be set to INADDR_ANY on error */
1681 return ip;
1682}
1683
1684/**
1685 * We need check if we've activated port forwarding
1686 * for specific machine ... that of course relates to
1687 * service mode
1688 * @todo finish this for service case
1689 */
1690static void activate_port_forwarding(PNATState pData, const uint8_t *h_source)
1691{
1692 struct port_forward_rule *rule, *tmp;
1693
1694 /* check mac here */
1695 LIST_FOREACH_SAFE(rule, &pData->port_forward_rule_head, list, tmp)
1696 {
1697 struct socket *so;
1698 struct alias_link *alias_link;
1699 struct libalias *lib;
1700 int flags;
1701 struct sockaddr sa;
1702 struct sockaddr_in *psin;
1703 socklen_t socketlen;
1704 struct in_addr alias;
1705 int rc;
1706 uint32_t guest_addr; /* need to understand if we already give address to guest */
1707
1708 if (rule->activated)
1709 continue;
1710
1711#ifdef VBOX_WITH_NAT_SERVICE
1712 if (memcmp(rule->mac_address, h_source, ETH_ALEN) != 0)
1713 continue; /*not right mac, @todo: it'd be better do the list port forwarding per mac */
1714 guest_addr = find_guest_ip(pData, h_source);
1715#else
1716#if 0
1717 if (memcmp(client_ethaddr, h_source, ETH_ALEN) != 0)
1718 continue;
1719#endif
1720 guest_addr = find_guest_ip(pData, h_source);
1721#endif
1722 if (guest_addr == INADDR_ANY)
1723 {
1724 /* the address wasn't granted */
1725 return;
1726 }
1727
1728#if !defined(VBOX_WITH_NAT_SERVICE)
1729 if ( rule->guest_addr.s_addr != guest_addr
1730 && rule->guest_addr.s_addr != INADDR_ANY)
1731 continue;
1732 if (rule->guest_addr.s_addr == INADDR_ANY)
1733 rule->guest_addr.s_addr = guest_addr;
1734#endif
1735
1736 LogRel(("NAT: set redirect %s host port %d => guest port %d @ %RTnaipv4\n",
1737 rule->proto == IPPROTO_UDP ? "UDP" : "TCP", rule->host_port, rule->guest_port, guest_addr));
1738
1739 if (rule->proto == IPPROTO_UDP)
1740 so = udp_listen(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port), guest_addr,
1741 RT_H2N_U16(rule->guest_port), 0);
1742 else
1743 so = solisten(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port), guest_addr,
1744 RT_H2N_U16(rule->guest_port), 0);
1745
1746 if (so == NULL)
1747 goto remove_port_forwarding;
1748
1749 psin = (struct sockaddr_in *)&sa;
1750 psin->sin_family = AF_INET;
1751 psin->sin_port = 0;
1752 psin->sin_addr.s_addr = INADDR_ANY;
1753 socketlen = sizeof(struct sockaddr);
1754
1755 rc = getsockname(so->s, &sa, &socketlen);
1756 if (rc < 0 || sa.sa_family != AF_INET)
1757 goto remove_port_forwarding;
1758
1759 psin = (struct sockaddr_in *)&sa;
1760
1761 lib = LibAliasInit(pData, NULL);
1762 flags = LibAliasSetMode(lib, 0, 0);
1763 flags |= pData->i32AliasMode;
1764 flags |= PKT_ALIAS_REVERSE; /* set reverse */
1765 flags = LibAliasSetMode(lib, flags, ~0);
1766
1767 alias.s_addr = RT_H2N_U32(RT_N2H_U32(guest_addr) | CTL_ALIAS);
1768 alias_link = LibAliasRedirectPort(lib, psin->sin_addr, RT_H2N_U16(rule->host_port),
1769 alias, RT_H2N_U16(rule->guest_port),
1770 pData->special_addr, -1, /* not very clear for now */
1771 rule->proto);
1772 if (!alias_link)
1773 goto remove_port_forwarding;
1774
1775 so->so_la = lib;
1776 rule->activated = 1;
1777 rule->so = so;
1778 pData->cRedirectionsActive++;
1779 continue;
1780
1781 remove_port_forwarding:
1782 LogRel(("NAT: failed to redirect %s %d => %d\n",
1783 (rule->proto == IPPROTO_UDP?"UDP":"TCP"), rule->host_port, rule->guest_port));
1784 LIST_REMOVE(rule, list);
1785 pData->cRedirectionsStored--;
1786 RTMemFree(rule);
1787 }
1788}
1789
1790/**
1791 * Changes in 3.1 instead of opening new socket do the following:
1792 * gain more information:
1793 * 1. bind IP
1794 * 2. host port
1795 * 3. guest port
1796 * 4. proto
1797 * 5. guest MAC address
1798 * the guest's MAC address is rather important for service, but we easily
1799 * could get it from VM configuration in DrvNAT or Service, the idea is activating
1800 * corresponding port-forwarding
1801 */
1802int slirp_add_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1803 struct in_addr guest_addr, int guest_port, const uint8_t *ethaddr)
1804{
1805 struct port_forward_rule *rule = NULL;
1806 Assert(ethaddr);
1807 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
1808 {
1809 if ( rule->proto == (is_udp ? IPPROTO_UDP : IPPROTO_TCP)
1810 && rule->host_port == host_port
1811 && rule->bind_ip.s_addr == host_addr.s_addr
1812 && rule->guest_port == guest_port
1813 && rule->guest_addr.s_addr == guest_addr.s_addr
1814 )
1815 return 0; /* rule has been already registered */
1816 }
1817
1818 rule = RTMemAllocZ(sizeof(struct port_forward_rule));
1819 if (rule == NULL)
1820 return 1;
1821
1822 rule->proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
1823 rule->host_port = host_port;
1824 rule->guest_port = guest_port;
1825 rule->guest_addr.s_addr = guest_addr.s_addr;
1826 rule->bind_ip.s_addr = host_addr.s_addr;
1827 memcpy(rule->mac_address, ethaddr, ETH_ALEN);
1828 /* @todo add mac address */
1829 LIST_INSERT_HEAD(&pData->port_forward_rule_head, rule, list);
1830 pData->cRedirectionsStored++;
1831 /* activate port-forwarding if guest has already got assigned IP */
1832 if (memcmp(ethaddr, zerro_ethaddr, ETH_ALEN))
1833 activate_port_forwarding(pData, ethaddr);
1834 return 0;
1835}
1836
1837int slirp_remove_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1838 struct in_addr guest_addr, int guest_port)
1839{
1840 struct port_forward_rule *rule = NULL;
1841 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
1842 {
1843 if ( rule->proto == (is_udp ? IPPROTO_UDP : IPPROTO_TCP)
1844 && rule->host_port == host_port
1845 && rule->guest_port == guest_port
1846 && rule->bind_ip.s_addr == host_addr.s_addr
1847 && rule->guest_addr.s_addr == guest_addr.s_addr
1848 && rule->activated)
1849 {
1850 LogRel(("NAT: remove redirect %s host port %d => guest port %d @ %RTnaipv4\n",
1851 rule->proto == IPPROTO_UDP ? "UDP" : "TCP", rule->host_port, rule->guest_port, guest_addr));
1852
1853 LibAliasUninit(rule->so->so_la);
1854 if (is_udp)
1855 udp_detach(pData, rule->so);
1856 else
1857 tcp_close(pData, sototcpcb(rule->so));
1858 LIST_REMOVE(rule, list);
1859 RTMemFree(rule);
1860 pData->cRedirectionsStored--;
1861 break;
1862 }
1863
1864 }
1865 return 0;
1866}
1867
1868void slirp_set_ethaddr_and_activate_port_forwarding(PNATState pData, const uint8_t *ethaddr, uint32_t GuestIP)
1869{
1870#ifndef VBOX_WITH_NAT_SERVICE
1871 memcpy(client_ethaddr, ethaddr, ETH_ALEN);
1872#endif
1873 if (GuestIP != INADDR_ANY)
1874 {
1875 slirp_arp_cache_update_or_add(pData, GuestIP, ethaddr);
1876 activate_port_forwarding(pData, ethaddr);
1877 }
1878}
1879
1880#if defined(RT_OS_WINDOWS)
1881HANDLE *slirp_get_events(PNATState pData)
1882{
1883 return pData->phEvents;
1884}
1885void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index)
1886{
1887 pData->phEvents[index] = hEvent;
1888}
1889#endif
1890
1891unsigned int slirp_get_timeout_ms(PNATState pData)
1892{
1893 if (link_up)
1894 {
1895 if (time_fasttimo)
1896 return 2;
1897 if (do_slowtimo)
1898 return 500; /* see PR_SLOWHZ */
1899 }
1900 return 3600*1000; /* one hour */
1901}
1902
1903#ifndef RT_OS_WINDOWS
1904int slirp_get_nsock(PNATState pData)
1905{
1906 return pData->nsock;
1907}
1908#endif
1909
1910/*
1911 * this function called from NAT thread
1912 */
1913void slirp_post_sent(PNATState pData, void *pvArg)
1914{
1915 struct mbuf *m = (struct mbuf *)pvArg;
1916 m_freem(pData, m);
1917}
1918#ifdef VBOX_WITH_SLIRP_MT
1919void slirp_process_queue(PNATState pData)
1920{
1921 RTReqProcess(pData->pReqQueue, RT_INDEFINITE_WAIT);
1922}
1923void *slirp_get_queue(PNATState pData)
1924{
1925 return pData->pReqQueue;
1926}
1927#endif
1928
1929void slirp_set_dhcp_TFTP_prefix(PNATState pData, const char *tftpPrefix)
1930{
1931 Log2(("tftp_prefix: %s\n", tftpPrefix));
1932 tftp_prefix = tftpPrefix;
1933}
1934
1935void slirp_set_dhcp_TFTP_bootfile(PNATState pData, const char *bootFile)
1936{
1937 Log2(("bootFile: %s\n", bootFile));
1938 bootp_filename = bootFile;
1939}
1940
1941void slirp_set_dhcp_next_server(PNATState pData, const char *next_server)
1942{
1943 Log2(("next_server: %s\n", next_server));
1944 if (next_server == NULL)
1945 pData->tftp_server.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_TFTP);
1946 else
1947 inet_aton(next_server, &pData->tftp_server);
1948}
1949
1950int slirp_set_binding_address(PNATState pData, char *addr)
1951{
1952 if (addr == NULL || (inet_aton(addr, &pData->bindIP) == 0))
1953 {
1954 pData->bindIP.s_addr = INADDR_ANY;
1955 return 1;
1956 }
1957 return 0;
1958}
1959
1960void slirp_set_dhcp_dns_proxy(PNATState pData, bool fDNSProxy)
1961{
1962 if (!pData->fUseHostResolver)
1963 {
1964 Log2(("NAT: DNS proxy switched %s\n", (fDNSProxy ? "on" : "off")));
1965 pData->fUseDnsProxy = fDNSProxy;
1966 }
1967 else
1968 LogRel(("NAT: Host Resolver conflicts with DNS proxy, the last one was forcely ignored\n"));
1969}
1970
1971#define CHECK_ARG(name, val, lim_min, lim_max) \
1972 do { \
1973 if ((val) < (lim_min) || (val) > (lim_max)) \
1974 { \
1975 LogRel(("NAT: (" #name ":%d) has been ignored, " \
1976 "because out of range (%d, %d)\n", (val), (lim_min), (lim_max))); \
1977 return; \
1978 } \
1979 else \
1980 LogRel(("NAT: (" #name ":%d)\n", (val))); \
1981 } while (0)
1982
1983void slirp_set_somaxconn(PNATState pData, int iSoMaxConn)
1984{
1985 LogFlowFunc(("iSoMaxConn:d\n", iSoMaxConn));
1986 if (iSoMaxConn > SOMAXCONN)
1987 {
1988 LogRel(("New value of somaxconn(%d) bigger than SOMAXCONN(%d)\n", iSoMaxConn, SOMAXCONN));
1989 iSoMaxConn = SOMAXCONN;
1990 }
1991 pData->soMaxConn = iSoMaxConn > 0 ? iSoMaxConn : pData->soMaxConn;
1992 if (pData->soMaxConn > 1)
1993 LogRel(("New value of somaxconn: %d\n", pData->soMaxConn));
1994 LogFlowFuncLeave();
1995}
1996/* don't allow user set less 8kB and more than 1M values */
1997#define _8K_1M_CHECK_ARG(name, val) CHECK_ARG(name, (val), 8, 1024)
1998void slirp_set_rcvbuf(PNATState pData, int kilobytes)
1999{
2000 _8K_1M_CHECK_ARG("SOCKET_RCVBUF", kilobytes);
2001 pData->socket_rcv = kilobytes;
2002}
2003void slirp_set_sndbuf(PNATState pData, int kilobytes)
2004{
2005 _8K_1M_CHECK_ARG("SOCKET_SNDBUF", kilobytes);
2006 pData->socket_snd = kilobytes * _1K;
2007}
2008void slirp_set_tcp_rcvspace(PNATState pData, int kilobytes)
2009{
2010 _8K_1M_CHECK_ARG("TCP_RCVSPACE", kilobytes);
2011 tcp_rcvspace = kilobytes * _1K;
2012}
2013void slirp_set_tcp_sndspace(PNATState pData, int kilobytes)
2014{
2015 _8K_1M_CHECK_ARG("TCP_SNDSPACE", kilobytes);
2016 tcp_sndspace = kilobytes * _1K;
2017}
2018
2019/*
2020 * Looking for Ether by ip in ARP-cache
2021 * Note: it´s responsible of caller to allocate buffer for result
2022 * @returns iprt status code
2023 */
2024int slirp_arp_lookup_ether_by_ip(PNATState pData, uint32_t ip, uint8_t *ether)
2025{
2026 struct arp_cache_entry *ac;
2027
2028 if (ether == NULL)
2029 return VERR_INVALID_PARAMETER;
2030
2031 if (LIST_EMPTY(&pData->arp_cache))
2032 return VERR_NOT_FOUND;
2033
2034 LIST_FOREACH(ac, &pData->arp_cache, list)
2035 {
2036 if ( ac->ip == ip
2037 && memcmp(ac->ether, broadcast_ethaddr, ETH_ALEN) != 0)
2038 {
2039 memcpy(ether, ac->ether, ETH_ALEN);
2040 return VINF_SUCCESS;
2041 }
2042 }
2043 return VERR_NOT_FOUND;
2044}
2045
2046/*
2047 * Looking for IP by Ether in ARP-cache
2048 * Note: it´s responsible of caller to allocate buffer for result
2049 * @returns 0 - if found, 1 - otherwise
2050 */
2051int slirp_arp_lookup_ip_by_ether(PNATState pData, const uint8_t *ether, uint32_t *ip)
2052{
2053 struct arp_cache_entry *ac;
2054 *ip = INADDR_ANY;
2055
2056 if (LIST_EMPTY(&pData->arp_cache))
2057 return VERR_NOT_FOUND;
2058
2059 LIST_FOREACH(ac, &pData->arp_cache, list)
2060 {
2061 if (memcmp(ether, ac->ether, ETH_ALEN) == 0)
2062 {
2063 *ip = ac->ip;
2064 return VINF_SUCCESS;
2065 }
2066 }
2067 return VERR_NOT_FOUND;
2068}
2069
2070void slirp_arp_who_has(PNATState pData, uint32_t dst)
2071{
2072 struct mbuf *m;
2073 struct ethhdr *ehdr;
2074 struct arphdr *ahdr;
2075 LogFlowFunc(("ENTER: %RTnaipv4\n", dst));
2076
2077 m = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
2078 if (m == NULL)
2079 {
2080 Log(("NAT: Can't alloc mbuf for ARP request\n"));
2081 LogFlowFuncLeave();
2082 return;
2083 }
2084 ehdr = mtod(m, struct ethhdr *);
2085 memset(ehdr->h_source, 0xff, ETH_ALEN);
2086 ahdr = (struct arphdr *)&ehdr[1];
2087 ahdr->ar_hrd = RT_H2N_U16_C(1);
2088 ahdr->ar_pro = RT_H2N_U16_C(ETH_P_IP);
2089 ahdr->ar_hln = ETH_ALEN;
2090 ahdr->ar_pln = 4;
2091 ahdr->ar_op = RT_H2N_U16_C(ARPOP_REQUEST);
2092 memcpy(ahdr->ar_sha, special_ethaddr, ETH_ALEN);
2093 /* we assume that this request come from gw, but not from DNS or TFTP */
2094 ahdr->ar_sha[5] = CTL_ALIAS;
2095 *(uint32_t *)ahdr->ar_sip = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
2096 memset(ahdr->ar_tha, 0xff, ETH_ALEN); /*broadcast*/
2097 *(uint32_t *)ahdr->ar_tip = dst;
2098 /* warn!!! should falls in mbuf minimal size */
2099 m->m_len = sizeof(struct arphdr) + ETH_HLEN;
2100 m->m_data += ETH_HLEN;
2101 m->m_len -= ETH_HLEN;
2102 if_encap(pData, ETH_P_ARP, m, ETH_ENCAP_URG);
2103 LogFlowFuncLeave();
2104}
2105
2106/* updates the arp cache
2107 * @note: this is helper function, slirp_arp_cache_update_or_add should be used.
2108 * @returns 0 - if has found and updated
2109 * 1 - if hasn't found.
2110 */
2111static inline int slirp_arp_cache_update(PNATState pData, uint32_t dst, const uint8_t *mac)
2112{
2113 struct arp_cache_entry *ac;
2114 Assert(( memcmp(mac, broadcast_ethaddr, ETH_ALEN)
2115 && memcmp(mac, zerro_ethaddr, ETH_ALEN)));
2116 LIST_FOREACH(ac, &pData->arp_cache, list)
2117 {
2118 if (!memcmp(ac->ether, mac, ETH_ALEN))
2119 {
2120 ac->ip = dst;
2121 return 0;
2122 }
2123 }
2124 return 1;
2125}
2126/**
2127 * add entry to the arp cache
2128 * @note: this is helper function, slirp_arp_cache_update_or_add should be used.
2129 */
2130
2131static inline void slirp_arp_cache_add(PNATState pData, uint32_t ip, const uint8_t *ether)
2132{
2133 struct arp_cache_entry *ac = NULL;
2134 Assert(( memcmp(ether, broadcast_ethaddr, ETH_ALEN)
2135 && memcmp(ether, zerro_ethaddr, ETH_ALEN)));
2136 ac = RTMemAllocZ(sizeof(struct arp_cache_entry));
2137 if (ac == NULL)
2138 {
2139 Log(("NAT: Can't allocate arp cache entry\n"));
2140 return;
2141 }
2142 ac->ip = ip;
2143 memcpy(ac->ether, ether, ETH_ALEN);
2144 LIST_INSERT_HEAD(&pData->arp_cache, ac, list);
2145}
2146
2147/* updates or adds entry to the arp cache
2148 * @returns 0 - if has found and updated
2149 * 1 - if hasn't found.
2150 */
2151int slirp_arp_cache_update_or_add(PNATState pData, uint32_t dst, const uint8_t *mac)
2152{
2153 if ( !memcmp(mac, broadcast_ethaddr, ETH_ALEN)
2154 || !memcmp(mac, zerro_ethaddr, ETH_ALEN))
2155 {
2156 static bool fBroadcastEtherAddReported;
2157 if (!fBroadcastEtherAddReported)
2158 {
2159 LogRel(("NAT: Attempt to add pair [%RTmac:%RTnaipv4] in ARP cache was ignored\n",
2160 mac, dst));
2161 fBroadcastEtherAddReported = true;
2162 }
2163 return 1;
2164 }
2165 if (slirp_arp_cache_update(pData, dst, mac))
2166 slirp_arp_cache_add(pData, dst, mac);
2167
2168 return 0;
2169}
2170
2171
2172void slirp_set_mtu(PNATState pData, int mtu)
2173{
2174 if (mtu < 20 || mtu >= 16000)
2175 {
2176 LogRel(("NAT: mtu(%d) is out of range (20;16000] mtu forcely assigned to 1500\n", mtu));
2177 mtu = 1500;
2178 }
2179 /* MTU is maximum transition unit on */
2180 if_mtu =
2181 if_mru = mtu;
2182}
2183
2184/**
2185 * Info handler.
2186 */
2187void slirp_info(PNATState pData, PCDBGFINFOHLP pHlp, const char *pszArgs)
2188{
2189 struct socket *so, *so_next;
2190 struct arp_cache_entry *ac;
2191 struct port_forward_rule *rule;
2192 NOREF(pszArgs);
2193
2194 pHlp->pfnPrintf(pHlp, "NAT parameters: MTU=%d\n", if_mtu);
2195 pHlp->pfnPrintf(pHlp, "NAT TCP ports:\n");
2196 QSOCKET_FOREACH(so, so_next, tcp)
2197 /* { */
2198 pHlp->pfnPrintf(pHlp, " %R[natsock]\n", so);
2199 }
2200
2201 pHlp->pfnPrintf(pHlp, "NAT UDP ports:\n");
2202 QSOCKET_FOREACH(so, so_next, udp)
2203 /* { */
2204 pHlp->pfnPrintf(pHlp, " %R[natsock]\n", so);
2205 }
2206
2207 pHlp->pfnPrintf(pHlp, "NAT ARP cache:\n");
2208 LIST_FOREACH(ac, &pData->arp_cache, list)
2209 {
2210 pHlp->pfnPrintf(pHlp, " %RTnaipv4 %RTmac\n", ac->ip, &ac->ether);
2211 }
2212
2213 pHlp->pfnPrintf(pHlp, "NAT rules:\n");
2214 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
2215 {
2216 pHlp->pfnPrintf(pHlp, " %s %d => %RTnaipv4:%d %c\n",
2217 rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
2218 rule->host_port, rule->guest_addr.s_addr, rule->guest_port,
2219 rule->activated ? ' ' : '*');
2220 }
2221}
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