VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp@ 50068

Last change on this file since 50068 was 50068, checked in by vboxsync, 11 years ago

Add ifdefed out code to use debug helper for raw ICMP sockets.
Add to the makefile commented out option to enable it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.3 KB
Line 
1/* $Id: VBoxNetLwipNAT.cpp 50068 2014-01-14 02:58:46Z vboxsync $ */
2/** @file
3 * VBoxNetNAT - NAT Service for connecting to IntNet.
4 */
5
6/*
7 * Copyright (C) 2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "winutils.h"
19
20#include <VBox/com/assert.h>
21#include <VBox/com/com.h>
22#include <VBox/com/listeners.h>
23#include <VBox/com/string.h>
24#include <VBox/com/Guid.h>
25#include <VBox/com/array.h>
26#include <VBox/com/ErrorInfo.h>
27#include <VBox/com/errorprint.h>
28#include <VBox/com/VirtualBox.h>
29
30#include <iprt/net.h>
31#include <iprt/initterm.h>
32#include <iprt/alloca.h>
33#ifndef RT_OS_WINDOWS
34# include <arpa/inet.h>
35#endif
36#include <iprt/err.h>
37#include <iprt/time.h>
38#include <iprt/timer.h>
39#include <iprt/thread.h>
40#include <iprt/stream.h>
41#include <iprt/path.h>
42#include <iprt/param.h>
43#include <iprt/pipe.h>
44#include <iprt/getopt.h>
45#include <iprt/string.h>
46#include <iprt/mem.h>
47#include <iprt/message.h>
48#include <iprt/req.h>
49#include <iprt/file.h>
50#include <iprt/semaphore.h>
51#include <iprt/cpp/utils.h>
52#define LOG_GROUP LOG_GROUP_NAT_SERVICE
53#include <VBox/log.h>
54
55#include <VBox/sup.h>
56#include <VBox/intnet.h>
57#include <VBox/intnetinline.h>
58#include <VBox/vmm/pdmnetinline.h>
59#include <VBox/vmm/vmm.h>
60#include <VBox/version.h>
61
62#ifndef RT_OS_WINDOWS
63# include <sys/poll.h>
64# include <sys/socket.h>
65# include <netinet/in.h>
66# ifdef RT_OS_LINUX
67# include <linux/icmp.h> /* ICMP_FILTER */
68# endif
69# include <netinet/icmp6.h>
70#endif
71
72#include <map>
73#include <vector>
74#include <string>
75
76#include "../NetLib/VBoxNetLib.h"
77#include "../NetLib/VBoxNetBaseService.h"
78#include "../NetLib/utils.h"
79#include "VBoxLwipCore.h"
80
81extern "C"
82{
83/* bunch of LWIP headers */
84#include "lwip/opt.h"
85#ifdef LWIP_SOCKET
86# undef LWIP_SOCKET
87# define LWIP_SOCKET 0
88#endif
89#include "lwip/sys.h"
90#include "lwip/pbuf.h"
91#include "lwip/netif.h"
92#include "lwip/ethip6.h"
93#include "lwip/nd6.h" // for proxy_na_hook
94#include "lwip/mld6.h"
95#include "lwip/tcpip.h"
96#include "netif/etharp.h"
97
98#include "proxy.h"
99#include "pxremap.h"
100#include "portfwd.h"
101}
102
103
104#if defined(VBOX_RAWSOCK_DEBUG_HELPER) \
105 && (defined(VBOX_WITH_HARDENING) \
106 || defined(RT_OS_WINDOWS) \
107 || defined(RT_OS_DARWIN))
108# error Have you forgotten to turn off VBOX_RAWSOCK_DEBUG_HELPER?
109#endif
110
111#ifdef VBOX_RAWSOCK_DEBUG_HELPER
112extern "C" int getrawsock(int type);
113#endif
114
115#include "../NetLib/VBoxPortForwardString.h"
116
117static RTGETOPTDEF g_aGetOptDef[] =
118{
119 { "--port-forward4", 'p', RTGETOPT_REQ_STRING },
120 { "--port-forward6", 'P', RTGETOPT_REQ_STRING }
121};
122
123typedef struct NATSEVICEPORTFORWARDRULE
124{
125 PORTFORWARDRULE Pfr;
126 fwspec FWSpec;
127} NATSEVICEPORTFORWARDRULE, *PNATSEVICEPORTFORWARDRULE;
128
129typedef std::vector<NATSEVICEPORTFORWARDRULE> VECNATSERVICEPF;
130typedef VECNATSERVICEPF::iterator ITERATORNATSERVICEPF;
131typedef VECNATSERVICEPF::const_iterator CITERATORNATSERVICEPF;
132
133static int fetchNatPortForwardRules(const ComNatPtr&, bool, VECNATSERVICEPF&);
134
135
136class VBoxNetLwipNAT: public VBoxNetBaseService, public NATNetworkEventAdapter
137{
138 friend class NATNetworkListener;
139 public:
140 VBoxNetLwipNAT(SOCKET icmpsock4, SOCKET icmpsock6);
141 virtual ~VBoxNetLwipNAT();
142 void usage(){ /* @todo: should be implemented */ };
143 int run();
144 virtual int init(void);
145 virtual int parseOpt(int rc, const RTGETOPTUNION& getOptVal);
146 /* VBoxNetNAT always needs Main */
147 virtual bool isMainNeeded() const { return true; }
148 virtual int processFrame(void *, size_t);
149 virtual int processGSO(PCPDMNETWORKGSO, size_t);
150 virtual int processUDP(void *, size_t) { return VERR_IGNORED; }
151
152 private:
153 struct proxy_options m_ProxyOptions;
154 struct sockaddr_in m_src4;
155 struct sockaddr_in6 m_src6;
156 /**
157 * place for registered local interfaces.
158 */
159 ip4_lomap m_lo2off[10];
160 ip4_lomap_desc m_loOptDescriptor;
161
162 uint16_t m_u16Mtu;
163 netif m_LwipNetIf;
164
165 /* Our NAT network descriptor in Main */
166 ComPtr<INATNetwork> m_net;
167 ComNatListenerPtr m_listener;
168
169 ComPtr<IHost> m_host;
170 ComNatListenerPtr m_vboxListener;
171 static INTNETSEG aXmitSeg[64];
172
173 HRESULT HandleEvent(VBoxEventType_T aEventType, IEvent *pEvent);
174
175 const char **getHostNameservers();
176
177 /* Only for debug needs, by default NAT service should load rules from SVC
178 * on startup, and then on sync them on events.
179 */
180 bool fDontLoadRulesOnStartup;
181 static void onLwipTcpIpInit(void *arg);
182 static void onLwipTcpIpFini(void *arg);
183 static err_t netifInit(netif *pNetif);
184 static err_t netifLinkoutput(netif *pNetif, pbuf *pBuf);
185 static int intNetThreadRecv(RTTHREAD, void *);
186
187 VECNATSERVICEPF m_vecPortForwardRule4;
188 VECNATSERVICEPF m_vecPortForwardRule6;
189
190 static int natServicePfRegister(NATSEVICEPORTFORWARDRULE& natServicePf);
191 static int natServiceProcessRegisteredPf(VECNATSERVICEPF& vecPf);
192};
193
194
195static VBoxNetLwipNAT *g_pLwipNat;
196INTNETSEG VBoxNetLwipNAT::aXmitSeg[64];
197
198/**
199 * @note: this work on Event thread.
200 */
201HRESULT VBoxNetLwipNAT::HandleEvent(VBoxEventType_T aEventType,
202 IEvent *pEvent)
203{
204 HRESULT hrc = S_OK;
205 switch (aEventType)
206 {
207 case VBoxEventType_OnNATNetworkSetting:
208 {
209 ComPtr<INATNetworkSettingEvent> evSettings(pEvent);
210 // XXX: only handle IPv6 default route for now
211
212 if (!m_ProxyOptions.ipv6_enabled)
213 {
214 break;
215 }
216
217 BOOL fIPv6DefaultRoute = FALSE;
218 hrc = evSettings->COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(&fIPv6DefaultRoute);
219 AssertReturn(SUCCEEDED(hrc), hrc);
220
221 if (m_ProxyOptions.ipv6_defroute == fIPv6DefaultRoute)
222 {
223 break;
224 }
225
226 m_ProxyOptions.ipv6_defroute = fIPv6DefaultRoute;
227 tcpip_callback_with_block(proxy_rtadvd_do_quick, &m_LwipNetIf, 0);
228
229 break;
230 }
231
232 case VBoxEventType_OnNATNetworkPortForward:
233 {
234 com::Bstr name, strHostAddr, strGuestAddr;
235 LONG lHostPort, lGuestPort;
236 BOOL fCreateFW, fIPv6FW;
237 NATProtocol_T proto = NATProtocol_TCP;
238
239
240 ComPtr<INATNetworkPortForwardEvent> pfEvt = pEvent;
241
242 hrc = pfEvt->COMGETTER(Name)(name.asOutParam());
243 AssertReturn(SUCCEEDED(hrc), hrc);
244
245 hrc = pfEvt->COMGETTER(Proto)(&proto);
246 AssertReturn(SUCCEEDED(hrc), hrc);
247
248 hrc = pfEvt->COMGETTER(HostIp)(strHostAddr.asOutParam());
249 AssertReturn(SUCCEEDED(hrc), hrc);
250
251 hrc = pfEvt->COMGETTER(HostPort)(&lHostPort);
252 AssertReturn(SUCCEEDED(hrc), hrc);
253
254 hrc = pfEvt->COMGETTER(GuestIp)(strGuestAddr.asOutParam());
255 AssertReturn(SUCCEEDED(hrc), hrc);
256
257 hrc = pfEvt->COMGETTER(GuestPort)(&lGuestPort);
258 AssertReturn(SUCCEEDED(hrc), hrc);
259
260 hrc = pfEvt->COMGETTER(Create)(&fCreateFW);
261 AssertReturn(SUCCEEDED(hrc), hrc);
262
263 hrc = pfEvt->COMGETTER(Ipv6)(&fIPv6FW);
264 AssertReturn(SUCCEEDED(hrc), hrc);
265
266 VECNATSERVICEPF& rules = (fIPv6FW ?
267 m_vecPortForwardRule6 :
268 m_vecPortForwardRule4);
269
270 NATSEVICEPORTFORWARDRULE r;
271
272 RT_ZERO(r);
273
274 if (name.length() > sizeof(r.Pfr.szPfrName))
275 {
276 hrc = E_INVALIDARG;
277 goto port_forward_done;
278 }
279
280 r.Pfr.fPfrIPv6 = fIPv6FW;
281
282 switch (proto)
283 {
284 case NATProtocol_TCP:
285 r.Pfr.iPfrProto = IPPROTO_TCP;
286 break;
287 case NATProtocol_UDP:
288 r.Pfr.iPfrProto = IPPROTO_UDP;
289 break;
290 default:
291 goto port_forward_done;
292 }
293
294
295 RTStrPrintf(r.Pfr.szPfrName, sizeof(r.Pfr.szPfrName),
296 "%s", com::Utf8Str(name).c_str());
297
298 RTStrPrintf(r.Pfr.szPfrHostAddr, sizeof(r.Pfr.szPfrHostAddr),
299 "%s", com::Utf8Str(strHostAddr).c_str());
300
301 /* XXX: limits should be checked */
302 r.Pfr.u16PfrHostPort = (uint16_t)lHostPort;
303
304 RTStrPrintf(r.Pfr.szPfrGuestAddr, sizeof(r.Pfr.szPfrGuestAddr),
305 "%s", com::Utf8Str(strGuestAddr).c_str());
306
307 /* XXX: limits should be checked */
308 r.Pfr.u16PfrGuestPort = (uint16_t)lGuestPort;
309
310 if (fCreateFW) /* Addition */
311 {
312 rules.push_back(r);
313
314 natServicePfRegister(rules.back());
315 }
316 else /* Deletion */
317 {
318 ITERATORNATSERVICEPF it;
319 for (it = rules.begin(); it != rules.end(); ++it)
320 {
321 /* compare */
322 NATSEVICEPORTFORWARDRULE& natFw = *it;
323 if ( natFw.Pfr.iPfrProto == r.Pfr.iPfrProto
324 && natFw.Pfr.u16PfrHostPort == r.Pfr.u16PfrHostPort
325 && (strncmp(natFw.Pfr.szPfrHostAddr, r.Pfr.szPfrHostAddr, INET6_ADDRSTRLEN) == 0)
326 && natFw.Pfr.u16PfrGuestPort == r.Pfr.u16PfrGuestPort
327 && (strncmp(natFw.Pfr.szPfrGuestAddr, r.Pfr.szPfrGuestAddr, INET6_ADDRSTRLEN) == 0))
328 {
329 fwspec *pFwCopy = (fwspec *)RTMemAllocZ(sizeof(fwspec));
330 if (!pFwCopy)
331 {
332 break;
333 }
334 memcpy(pFwCopy, &natFw.FWSpec, sizeof(fwspec));
335
336 /* We shouldn't care about pFwCopy this memory will be freed when
337 * will message will arrive to the destination.
338 */
339 portfwd_rule_del(pFwCopy);
340
341 rules.erase(it);
342 break;
343 }
344 } /* loop over vector elements */
345 } /* condition add or delete */
346 port_forward_done:
347 /* clean up strings */
348 name.setNull();
349 strHostAddr.setNull();
350 strGuestAddr.setNull();
351 break;
352 }
353
354 case VBoxEventType_OnHostNameResolutionConfigurationChange:
355 {
356 const char **ppcszNameServers = getHostNameservers();
357 err_t error;
358
359 error = tcpip_callback_with_block(pxdns_set_nameservers,
360 ppcszNameServers,
361 /* :block */ 0);
362 if (error != ERR_OK && ppcszNameServers != NULL)
363 {
364 RTMemFree(ppcszNameServers);
365 }
366 break;
367 }
368 }
369 return hrc;
370}
371
372
373void VBoxNetLwipNAT::onLwipTcpIpInit(void* arg)
374{
375 AssertPtrReturnVoid(arg);
376 VBoxNetLwipNAT *pNat = static_cast<VBoxNetLwipNAT *>(arg);
377
378 HRESULT hrc = com::Initialize();
379 Assert(!FAILED(hrc));
380
381 proxy_arp_hook = pxremap_proxy_arp;
382 proxy_ip4_divert_hook = pxremap_ip4_divert;
383
384 proxy_na_hook = pxremap_proxy_na;
385 proxy_ip6_divert_hook = pxremap_ip6_divert;
386
387 /* lwip thread */
388 RTNETADDRIPV4 network;
389 RTNETADDRIPV4 address = g_pLwipNat->getIpv4Address();
390 RTNETADDRIPV4 netmask = g_pLwipNat->getIpv4Netmask();
391 network.u = address.u & netmask.u;
392
393 ip_addr LwipIpAddr, LwipIpNetMask, LwipIpNetwork;
394
395 memcpy(&LwipIpAddr, &address, sizeof(ip_addr));
396 memcpy(&LwipIpNetMask, &netmask, sizeof(ip_addr));
397 memcpy(&LwipIpNetwork, &network, sizeof(ip_addr));
398
399 netif *pNetif = netif_add(&g_pLwipNat->m_LwipNetIf /* Lwip Interface */,
400 &LwipIpAddr /* IP address*/,
401 &LwipIpNetMask /* Network mask */,
402 &LwipIpAddr /* gateway address, @todo: is self IP acceptable? */,
403 g_pLwipNat /* state */,
404 VBoxNetLwipNAT::netifInit /* netif_init_fn */,
405 lwip_tcpip_input /* netif_input_fn */);
406
407 AssertPtrReturnVoid(pNetif);
408
409 netif_set_up(pNetif);
410 netif_set_link_up(pNetif);
411
412 if (pNat->m_ProxyOptions.ipv6_enabled) {
413 /*
414 * XXX: lwIP currently only ever calls mld6_joingroup() in
415 * nd6_tmr() for fresh tentative addresses, which is a wrong place
416 * to do it - but I'm not keen on fixing this properly for now
417 * (with correct handling of interface up and down transitions,
418 * etc). So stick it here as a kludge.
419 */
420 for (int i = 0; i <= 1; ++i) {
421 ip6_addr_t *paddr = netif_ip6_addr(pNetif, i);
422
423 ip6_addr_t solicited_node_multicast_address;
424 ip6_addr_set_solicitednode(&solicited_node_multicast_address,
425 paddr->addr[3]);
426 mld6_joingroup(paddr, &solicited_node_multicast_address);
427 }
428
429 /*
430 * XXX: We must join the solicited-node multicast for the
431 * addresses we do IPv6 NA-proxy for. We map IPv6 loopback to
432 * proxy address + 1. We only need the low 24 bits, and those are
433 * fixed.
434 */
435 {
436 ip6_addr_t solicited_node_multicast_address;
437
438 ip6_addr_set_solicitednode(&solicited_node_multicast_address,
439 /* last 24 bits of the address */
440 PP_HTONL(0x00000002));
441 mld6_netif_joingroup(pNetif, &solicited_node_multicast_address);
442 }
443 }
444
445 proxy_init(&g_pLwipNat->m_LwipNetIf, &g_pLwipNat->m_ProxyOptions);
446
447 natServiceProcessRegisteredPf(g_pLwipNat->m_vecPortForwardRule4);
448 natServiceProcessRegisteredPf(g_pLwipNat->m_vecPortForwardRule6);
449}
450
451
452void VBoxNetLwipNAT::onLwipTcpIpFini(void* arg)
453{
454 AssertPtrReturnVoid(arg);
455 VBoxNetLwipNAT *pThis = (VBoxNetLwipNAT *)arg;
456
457 /* XXX: proxy finalization */
458 netif_set_link_down(&g_pLwipNat->m_LwipNetIf);
459 netif_set_down(&g_pLwipNat->m_LwipNetIf);
460 netif_remove(&g_pLwipNat->m_LwipNetIf);
461
462}
463
464/*
465 * Callback for netif_add() to initialize the interface.
466 */
467err_t VBoxNetLwipNAT::netifInit(netif *pNetif)
468{
469 err_t rcLwip = ERR_OK;
470
471 AssertPtrReturn(pNetif, ERR_ARG);
472
473 VBoxNetLwipNAT *pNat = static_cast<VBoxNetLwipNAT *>(pNetif->state);
474 AssertPtrReturn(pNat, ERR_ARG);
475
476 LogFlowFunc(("ENTER: pNetif[%c%c%d]\n", pNetif->name[0], pNetif->name[1], pNetif->num));
477 /* validity */
478 AssertReturn( pNetif->name[0] == 'N'
479 && pNetif->name[1] == 'T', ERR_ARG);
480
481
482 pNetif->hwaddr_len = sizeof(RTMAC);
483 RTMAC mac = g_pLwipNat->getMacAddress();
484 memcpy(pNetif->hwaddr, &mac, sizeof(RTMAC));
485
486 pNat->m_u16Mtu = 1500; // XXX: FIXME
487 pNetif->mtu = pNat->m_u16Mtu;
488
489 pNetif->flags = NETIF_FLAG_BROADCAST
490 | NETIF_FLAG_ETHARP /* Don't bother driver with ARP and let Lwip resolve ARP handling */
491 | NETIF_FLAG_ETHERNET; /* Lwip works with ethernet too */
492
493 pNetif->linkoutput = netifLinkoutput; /* ether-level-pipe */
494 pNetif->output = lwip_etharp_output; /* ip-pipe */
495
496 if (pNat->m_ProxyOptions.ipv6_enabled) {
497 pNetif->output_ip6 = ethip6_output;
498
499 /* IPv6 link-local address in slot 0 */
500 netif_create_ip6_linklocal_address(pNetif, /* :from_mac_48bit */ 1);
501 netif_ip6_addr_set_state(pNetif, 0, IP6_ADDR_PREFERRED); // skip DAD
502
503 /*
504 * RFC 4193 Locally Assigned Global ID (ULA) in slot 1
505 * [fd17:625c:f037:XXXX::1] where XXXX, 16 bit Subnet ID, are two
506 * bytes from the middle of the IPv4 address, e.g. :dead: for
507 * 10.222.173.1
508 */
509 u8_t nethi = ip4_addr2(&pNetif->ip_addr);
510 u8_t netlo = ip4_addr3(&pNetif->ip_addr);
511
512 ip6_addr_t *paddr = netif_ip6_addr(pNetif, 1);
513 IP6_ADDR(paddr, 0, 0xFD, 0x17, 0x62, 0x5C);
514 IP6_ADDR(paddr, 1, 0xF0, 0x37, nethi, netlo);
515 IP6_ADDR(paddr, 2, 0x00, 0x00, 0x00, 0x00);
516 IP6_ADDR(paddr, 3, 0x00, 0x00, 0x00, 0x01);
517 netif_ip6_addr_set_state(pNetif, 1, IP6_ADDR_PREFERRED);
518
519#if LWIP_IPV6_SEND_ROUTER_SOLICIT
520 pNetif->rs_count = 0;
521#endif
522 }
523
524 LogFlowFunc(("LEAVE: %d\n", rcLwip));
525 return rcLwip;
526}
527
528
529err_t VBoxNetLwipNAT::netifLinkoutput(netif *pNetif, pbuf *pPBuf)
530{
531 AssertPtrReturn(pNetif, ERR_ARG);
532 AssertPtrReturn(pPBuf, ERR_ARG);
533 AssertReturn((void *)g_pLwipNat == pNetif->state, ERR_ARG);
534
535 LogFlowFunc(("ENTER: pNetif[%c%c%d], pPbuf:%p\n",
536 pNetif->name[0],
537 pNetif->name[1],
538 pNetif->num,
539 pPBuf));
540
541 RT_ZERO(VBoxNetLwipNAT::aXmitSeg);
542
543 unsigned idx = 0;
544 for( struct pbuf *pPBufPtr = pPBuf;
545 pPBufPtr;
546 pPBufPtr = pPBufPtr->next, ++idx)
547 {
548 AssertReturn(idx < RT_ELEMENTS(VBoxNetLwipNAT::aXmitSeg), ERR_MEM);
549 VBoxNetLwipNAT::aXmitSeg[idx].pv = pPBufPtr->payload;
550 VBoxNetLwipNAT::aXmitSeg[idx].cb = pPBufPtr->len;
551 }
552
553 int rc = g_pLwipNat->sendBufferOnWire(VBoxNetLwipNAT::aXmitSeg, idx, pPBuf->tot_len);
554 AssertRCReturn(rc, ERR_IF);
555
556 g_pLwipNat->flushWire();
557
558 LogFlowFunc(("LEAVE: %d\n", ERR_OK));
559 return ERR_OK;
560}
561
562
563VBoxNetLwipNAT::VBoxNetLwipNAT(SOCKET icmpsock4, SOCKET icmpsock6) : VBoxNetBaseService("VBoxNetNAT", "nat-network")
564{
565 LogFlowFuncEnter();
566
567 m_ProxyOptions.ipv6_enabled = 0;
568 m_ProxyOptions.ipv6_defroute = 0;
569 m_ProxyOptions.icmpsock4 = icmpsock4;
570 m_ProxyOptions.icmpsock6 = icmpsock6;
571 m_ProxyOptions.tftp_root = NULL;
572 m_ProxyOptions.src4 = NULL;
573 m_ProxyOptions.src6 = NULL;
574 memset(&m_src4, 0, sizeof(m_src4));
575 memset(&m_src6, 0, sizeof(m_src6));
576 m_src4.sin_family = AF_INET;
577 m_src6.sin6_family = AF_INET6;
578#if HAVE_SA_LEN
579 m_src4.sin_len = sizeof(m_src4);
580 m_src6.sin6_len = sizeof(m_src6);
581#endif
582 m_ProxyOptions.nameservers = NULL;
583
584 m_LwipNetIf.name[0] = 'N';
585 m_LwipNetIf.name[1] = 'T';
586
587 RTMAC mac;
588 mac.au8[0] = 0x52;
589 mac.au8[1] = 0x54;
590 mac.au8[2] = 0;
591 mac.au8[3] = 0x12;
592 mac.au8[4] = 0x35;
593 mac.au8[5] = 0;
594 setMacAddress(mac);
595
596 RTNETADDRIPV4 address;
597 address.u = RT_MAKE_U32_FROM_U8( 10, 0, 2, 2); // NB: big-endian
598 setIpv4Address(address);
599
600 address.u = RT_H2N_U32_C(0xffffff00);
601 setIpv4Netmask(address);
602
603 fDontLoadRulesOnStartup = false;
604
605 for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
606 addCommandLineOption(&g_aGetOptDef[i]);
607
608 LogFlowFuncLeave();
609}
610
611
612VBoxNetLwipNAT::~VBoxNetLwipNAT()
613{
614 if (m_ProxyOptions.tftp_root != NULL)
615 {
616 RTStrFree((char *)m_ProxyOptions.tftp_root);
617 }
618}
619
620
621int VBoxNetLwipNAT::natServicePfRegister(NATSEVICEPORTFORWARDRULE& natPf)
622{
623 int lrc = 0;
624 int rc = VINF_SUCCESS;
625 int socketSpec = SOCK_STREAM;
626 char *pszHostAddr;
627 int sockFamily = (natPf.Pfr.fPfrIPv6 ? PF_INET6 : PF_INET);
628
629 switch(natPf.Pfr.iPfrProto)
630 {
631 case IPPROTO_TCP:
632 socketSpec = SOCK_STREAM;
633 break;
634 case IPPROTO_UDP:
635 socketSpec = SOCK_DGRAM;
636 break;
637 default:
638 return VERR_IGNORED; /* Ah, just ignore the garbage */
639 }
640
641 pszHostAddr = natPf.Pfr.szPfrHostAddr;
642
643 /* XXX: workaround for inet_pton and an empty ipv4 address
644 * in rule declaration.
645 */
646 if ( sockFamily == PF_INET
647 && pszHostAddr[0] == 0)
648 pszHostAddr = (char *)"0.0.0.0"; /* XXX: fix it! without type cast */
649
650
651 lrc = fwspec_set(&natPf.FWSpec,
652 sockFamily,
653 socketSpec,
654 pszHostAddr,
655 natPf.Pfr.u16PfrHostPort,
656 natPf.Pfr.szPfrGuestAddr,
657 natPf.Pfr.u16PfrGuestPort);
658
659 AssertReturn(!lrc, VERR_IGNORED);
660
661 fwspec *pFwCopy = (fwspec *)RTMemAllocZ(sizeof(fwspec));
662 AssertPtrReturn(pFwCopy, VERR_IGNORED);
663
664 /*
665 * We need pass the copy, because we can't be sure
666 * how much this pointer will be valid in LWIP environment.
667 */
668 memcpy(pFwCopy, &natPf.FWSpec, sizeof(fwspec));
669
670 lrc = portfwd_rule_add(pFwCopy);
671
672 AssertReturn(!lrc, VERR_IGNORED);
673
674 return VINF_SUCCESS;
675}
676
677
678int VBoxNetLwipNAT::natServiceProcessRegisteredPf(VECNATSERVICEPF& vecRules){
679 ITERATORNATSERVICEPF it;
680 for (it = vecRules.begin();
681 it != vecRules.end(); ++it)
682 {
683 int rc = natServicePfRegister((*it));
684 if (RT_FAILURE(rc))
685 {
686 LogRel(("PF: %s is ignored\n", (*it).Pfr.szPfrName));
687 continue;
688 }
689 }
690 return VINF_SUCCESS;
691}
692
693
694/** This method executed on main thread, only at the end threr're one threads started explcitly (LWIP and later in ::run()
695 * RECV)
696 */
697int VBoxNetLwipNAT::init()
698{
699 LogFlowFuncEnter();
700
701 /* virtualbox initialized in super class */
702 int rc = ::VBoxNetBaseService::init();
703 AssertRCReturn(rc, rc);
704
705 std::string networkName = getNetwork();
706 rc = findNatNetwork(virtualbox, networkName, m_net);
707 AssertRCReturn(rc, rc);
708
709 ComEventTypeArray aNetEvents;
710 aNetEvents.push_back(VBoxEventType_OnNATNetworkPortForward);
711 aNetEvents.push_back(VBoxEventType_OnNATNetworkSetting);
712 rc = createNatListener(m_listener, virtualbox, this, aNetEvents);
713 AssertRCReturn(rc, rc);
714
715
716 // resolver changes are reported on vbox but are retrieved from
717 // host so stash a pointer for future lookups
718 HRESULT hrc = virtualbox->COMGETTER(Host)(m_host.asOutParam());
719 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
720
721 ComEventTypeArray aVBoxEvents;
722 aVBoxEvents.push_back(VBoxEventType_OnHostNameResolutionConfigurationChange);
723 rc = createNatListener(m_vboxListener, virtualbox, this, aVBoxEvents);
724 AssertRCReturn(rc, rc);
725
726 BOOL fIPv6Enabled = FALSE;
727 hrc = m_net->COMGETTER(IPv6Enabled)(&fIPv6Enabled);
728 AssertComRCReturn(hrc, VERR_NOT_FOUND);
729
730 BOOL fIPv6DefaultRoute = FALSE;
731 if (fIPv6Enabled)
732 {
733 hrc = m_net->COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(&fIPv6DefaultRoute);
734 AssertComRCReturn(hrc, VERR_NOT_FOUND);
735 }
736
737 m_ProxyOptions.ipv6_enabled = fIPv6Enabled;
738 m_ProxyOptions.ipv6_defroute = fIPv6DefaultRoute;
739
740
741 com::Bstr bstrSourceIp4Key = com::BstrFmt("NAT/%s/SourceIp4", networkName.c_str());
742 com::Bstr bstrSourceIpX;
743 hrc = virtualbox->GetExtraData(bstrSourceIp4Key.raw(), bstrSourceIpX.asOutParam());
744 if (SUCCEEDED(hrc))
745 {
746 RTNETADDRIPV4 addr;
747 rc = RTNetStrToIPv4Addr(com::Utf8Str(bstrSourceIpX).c_str(), &addr);
748 if (RT_SUCCESS(rc))
749 {
750 RT_ZERO(m_src4);
751
752 m_src4.sin_addr.s_addr = addr.u;
753 m_ProxyOptions.src4 = &m_src4;
754
755 bstrSourceIpX.setNull();
756 }
757 }
758
759 if (!fDontLoadRulesOnStartup)
760 {
761 fetchNatPortForwardRules(m_net, false, m_vecPortForwardRule4);
762 fetchNatPortForwardRules(m_net, true, m_vecPortForwardRule6);
763 } /* if (!fDontLoadRulesOnStartup) */
764
765 AddressToOffsetMapping tmp;
766 rc = localMappings(m_net, tmp);
767 if (RT_SUCCESS(rc) && tmp.size() != 0)
768 {
769 unsigned long i = 0;
770 for (AddressToOffsetMapping::iterator it = tmp.begin();
771 it != tmp.end() && i < RT_ELEMENTS(m_lo2off);
772 ++it, ++i)
773 {
774 ip4_addr_set_u32(&m_lo2off[i].loaddr, it->first.u);
775 m_lo2off[i].off = it->second;
776 }
777
778 m_loOptDescriptor.lomap = m_lo2off;
779 m_loOptDescriptor.num_lomap = i;
780 m_ProxyOptions.lomap_desc = &m_loOptDescriptor;
781 }
782
783 com::Bstr bstr;
784 hrc = virtualbox->COMGETTER(HomeFolder)(bstr.asOutParam());
785 AssertComRCReturn(hrc, VERR_NOT_FOUND);
786 if (!bstr.isEmpty())
787 {
788 com::Utf8Str strTftpRoot(com::Utf8StrFmt("%ls%c%s",
789 bstr.raw(), RTPATH_DELIMITER, "TFTP"));
790 char *pszStrTemp; // avoid const char ** vs char **
791 rc = RTStrUtf8ToCurrentCP(&pszStrTemp, strTftpRoot.c_str());
792 AssertRC(rc);
793 m_ProxyOptions.tftp_root = pszStrTemp;
794 }
795
796 m_ProxyOptions.nameservers = getHostNameservers();
797
798 /* end of COM initialization */
799
800 rc = g_pLwipNat->tryGoOnline();
801 if (RT_FAILURE(rc))
802 {
803 return rc;
804 }
805
806 /* this starts LWIP thread */
807 vboxLwipCoreInitialize(VBoxNetLwipNAT::onLwipTcpIpInit, this);
808
809 LogFlowFuncLeaveRC(rc);
810 return rc;
811}
812
813
814const char **VBoxNetLwipNAT::getHostNameservers()
815{
816 HRESULT hrc;
817
818 if (m_host.isNull())
819 {
820 return NULL;
821 }
822
823 com::SafeArray<BSTR> aNameServers;
824 hrc = m_host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(aNameServers));
825 if (FAILED(hrc))
826 {
827 return NULL;
828 }
829
830 const size_t cNameServers = aNameServers.size();
831 if (cNameServers == 0)
832 {
833 return NULL;
834 }
835
836 const char **ppcszNameServers =
837 (const char **)RTMemAllocZ(sizeof(char *) * (cNameServers + 1));
838 if (ppcszNameServers == NULL)
839 {
840 return NULL;
841 }
842
843 size_t idxLast = 0;
844 for (size_t i = 0; i < cNameServers; ++i)
845 {
846 com::Utf8Str strNameServer(aNameServers[i]);
847 ppcszNameServers[idxLast] = RTStrDup(strNameServer.c_str());
848 if (ppcszNameServers[idxLast] != NULL)
849 {
850 ++idxLast;
851 }
852 }
853
854 if (idxLast == 0)
855 {
856 RTMemFree(ppcszNameServers);
857 return NULL;
858 }
859
860 return ppcszNameServers;
861}
862
863
864int VBoxNetLwipNAT::parseOpt(int rc, const RTGETOPTUNION& Val)
865{
866 switch (rc)
867 {
868 case 'p':
869 case 'P':
870 {
871 NATSEVICEPORTFORWARDRULE Rule;
872 VECNATSERVICEPF& rules = (rc == 'P'?
873 m_vecPortForwardRule6
874 : m_vecPortForwardRule4);
875
876 fDontLoadRulesOnStartup = true;
877
878 RT_ZERO(Rule);
879
880 int irc = netPfStrToPf(Val.psz, (rc == 'P'), &Rule.Pfr);
881 rules.push_back(Rule);
882 return VINF_SUCCESS;
883 }
884 default:;
885 }
886 return VERR_NOT_FOUND;
887}
888
889
890int VBoxNetLwipNAT::processFrame(void *pvFrame, size_t cbFrame)
891{
892 AssertReturn(pvFrame && cbFrame, VERR_INVALID_PARAMETER);
893
894 struct pbuf *pPbufHdr, *pPbuf;
895 pPbufHdr = pPbuf = pbuf_alloc(PBUF_RAW, cbFrame, PBUF_POOL);
896
897 AssertMsgReturn(pPbuf, ("NAT: Can't allocate send buffer cbFrame=%u\n", cbFrame), VERR_INTERNAL_ERROR);
898 AssertReturn(pPbufHdr->tot_len == cbFrame, VERR_INTERNAL_ERROR);
899
900 uint8_t *pu8Frame = (uint8_t *)pvFrame;
901 while(pPbuf)
902 {
903 memcpy(pPbuf->payload, pu8Frame, pPbuf->len);
904 pu8Frame += pPbuf->len;
905 pPbuf = pPbuf->next;
906 }
907
908 m_LwipNetIf.input(pPbufHdr, &m_LwipNetIf);
909
910 return VINF_SUCCESS;
911}
912
913
914int VBoxNetLwipNAT::processGSO(PCPDMNETWORKGSO pGso, size_t cbFrame)
915{
916 if (!PDMNetGsoIsValid(pGso, cbFrame,
917 cbFrame - sizeof(PDMNETWORKGSO)))
918 return VERR_INVALID_PARAMETER;
919
920 cbFrame -= sizeof(PDMNETWORKGSO);
921 uint8_t abHdrScratch[256];
922 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso,
923 cbFrame);
924 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
925 {
926 uint32_t cbSegFrame;
927 void *pvSegFrame =
928 PDMNetGsoCarveSegmentQD(pGso,
929 (uint8_t *)(pGso + 1),
930 cbFrame,
931 abHdrScratch,
932 iSeg,
933 cSegs,
934 &cbSegFrame);
935
936 struct pbuf *pPbuf = pbuf_alloc(PBUF_RAW, cbSegFrame, PBUF_POOL);
937
938 AssertMsgReturn(pPbuf, ("NAT: Can't allocate send buffer cbFrame=%u\n", cbSegFrame), VERR_INTERNAL_ERROR);
939 AssertReturn(!pPbuf->next && pPbuf->len == cbSegFrame, VERR_INTERNAL_ERROR);
940
941 memcpy(pPbuf->payload, pvSegFrame, cbSegFrame);
942 m_LwipNetIf.input(pPbuf, &g_pLwipNat->m_LwipNetIf);
943 }
944
945 return VINF_SUCCESS;
946}
947
948
949int VBoxNetLwipNAT::run()
950{
951 /* Father starts receiving thread and enter event loop. */
952 VBoxNetBaseService::run();
953
954 vboxLwipCoreFinalize(VBoxNetLwipNAT::onLwipTcpIpFini, this);
955
956 m_vecPortForwardRule4.clear();
957 m_vecPortForwardRule6.clear();
958
959 return VINF_SUCCESS;
960}
961
962
963/**
964 * Entry point.
965 */
966extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
967{
968 LogFlowFuncEnter();
969
970 NOREF(envp);
971
972#ifdef RT_OS_WINDOWS
973 WSADATA wsaData;
974 int err;
975
976 err = WSAStartup(MAKEWORD(2,2), &wsaData);
977 if (err)
978 {
979 fprintf(stderr, "wsastartup: failed (%d)\n", err);
980 return 1;
981 }
982#endif
983
984 SOCKET icmpsock4 = INVALID_SOCKET;
985 SOCKET icmpsock6 = INVALID_SOCKET;
986#ifndef RT_OS_DARWIN
987 const int icmpstype = SOCK_RAW;
988#else
989 /* on OS X it's not privileged */
990 const int icmpstype = SOCK_DGRAM;
991#endif
992
993 icmpsock4 = socket(AF_INET, icmpstype, IPPROTO_ICMP);
994 if (icmpsock4 == INVALID_SOCKET)
995 {
996 perror("IPPROTO_ICMP");
997#ifdef VBOX_RAWSOCK_DEBUG_HELPER
998 icmpsock4 = getrawsock(AF_INET);
999#endif
1000 }
1001
1002 if (icmpsock4 != INVALID_SOCKET)
1003 {
1004#ifdef ICMP_FILTER // Linux specific
1005 struct icmp_filter flt = {
1006 ~(uint32_t)(
1007 (1U << ICMP_ECHOREPLY)
1008 | (1U << ICMP_DEST_UNREACH)
1009 | (1U << ICMP_TIME_EXCEEDED)
1010 )
1011 };
1012
1013 int status = setsockopt(icmpsock4, SOL_RAW, ICMP_FILTER,
1014 &flt, sizeof(flt));
1015 if (status < 0)
1016 {
1017 perror("ICMP_FILTER");
1018 }
1019#endif
1020 }
1021
1022 icmpsock6 = socket(AF_INET6, icmpstype, IPPROTO_ICMPV6);
1023 if (icmpsock6 == INVALID_SOCKET)
1024 {
1025 perror("IPPROTO_ICMPV6");
1026#ifdef VBOX_RAWSOCK_DEBUG_HELPER
1027 icmpsock6 = getrawsock(AF_INET6);
1028#endif
1029 }
1030
1031 if (icmpsock6 != INVALID_SOCKET)
1032 {
1033#ifdef ICMP6_FILTER // Windows doesn't support RFC 3542 API
1034 /*
1035 * XXX: We do this here for now, not in pxping.c, to avoid
1036 * name clashes between lwIP and system headers.
1037 */
1038 struct icmp6_filter flt;
1039 ICMP6_FILTER_SETBLOCKALL(&flt);
1040
1041 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &flt);
1042
1043 ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &flt);
1044 ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &flt);
1045 ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &flt);
1046 ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &flt);
1047
1048 int status = setsockopt(icmpsock6, IPPROTO_ICMPV6, ICMP6_FILTER,
1049 &flt, sizeof(flt));
1050 if (status < 0)
1051 {
1052 perror("ICMP6_FILTER");
1053 }
1054#endif
1055 }
1056
1057 HRESULT hrc = com::Initialize();
1058#ifdef VBOX_WITH_XPCOM
1059 if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
1060 {
1061 char szHome[RTPATH_MAX] = "";
1062 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
1063 return RTMsgErrorExit(RTEXITCODE_FAILURE,
1064 "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
1065 }
1066#endif
1067 if (FAILED(hrc))
1068 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
1069
1070 g_pLwipNat = new VBoxNetLwipNAT(icmpsock4, icmpsock6);
1071
1072 Log2(("NAT: initialization\n"));
1073 int rc = g_pLwipNat->parseArgs(argc - 1, argv + 1);
1074 rc = (rc == 0) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /* XXX: FIXME */
1075
1076 if (RT_SUCCESS(rc))
1077 {
1078 rc = g_pLwipNat->init();
1079 }
1080
1081 if (RT_SUCCESS(rc))
1082 {
1083 g_pLwipNat->run();
1084 }
1085
1086 delete g_pLwipNat;
1087 return 0;
1088}
1089
1090
1091static int fetchNatPortForwardRules(const ComNatPtr& nat, bool fIsIPv6, VECNATSERVICEPF& vec)
1092{
1093 HRESULT hrc;
1094 com::SafeArray<BSTR> rules;
1095 if (fIsIPv6)
1096 hrc = nat->COMGETTER(PortForwardRules6)(ComSafeArrayAsOutParam(rules));
1097 else
1098 hrc = nat->COMGETTER(PortForwardRules4)(ComSafeArrayAsOutParam(rules));
1099 AssertReturn(SUCCEEDED(hrc), VERR_INTERNAL_ERROR);
1100
1101 NATSEVICEPORTFORWARDRULE Rule;
1102 for (size_t idxRules = 0; idxRules < rules.size(); ++idxRules)
1103 {
1104 Log(("%d-%s rule: %ls\n", idxRules, (fIsIPv6 ? "IPv6" : "IPv4"), rules[idxRules]));
1105 RT_ZERO(Rule);
1106
1107 int rc = netPfStrToPf(com::Utf8Str(rules[idxRules]).c_str(), 0, &Rule.Pfr);
1108 if (RT_FAILURE(rc))
1109 continue;
1110
1111 vec.push_back(Rule);
1112 }
1113
1114 return VINF_SUCCESS;
1115}
1116
1117
1118#ifndef VBOX_WITH_HARDENING
1119
1120int main(int argc, char **argv, char **envp)
1121{
1122 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
1123 if (RT_FAILURE(rc))
1124 return RTMsgInitFailure(rc);
1125
1126 return TrustedMain(argc, argv, envp);
1127}
1128
1129# if defined(RT_OS_WINDOWS)
1130
1131static LRESULT CALLBACK WindowProc(HWND hwnd,
1132 UINT uMsg,
1133 WPARAM wParam,
1134 LPARAM lParam
1135)
1136{
1137 if(uMsg == WM_DESTROY)
1138 {
1139 PostQuitMessage(0);
1140 return 0;
1141 }
1142 return DefWindowProc (hwnd, uMsg, wParam, lParam);
1143}
1144
1145static LPCWSTR g_WndClassName = L"VBoxNetNatLwipClass";
1146
1147static DWORD WINAPI MsgThreadProc(__in LPVOID lpParameter)
1148{
1149 HWND hwnd = 0;
1150 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
1151 bool bExit = false;
1152
1153 /* Register the Window Class. */
1154 WNDCLASS wc;
1155 wc.style = 0;
1156 wc.lpfnWndProc = WindowProc;
1157 wc.cbClsExtra = 0;
1158 wc.cbWndExtra = sizeof(void *);
1159 wc.hInstance = hInstance;
1160 wc.hIcon = NULL;
1161 wc.hCursor = NULL;
1162 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1163 wc.lpszMenuName = NULL;
1164 wc.lpszClassName = g_WndClassName;
1165
1166 ATOM atomWindowClass = RegisterClass(&wc);
1167
1168 if (atomWindowClass != 0)
1169 {
1170 /* Create the window. */
1171 hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1172 g_WndClassName, g_WndClassName,
1173 WS_POPUPWINDOW,
1174 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1175
1176 if (hwnd)
1177 {
1178 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
1179 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1180
1181 MSG msg;
1182 while (GetMessage(&msg, NULL, 0, 0))
1183 {
1184 TranslateMessage(&msg);
1185 DispatchMessage(&msg);
1186 }
1187
1188 DestroyWindow (hwnd);
1189
1190 bExit = true;
1191 }
1192
1193 UnregisterClass (g_WndClassName, hInstance);
1194 }
1195
1196 if(bExit)
1197 {
1198 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
1199 exit(0);
1200 }
1201
1202 return 0;
1203}
1204
1205
1206
1207/** (We don't want a console usually.) */
1208int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
1209{
1210#if 0
1211 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
1212
1213 HANDLE hThread = CreateThread(
1214 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
1215 0, /*__in SIZE_T dwStackSize, */
1216 MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
1217 NULL, /*__in_opt LPVOID lpParameter,*/
1218 0, /*__in DWORD dwCreationFlags,*/
1219 NULL /*__out_opt LPDWORD lpThreadId*/
1220 );
1221
1222 if(hThread != NULL)
1223 CloseHandle(hThread);
1224
1225#endif
1226 return main(__argc, __argv, environ);
1227}
1228# endif /* RT_OS_WINDOWS */
1229
1230#endif /* !VBOX_WITH_HARDENING */
Note: See TracBrowser for help on using the repository browser.

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