VirtualBox

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

Last change on this file since 57784 was 57784, checked in by vboxsync, 10 years ago

NAT: rewrite handling of port-forwarding.

The most interesting part is handling of wildcard guest address
(0.0.0.0) for which we are supposed to guess the real guest IP. For
TCP we delay the decision until new connection come and the we can use
the current guess for each new connection. For UDP things are
trickier. For now we set the current guess as the destination on
first incoming packet, but that doesn't handle changes of the guest
address or outgoing packets. This needs more thought.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.6 KB
Line 
1/* $Id: slirp.c 57784 2015-09-16 15:36:31Z vboxsync $ */
2/** @file
3 * NAT - slirp glue.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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/dbgf.h>
51#include <VBox/vmm/pdmdrv.h>
52#include <iprt/assert.h>
53#include <iprt/file.h>
54#ifndef RT_OS_WINDOWS
55# include <sys/ioctl.h>
56# include <poll.h>
57# include <netinet/in.h>
58#else
59# include <Winnls.h>
60# define _WINSOCK2API_
61# include <IPHlpApi.h>
62#endif
63#include <alias.h>
64
65#ifndef RT_OS_WINDOWS
66/**
67 * XXX: It shouldn't be non-Windows specific.
68 * resolv_conf_parser.h client's structure isn't OS specific, it's just need to be generalized a
69 * a bit to replace slirp_state.h DNS server (domain) lists with rcp_state like structure.
70 */
71# include "resolv_conf_parser.h"
72#endif
73
74#ifndef RT_OS_WINDOWS
75# define DO_ENGAGE_EVENT1(so, fdset, label) \
76 do { \
77 if ( so->so_poll_index != -1 \
78 && so->s == polls[so->so_poll_index].fd) \
79 { \
80 polls[so->so_poll_index].events |= N_(fdset ## _poll); \
81 break; \
82 } \
83 AssertRelease(poll_index < (nfds)); \
84 AssertRelease(poll_index >= 0 && poll_index < (nfds)); \
85 polls[poll_index].fd = (so)->s; \
86 (so)->so_poll_index = poll_index; \
87 polls[poll_index].events = N_(fdset ## _poll); \
88 polls[poll_index].revents = 0; \
89 poll_index++; \
90 } while (0)
91
92# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
93 do { \
94 if ( so->so_poll_index != -1 \
95 && so->s == polls[so->so_poll_index].fd) \
96 { \
97 polls[so->so_poll_index].events |= \
98 N_(fdset1 ## _poll) | N_(fdset2 ## _poll); \
99 break; \
100 } \
101 AssertRelease(poll_index < (nfds)); \
102 polls[poll_index].fd = (so)->s; \
103 (so)->so_poll_index = poll_index; \
104 polls[poll_index].events = \
105 N_(fdset1 ## _poll) | N_(fdset2 ## _poll); \
106 poll_index++; \
107 } while (0)
108
109# define DO_POLL_EVENTS(rc, error, so, events, label) do {} while (0)
110
111/*
112 * DO_CHECK_FD_SET is used in dumping events on socket, including POLLNVAL.
113 * gcc warns about attempts to log POLLNVAL so construction in a last to lines
114 * used to catch POLLNVAL while logging and return false in case of error while
115 * normal usage.
116 */
117# define DO_CHECK_FD_SET(so, events, fdset) \
118 ( ((so)->so_poll_index != -1) \
119 && ((so)->so_poll_index <= ndfs) \
120 && ((so)->s == polls[so->so_poll_index].fd) \
121 && (polls[(so)->so_poll_index].revents & N_(fdset ## _poll)) \
122 && ( N_(fdset ## _poll) == POLLNVAL \
123 || !(polls[(so)->so_poll_index].revents & POLLNVAL)))
124
125 /* specific for Windows Winsock API */
126# define DO_WIN_CHECK_FD_SET(so, events, fdset) 0
127
128# ifndef RT_OS_LINUX
129# define readfds_poll (POLLRDNORM)
130# define writefds_poll (POLLWRNORM)
131# else
132# define readfds_poll (POLLIN)
133# define writefds_poll (POLLOUT)
134# endif
135# define xfds_poll (POLLPRI)
136# define closefds_poll (POLLHUP)
137# define rderr_poll (POLLERR)
138# if 0 /* unused yet */
139# define rdhup_poll (POLLHUP)
140# define nval_poll (POLLNVAL)
141# endif
142
143# define ICMP_ENGAGE_EVENT(so, fdset) \
144 do { \
145 if (pData->icmp_socket.s != -1) \
146 DO_ENGAGE_EVENT1((so), fdset, ICMP); \
147 } while (0)
148
149#else /* RT_OS_WINDOWS */
150
151/*
152 * On Windows, we will be notified by IcmpSendEcho2() when the response arrives.
153 * So no call to WSAEventSelect necessary.
154 */
155# define ICMP_ENGAGE_EVENT(so, fdset) do {} while (0)
156
157/*
158 * On Windows we use FD_ALL_EVENTS to ensure that we don't miss any event.
159 */
160# define DO_ENGAGE_EVENT1(so, fdset1, label) \
161 do { \
162 rc = WSAEventSelect((so)->s, VBOX_SOCKET_EVENT, FD_ALL_EVENTS); \
163 if (rc == SOCKET_ERROR) \
164 { \
165 /* This should not happen */ \
166 error = WSAGetLastError(); \
167 LogRel(("WSAEventSelect (" #label ") error %d (so=%x, socket=%s, event=%x)\n", \
168 error, (so), (so)->s, VBOX_SOCKET_EVENT)); \
169 } \
170 } while (0); \
171 CONTINUE(label)
172
173# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
174 DO_ENGAGE_EVENT1((so), (fdset1), label)
175
176# define DO_POLL_EVENTS(rc, error, so, events, label) \
177 (rc) = WSAEnumNetworkEvents((so)->s, VBOX_SOCKET_EVENT, (events)); \
178 if ((rc) == SOCKET_ERROR) \
179 { \
180 (error) = WSAGetLastError(); \
181 LogRel(("WSAEnumNetworkEvents %R[natsock] " #label " error %d\n", (so), (error))); \
182 LogFunc(("WSAEnumNetworkEvents %R[natsock] " #label " error %d\n", (so), (error))); \
183 CONTINUE(label); \
184 }
185
186# define acceptds_win FD_ACCEPT
187# define acceptds_win_bit FD_ACCEPT_BIT
188# define readfds_win FD_READ
189# define readfds_win_bit FD_READ_BIT
190# define writefds_win FD_WRITE
191# define writefds_win_bit FD_WRITE_BIT
192# define xfds_win FD_OOB
193# define xfds_win_bit FD_OOB_BIT
194# define closefds_win FD_CLOSE
195# define closefds_win_bit FD_CLOSE_BIT
196# define connectfds_win FD_CONNECT
197# define connectfds_win_bit FD_CONNECT_BIT
198
199# define closefds_win FD_CLOSE
200# define closefds_win_bit FD_CLOSE_BIT
201
202# define DO_CHECK_FD_SET(so, events, fdset) \
203 ((events).lNetworkEvents & fdset ## _win)
204
205# define DO_WIN_CHECK_FD_SET(so, events, fdset) DO_CHECK_FD_SET((so), (events), fdset)
206# define DO_UNIX_CHECK_FD_SET(so, events, fdset) 1 /*specific for Unix API */
207
208#endif /* RT_OS_WINDOWS */
209
210#define TCP_ENGAGE_EVENT1(so, fdset) \
211 DO_ENGAGE_EVENT1((so), fdset, tcp)
212
213#define TCP_ENGAGE_EVENT2(so, fdset1, fdset2) \
214 DO_ENGAGE_EVENT2((so), fdset1, fdset2, tcp)
215
216#ifdef RT_OS_WINDOWS
217# define WIN_TCP_ENGAGE_EVENT2(so, fdset, fdset2) TCP_ENGAGE_EVENT2(so, fdset1, fdset2)
218#endif
219
220#define UDP_ENGAGE_EVENT(so, fdset) \
221 DO_ENGAGE_EVENT1((so), fdset, udp)
222
223#define POLL_TCP_EVENTS(rc, error, so, events) \
224 DO_POLL_EVENTS((rc), (error), (so), (events), tcp)
225
226#define POLL_UDP_EVENTS(rc, error, so, events) \
227 DO_POLL_EVENTS((rc), (error), (so), (events), udp)
228
229#define CHECK_FD_SET(so, events, set) \
230 (DO_CHECK_FD_SET((so), (events), set))
231
232#define WIN_CHECK_FD_SET(so, events, set) \
233 (DO_WIN_CHECK_FD_SET((so), (events), set))
234
235/*
236 * Loging macros
237 */
238#if VBOX_WITH_DEBUG_NAT_SOCKETS
239# if defined(RT_OS_WINDOWS)
240# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
241 do { \
242 LogRel((" " #proto " %R[natsock] %R[natwinnetevents]\n", (so), (winevent))); \
243 } while (0)
244# else /* !RT_OS_WINDOWS */
245# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
246 do { \
247 LogRel((" " #proto " %R[natsock] %s %s %s er: %s, %s, %s\n", (so), \
248 CHECK_FD_SET(so, ign ,r_fdset) ? "READ":"", \
249 CHECK_FD_SET(so, ign, w_fdset) ? "WRITE":"", \
250 CHECK_FD_SET(so, ign, x_fdset) ? "OOB":"", \
251 CHECK_FD_SET(so, ign, rderr) ? "RDERR":"", \
252 CHECK_FD_SET(so, ign, rdhup) ? "RDHUP":"", \
253 CHECK_FD_SET(so, ign, nval) ? "RDNVAL":"")); \
254 } while (0)
255# endif /* !RT_OS_WINDOWS */
256#else /* !VBOX_WITH_DEBUG_NAT_SOCKETS */
257# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) do {} while (0)
258#endif /* !VBOX_WITH_DEBUG_NAT_SOCKETS */
259
260#define LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
261 DO_LOG_NAT_SOCK((so), proto, (winevent), r_fdset, w_fdset, x_fdset)
262
263static const uint8_t special_ethaddr[6] =
264{
265 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
266};
267
268static const uint8_t broadcast_ethaddr[6] =
269{
270 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
271};
272
273const uint8_t zerro_ethaddr[6] =
274{
275 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
276};
277
278/**
279 * This helper routine do the checks in descriptions to
280 * ''fUnderPolling'' and ''fShouldBeRemoved'' flags
281 * @returns 1 if socket removed and 0 if no changes was made.
282 */
283static int slirpVerifyAndFreeSocket(PNATState pData, struct socket *pSocket)
284{
285 AssertPtrReturn(pData, 0);
286 AssertPtrReturn(pSocket, 0);
287 AssertReturn(pSocket->fUnderPolling, 0);
288 if (pSocket->fShouldBeRemoved)
289 {
290 pSocket->fUnderPolling = 0;
291 sofree(pData, pSocket);
292 /* pSocket is PHANTOM, now */
293 return 1;
294 }
295 return 0;
296}
297
298int slirp_init(PNATState *ppData, uint32_t u32NetAddr, uint32_t u32Netmask,
299 bool fPassDomain, bool fUseHostResolver, int i32AliasMode,
300 int iIcmpCacheLimit, void *pvUser)
301{
302 int rc;
303 PNATState pData;
304 if (u32Netmask & 0x1f)
305 {
306 /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
307 LogRel(("The last 5 bits of the netmask (%RTnaipv4) need to be unset\n", RT_BE2H_U32(u32Netmask)));
308 return VERR_INVALID_PARAMETER;
309 }
310 pData = RTMemAllocZ(RT_ALIGN_Z(sizeof(NATState), sizeof(uint64_t)));
311 *ppData = pData;
312 if (!pData)
313 return VERR_NO_MEMORY;
314 pData->fPassDomain = !fUseHostResolver ? fPassDomain : false;
315 pData->fUseHostResolver = fUseHostResolver;
316 pData->fUseHostResolverPermanent = fUseHostResolver;
317 pData->pvUser = pvUser;
318 pData->netmask = u32Netmask;
319
320 rc = RTCritSectRwInit(&pData->CsRwHandlerChain);
321 if (RT_FAILURE(rc))
322 return rc;
323
324 /* sockets & TCP defaults */
325 pData->socket_rcv = 64 * _1K;
326 pData->socket_snd = 64 * _1K;
327 tcp_sndspace = 64 * _1K;
328 tcp_rcvspace = 64 * _1K;
329
330 /*
331 * Use the same default here as in DevNAT.cpp (SoMaxConnection CFGM value)
332 * to avoid release log noise.
333 */
334 pData->soMaxConn = 10;
335
336#ifdef RT_OS_WINDOWS
337 {
338 WSADATA Data;
339 RTLDRMOD hLdrMod;
340
341 WSAStartup(MAKEWORD(2, 0), &Data);
342
343 rc = RTLdrLoadSystem("Iphlpapi.dll", /* :fNoUnload */ true, &hLdrMod);
344 if (RT_SUCCESS(rc))
345 {
346 rc = RTLdrGetSymbol(hLdrMod, "GetAdaptersAddresses", (void **)&pData->pfGetAdaptersAddresses);
347 if (RT_FAILURE(rc))
348 LogRel(("NAT: Can't find GetAdapterAddresses in Iphlpapi.dll\n"));
349
350 RTLdrClose(hLdrMod);
351 }
352 }
353 pData->phEvents[VBOX_SOCKET_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
354#endif
355
356 rc = bootp_dhcp_init(pData);
357 if (RT_FAILURE(rc))
358 {
359 Log(("NAT: DHCP server initialization failed\n"));
360 RTMemFree(pData);
361 *ppData = NULL;
362 return rc;
363 }
364 debug_init(pData);
365 if_init(pData);
366 ip_init(pData);
367 icmp_init(pData, iIcmpCacheLimit);
368
369 /* Initialise mbufs *after* setting the MTU */
370 mbuf_init(pData);
371
372 pData->special_addr.s_addr = u32NetAddr;
373 pData->slirp_ethaddr = &special_ethaddr[0];
374 alias_addr.s_addr = pData->special_addr.s_addr | RT_H2N_U32_C(CTL_ALIAS);
375 /* @todo: add ability to configure this staff */
376
377 /* set default addresses */
378 inet_aton("127.0.0.1", &loopback_addr);
379
380 rc = slirpTftpInit(pData);
381 AssertRCReturn(rc, VINF_NAT_DNS);
382
383 if (i32AliasMode & ~(PKT_ALIAS_LOG|PKT_ALIAS_SAME_PORTS|PKT_ALIAS_PROXY_ONLY))
384 {
385 Log(("NAT: alias mode %x is ignored\n", i32AliasMode));
386 i32AliasMode = 0;
387 }
388 pData->i32AliasMode = i32AliasMode;
389 getouraddr(pData);
390 {
391 int flags = 0;
392 struct in_addr proxy_addr;
393 pData->proxy_alias = LibAliasInit(pData, NULL);
394 if (pData->proxy_alias == NULL)
395 {
396 Log(("NAT: LibAlias default rule wasn't initialized\n"));
397 AssertMsgFailed(("NAT: LibAlias default rule wasn't initialized\n"));
398 }
399 flags = LibAliasSetMode(pData->proxy_alias, 0, 0);
400#ifndef NO_FW_PUNCH
401 flags |= PKT_ALIAS_PUNCH_FW;
402#endif
403 flags |= pData->i32AliasMode; /* do transparent proxying */
404 flags = LibAliasSetMode(pData->proxy_alias, flags, ~0);
405 proxy_addr.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
406 LibAliasSetAddress(pData->proxy_alias, proxy_addr);
407 ftp_alias_load(pData);
408 nbt_alias_load(pData);
409 if (pData->fUseHostResolver)
410 dns_alias_load(pData);
411 }
412#ifdef VBOX_WITH_NAT_SEND2HOME
413 /* @todo: we should know all interfaces available on host. */
414 pData->pInSockAddrHomeAddress = RTMemAllocZ(sizeof(struct sockaddr));
415 pData->cInHomeAddressSize = 1;
416 inet_aton("192.168.1.25", &pData->pInSockAddrHomeAddress[0].sin_addr);
417 pData->pInSockAddrHomeAddress[0].sin_family = AF_INET;
418# ifdef RT_OS_DARWIN
419 pData->pInSockAddrHomeAddress[0].sin_len = sizeof(struct sockaddr_in);
420# endif
421#endif
422
423 slirp_link_up(pData);
424 return VINF_SUCCESS;
425}
426
427/**
428 * Register statistics.
429 */
430void slirp_register_statistics(PNATState pData, PPDMDRVINS pDrvIns)
431{
432#ifdef VBOX_WITH_STATISTICS
433# define PROFILE_COUNTER(name, dsc) REGISTER_COUNTER(name, pData, STAMTYPE_PROFILE, STAMUNIT_TICKS_PER_CALL, dsc)
434# define COUNTING_COUNTER(name, dsc) REGISTER_COUNTER(name, pData, STAMTYPE_COUNTER, STAMUNIT_COUNT, dsc)
435# include "counters.h"
436# undef COUNTER
437/** @todo register statistics for the variables dumped by:
438 * ipstats(pData); tcpstats(pData); udpstats(pData); icmpstats(pData);
439 * mbufstats(pData); sockstats(pData); */
440#else /* VBOX_WITH_STATISTICS */
441 NOREF(pData);
442 NOREF(pDrvIns);
443#endif /* !VBOX_WITH_STATISTICS */
444}
445
446/**
447 * Deregister statistics.
448 */
449void slirp_deregister_statistics(PNATState pData, PPDMDRVINS pDrvIns)
450{
451 if (pData == NULL)
452 return;
453#ifdef VBOX_WITH_STATISTICS
454# define PROFILE_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pData)
455# define COUNTING_COUNTER(name, dsc) DEREGISTER_COUNTER(name, pData)
456# include "counters.h"
457#else /* VBOX_WITH_STATISTICS */
458 NOREF(pData);
459 NOREF(pDrvIns);
460#endif /* !VBOX_WITH_STATISTICS */
461}
462
463/**
464 * Marks the link as up, making it possible to establish new connections.
465 */
466void slirp_link_up(PNATState pData)
467{
468 struct arp_cache_entry *ac;
469
470 if (link_up == 1)
471 return;
472
473 link_up = 1;
474
475 if (!pData->fUseHostResolverPermanent)
476 slirpInitializeDnsSettings(pData);
477}
478
479/**
480 * Marks the link as down and cleans up the current connections.
481 */
482void slirp_link_down(PNATState pData)
483{
484 struct port_forward_rule *rule;
485
486 if (link_up == 0)
487 return;
488
489 slirpReleaseDnsSettings(pData);
490
491 link_up = 0;
492}
493
494/**
495 * Terminates the slirp component.
496 */
497void slirp_term(PNATState pData)
498{
499 struct socket *so;
500
501 if (pData == NULL)
502 return;
503
504 icmp_finit(pData);
505
506 while ((so = tcb.so_next) != &tcb)
507 {
508 /* Don't miss TCB releasing */
509 if ( !sototcpcb(so)
510 && ( so->so_state & SS_NOFDREF
511 || so->s == -1))
512 sofree(pData, so);
513 else
514 tcp_close(pData, sototcpcb(so));
515 }
516
517 while ((so = udb.so_next) != &udb)
518 udp_detach(pData, so);
519
520 slirp_link_down(pData);
521 ftp_alias_unload(pData);
522 nbt_alias_unload(pData);
523 if (pData->fUseHostResolver)
524 {
525 dns_alias_unload(pData);
526#ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER
527 while (!LIST_EMPTY(&pData->DNSMapHead))
528 {
529 PDNSMAPPINGENTRY pDnsEntry = LIST_FIRST(&pData->DNSMapHead);
530 LIST_REMOVE(pDnsEntry, MapList);
531 RTStrFree(pDnsEntry->pszCName);
532 RTMemFree(pDnsEntry);
533 }
534#endif
535 }
536 while (!LIST_EMPTY(&instancehead))
537 {
538 struct libalias *la = LIST_FIRST(&instancehead);
539 /* libalias do all clean up */
540 LibAliasUninit(la);
541 }
542 while (!LIST_EMPTY(&pData->arp_cache))
543 {
544 struct arp_cache_entry *ac = LIST_FIRST(&pData->arp_cache);
545 LIST_REMOVE(ac, list);
546 RTMemFree(ac);
547 }
548 slirpTftpTerm(pData);
549 bootp_dhcp_fini(pData);
550 m_fini(pData);
551#ifdef RT_OS_WINDOWS
552 WSACleanup();
553#endif
554#ifdef LOG_ENABLED
555 Log(("\n"
556 "NAT statistics\n"
557 "--------------\n"
558 "\n"));
559 ipstats(pData);
560 tcpstats(pData);
561 udpstats(pData);
562 icmpstats(pData);
563 mbufstats(pData);
564 sockstats(pData);
565 Log(("\n"
566 "\n"
567 "\n"));
568#endif
569 RTCritSectRwDelete(&pData->CsRwHandlerChain);
570 RTMemFree(pData);
571}
572
573
574#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
575#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
576
577/*
578 * curtime kept to an accuracy of 1ms
579 */
580static void updtime(PNATState pData)
581{
582#ifdef RT_OS_WINDOWS
583 struct _timeb tb;
584
585 _ftime(&tb);
586 curtime = (u_int)tb.time * (u_int)1000;
587 curtime += (u_int)tb.millitm;
588#else
589 gettimeofday(&tt, 0);
590
591 curtime = (u_int)tt.tv_sec * (u_int)1000;
592 curtime += (u_int)tt.tv_usec / (u_int)1000;
593
594 if ((tt.tv_usec % 1000) >= 500)
595 curtime++;
596#endif
597}
598
599#ifdef RT_OS_WINDOWS
600void slirp_select_fill(PNATState pData, int *pnfds)
601#else /* RT_OS_WINDOWS */
602void slirp_select_fill(PNATState pData, int *pnfds, struct pollfd *polls)
603#endif /* !RT_OS_WINDOWS */
604{
605 struct socket *so, *so_next;
606 int nfds;
607#if defined(RT_OS_WINDOWS)
608 int rc;
609 int error;
610#else
611 int poll_index = 0;
612#endif
613 int i;
614
615 STAM_PROFILE_START(&pData->StatFill, a);
616
617 nfds = *pnfds;
618
619 /*
620 * First, TCP sockets
621 */
622 do_slowtimo = 0;
623 if (!link_up)
624 goto done;
625
626 /*
627 * *_slowtimo needs calling if there are IP fragments
628 * in the fragment queue, or there are TCP connections active
629 */
630 /* XXX:
631 * triggering of fragment expiration should be the same but use new macroses
632 */
633 do_slowtimo = (tcb.so_next != &tcb);
634 if (!do_slowtimo)
635 {
636 for (i = 0; i < IPREASS_NHASH; i++)
637 {
638 if (!TAILQ_EMPTY(&ipq[i]))
639 {
640 do_slowtimo = 1;
641 break;
642 }
643 }
644 }
645 /* always add the ICMP socket */
646#ifndef RT_OS_WINDOWS
647 pData->icmp_socket.so_poll_index = -1;
648#endif
649 ICMP_ENGAGE_EVENT(&pData->icmp_socket, readfds);
650
651 STAM_COUNTER_RESET(&pData->StatTCP);
652 STAM_COUNTER_RESET(&pData->StatTCPHot);
653
654 QSOCKET_FOREACH(so, so_next, tcp)
655 /* { */
656 Assert(so->so_type == IPPROTO_TCP);
657#if !defined(RT_OS_WINDOWS)
658 so->so_poll_index = -1;
659#endif
660 STAM_COUNTER_INC(&pData->StatTCP);
661#ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE
662 /* TCP socket can't be cloned */
663 Assert((!so->so_cloneOf));
664#endif
665 /*
666 * See if we need a tcp_fasttimo
667 */
668 if ( time_fasttimo == 0
669 && so->so_tcpcb != NULL
670 && so->so_tcpcb->t_flags & TF_DELACK)
671 {
672 time_fasttimo = curtime; /* Flag when we want a fasttimo */
673 }
674
675 /*
676 * NOFDREF can include still connecting to local-host,
677 * newly socreated() sockets etc. Don't want to select these.
678 */
679 if (so->so_state & SS_NOFDREF || so->s == -1)
680 CONTINUE(tcp);
681
682 /*
683 * Set for reading sockets which are accepting
684 */
685 if (so->so_state & SS_FACCEPTCONN)
686 {
687 STAM_COUNTER_INC(&pData->StatTCPHot);
688 TCP_ENGAGE_EVENT1(so, readfds);
689 CONTINUE(tcp);
690 }
691
692 /*
693 * Set for writing sockets which are connecting
694 */
695 if (so->so_state & SS_ISFCONNECTING)
696 {
697 Log2(("connecting %R[natsock] engaged\n",so));
698 STAM_COUNTER_INC(&pData->StatTCPHot);
699#ifdef RT_OS_WINDOWS
700 WIN_TCP_ENGAGE_EVENT2(so, writefds, connectfds);
701#else
702 TCP_ENGAGE_EVENT1(so, writefds);
703#endif
704 }
705
706 /*
707 * Set for writing if we are connected, can send more, and
708 * we have something to send
709 */
710 if (CONN_CANFSEND(so) && SBUF_LEN(&so->so_rcv))
711 {
712 STAM_COUNTER_INC(&pData->StatTCPHot);
713 TCP_ENGAGE_EVENT1(so, writefds);
714 }
715
716 /*
717 * Set for reading (and urgent data) if we are connected, can
718 * receive more, and we have room for it XXX /2 ?
719 */
720 /* @todo: vvl - check which predicat here will be more useful here in rerm of new sbufs. */
721 if ( CONN_CANFRCV(so)
722 && (SBUF_LEN(&so->so_snd) < (SBUF_SIZE(&so->so_snd)/2))
723#ifdef RT_OS_WINDOWS
724 && !(so->so_state & SS_ISFCONNECTING)
725#endif
726 )
727 {
728 STAM_COUNTER_INC(&pData->StatTCPHot);
729 TCP_ENGAGE_EVENT2(so, readfds, xfds);
730 }
731 LOOP_LABEL(tcp, so, so_next);
732 }
733
734 /*
735 * UDP sockets
736 */
737 STAM_COUNTER_RESET(&pData->StatUDP);
738 STAM_COUNTER_RESET(&pData->StatUDPHot);
739
740 QSOCKET_FOREACH(so, so_next, udp)
741 /* { */
742
743 Assert(so->so_type == IPPROTO_UDP);
744 STAM_COUNTER_INC(&pData->StatUDP);
745#if !defined(RT_OS_WINDOWS)
746 so->so_poll_index = -1;
747#endif
748
749 /*
750 * See if it's timed out
751 */
752 if (so->so_expire)
753 {
754 if (so->so_expire <= curtime)
755 {
756 Log2(("NAT: %R[natsock] expired\n", so));
757 if (so->so_timeout != NULL)
758 {
759 /* so_timeout - might change the so_expire value or
760 * drop so_timeout* from so.
761 */
762 so->so_timeout(pData, so, so->so_timeout_arg);
763 /* on 4.2 so->
764 */
765 if ( so_next->so_prev != so /* so_timeout freed the socket */
766 || so->so_timeout) /* so_timeout just freed so_timeout */
767 CONTINUE_NO_UNLOCK(udp);
768 }
769 UDP_DETACH(pData, so, so_next);
770 CONTINUE_NO_UNLOCK(udp);
771 }
772 }
773#ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE
774 if (so->so_cloneOf)
775 CONTINUE_NO_UNLOCK(udp);
776#endif
777
778 /*
779 * When UDP packets are received from over the link, they're
780 * sendto()'d straight away, so no need for setting for writing
781 * Limit the number of packets queued by this session to 4.
782 * Note that even though we try and limit this to 4 packets,
783 * the session could have more queued if the packets needed
784 * to be fragmented.
785 *
786 * (XXX <= 4 ?)
787 */
788 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4)
789 {
790 STAM_COUNTER_INC(&pData->StatUDPHot);
791 UDP_ENGAGE_EVENT(so, readfds);
792 }
793 LOOP_LABEL(udp, so, so_next);
794 }
795done:
796
797#if defined(RT_OS_WINDOWS)
798 *pnfds = VBOX_EVENT_COUNT;
799#else /* RT_OS_WINDOWS */
800 AssertRelease(poll_index <= *pnfds);
801 *pnfds = poll_index;
802#endif /* !RT_OS_WINDOWS */
803
804 STAM_PROFILE_STOP(&pData->StatFill, a);
805}
806
807
808/**
809 * This function do Connection or sending tcp sequence to.
810 * @returns if true operation completed
811 * @note: functions call tcp_input that potentially could lead to tcp_drop
812 */
813static bool slirpConnectOrWrite(PNATState pData, struct socket *so, bool fConnectOnly)
814{
815 int ret;
816 LogFlowFunc(("ENTER: so:%R[natsock], fConnectOnly:%RTbool\n", so, fConnectOnly));
817 /*
818 * Check for non-blocking, still-connecting sockets
819 */
820 if (so->so_state & SS_ISFCONNECTING)
821 {
822 Log2(("connecting %R[natsock] catched\n", so));
823 /* Connected */
824 so->so_state &= ~SS_ISFCONNECTING;
825
826 /*
827 * This should be probably guarded by PROBE_CONN too. Anyway,
828 * we disable it on OS/2 because the below send call returns
829 * EFAULT which causes the opened TCP socket to close right
830 * after it has been opened and connected.
831 */
832#ifndef RT_OS_OS2
833 ret = send(so->s, (const char *)&ret, 0, 0);
834 if (ret < 0)
835 {
836 /* XXXXX Must fix, zero bytes is a NOP */
837 if ( soIgnorableErrorCode(errno)
838 || errno == ENOTCONN)
839 {
840 LogFlowFunc(("LEAVE: false\n"));
841 return false;
842 }
843
844 /* else failed */
845 so->so_state = SS_NOFDREF;
846 }
847 /* else so->so_state &= ~SS_ISFCONNECTING; */
848#endif
849
850 /*
851 * Continue tcp_input
852 */
853 TCP_INPUT(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
854 /* continue; */
855 }
856 else if (!fConnectOnly)
857 {
858 SOWRITE(ret, pData, so);
859 if (RT_LIKELY(ret > 0))
860 {
861 /*
862 * Make sure we will send window update to peer. This is
863 * a moral equivalent of calling tcp_output() for PRU_RCVD
864 * in tcp_usrreq() of the real stack.
865 */
866 struct tcpcb *tp = sototcpcb(so);
867 if (RT_LIKELY(tp != NULL))
868 tp->t_flags |= TF_DELACK;
869 }
870 }
871
872 LogFlowFunc(("LEAVE: true\n"));
873 return true;
874}
875
876#if defined(RT_OS_WINDOWS)
877void slirp_select_poll(PNATState pData, int fTimeout)
878#else /* RT_OS_WINDOWS */
879void slirp_select_poll(PNATState pData, struct pollfd *polls, int ndfs)
880#endif /* !RT_OS_WINDOWS */
881{
882 struct socket *so, *so_next;
883 int ret;
884#if defined(RT_OS_WINDOWS)
885 WSANETWORKEVENTS NetworkEvents;
886 int rc;
887 int error;
888#endif
889
890 STAM_PROFILE_START(&pData->StatPoll, a);
891
892 /* Update time */
893 updtime(pData);
894
895 /*
896 * See if anything has timed out
897 */
898 if (link_up)
899 {
900 if (time_fasttimo && ((curtime - time_fasttimo) >= 2))
901 {
902 STAM_PROFILE_START(&pData->StatFastTimer, b);
903 tcp_fasttimo(pData);
904 time_fasttimo = 0;
905 STAM_PROFILE_STOP(&pData->StatFastTimer, b);
906 }
907 if (do_slowtimo && ((curtime - last_slowtimo) >= 499))
908 {
909 STAM_PROFILE_START(&pData->StatSlowTimer, c);
910 ip_slowtimo(pData);
911 tcp_slowtimo(pData);
912 last_slowtimo = curtime;
913 STAM_PROFILE_STOP(&pData->StatSlowTimer, c);
914 }
915 }
916#if defined(RT_OS_WINDOWS)
917 if (fTimeout)
918 return; /* only timer update */
919#endif
920
921 /*
922 * Check sockets
923 */
924 if (!link_up)
925 goto done;
926#if defined(RT_OS_WINDOWS)
927 icmpwin_process(pData);
928#else
929 if ( (pData->icmp_socket.s != -1)
930 && CHECK_FD_SET(&pData->icmp_socket, ignored, readfds))
931 sorecvfrom(pData, &pData->icmp_socket);
932#endif
933 /*
934 * Check TCP sockets
935 */
936 QSOCKET_FOREACH(so, so_next, tcp)
937 /* { */
938 /* TCP socket can't be cloned */
939#ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE
940 Assert((!so->so_cloneOf));
941#endif
942 Assert(!so->fUnderPolling);
943 so->fUnderPolling = 1;
944 if (slirpVerifyAndFreeSocket(pData, so))
945 CONTINUE(tcp);
946 /*
947 * FD_ISSET is meaningless on these sockets
948 * (and they can crash the program)
949 */
950 if (so->so_state & SS_NOFDREF || so->s == -1)
951 {
952 so->fUnderPolling = 0;
953 CONTINUE(tcp);
954 }
955
956 POLL_TCP_EVENTS(rc, error, so, &NetworkEvents);
957
958 LOG_NAT_SOCK(so, TCP, &NetworkEvents, readfds, writefds, xfds);
959
960 if (so->so_state & SS_ISFCONNECTING)
961 {
962 int sockerr = 0;
963#if !defined(RT_OS_WINDOWS)
964 {
965 int revents = 0;
966
967 /*
968 * Failed connect(2) is reported by poll(2) on
969 * different OSes with different combinations of
970 * POLLERR, POLLHUP, and POLLOUT.
971 */
972 if ( CHECK_FD_SET(so, NetworkEvents, closefds) /* POLLHUP */
973 || CHECK_FD_SET(so, NetworkEvents, rderr)) /* POLLERR */
974 {
975 revents = POLLHUP; /* squash to single "failed" flag */
976 }
977#if defined(RT_OS_SOLARIS) || defined(RT_OS_NETBSD)
978 /* Solaris and NetBSD report plain POLLOUT even on error */
979 else if (CHECK_FD_SET(so, NetworkEvents, writefds)) /* POLLOUT */
980 {
981 revents = POLLOUT;
982 }
983#endif
984
985 if (revents != 0)
986 {
987 socklen_t optlen = (socklen_t)sizeof(sockerr);
988 ret = getsockopt(so->s, SOL_SOCKET, SO_ERROR, &sockerr, &optlen);
989
990 if ( RT_UNLIKELY(ret < 0)
991 || ( (revents & POLLHUP)
992 && RT_UNLIKELY(sockerr == 0)))
993 sockerr = ETIMEDOUT;
994 }
995 }
996#else /* RT_OS_WINDOWS */
997 {
998 if (NetworkEvents.lNetworkEvents & FD_CONNECT)
999 sockerr = NetworkEvents.iErrorCode[FD_CONNECT_BIT];
1000 }
1001#endif
1002 if (sockerr != 0)
1003 {
1004 tcp_fconnect_failed(pData, so, sockerr);
1005 ret = slirpVerifyAndFreeSocket(pData, so);
1006 Assert(ret == 1); /* freed */
1007 CONTINUE(tcp);
1008 }
1009
1010 /*
1011 * XXX: For now just fall through to the old code to
1012 * handle successful connect(2).
1013 */
1014 }
1015
1016 /*
1017 * Check for URG data
1018 * This will soread as well, so no need to
1019 * test for readfds below if this succeeds
1020 */
1021
1022 /* out-of-band data */
1023 if ( CHECK_FD_SET(so, NetworkEvents, xfds)
1024#ifdef RT_OS_DARWIN
1025 /* Darwin and probably BSD hosts generates POLLPRI|POLLHUP event on receiving TCP.flags.{ACK|URG|FIN} this
1026 * combination on other Unixs hosts doesn't enter to this branch
1027 */
1028 && !CHECK_FD_SET(so, NetworkEvents, closefds)
1029#endif
1030#ifdef RT_OS_WINDOWS
1031 /**
1032 * In some cases FD_CLOSE comes with FD_OOB, that confuse tcp processing.
1033 */
1034 && !WIN_CHECK_FD_SET(so, NetworkEvents, closefds)
1035#endif
1036 )
1037 {
1038 sorecvoob(pData, so);
1039 if (slirpVerifyAndFreeSocket(pData, so))
1040 CONTINUE(tcp);
1041 }
1042
1043 /*
1044 * Check sockets for reading
1045 */
1046 else if ( CHECK_FD_SET(so, NetworkEvents, readfds)
1047 || WIN_CHECK_FD_SET(so, NetworkEvents, acceptds))
1048 {
1049
1050#ifdef RT_OS_WINDOWS
1051 if (WIN_CHECK_FD_SET(so, NetworkEvents, connectfds))
1052 {
1053 /* Finish connection first */
1054 /* should we ignore return value? */
1055 bool fRet = slirpConnectOrWrite(pData, so, true);
1056 LogFunc(("fRet:%RTbool\n", fRet));
1057 if (slirpVerifyAndFreeSocket(pData, so))
1058 CONTINUE(tcp);
1059 }
1060#endif
1061 /*
1062 * Check for incoming connections
1063 */
1064 if (so->so_state & SS_FACCEPTCONN)
1065 {
1066 TCP_CONNECT(pData, so);
1067 if (slirpVerifyAndFreeSocket(pData, so))
1068 CONTINUE(tcp);
1069 if (!CHECK_FD_SET(so, NetworkEvents, closefds))
1070 {
1071 so->fUnderPolling = 0;
1072 CONTINUE(tcp);
1073 }
1074 }
1075
1076 ret = soread(pData, so);
1077 if (slirpVerifyAndFreeSocket(pData, so))
1078 CONTINUE(tcp);
1079 /* Output it if we read something */
1080 if (RT_LIKELY(ret > 0))
1081 TCP_OUTPUT(pData, sototcpcb(so));
1082
1083 if (slirpVerifyAndFreeSocket(pData, so))
1084 CONTINUE(tcp);
1085 }
1086
1087 /*
1088 * Check for FD_CLOSE events.
1089 * in some cases once FD_CLOSE engaged on socket it could be flashed latter (for some reasons)
1090 */
1091 if ( CHECK_FD_SET(so, NetworkEvents, closefds)
1092 || (so->so_close == 1))
1093 {
1094 /*
1095 * drain the socket
1096 */
1097 for (; so_next->so_prev == so
1098 && !slirpVerifyAndFreeSocket(pData, so);)
1099 {
1100 ret = soread(pData, so);
1101 if (slirpVerifyAndFreeSocket(pData, so))
1102 break;
1103
1104 if (ret > 0)
1105 TCP_OUTPUT(pData, sototcpcb(so));
1106 else if (so_next->so_prev == so)
1107 {
1108 Log2(("%R[natsock] errno %d (%s)\n", so, errno, strerror(errno)));
1109 break;
1110 }
1111 }
1112
1113 /* if socket freed ''so'' is PHANTOM and next socket isn't points on it */
1114 if (so_next->so_prev == so)
1115 {
1116 /* mark the socket for termination _after_ it was drained */
1117 so->so_close = 1;
1118 /* No idea about Windows but on Posix, POLLHUP means that we can't send more.
1119 * Actually in the specific error scenario, POLLERR is set as well. */
1120#ifndef RT_OS_WINDOWS
1121 if (CHECK_FD_SET(so, NetworkEvents, rderr))
1122 sofcantsendmore(so);
1123#endif
1124 }
1125 if (so_next->so_prev == so)
1126 so->fUnderPolling = 0;
1127 CONTINUE(tcp);
1128 }
1129
1130 /*
1131 * Check sockets for writing
1132 */
1133 if ( CHECK_FD_SET(so, NetworkEvents, writefds)
1134#ifdef RT_OS_WINDOWS
1135 || WIN_CHECK_FD_SET(so, NetworkEvents, connectfds)
1136#endif
1137 )
1138 {
1139 int fConnectOrWriteSuccess = slirpConnectOrWrite(pData, so, false);
1140 /* slirpConnectOrWrite could return true even if tcp_input called tcp_drop,
1141 * so we should be ready to such situations.
1142 */
1143 if (slirpVerifyAndFreeSocket(pData, so))
1144 CONTINUE(tcp);
1145 else if (!fConnectOrWriteSuccess)
1146 {
1147 so->fUnderPolling = 0;
1148 CONTINUE(tcp);
1149 }
1150 /* slirpConnectionOrWrite succeeded and socket wasn't dropped */
1151 }
1152
1153 /*
1154 * Probe a still-connecting, non-blocking socket
1155 * to check if it's still alive
1156 */
1157#ifdef PROBE_CONN
1158 if (so->so_state & SS_ISFCONNECTING)
1159 {
1160 ret = recv(so->s, (char *)&ret, 0, 0);
1161
1162 if (ret < 0)
1163 {
1164 /* XXX */
1165 if ( soIgnorableErrorCode(errno)
1166 || errno == ENOTCONN)
1167 {
1168 CONTINUE(tcp); /* Still connecting, continue */
1169 }
1170
1171 /* else failed */
1172 so->so_state = SS_NOFDREF;
1173
1174 /* tcp_input will take care of it */
1175 }
1176 else
1177 {
1178 ret = send(so->s, &ret, 0, 0);
1179 if (ret < 0)
1180 {
1181 /* XXX */
1182 if ( soIgnorableErrorCode(errno)
1183 || errno == ENOTCONN)
1184 {
1185 CONTINUE(tcp);
1186 }
1187 /* else failed */
1188 so->so_state = SS_NOFDREF;
1189 }
1190 else
1191 so->so_state &= ~SS_ISFCONNECTING;
1192
1193 }
1194 TCP_INPUT((struct mbuf *)NULL, sizeof(struct ip),so);
1195 } /* SS_ISFCONNECTING */
1196#endif
1197 if (!slirpVerifyAndFreeSocket(pData, so))
1198 so->fUnderPolling = 0;
1199 LOOP_LABEL(tcp, so, so_next);
1200 }
1201
1202 /*
1203 * Now UDP sockets.
1204 * Incoming packets are sent straight away, they're not buffered.
1205 * Incoming UDP data isn't buffered either.
1206 */
1207 QSOCKET_FOREACH(so, so_next, udp)
1208 /* { */
1209#ifdef VBOX_WITH_NAT_UDP_SOCKET_CLONE
1210 if (so->so_cloneOf)
1211 CONTINUE_NO_UNLOCK(udp);
1212#endif
1213#if 0
1214 so->fUnderPolling = 1;
1215 if(slirpVerifyAndFreeSocket(pData, so));
1216 CONTINUE(udp);
1217 so->fUnderPolling = 0;
1218#endif
1219
1220 POLL_UDP_EVENTS(rc, error, so, &NetworkEvents);
1221
1222 LOG_NAT_SOCK(so, UDP, &NetworkEvents, readfds, writefds, xfds);
1223
1224 if (so->s != -1 && CHECK_FD_SET(so, NetworkEvents, readfds))
1225 {
1226 SORECVFROM(pData, so);
1227 }
1228 LOOP_LABEL(udp, so, so_next);
1229 }
1230
1231done:
1232
1233 STAM_PROFILE_STOP(&pData->StatPoll, a);
1234}
1235
1236
1237struct arphdr
1238{
1239 unsigned short ar_hrd; /* format of hardware address */
1240 unsigned short ar_pro; /* format of protocol address */
1241 unsigned char ar_hln; /* length of hardware address */
1242 unsigned char ar_pln; /* length of protocol address */
1243 unsigned short ar_op; /* ARP opcode (command) */
1244
1245 /*
1246 * Ethernet looks like this : This bit is variable sized however...
1247 */
1248 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
1249 unsigned char ar_sip[4]; /* sender IP address */
1250 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
1251 unsigned char ar_tip[4]; /* target IP address */
1252};
1253AssertCompileSize(struct arphdr, 28);
1254
1255static void arp_output(PNATState pData, const uint8_t *pcu8EtherSource, const struct arphdr *pcARPHeaderSource, uint32_t ip4TargetAddress)
1256{
1257 struct ethhdr *pEtherHeaderResponse;
1258 struct arphdr *pARPHeaderResponse;
1259 uint32_t ip4TargetAddressInHostFormat;
1260 struct mbuf *pMbufResponse;
1261
1262 Assert((pcu8EtherSource));
1263 if (!pcu8EtherSource)
1264 return;
1265 ip4TargetAddressInHostFormat = RT_N2H_U32(ip4TargetAddress);
1266
1267 pMbufResponse = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
1268 if (!pMbufResponse)
1269 return;
1270 pEtherHeaderResponse = mtod(pMbufResponse, struct ethhdr *);
1271 /* @note: if_encap will swap src and dst*/
1272 memcpy(pEtherHeaderResponse->h_source, pcu8EtherSource, ETH_ALEN);
1273 pMbufResponse->m_data += ETH_HLEN;
1274 pARPHeaderResponse = mtod(pMbufResponse, struct arphdr *);
1275 pMbufResponse->m_len = sizeof(struct arphdr);
1276
1277 pARPHeaderResponse->ar_hrd = RT_H2N_U16_C(1);
1278 pARPHeaderResponse->ar_pro = RT_H2N_U16_C(ETH_P_IP);
1279 pARPHeaderResponse->ar_hln = ETH_ALEN;
1280 pARPHeaderResponse->ar_pln = 4;
1281 pARPHeaderResponse->ar_op = RT_H2N_U16_C(ARPOP_REPLY);
1282 memcpy(pARPHeaderResponse->ar_sha, special_ethaddr, ETH_ALEN);
1283
1284 if (!slirpMbufTagService(pData, pMbufResponse, (uint8_t)(ip4TargetAddressInHostFormat & ~pData->netmask)))
1285 {
1286 static bool fTagErrorReported;
1287 if (!fTagErrorReported)
1288 {
1289 LogRel(("NAT: couldn't add the tag(PACKET_SERVICE:%d)\n",
1290 (uint8_t)(ip4TargetAddressInHostFormat & ~pData->netmask)));
1291 fTagErrorReported = true;
1292 }
1293 }
1294 pARPHeaderResponse->ar_sha[5] = (uint8_t)(ip4TargetAddressInHostFormat & ~pData->netmask);
1295
1296 memcpy(pARPHeaderResponse->ar_sip, pcARPHeaderSource->ar_tip, 4);
1297 memcpy(pARPHeaderResponse->ar_tha, pcARPHeaderSource->ar_sha, ETH_ALEN);
1298 memcpy(pARPHeaderResponse->ar_tip, pcARPHeaderSource->ar_sip, 4);
1299 if_encap(pData, ETH_P_ARP, pMbufResponse, ETH_ENCAP_URG);
1300}
1301
1302/**
1303 * @note This function will free m!
1304 */
1305static void arp_input(PNATState pData, struct mbuf *m)
1306{
1307 struct ethhdr *pEtherHeader;
1308 struct arphdr *pARPHeader;
1309 uint32_t ip4TargetAddress;
1310
1311 int ar_op;
1312 pEtherHeader = mtod(m, struct ethhdr *);
1313 pARPHeader = (struct arphdr *)&pEtherHeader[1];
1314
1315 ar_op = RT_N2H_U16(pARPHeader->ar_op);
1316 ip4TargetAddress = *(uint32_t*)pARPHeader->ar_tip;
1317
1318 switch (ar_op)
1319 {
1320 case ARPOP_REQUEST:
1321 if ( CTL_CHECK(ip4TargetAddress, CTL_DNS)
1322 || CTL_CHECK(ip4TargetAddress, CTL_ALIAS)
1323 || CTL_CHECK(ip4TargetAddress, CTL_TFTP))
1324 {
1325 slirp_update_guest_addr_guess(pData, *(uint32_t *)pARPHeader->ar_sip, "arp request");
1326 arp_output(pData, pEtherHeader->h_source, pARPHeader, ip4TargetAddress);
1327 break;
1328 }
1329
1330 /* Gratuitous ARP */
1331 if ( *(uint32_t *)pARPHeader->ar_sip == *(uint32_t *)pARPHeader->ar_tip
1332 && ( memcmp(pARPHeader->ar_tha, zerro_ethaddr, ETH_ALEN) == 0
1333 || memcmp(pARPHeader->ar_tha, broadcast_ethaddr, ETH_ALEN) == 0)
1334 && memcmp(pEtherHeader->h_dest, broadcast_ethaddr, ETH_ALEN) == 0)
1335 {
1336 LogRel2(("NAT: gratuitous ARP from %RTnaipv4 at %RTmac\n",
1337 *(uint32_t *)pARPHeader->ar_sip, pARPHeader->ar_sha));
1338 slirp_update_guest_addr_guess(pData, *(uint32_t *)pARPHeader->ar_sip, "gratuitous arp");
1339 slirp_arp_cache_update_or_add(pData, *(uint32_t *)pARPHeader->ar_sip, &pARPHeader->ar_sha[0]);
1340 }
1341 break;
1342
1343 case ARPOP_REPLY:
1344 slirp_arp_cache_update_or_add(pData, *(uint32_t *)pARPHeader->ar_sip, &pARPHeader->ar_sha[0]);
1345 break;
1346
1347 default:
1348 break;
1349 }
1350
1351 m_freem(pData, m);
1352}
1353
1354/**
1355 * Feed a packet into the slirp engine.
1356 *
1357 * @param m Data buffer, m_len is not valid.
1358 * @param cbBuf The length of the data in m.
1359 */
1360void slirp_input(PNATState pData, struct mbuf *m, size_t cbBuf)
1361{
1362 int proto;
1363 static bool fWarnedIpv6;
1364 struct ethhdr *eh;
1365 uint8_t au8Ether[ETH_ALEN];
1366
1367 m->m_len = cbBuf;
1368 if (cbBuf < ETH_HLEN)
1369 {
1370 Log(("NAT: packet having size %d has been ignored\n", m->m_len));
1371 m_freem(pData, m);
1372 return;
1373 }
1374 eh = mtod(m, struct ethhdr *);
1375 proto = RT_N2H_U16(eh->h_proto);
1376
1377 memcpy(au8Ether, eh->h_source, ETH_ALEN);
1378
1379 switch(proto)
1380 {
1381 case ETH_P_ARP:
1382 arp_input(pData, m);
1383 break;
1384
1385 case ETH_P_IP:
1386 /* Update time. Important if the network is very quiet, as otherwise
1387 * the first outgoing connection gets an incorrect timestamp. */
1388 updtime(pData);
1389 m_adj(m, ETH_HLEN);
1390 M_ASSERTPKTHDR(m);
1391 m->m_pkthdr.header = mtod(m, void *);
1392 ip_input(pData, m);
1393 break;
1394
1395 case ETH_P_IPV6:
1396 m_freem(pData, m);
1397 if (!fWarnedIpv6)
1398 {
1399 LogRel(("NAT: IPv6 not supported\n"));
1400 fWarnedIpv6 = true;
1401 }
1402 break;
1403
1404 default:
1405 Log(("NAT: Unsupported protocol %x\n", proto));
1406 m_freem(pData, m);
1407 break;
1408 }
1409}
1410
1411/**
1412 * Output the IP packet to the ethernet device.
1413 *
1414 * @note This function will free m!
1415 */
1416void if_encap(PNATState pData, uint16_t eth_proto, struct mbuf *m, int flags)
1417{
1418 struct ethhdr *eh;
1419 uint8_t *mbuf = NULL;
1420 size_t mlen = 0;
1421 STAM_PROFILE_START(&pData->StatIF_encap, a);
1422 LogFlowFunc(("ENTER: pData:%p, eth_proto:%RX16, m:%p, flags:%d\n",
1423 pData, eth_proto, m, flags));
1424
1425 M_ASSERTPKTHDR(m);
1426
1427 Assert(M_LEADINGSPACE(m) >= ETH_HLEN);
1428 m->m_data -= ETH_HLEN;
1429 m->m_len += ETH_HLEN;
1430 eh = mtod(m, struct ethhdr *);
1431 mlen = m->m_len;
1432
1433 if (memcmp(eh->h_source, special_ethaddr, ETH_ALEN) != 0)
1434 {
1435 struct m_tag *t = m_tag_first(m);
1436 uint8_t u8ServiceId = CTL_ALIAS;
1437 memcpy(eh->h_dest, eh->h_source, ETH_ALEN);
1438 memcpy(eh->h_source, special_ethaddr, ETH_ALEN);
1439 Assert(memcmp(eh->h_dest, special_ethaddr, ETH_ALEN) != 0);
1440 if (memcmp(eh->h_dest, zerro_ethaddr, ETH_ALEN) == 0)
1441 {
1442 /* don't do anything */
1443 m_freem(pData, m);
1444 goto done;
1445 }
1446 if ( t
1447 && (t = m_tag_find(m, PACKET_SERVICE, NULL)))
1448 {
1449 Assert(t);
1450 u8ServiceId = *(uint8_t *)&t[1];
1451 }
1452 eh->h_source[5] = u8ServiceId;
1453 }
1454 /*
1455 * we're processing the chain, that isn't not expected.
1456 */
1457 Assert((!m->m_next));
1458 if (m->m_next)
1459 {
1460 Log(("NAT: if_encap's recived the chain, dropping...\n"));
1461 m_freem(pData, m);
1462 goto done;
1463 }
1464 mbuf = mtod(m, uint8_t *);
1465 eh->h_proto = RT_H2N_U16(eth_proto);
1466 LogFunc(("eh(dst:%RTmac, src:%RTmac)\n", eh->h_dest, eh->h_source));
1467 if (flags & ETH_ENCAP_URG)
1468 slirp_urg_output(pData->pvUser, m, mbuf, mlen);
1469 else
1470 slirp_output(pData->pvUser, m, mbuf, mlen);
1471done:
1472 STAM_PROFILE_STOP(&pData->StatIF_encap, a);
1473 LogFlowFuncLeave();
1474}
1475
1476
1477void
1478slirp_update_guest_addr_guess(PNATState pData, uint32_t guess, const char *msg)
1479{
1480 Assert(msg != NULL);
1481
1482 if (pData->guest_addr_guess.s_addr == guess)
1483 {
1484 LogRel2(("NAT: guest address guess %RTnaipv4 re-confirmed by %s\n",
1485 pData->guest_addr_guess.s_addr, msg));
1486 return;
1487 }
1488
1489 if (pData->guest_addr_guess.s_addr == INADDR_ANY)
1490 {
1491 pData->guest_addr_guess.s_addr = guess;
1492 LogRel(("NAT: guest address guess set to %RTnaipv4 by %s\n",
1493 pData->guest_addr_guess.s_addr, msg));
1494 return;
1495 }
1496 else
1497 {
1498 LogRel(("NAT: guest address guess changed from %RTnaipv4 to %RTnaipv4 by %s\n",
1499 pData->guest_addr_guess.s_addr, guess, msg));
1500 pData->guest_addr_guess.s_addr = guess;
1501 return;
1502 }
1503}
1504
1505
1506static struct port_forward_rule *
1507slirp_find_redirect(PNATState pData,
1508 int is_udp,
1509 struct in_addr host_addr, int host_port,
1510 struct in_addr guest_addr, int guest_port)
1511{
1512 struct port_forward_rule *rule;
1513 uint16_t proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
1514
1515 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
1516 {
1517 if ( rule->proto == proto
1518 && rule->host_port == host_port
1519 && rule->bind_ip.s_addr == host_addr.s_addr
1520 && rule->guest_port == guest_port
1521 && rule->guest_addr.s_addr == guest_addr.s_addr)
1522 {
1523 return rule;
1524 }
1525 }
1526
1527 return NULL;
1528}
1529
1530
1531int slirp_add_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1532 struct in_addr guest_addr, int guest_port)
1533{
1534 struct port_forward_rule *rule;
1535
1536 rule = slirp_find_redirect(pData, is_udp, host_addr, host_port, guest_addr, guest_port);
1537 if (rule != NULL) /* rule has been already registered */
1538 {
1539 /* XXX: this shouldn't happen */
1540 return 0;
1541 }
1542
1543 rule = RTMemAllocZ(sizeof(struct port_forward_rule));
1544 if (rule == NULL)
1545 return 1;
1546
1547 rule->proto = (is_udp ? IPPROTO_UDP : IPPROTO_TCP);
1548 rule->bind_ip.s_addr = host_addr.s_addr;
1549 rule->host_port = host_port;
1550 rule->guest_addr.s_addr = guest_addr.s_addr;
1551 rule->guest_port = guest_port;
1552
1553 if (rule->proto == IPPROTO_UDP)
1554 rule->so = udp_listen(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port),
1555 rule->guest_addr.s_addr, RT_H2N_U16(rule->guest_port), 0);
1556 else
1557 rule->so = solisten(pData, rule->bind_ip.s_addr, RT_H2N_U16(rule->host_port),
1558 rule->guest_addr.s_addr, RT_H2N_U16(rule->guest_port), 0);
1559
1560 if (rule->so == NULL)
1561 {
1562 LogRel(("NAT: failed to redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
1563 rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
1564 rule->bind_ip.s_addr, rule->host_port,
1565 guest_addr, rule->guest_port));
1566 RTMemFree(rule);
1567 return 1;
1568 }
1569
1570 LogRel(("NAT: set redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
1571 rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
1572 rule->bind_ip.s_addr, rule->host_port,
1573 guest_addr, rule->guest_port));
1574
1575 LIST_INSERT_HEAD(&pData->port_forward_rule_head, rule, list);
1576 return 0;
1577}
1578
1579
1580int slirp_remove_redirect(PNATState pData, int is_udp, struct in_addr host_addr, int host_port,
1581 struct in_addr guest_addr, int guest_port)
1582{
1583 struct port_forward_rule *rule;
1584
1585 rule = slirp_find_redirect(pData, is_udp, host_addr, host_port, guest_addr, guest_port);
1586 if (rule == NULL)
1587 {
1588 LogRel(("NAT: unable to find redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
1589 rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
1590 rule->bind_ip.s_addr, rule->host_port,
1591 guest_addr.s_addr, rule->guest_port));
1592 return 0;
1593 }
1594
1595 LogRel(("NAT: remove redirect %s %RTnaipv4:%d -> %RTnaipv4:%d\n",
1596 rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
1597 rule->bind_ip.s_addr, rule->host_port,
1598 guest_addr.s_addr, rule->guest_port));
1599
1600 if (rule->so != NULL)
1601 {
1602 if (is_udp)
1603 udp_detach(pData, rule->so);
1604 else
1605 tcp_close(pData, sototcpcb(rule->so));
1606 }
1607
1608 LIST_REMOVE(rule, list);
1609 RTMemFree(rule);
1610 return 0;
1611}
1612
1613
1614#if defined(RT_OS_WINDOWS)
1615HANDLE *slirp_get_events(PNATState pData)
1616{
1617 return pData->phEvents;
1618}
1619void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index)
1620{
1621 pData->phEvents[index] = hEvent;
1622}
1623#endif
1624
1625unsigned int slirp_get_timeout_ms(PNATState pData)
1626{
1627 if (link_up)
1628 {
1629 if (time_fasttimo)
1630 return 2;
1631 if (do_slowtimo)
1632 return 500; /* see PR_SLOWHZ */
1633 }
1634 return 3600*1000; /* one hour */
1635}
1636
1637#ifndef RT_OS_WINDOWS
1638int slirp_get_nsock(PNATState pData)
1639{
1640 return pData->nsock;
1641}
1642#endif
1643
1644/*
1645 * this function called from NAT thread
1646 */
1647void slirp_post_sent(PNATState pData, void *pvArg)
1648{
1649 struct mbuf *m = (struct mbuf *)pvArg;
1650 m_freem(pData, m);
1651}
1652
1653void slirp_set_dhcp_TFTP_prefix(PNATState pData, const char *tftpPrefix)
1654{
1655 Log2(("tftp_prefix: %s\n", tftpPrefix));
1656 tftp_prefix = tftpPrefix;
1657}
1658
1659void slirp_set_dhcp_TFTP_bootfile(PNATState pData, const char *bootFile)
1660{
1661 Log2(("bootFile: %s\n", bootFile));
1662 bootp_filename = bootFile;
1663}
1664
1665void slirp_set_dhcp_next_server(PNATState pData, const char *next_server)
1666{
1667 Log2(("next_server: %s\n", next_server));
1668 if (next_server == NULL)
1669 pData->tftp_server.s_addr = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_TFTP);
1670 else
1671 inet_aton(next_server, &pData->tftp_server);
1672}
1673
1674int slirp_set_binding_address(PNATState pData, char *addr)
1675{
1676 if (addr == NULL || (inet_aton(addr, &pData->bindIP) == 0))
1677 {
1678 pData->bindIP.s_addr = INADDR_ANY;
1679 return 1;
1680 }
1681 return 0;
1682}
1683
1684void slirp_set_dhcp_dns_proxy(PNATState pData, bool fDNSProxy)
1685{
1686 if (!pData->fUseHostResolver)
1687 {
1688 Log2(("NAT: DNS proxy switched %s\n", (fDNSProxy ? "on" : "off")));
1689 pData->fUseDnsProxy = fDNSProxy;
1690 }
1691 else if (fDNSProxy)
1692 LogRel(("NAT: Host Resolver conflicts with DNS proxy, the last one was forcely ignored\n"));
1693}
1694
1695#define CHECK_ARG(name, val, lim_min, lim_max) \
1696 do { \
1697 if ((val) < (lim_min) || (val) > (lim_max)) \
1698 { \
1699 LogRel(("NAT: (" #name ":%d) has been ignored, " \
1700 "because out of range (%d, %d)\n", (val), (lim_min), (lim_max))); \
1701 return; \
1702 } \
1703 else \
1704 LogRel(("NAT: (" #name ":%d)\n", (val))); \
1705 } while (0)
1706
1707void slirp_set_somaxconn(PNATState pData, int iSoMaxConn)
1708{
1709 LogFlowFunc(("iSoMaxConn:%d\n", iSoMaxConn));
1710 /* Conditions */
1711 if (iSoMaxConn > SOMAXCONN)
1712 {
1713 LogRel(("NAT: value of somaxconn(%d) bigger than SOMAXCONN(%d)\n", iSoMaxConn, SOMAXCONN));
1714 iSoMaxConn = SOMAXCONN;
1715 }
1716
1717 if (iSoMaxConn < 1)
1718 {
1719 LogRel(("NAT: proposed value(%d) of somaxconn is invalid, default value is used (%d)\n", iSoMaxConn, pData->soMaxConn));
1720 LogFlowFuncLeave();
1721 return;
1722 }
1723
1724 /* Asignment */
1725 if (pData->soMaxConn != iSoMaxConn)
1726 {
1727 LogRel(("NAT: value of somaxconn has been changed from %d to %d\n",
1728 pData->soMaxConn, iSoMaxConn));
1729 pData->soMaxConn = iSoMaxConn;
1730 }
1731 LogFlowFuncLeave();
1732}
1733/* don't allow user set less 8kB and more than 1M values */
1734#define _8K_1M_CHECK_ARG(name, val) CHECK_ARG(name, (val), 8, 1024)
1735void slirp_set_rcvbuf(PNATState pData, int kilobytes)
1736{
1737 _8K_1M_CHECK_ARG("SOCKET_RCVBUF", kilobytes);
1738 pData->socket_rcv = kilobytes;
1739}
1740void slirp_set_sndbuf(PNATState pData, int kilobytes)
1741{
1742 _8K_1M_CHECK_ARG("SOCKET_SNDBUF", kilobytes);
1743 pData->socket_snd = kilobytes * _1K;
1744}
1745void slirp_set_tcp_rcvspace(PNATState pData, int kilobytes)
1746{
1747 _8K_1M_CHECK_ARG("TCP_RCVSPACE", kilobytes);
1748 tcp_rcvspace = kilobytes * _1K;
1749}
1750void slirp_set_tcp_sndspace(PNATState pData, int kilobytes)
1751{
1752 _8K_1M_CHECK_ARG("TCP_SNDSPACE", kilobytes);
1753 tcp_sndspace = kilobytes * _1K;
1754}
1755
1756/*
1757 * Looking for Ether by ip in ARP-cache
1758 * Note: it´s responsible of caller to allocate buffer for result
1759 * @returns iprt status code
1760 */
1761int slirp_arp_lookup_ether_by_ip(PNATState pData, uint32_t ip, uint8_t *ether)
1762{
1763 struct arp_cache_entry *ac;
1764
1765 if (ether == NULL)
1766 return VERR_INVALID_PARAMETER;
1767
1768 if (LIST_EMPTY(&pData->arp_cache))
1769 return VERR_NOT_FOUND;
1770
1771 LIST_FOREACH(ac, &pData->arp_cache, list)
1772 {
1773 if ( ac->ip == ip
1774 && memcmp(ac->ether, broadcast_ethaddr, ETH_ALEN) != 0)
1775 {
1776 memcpy(ether, ac->ether, ETH_ALEN);
1777 return VINF_SUCCESS;
1778 }
1779 }
1780 return VERR_NOT_FOUND;
1781}
1782
1783/*
1784 * Looking for IP by Ether in ARP-cache
1785 * Note: it´s responsible of caller to allocate buffer for result
1786 * @returns 0 - if found, 1 - otherwise
1787 */
1788int slirp_arp_lookup_ip_by_ether(PNATState pData, const uint8_t *ether, uint32_t *ip)
1789{
1790 struct arp_cache_entry *ac;
1791 *ip = INADDR_ANY;
1792
1793 if (LIST_EMPTY(&pData->arp_cache))
1794 return VERR_NOT_FOUND;
1795
1796 LIST_FOREACH(ac, &pData->arp_cache, list)
1797 {
1798 if (memcmp(ether, ac->ether, ETH_ALEN) == 0)
1799 {
1800 *ip = ac->ip;
1801 return VINF_SUCCESS;
1802 }
1803 }
1804 return VERR_NOT_FOUND;
1805}
1806
1807void slirp_arp_who_has(PNATState pData, uint32_t dst)
1808{
1809 struct mbuf *m;
1810 struct ethhdr *ehdr;
1811 struct arphdr *ahdr;
1812 static bool fWarned = false;
1813 LogFlowFunc(("ENTER: %RTnaipv4\n", dst));
1814
1815 /* ARP request WHO HAS 0.0.0.0 is one of the signals
1816 * that something has been broken at Slirp. Investigating
1817 * pcap dumps it's easy to miss warning ARP requests being
1818 * focused on investigation of other protocols flow.
1819 */
1820#ifdef DEBUG_vvl
1821 Assert((dst != INADDR_ANY));
1822 NOREF(fWarned);
1823#else
1824 if ( dst == INADDR_ANY
1825 && !fWarned)
1826 {
1827 LogRel(("NAT:ARP: \"WHO HAS INADDR_ANY\" request has been detected\n"));
1828 fWarned = true;
1829 }
1830#endif /* !DEBUG_vvl */
1831
1832 m = m_getcl(pData, M_NOWAIT, MT_HEADER, M_PKTHDR);
1833 if (m == NULL)
1834 {
1835 Log(("NAT: Can't alloc mbuf for ARP request\n"));
1836 LogFlowFuncLeave();
1837 return;
1838 }
1839 ehdr = mtod(m, struct ethhdr *);
1840 memset(ehdr->h_source, 0xff, ETH_ALEN);
1841 ahdr = (struct arphdr *)&ehdr[1];
1842 ahdr->ar_hrd = RT_H2N_U16_C(1);
1843 ahdr->ar_pro = RT_H2N_U16_C(ETH_P_IP);
1844 ahdr->ar_hln = ETH_ALEN;
1845 ahdr->ar_pln = 4;
1846 ahdr->ar_op = RT_H2N_U16_C(ARPOP_REQUEST);
1847 memcpy(ahdr->ar_sha, special_ethaddr, ETH_ALEN);
1848 /* we assume that this request come from gw, but not from DNS or TFTP */
1849 ahdr->ar_sha[5] = CTL_ALIAS;
1850 *(uint32_t *)ahdr->ar_sip = RT_H2N_U32(RT_N2H_U32(pData->special_addr.s_addr) | CTL_ALIAS);
1851 memset(ahdr->ar_tha, 0xff, ETH_ALEN); /*broadcast*/
1852 *(uint32_t *)ahdr->ar_tip = dst;
1853 /* warn!!! should falls in mbuf minimal size */
1854 m->m_len = sizeof(struct arphdr) + ETH_HLEN;
1855 m->m_data += ETH_HLEN;
1856 m->m_len -= ETH_HLEN;
1857 if_encap(pData, ETH_P_ARP, m, ETH_ENCAP_URG);
1858 LogFlowFuncLeave();
1859}
1860#ifdef VBOX_WITH_DNSMAPPING_IN_HOSTRESOLVER
1861void slirp_add_host_resolver_mapping(PNATState pData, const char *pszHostName, const char *pszHostNamePattern, uint32_t u32HostIP)
1862{
1863 LogFlowFunc(("ENTER: pszHostName:%s, pszHostNamePattern:%s u32HostIP:%RTnaipv4\n",
1864 pszHostName ? pszHostName : "(null)",
1865 pszHostNamePattern ? pszHostNamePattern : "(null)",
1866 u32HostIP));
1867 if ( ( pszHostName
1868 || pszHostNamePattern)
1869 && u32HostIP != INADDR_ANY
1870 && u32HostIP != INADDR_BROADCAST)
1871 {
1872 PDNSMAPPINGENTRY pDnsMapping = RTMemAllocZ(sizeof(DNSMAPPINGENTRY));
1873 if (!pDnsMapping)
1874 {
1875 LogFunc(("Can't allocate DNSMAPPINGENTRY\n"));
1876 LogFlowFuncLeave();
1877 return;
1878 }
1879 pDnsMapping->u32IpAddress = u32HostIP;
1880 if (pszHostName)
1881 pDnsMapping->pszCName = RTStrDup(pszHostName);
1882 else if (pszHostNamePattern)
1883 pDnsMapping->pszPattern = RTStrDup(pszHostNamePattern);
1884 if ( !pDnsMapping->pszCName
1885 && !pDnsMapping->pszPattern)
1886 {
1887 LogFunc(("Can't allocate enough room for %s\n", pszHostName ? pszHostName : pszHostNamePattern));
1888 RTMemFree(pDnsMapping);
1889 LogFlowFuncLeave();
1890 return;
1891 }
1892 LIST_INSERT_HEAD(&pData->DNSMapHead, pDnsMapping, MapList);
1893 LogRel(("NAT: user-defined mapping %s: %RTnaipv4 is registered\n",
1894 pDnsMapping->pszCName ? pDnsMapping->pszCName : pDnsMapping->pszPattern,
1895 pDnsMapping->u32IpAddress));
1896 }
1897 LogFlowFuncLeave();
1898}
1899#endif
1900
1901/* updates the arp cache
1902 * @note: this is helper function, slirp_arp_cache_update_or_add should be used.
1903 * @returns 0 - if has found and updated
1904 * 1 - if hasn't found.
1905 */
1906static inline int slirp_arp_cache_update(PNATState pData, uint32_t dst, const uint8_t *mac)
1907{
1908 struct arp_cache_entry *ac;
1909 Assert(( memcmp(mac, broadcast_ethaddr, ETH_ALEN)
1910 && memcmp(mac, zerro_ethaddr, ETH_ALEN)));
1911 LIST_FOREACH(ac, &pData->arp_cache, list)
1912 {
1913 if (ac->ip == dst)
1914 {
1915 memcpy(ac->ether, mac, ETH_ALEN);
1916 return 0;
1917 }
1918 }
1919 return 1;
1920}
1921
1922/**
1923 * add entry to the arp cache
1924 * @note: this is helper function, slirp_arp_cache_update_or_add should be used.
1925 */
1926static inline void slirp_arp_cache_add(PNATState pData, uint32_t ip, const uint8_t *ether)
1927{
1928 struct arp_cache_entry *ac = NULL;
1929 Assert(( memcmp(ether, broadcast_ethaddr, ETH_ALEN)
1930 && memcmp(ether, zerro_ethaddr, ETH_ALEN)));
1931 ac = RTMemAllocZ(sizeof(struct arp_cache_entry));
1932 if (ac == NULL)
1933 {
1934 Log(("NAT: Can't allocate arp cache entry\n"));
1935 return;
1936 }
1937 ac->ip = ip;
1938 memcpy(ac->ether, ether, ETH_ALEN);
1939 LIST_INSERT_HEAD(&pData->arp_cache, ac, list);
1940}
1941
1942/* updates or adds entry to the arp cache
1943 * @returns 0 - if has found and updated
1944 * 1 - if hasn't found.
1945 */
1946int slirp_arp_cache_update_or_add(PNATState pData, uint32_t dst, const uint8_t *mac)
1947{
1948 if ( !memcmp(mac, broadcast_ethaddr, ETH_ALEN)
1949 || !memcmp(mac, zerro_ethaddr, ETH_ALEN))
1950 {
1951 static bool fBroadcastEtherAddReported;
1952 if (!fBroadcastEtherAddReported)
1953 {
1954 LogRel(("NAT: Attempt to add pair [%RTmac:%RTnaipv4] in ARP cache was ignored\n",
1955 mac, dst));
1956 fBroadcastEtherAddReported = true;
1957 }
1958 return 1;
1959 }
1960 if (slirp_arp_cache_update(pData, dst, mac))
1961 slirp_arp_cache_add(pData, dst, mac);
1962
1963 return 0;
1964}
1965
1966
1967void slirp_set_mtu(PNATState pData, int mtu)
1968{
1969 if (mtu < 20 || mtu >= 16000)
1970 {
1971 LogRel(("NAT: mtu(%d) is out of range (20;16000] mtu forcely assigned to 1500\n", mtu));
1972 mtu = 1500;
1973 }
1974 /* MTU is maximum transition unit on */
1975 if_mtu =
1976 if_mru = mtu;
1977}
1978
1979/**
1980 * Info handler.
1981 */
1982void slirp_info(PNATState pData, const void *pvArg, const char *pszArgs)
1983{
1984 struct socket *so, *so_next;
1985 struct arp_cache_entry *ac;
1986 struct port_forward_rule *rule;
1987 PCDBGFINFOHLP pHlp = (PCDBGFINFOHLP)pvArg;
1988 NOREF(pszArgs);
1989
1990 pHlp->pfnPrintf(pHlp, "NAT parameters: MTU=%d\n", if_mtu);
1991 pHlp->pfnPrintf(pHlp, "NAT TCP ports:\n");
1992 QSOCKET_FOREACH(so, so_next, tcp)
1993 /* { */
1994 pHlp->pfnPrintf(pHlp, " %R[natsock]\n", so);
1995 }
1996
1997 pHlp->pfnPrintf(pHlp, "NAT UDP ports:\n");
1998 QSOCKET_FOREACH(so, so_next, udp)
1999 /* { */
2000 pHlp->pfnPrintf(pHlp, " %R[natsock]\n", so);
2001 }
2002
2003 pHlp->pfnPrintf(pHlp, "NAT ARP cache:\n");
2004 LIST_FOREACH(ac, &pData->arp_cache, list)
2005 {
2006 pHlp->pfnPrintf(pHlp, " %RTnaipv4 %RTmac\n", ac->ip, &ac->ether);
2007 }
2008
2009 pHlp->pfnPrintf(pHlp, "NAT rules:\n");
2010 LIST_FOREACH(rule, &pData->port_forward_rule_head, list)
2011 {
2012 pHlp->pfnPrintf(pHlp, " %s %d => %RTnaipv4:%d %c\n",
2013 rule->proto == IPPROTO_UDP ? "UDP" : "TCP",
2014 rule->host_port, rule->guest_addr.s_addr, rule->guest_port,
2015 rule->activated ? ' ' : '*');
2016 }
2017}
2018
2019/**
2020 * @note: NATState::fUseHostResolver could be changed in bootp.c::dhcp_decode
2021 * @note: this function is executed on GUI/VirtualBox or main/VBoxHeadless thread.
2022 * @note: this function can potentially race with bootp.c::dhcp_decode (except Darwin)
2023 */
2024int slirp_host_network_configuration_change_strategy_selector(const PNATState pData)
2025{
2026 if (pData->fUseHostResolverPermanent)
2027 return VBOX_NAT_DNS_HOSTRESOLVER;
2028
2029 if (pData->fUseDnsProxy) {
2030#if HAVE_NOTIFICATION_FOR_DNS_UPDATE /* XXX */ && !defined(RT_OS_WINDOWS)
2031 /* We dont conflict with bootp.c::dhcp_decode */
2032 struct rcp_state rcp_state;
2033 int rc;
2034
2035 rcp_state.rcps_flags |= RCPSF_IGNORE_IPV6;
2036 rc = rcp_parse(&rcp_state, RESOLV_CONF_FILE);
2037 LogRelFunc(("NAT: rcp_parse:%Rrc old domain:%s new domain:%s\n",
2038 rc, LIST_EMPTY(&pData->pDomainList)
2039 ? "(null)"
2040 : LIST_FIRST(&pData->pDomainList)->dd_pszDomain,
2041 rcp_state.rcps_domain));
2042 if ( RT_FAILURE(rc)
2043 || LIST_EMPTY(&pData->pDomainList))
2044 return VBOX_NAT_DNS_DNSPROXY;
2045
2046 if ( rcp_state.rcps_domain
2047 && strcmp(rcp_state.rcps_domain, LIST_FIRST(&pData->pDomainList)->dd_pszDomain) == 0)
2048 return VBOX_NAT_DNS_DNSPROXY;
2049 else
2050 return VBOX_NAT_DNS_EXTERNAL;
2051#else
2052 /* copy domain name */
2053 /* domain only compare with coy version */
2054 return VBOX_NAT_DNS_DNSPROXY;
2055#endif
2056 }
2057 return VBOX_NAT_DNS_EXTERNAL;
2058}
Note: See TracBrowser for help on using the repository browser.

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