VirtualBox

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

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

Create NAT Network release logger. This can probably use some
improvements. Log rotation is not implemented yet.

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