VirtualBox

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

最後變更 在這個檔案從43575是 43233,由 vboxsync 提交於 13 年 前

NAT: destroy really all memory in drvNATDestruct

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

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