VirtualBox

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

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

spaces

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

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