VirtualBox

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

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

Get rid of LWIP_SOCKET - we don't need it for NAT and it pollutes namespace.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1/* $Id: VBoxNetLwipNAT.cpp 50075 2014-01-14 05:32:49Z 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 AssertReturn((void *)g_pLwipNat == pNetif->state, ERR_ARG);
529
530 LogFlowFunc(("ENTER: pNetif[%c%c%d], pPbuf:%p\n",
531 pNetif->name[0],
532 pNetif->name[1],
533 pNetif->num,
534 pPBuf));
535
536 RT_ZERO(VBoxNetLwipNAT::aXmitSeg);
537
538 unsigned idx = 0;
539 for( struct pbuf *pPBufPtr = pPBuf;
540 pPBufPtr;
541 pPBufPtr = pPBufPtr->next, ++idx)
542 {
543 AssertReturn(idx < RT_ELEMENTS(VBoxNetLwipNAT::aXmitSeg), ERR_MEM);
544 VBoxNetLwipNAT::aXmitSeg[idx].pv = pPBufPtr->payload;
545 VBoxNetLwipNAT::aXmitSeg[idx].cb = pPBufPtr->len;
546 }
547
548 int rc = g_pLwipNat->sendBufferOnWire(VBoxNetLwipNAT::aXmitSeg, idx, pPBuf->tot_len);
549 AssertRCReturn(rc, ERR_IF);
550
551 g_pLwipNat->flushWire();
552
553 LogFlowFunc(("LEAVE: %d\n", ERR_OK));
554 return ERR_OK;
555}
556
557
558VBoxNetLwipNAT::VBoxNetLwipNAT(SOCKET icmpsock4, SOCKET icmpsock6) : VBoxNetBaseService("VBoxNetNAT", "nat-network")
559{
560 LogFlowFuncEnter();
561
562 m_ProxyOptions.ipv6_enabled = 0;
563 m_ProxyOptions.ipv6_defroute = 0;
564 m_ProxyOptions.icmpsock4 = icmpsock4;
565 m_ProxyOptions.icmpsock6 = icmpsock6;
566 m_ProxyOptions.tftp_root = NULL;
567 m_ProxyOptions.src4 = NULL;
568 m_ProxyOptions.src6 = NULL;
569 memset(&m_src4, 0, sizeof(m_src4));
570 memset(&m_src6, 0, sizeof(m_src6));
571 m_src4.sin_family = AF_INET;
572 m_src6.sin6_family = AF_INET6;
573#if HAVE_SA_LEN
574 m_src4.sin_len = sizeof(m_src4);
575 m_src6.sin6_len = sizeof(m_src6);
576#endif
577 m_ProxyOptions.nameservers = NULL;
578
579 m_LwipNetIf.name[0] = 'N';
580 m_LwipNetIf.name[1] = 'T';
581
582 RTMAC mac;
583 mac.au8[0] = 0x52;
584 mac.au8[1] = 0x54;
585 mac.au8[2] = 0;
586 mac.au8[3] = 0x12;
587 mac.au8[4] = 0x35;
588 mac.au8[5] = 0;
589 setMacAddress(mac);
590
591 RTNETADDRIPV4 address;
592 address.u = RT_MAKE_U32_FROM_U8( 10, 0, 2, 2); // NB: big-endian
593 setIpv4Address(address);
594
595 address.u = RT_H2N_U32_C(0xffffff00);
596 setIpv4Netmask(address);
597
598 fDontLoadRulesOnStartup = false;
599
600 for(unsigned int i = 0; i < RT_ELEMENTS(g_aGetOptDef); ++i)
601 addCommandLineOption(&g_aGetOptDef[i]);
602
603 LogFlowFuncLeave();
604}
605
606
607VBoxNetLwipNAT::~VBoxNetLwipNAT()
608{
609 if (m_ProxyOptions.tftp_root != NULL)
610 {
611 RTStrFree((char *)m_ProxyOptions.tftp_root);
612 }
613}
614
615
616int VBoxNetLwipNAT::natServicePfRegister(NATSEVICEPORTFORWARDRULE& natPf)
617{
618 int lrc = 0;
619 int rc = VINF_SUCCESS;
620 int socketSpec = SOCK_STREAM;
621 char *pszHostAddr;
622 int sockFamily = (natPf.Pfr.fPfrIPv6 ? PF_INET6 : PF_INET);
623
624 switch(natPf.Pfr.iPfrProto)
625 {
626 case IPPROTO_TCP:
627 socketSpec = SOCK_STREAM;
628 break;
629 case IPPROTO_UDP:
630 socketSpec = SOCK_DGRAM;
631 break;
632 default:
633 return VERR_IGNORED; /* Ah, just ignore the garbage */
634 }
635
636 pszHostAddr = natPf.Pfr.szPfrHostAddr;
637
638 /* XXX: workaround for inet_pton and an empty ipv4 address
639 * in rule declaration.
640 */
641 if ( sockFamily == PF_INET
642 && pszHostAddr[0] == 0)
643 pszHostAddr = (char *)"0.0.0.0"; /* XXX: fix it! without type cast */
644
645
646 lrc = fwspec_set(&natPf.FWSpec,
647 sockFamily,
648 socketSpec,
649 pszHostAddr,
650 natPf.Pfr.u16PfrHostPort,
651 natPf.Pfr.szPfrGuestAddr,
652 natPf.Pfr.u16PfrGuestPort);
653
654 AssertReturn(!lrc, VERR_IGNORED);
655
656 fwspec *pFwCopy = (fwspec *)RTMemAllocZ(sizeof(fwspec));
657 AssertPtrReturn(pFwCopy, VERR_IGNORED);
658
659 /*
660 * We need pass the copy, because we can't be sure
661 * how much this pointer will be valid in LWIP environment.
662 */
663 memcpy(pFwCopy, &natPf.FWSpec, sizeof(fwspec));
664
665 lrc = portfwd_rule_add(pFwCopy);
666
667 AssertReturn(!lrc, VERR_IGNORED);
668
669 return VINF_SUCCESS;
670}
671
672
673int VBoxNetLwipNAT::natServiceProcessRegisteredPf(VECNATSERVICEPF& vecRules){
674 ITERATORNATSERVICEPF it;
675 for (it = vecRules.begin();
676 it != vecRules.end(); ++it)
677 {
678 int rc = natServicePfRegister((*it));
679 if (RT_FAILURE(rc))
680 {
681 LogRel(("PF: %s is ignored\n", (*it).Pfr.szPfrName));
682 continue;
683 }
684 }
685 return VINF_SUCCESS;
686}
687
688
689/** This method executed on main thread, only at the end threr're one threads started explcitly (LWIP and later in ::run()
690 * RECV)
691 */
692int VBoxNetLwipNAT::init()
693{
694 LogFlowFuncEnter();
695
696 /* virtualbox initialized in super class */
697 int rc = ::VBoxNetBaseService::init();
698 AssertRCReturn(rc, rc);
699
700 std::string networkName = getNetwork();
701 rc = findNatNetwork(virtualbox, networkName, m_net);
702 AssertRCReturn(rc, rc);
703
704 ComEventTypeArray aNetEvents;
705 aNetEvents.push_back(VBoxEventType_OnNATNetworkPortForward);
706 aNetEvents.push_back(VBoxEventType_OnNATNetworkSetting);
707 rc = createNatListener(m_listener, virtualbox, this, aNetEvents);
708 AssertRCReturn(rc, rc);
709
710
711 // resolver changes are reported on vbox but are retrieved from
712 // host so stash a pointer for future lookups
713 HRESULT hrc = virtualbox->COMGETTER(Host)(m_host.asOutParam());
714 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
715
716 ComEventTypeArray aVBoxEvents;
717 aVBoxEvents.push_back(VBoxEventType_OnHostNameResolutionConfigurationChange);
718 rc = createNatListener(m_vboxListener, virtualbox, this, aVBoxEvents);
719 AssertRCReturn(rc, rc);
720
721 BOOL fIPv6Enabled = FALSE;
722 hrc = m_net->COMGETTER(IPv6Enabled)(&fIPv6Enabled);
723 AssertComRCReturn(hrc, VERR_NOT_FOUND);
724
725 BOOL fIPv6DefaultRoute = FALSE;
726 if (fIPv6Enabled)
727 {
728 hrc = m_net->COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(&fIPv6DefaultRoute);
729 AssertComRCReturn(hrc, VERR_NOT_FOUND);
730 }
731
732 m_ProxyOptions.ipv6_enabled = fIPv6Enabled;
733 m_ProxyOptions.ipv6_defroute = fIPv6DefaultRoute;
734
735
736 com::Bstr bstrSourceIp4Key = com::BstrFmt("NAT/%s/SourceIp4", networkName.c_str());
737 com::Bstr bstrSourceIpX;
738 hrc = virtualbox->GetExtraData(bstrSourceIp4Key.raw(), bstrSourceIpX.asOutParam());
739 if (SUCCEEDED(hrc))
740 {
741 RTNETADDRIPV4 addr;
742 rc = RTNetStrToIPv4Addr(com::Utf8Str(bstrSourceIpX).c_str(), &addr);
743 if (RT_SUCCESS(rc))
744 {
745 RT_ZERO(m_src4);
746
747 m_src4.sin_addr.s_addr = addr.u;
748 m_ProxyOptions.src4 = &m_src4;
749
750 bstrSourceIpX.setNull();
751 }
752 }
753
754 if (!fDontLoadRulesOnStartup)
755 {
756 fetchNatPortForwardRules(m_net, false, m_vecPortForwardRule4);
757 fetchNatPortForwardRules(m_net, true, m_vecPortForwardRule6);
758 } /* if (!fDontLoadRulesOnStartup) */
759
760 AddressToOffsetMapping tmp;
761 rc = localMappings(m_net, tmp);
762 if (RT_SUCCESS(rc) && tmp.size() != 0)
763 {
764 unsigned long i = 0;
765 for (AddressToOffsetMapping::iterator it = tmp.begin();
766 it != tmp.end() && i < RT_ELEMENTS(m_lo2off);
767 ++it, ++i)
768 {
769 ip4_addr_set_u32(&m_lo2off[i].loaddr, it->first.u);
770 m_lo2off[i].off = it->second;
771 }
772
773 m_loOptDescriptor.lomap = m_lo2off;
774 m_loOptDescriptor.num_lomap = i;
775 m_ProxyOptions.lomap_desc = &m_loOptDescriptor;
776 }
777
778 com::Bstr bstr;
779 hrc = virtualbox->COMGETTER(HomeFolder)(bstr.asOutParam());
780 AssertComRCReturn(hrc, VERR_NOT_FOUND);
781 if (!bstr.isEmpty())
782 {
783 com::Utf8Str strTftpRoot(com::Utf8StrFmt("%ls%c%s",
784 bstr.raw(), RTPATH_DELIMITER, "TFTP"));
785 char *pszStrTemp; // avoid const char ** vs char **
786 rc = RTStrUtf8ToCurrentCP(&pszStrTemp, strTftpRoot.c_str());
787 AssertRC(rc);
788 m_ProxyOptions.tftp_root = pszStrTemp;
789 }
790
791 m_ProxyOptions.nameservers = getHostNameservers();
792
793 /* end of COM initialization */
794
795 rc = g_pLwipNat->tryGoOnline();
796 if (RT_FAILURE(rc))
797 {
798 return rc;
799 }
800
801 /* this starts LWIP thread */
802 vboxLwipCoreInitialize(VBoxNetLwipNAT::onLwipTcpIpInit, this);
803
804 LogFlowFuncLeaveRC(rc);
805 return rc;
806}
807
808
809const char **VBoxNetLwipNAT::getHostNameservers()
810{
811 HRESULT hrc;
812
813 if (m_host.isNull())
814 {
815 return NULL;
816 }
817
818 com::SafeArray<BSTR> aNameServers;
819 hrc = m_host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(aNameServers));
820 if (FAILED(hrc))
821 {
822 return NULL;
823 }
824
825 const size_t cNameServers = aNameServers.size();
826 if (cNameServers == 0)
827 {
828 return NULL;
829 }
830
831 const char **ppcszNameServers =
832 (const char **)RTMemAllocZ(sizeof(char *) * (cNameServers + 1));
833 if (ppcszNameServers == NULL)
834 {
835 return NULL;
836 }
837
838 size_t idxLast = 0;
839 for (size_t i = 0; i < cNameServers; ++i)
840 {
841 com::Utf8Str strNameServer(aNameServers[i]);
842 ppcszNameServers[idxLast] = RTStrDup(strNameServer.c_str());
843 if (ppcszNameServers[idxLast] != NULL)
844 {
845 ++idxLast;
846 }
847 }
848
849 if (idxLast == 0)
850 {
851 RTMemFree(ppcszNameServers);
852 return NULL;
853 }
854
855 return ppcszNameServers;
856}
857
858
859int VBoxNetLwipNAT::parseOpt(int rc, const RTGETOPTUNION& Val)
860{
861 switch (rc)
862 {
863 case 'p':
864 case 'P':
865 {
866 NATSEVICEPORTFORWARDRULE Rule;
867 VECNATSERVICEPF& rules = (rc == 'P'?
868 m_vecPortForwardRule6
869 : m_vecPortForwardRule4);
870
871 fDontLoadRulesOnStartup = true;
872
873 RT_ZERO(Rule);
874
875 int irc = netPfStrToPf(Val.psz, (rc == 'P'), &Rule.Pfr);
876 rules.push_back(Rule);
877 return VINF_SUCCESS;
878 }
879 default:;
880 }
881 return VERR_NOT_FOUND;
882}
883
884
885int VBoxNetLwipNAT::processFrame(void *pvFrame, size_t cbFrame)
886{
887 AssertReturn(pvFrame && cbFrame, VERR_INVALID_PARAMETER);
888
889 struct pbuf *pPbufHdr, *pPbuf;
890 pPbufHdr = pPbuf = pbuf_alloc(PBUF_RAW, cbFrame, PBUF_POOL);
891
892 AssertMsgReturn(pPbuf, ("NAT: Can't allocate send buffer cbFrame=%u\n", cbFrame), VERR_INTERNAL_ERROR);
893 AssertReturn(pPbufHdr->tot_len == cbFrame, VERR_INTERNAL_ERROR);
894
895 uint8_t *pu8Frame = (uint8_t *)pvFrame;
896 while(pPbuf)
897 {
898 memcpy(pPbuf->payload, pu8Frame, pPbuf->len);
899 pu8Frame += pPbuf->len;
900 pPbuf = pPbuf->next;
901 }
902
903 m_LwipNetIf.input(pPbufHdr, &m_LwipNetIf);
904
905 return VINF_SUCCESS;
906}
907
908
909int VBoxNetLwipNAT::processGSO(PCPDMNETWORKGSO pGso, size_t cbFrame)
910{
911 if (!PDMNetGsoIsValid(pGso, cbFrame,
912 cbFrame - sizeof(PDMNETWORKGSO)))
913 return VERR_INVALID_PARAMETER;
914
915 cbFrame -= sizeof(PDMNETWORKGSO);
916 uint8_t abHdrScratch[256];
917 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso,
918 cbFrame);
919 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
920 {
921 uint32_t cbSegFrame;
922 void *pvSegFrame =
923 PDMNetGsoCarveSegmentQD(pGso,
924 (uint8_t *)(pGso + 1),
925 cbFrame,
926 abHdrScratch,
927 iSeg,
928 cSegs,
929 &cbSegFrame);
930
931 struct pbuf *pPbuf = pbuf_alloc(PBUF_RAW, cbSegFrame, PBUF_POOL);
932
933 AssertMsgReturn(pPbuf, ("NAT: Can't allocate send buffer cbFrame=%u\n", cbSegFrame), VERR_INTERNAL_ERROR);
934 AssertReturn(!pPbuf->next && pPbuf->len == cbSegFrame, VERR_INTERNAL_ERROR);
935
936 memcpy(pPbuf->payload, pvSegFrame, cbSegFrame);
937 m_LwipNetIf.input(pPbuf, &g_pLwipNat->m_LwipNetIf);
938 }
939
940 return VINF_SUCCESS;
941}
942
943
944int VBoxNetLwipNAT::run()
945{
946 /* Father starts receiving thread and enter event loop. */
947 VBoxNetBaseService::run();
948
949 vboxLwipCoreFinalize(VBoxNetLwipNAT::onLwipTcpIpFini, this);
950
951 m_vecPortForwardRule4.clear();
952 m_vecPortForwardRule6.clear();
953
954 return VINF_SUCCESS;
955}
956
957
958/**
959 * Entry point.
960 */
961extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
962{
963 LogFlowFuncEnter();
964
965 NOREF(envp);
966
967#ifdef RT_OS_WINDOWS
968 WSADATA wsaData;
969 int err;
970
971 err = WSAStartup(MAKEWORD(2,2), &wsaData);
972 if (err)
973 {
974 fprintf(stderr, "wsastartup: failed (%d)\n", err);
975 return 1;
976 }
977#endif
978
979 SOCKET icmpsock4 = INVALID_SOCKET;
980 SOCKET icmpsock6 = INVALID_SOCKET;
981#ifndef RT_OS_DARWIN
982 const int icmpstype = SOCK_RAW;
983#else
984 /* on OS X it's not privileged */
985 const int icmpstype = SOCK_DGRAM;
986#endif
987
988 icmpsock4 = socket(AF_INET, icmpstype, IPPROTO_ICMP);
989 if (icmpsock4 == INVALID_SOCKET)
990 {
991 perror("IPPROTO_ICMP");
992#ifdef VBOX_RAWSOCK_DEBUG_HELPER
993 icmpsock4 = getrawsock(AF_INET);
994#endif
995 }
996
997 if (icmpsock4 != INVALID_SOCKET)
998 {
999#ifdef ICMP_FILTER // Linux specific
1000 struct icmp_filter flt = {
1001 ~(uint32_t)(
1002 (1U << ICMP_ECHOREPLY)
1003 | (1U << ICMP_DEST_UNREACH)
1004 | (1U << ICMP_TIME_EXCEEDED)
1005 )
1006 };
1007
1008 int status = setsockopt(icmpsock4, SOL_RAW, ICMP_FILTER,
1009 &flt, sizeof(flt));
1010 if (status < 0)
1011 {
1012 perror("ICMP_FILTER");
1013 }
1014#endif
1015 }
1016
1017 icmpsock6 = socket(AF_INET6, icmpstype, IPPROTO_ICMPV6);
1018 if (icmpsock6 == INVALID_SOCKET)
1019 {
1020 perror("IPPROTO_ICMPV6");
1021#ifdef VBOX_RAWSOCK_DEBUG_HELPER
1022 icmpsock6 = getrawsock(AF_INET6);
1023#endif
1024 }
1025
1026 if (icmpsock6 != INVALID_SOCKET)
1027 {
1028#ifdef ICMP6_FILTER // Windows doesn't support RFC 3542 API
1029 /*
1030 * XXX: We do this here for now, not in pxping.c, to avoid
1031 * name clashes between lwIP and system headers.
1032 */
1033 struct icmp6_filter flt;
1034 ICMP6_FILTER_SETBLOCKALL(&flt);
1035
1036 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &flt);
1037
1038 ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &flt);
1039 ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &flt);
1040 ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &flt);
1041 ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &flt);
1042
1043 int status = setsockopt(icmpsock6, IPPROTO_ICMPV6, ICMP6_FILTER,
1044 &flt, sizeof(flt));
1045 if (status < 0)
1046 {
1047 perror("ICMP6_FILTER");
1048 }
1049#endif
1050 }
1051
1052 HRESULT hrc = com::Initialize();
1053#ifdef VBOX_WITH_XPCOM
1054 if (hrc == NS_ERROR_FILE_ACCESS_DENIED)
1055 {
1056 char szHome[RTPATH_MAX] = "";
1057 com::GetVBoxUserHomeDirectory(szHome, sizeof(szHome));
1058 return RTMsgErrorExit(RTEXITCODE_FAILURE,
1059 "Failed to initialize COM because the global settings directory '%s' is not accessible!", szHome);
1060 }
1061#endif
1062 if (FAILED(hrc))
1063 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
1064
1065 g_pLwipNat = new VBoxNetLwipNAT(icmpsock4, icmpsock6);
1066
1067 Log2(("NAT: initialization\n"));
1068 int rc = g_pLwipNat->parseArgs(argc - 1, argv + 1);
1069 rc = (rc == 0) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /* XXX: FIXME */
1070
1071 if (RT_SUCCESS(rc))
1072 {
1073 rc = g_pLwipNat->init();
1074 }
1075
1076 if (RT_SUCCESS(rc))
1077 {
1078 g_pLwipNat->run();
1079 }
1080
1081 delete g_pLwipNat;
1082 return 0;
1083}
1084
1085
1086static int fetchNatPortForwardRules(const ComNatPtr& nat, bool fIsIPv6, VECNATSERVICEPF& vec)
1087{
1088 HRESULT hrc;
1089 com::SafeArray<BSTR> rules;
1090 if (fIsIPv6)
1091 hrc = nat->COMGETTER(PortForwardRules6)(ComSafeArrayAsOutParam(rules));
1092 else
1093 hrc = nat->COMGETTER(PortForwardRules4)(ComSafeArrayAsOutParam(rules));
1094 AssertReturn(SUCCEEDED(hrc), VERR_INTERNAL_ERROR);
1095
1096 NATSEVICEPORTFORWARDRULE Rule;
1097 for (size_t idxRules = 0; idxRules < rules.size(); ++idxRules)
1098 {
1099 Log(("%d-%s rule: %ls\n", idxRules, (fIsIPv6 ? "IPv6" : "IPv4"), rules[idxRules]));
1100 RT_ZERO(Rule);
1101
1102 int rc = netPfStrToPf(com::Utf8Str(rules[idxRules]).c_str(), 0, &Rule.Pfr);
1103 if (RT_FAILURE(rc))
1104 continue;
1105
1106 vec.push_back(Rule);
1107 }
1108
1109 return VINF_SUCCESS;
1110}
1111
1112
1113#ifndef VBOX_WITH_HARDENING
1114
1115int main(int argc, char **argv, char **envp)
1116{
1117 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
1118 if (RT_FAILURE(rc))
1119 return RTMsgInitFailure(rc);
1120
1121 return TrustedMain(argc, argv, envp);
1122}
1123
1124# if defined(RT_OS_WINDOWS)
1125
1126static LRESULT CALLBACK WindowProc(HWND hwnd,
1127 UINT uMsg,
1128 WPARAM wParam,
1129 LPARAM lParam
1130)
1131{
1132 if(uMsg == WM_DESTROY)
1133 {
1134 PostQuitMessage(0);
1135 return 0;
1136 }
1137 return DefWindowProc (hwnd, uMsg, wParam, lParam);
1138}
1139
1140static LPCWSTR g_WndClassName = L"VBoxNetNatLwipClass";
1141
1142static DWORD WINAPI MsgThreadProc(__in LPVOID lpParameter)
1143{
1144 HWND hwnd = 0;
1145 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle (NULL);
1146 bool bExit = false;
1147
1148 /* Register the Window Class. */
1149 WNDCLASS wc;
1150 wc.style = 0;
1151 wc.lpfnWndProc = WindowProc;
1152 wc.cbClsExtra = 0;
1153 wc.cbWndExtra = sizeof(void *);
1154 wc.hInstance = hInstance;
1155 wc.hIcon = NULL;
1156 wc.hCursor = NULL;
1157 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
1158 wc.lpszMenuName = NULL;
1159 wc.lpszClassName = g_WndClassName;
1160
1161 ATOM atomWindowClass = RegisterClass(&wc);
1162
1163 if (atomWindowClass != 0)
1164 {
1165 /* Create the window. */
1166 hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
1167 g_WndClassName, g_WndClassName,
1168 WS_POPUPWINDOW,
1169 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
1170
1171 if (hwnd)
1172 {
1173 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
1174 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
1175
1176 MSG msg;
1177 while (GetMessage(&msg, NULL, 0, 0))
1178 {
1179 TranslateMessage(&msg);
1180 DispatchMessage(&msg);
1181 }
1182
1183 DestroyWindow (hwnd);
1184
1185 bExit = true;
1186 }
1187
1188 UnregisterClass (g_WndClassName, hInstance);
1189 }
1190
1191 if(bExit)
1192 {
1193 /* no need any accuracy here, in anyway the DHCP server usually gets terminated with TerminateProcess */
1194 exit(0);
1195 }
1196
1197 return 0;
1198}
1199
1200
1201
1202/** (We don't want a console usually.) */
1203int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
1204{
1205#if 0
1206 NOREF(hInstance); NOREF(hPrevInstance); NOREF(lpCmdLine); NOREF(nCmdShow);
1207
1208 HANDLE hThread = CreateThread(
1209 NULL, /*__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, */
1210 0, /*__in SIZE_T dwStackSize, */
1211 MsgThreadProc, /*__in LPTHREAD_START_ROUTINE lpStartAddress,*/
1212 NULL, /*__in_opt LPVOID lpParameter,*/
1213 0, /*__in DWORD dwCreationFlags,*/
1214 NULL /*__out_opt LPDWORD lpThreadId*/
1215 );
1216
1217 if(hThread != NULL)
1218 CloseHandle(hThread);
1219
1220#endif
1221 return main(__argc, __argv, environ);
1222}
1223# endif /* RT_OS_WINDOWS */
1224
1225#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