VirtualBox

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

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

VBoxNetBaseService hides all details of internal network implementation and become responsible for supporting receiving loop. Notification of children are done via introduced interface:

virtual int processFrame(void *, size_t) = 0;
virtual int processGSO(PCPDMNETWORKGSO, size_t) = 0;
virtual int processUDP(void *, size_t) = 0;

processFrame() and processGSO() might return VERR_IGNORED, to inform base service switch to processUDP() (e.g. for DHCP needs)

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