VirtualBox

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

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

VBoxNetLwipNAT: Windows build fix.

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