VirtualBox

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

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

Massage release logging for port-forwarding a bit. Log rules on startup.

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

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