VirtualBox

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

Last change on this file since 55264 was 54700, checked in by vboxsync, 10 years ago

VBoxNetNAT, VBoxNetDHCP: use the VirtualBoxClient interface

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