VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use