VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/NATNetworkImpl.cpp@ 78093

Last change on this file since 78093 was 77436, checked in by vboxsync, 6 years ago

Main: Eradicate the use of BSTR in regular API code, there were leaks in almost every occurrence. Also do some Bstr->Utf8Str shuffling to reduce the number of conversions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.0 KB
Line 
1/* $Id: NATNetworkImpl.cpp 77436 2019-02-22 17:40:00Z vboxsync $ */
2/** @file
3 * INATNetwork implementation.
4 */
5
6/*
7 * Copyright (C) 2013-2019 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#define LOG_GROUP LOG_GROUP_MAIN_NATNETWORK
19#include "NetworkServiceRunner.h"
20#include "DHCPServerImpl.h"
21#include "NATNetworkImpl.h"
22#include "AutoCaller.h"
23
24#include <iprt/asm.h>
25#include <iprt/cpp/utils.h>
26#include <iprt/cidr.h>
27#include <iprt/net.h>
28#include <VBox/com/array.h>
29#include <VBox/com/ptr.h>
30#include <VBox/settings.h>
31
32#include "EventImpl.h"
33#include "LoggingNew.h"
34
35#include "VirtualBoxImpl.h"
36#include <algorithm>
37#include <list>
38
39#ifndef RT_OS_WINDOWS
40# include <netinet/in.h>
41#else
42# define IN_LOOPBACKNET 127
43#endif
44
45
46// constructor / destructor
47/////////////////////////////////////////////////////////////////////////////
48struct NATNetwork::Data
49{
50 Data()
51 : pVirtualBox(NULL)
52 , offGateway(0)
53 , offDhcp(0)
54 {
55 }
56 virtual ~Data(){}
57 const ComObjPtr<EventSource> pEventSource;
58#ifdef VBOX_WITH_NAT_SERVICE
59 NATNetworkServiceRunner NATRunner;
60 ComObjPtr<IDHCPServer> dhcpServer;
61#endif
62 /** weak VirtualBox parent */
63 VirtualBox * const pVirtualBox;
64
65 /** NATNetwork settings */
66 settings::NATNetwork s;
67
68 com::Utf8Str IPv4Gateway;
69 com::Utf8Str IPv4NetworkMask;
70 com::Utf8Str IPv4DhcpServer;
71 com::Utf8Str IPv4DhcpServerLowerIp;
72 com::Utf8Str IPv4DhcpServerUpperIp;
73
74 uint32_t offGateway;
75 uint32_t offDhcp;
76};
77
78
79NATNetwork::NATNetwork()
80 : m(NULL)
81{
82}
83
84
85NATNetwork::~NATNetwork()
86{
87}
88
89
90HRESULT NATNetwork::FinalConstruct()
91{
92 return BaseFinalConstruct();
93}
94
95
96void NATNetwork::FinalRelease()
97{
98 uninit();
99
100 BaseFinalRelease();
101}
102
103
104void NATNetwork::uninit()
105{
106 /* Enclose the state transition Ready->InUninit->NotReady */
107 AutoUninitSpan autoUninitSpan(this);
108 if (autoUninitSpan.uninitDone())
109 return;
110 unconst(m->pVirtualBox) = NULL;
111 delete m;
112 m = NULL;
113}
114
115HRESULT NATNetwork::init(VirtualBox *aVirtualBox, com::Utf8Str aName)
116{
117 AutoInitSpan autoInitSpan(this);
118 AssertReturn(autoInitSpan.isOk(), E_FAIL);
119
120 m = new Data();
121 /* share VirtualBox weakly */
122 unconst(m->pVirtualBox) = aVirtualBox;
123 m->s.strNetworkName = aName;
124 m->s.strIPv4NetworkCidr = "10.0.2.0/24";
125 m->offGateway = 1;
126 i_recalculateIPv6Prefix(); /* set m->strIPv6Prefix based on IPv4 */
127
128 settings::NATHostLoopbackOffset off;
129 off.strLoopbackHostAddress = "127.0.0.1";
130 off.u32Offset = (uint32_t)2;
131 m->s.llHostLoopbackOffsetList.push_back(off);
132
133 i_recalculateIpv4AddressAssignments();
134
135 HRESULT hrc = unconst(m->pEventSource).createObject();
136 if (FAILED(hrc)) throw hrc;
137
138 hrc = m->pEventSource->init();
139 if (FAILED(hrc)) throw hrc;
140
141 /* Confirm a successful initialization */
142 autoInitSpan.setSucceeded();
143
144 return S_OK;
145}
146
147
148HRESULT NATNetwork::i_loadSettings(const settings::NATNetwork &data)
149{
150 AutoCaller autoCaller(this);
151 AssertComRCReturnRC(autoCaller.rc());
152
153 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
154 m->s = data;
155 if ( m->s.strIPv6Prefix.isEmpty()
156 /* also clean up bogus old default */
157 || m->s.strIPv6Prefix == "fe80::/64")
158 i_recalculateIPv6Prefix(); /* set m->strIPv6Prefix based on IPv4 */
159 i_recalculateIpv4AddressAssignments();
160
161 return S_OK;
162}
163
164HRESULT NATNetwork::i_saveSettings(settings::NATNetwork &data)
165{
166 AutoCaller autoCaller(this);
167 if (FAILED(autoCaller.rc())) return autoCaller.rc();
168
169 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
170 AssertReturn(!m->s.strNetworkName.isEmpty(), E_FAIL);
171 data = m->s;
172
173 m->pVirtualBox->i_onNATNetworkSetting(Bstr(m->s.strNetworkName).raw(),
174 m->s.fEnabled,
175 Bstr(m->s.strIPv4NetworkCidr).raw(),
176 Bstr(m->IPv4Gateway).raw(),
177 m->s.fAdvertiseDefaultIPv6Route,
178 m->s.fNeedDhcpServer);
179
180 /* Notify listerners listening on this network only */
181 fireNATNetworkSettingEvent(m->pEventSource,
182 Bstr(m->s.strNetworkName).raw(),
183 m->s.fEnabled,
184 Bstr(m->s.strIPv4NetworkCidr).raw(),
185 Bstr(m->IPv4Gateway).raw(),
186 m->s.fAdvertiseDefaultIPv6Route,
187 m->s.fNeedDhcpServer);
188
189 return S_OK;
190}
191
192HRESULT NATNetwork::getEventSource(ComPtr<IEventSource> &aEventSource)
193{
194 /* event source is const, no need to lock */
195 m->pEventSource.queryInterfaceTo(aEventSource.asOutParam());
196 return S_OK;
197}
198
199HRESULT NATNetwork::getNetworkName(com::Utf8Str &aNetworkName)
200{
201 AssertReturn(!m->s.strNetworkName.isEmpty(), E_FAIL);
202 aNetworkName = m->s.strNetworkName;
203 return S_OK;
204}
205
206HRESULT NATNetwork::setNetworkName(const com::Utf8Str &aNetworkName)
207{
208 if (m->s.strNetworkName.isEmpty())
209 return setError(E_INVALIDARG,
210 tr("Network name cannot be empty"));
211 {
212 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
213 if (aNetworkName == m->s.strNetworkName)
214 return S_OK;
215
216 m->s.strNetworkName = aNetworkName;
217 }
218 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
219 HRESULT rc = m->pVirtualBox->i_saveSettings();
220 ComAssertComRCRetRC(rc);
221
222 return S_OK;
223}
224
225HRESULT NATNetwork::getEnabled(BOOL *aEnabled)
226{
227 *aEnabled = m->s.fEnabled;
228
229 i_recalculateIpv4AddressAssignments();
230 return S_OK;
231}
232
233HRESULT NATNetwork::setEnabled(const BOOL aEnabled)
234{
235 {
236 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
237 if (RT_BOOL(aEnabled) == m->s.fEnabled)
238 return S_OK;
239 m->s.fEnabled = RT_BOOL(aEnabled);
240 }
241
242 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
243 HRESULT rc = m->pVirtualBox->i_saveSettings();
244 ComAssertComRCRetRC(rc);
245 return S_OK;
246}
247
248HRESULT NATNetwork::getGateway(com::Utf8Str &aIPv4Gateway)
249{
250 aIPv4Gateway = m->IPv4Gateway;
251 return S_OK;
252}
253
254HRESULT NATNetwork::getNetwork(com::Utf8Str &aNetwork)
255{
256 aNetwork = m->s.strIPv4NetworkCidr;
257 return S_OK;
258}
259
260
261HRESULT NATNetwork::setNetwork(const com::Utf8Str &aIPv4NetworkCidr)
262{
263 {
264
265 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
266
267 if (aIPv4NetworkCidr == m->s.strIPv4NetworkCidr)
268 return S_OK;
269
270 /* silently ignore network cidr update for now.
271 * todo: keep internally guest address of port forward rule
272 * as offset from network id.
273 */
274 if (!m->s.mapPortForwardRules4.empty())
275 return S_OK;
276
277
278 m->s.strIPv4NetworkCidr = aIPv4NetworkCidr;
279 i_recalculateIpv4AddressAssignments();
280 }
281
282 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
283 HRESULT rc = m->pVirtualBox->i_saveSettings();
284 ComAssertComRCRetRC(rc);
285 return S_OK;
286}
287
288
289HRESULT NATNetwork::getIPv6Enabled(BOOL *aIPv6Enabled)
290{
291 *aIPv6Enabled = m->s.fIPv6Enabled;
292
293 return S_OK;
294}
295
296
297HRESULT NATNetwork::setIPv6Enabled(const BOOL aIPv6Enabled)
298{
299 {
300 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
301
302 if (RT_BOOL(aIPv6Enabled) == m->s.fIPv6Enabled)
303 return S_OK;
304
305 m->s.fIPv6Enabled = RT_BOOL(aIPv6Enabled);
306 }
307
308 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
309 HRESULT rc = m->pVirtualBox->i_saveSettings();
310 ComAssertComRCRetRC(rc);
311
312 return S_OK;
313}
314
315
316HRESULT NATNetwork::getIPv6Prefix(com::Utf8Str &aIPv6Prefix)
317{
318 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
319
320 aIPv6Prefix = m->s.strIPv6Prefix;
321 return S_OK;
322}
323
324HRESULT NATNetwork::setIPv6Prefix(const com::Utf8Str &aIPv6Prefix)
325{
326 {
327 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
328
329 if (aIPv6Prefix == m->s.strIPv6Prefix)
330 return S_OK;
331
332 /* silently ignore network IPv6 prefix update.
333 * todo: see similar todo in NATNetwork::COMSETTER(Network)(IN_BSTR)
334 */
335 if (!m->s.mapPortForwardRules6.empty())
336 return S_OK;
337
338 m->s.strIPv6Prefix = aIPv6Prefix;
339 }
340
341 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
342 HRESULT rc = m->pVirtualBox->i_saveSettings();
343 ComAssertComRCRetRC(rc);
344
345 return S_OK;
346}
347
348
349HRESULT NATNetwork::getAdvertiseDefaultIPv6RouteEnabled(BOOL *aAdvertiseDefaultIPv6Route)
350{
351 *aAdvertiseDefaultIPv6Route = m->s.fAdvertiseDefaultIPv6Route;
352
353 return S_OK;
354}
355
356
357HRESULT NATNetwork::setAdvertiseDefaultIPv6RouteEnabled(const BOOL aAdvertiseDefaultIPv6Route)
358{
359 {
360 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
361
362 if (RT_BOOL(aAdvertiseDefaultIPv6Route) == m->s.fAdvertiseDefaultIPv6Route)
363 return S_OK;
364
365 m->s.fAdvertiseDefaultIPv6Route = RT_BOOL(aAdvertiseDefaultIPv6Route);
366
367 }
368
369 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
370 HRESULT rc = m->pVirtualBox->i_saveSettings();
371 ComAssertComRCRetRC(rc);
372
373 return S_OK;
374}
375
376
377HRESULT NATNetwork::getNeedDhcpServer(BOOL *aNeedDhcpServer)
378{
379 *aNeedDhcpServer = m->s.fNeedDhcpServer;
380
381 return S_OK;
382}
383
384HRESULT NATNetwork::setNeedDhcpServer(const BOOL aNeedDhcpServer)
385{
386 {
387 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
388
389 if (RT_BOOL(aNeedDhcpServer) == m->s.fNeedDhcpServer)
390 return S_OK;
391
392 m->s.fNeedDhcpServer = RT_BOOL(aNeedDhcpServer);
393
394 i_recalculateIpv4AddressAssignments();
395
396 }
397
398 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
399 HRESULT rc = m->pVirtualBox->i_saveSettings();
400 ComAssertComRCRetRC(rc);
401
402 return S_OK;
403}
404
405HRESULT NATNetwork::getLocalMappings(std::vector<com::Utf8Str> &aLocalMappings)
406{
407 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
408
409 aLocalMappings.resize(m->s.llHostLoopbackOffsetList.size());
410 size_t i = 0;
411 for (settings::NATLoopbackOffsetList::const_iterator it = m->s.llHostLoopbackOffsetList.begin();
412 it != m->s.llHostLoopbackOffsetList.end(); ++it, ++i)
413 {
414 aLocalMappings[i] = Utf8StrFmt("%s=%d",
415 (*it).strLoopbackHostAddress.c_str(),
416 (*it).u32Offset);
417 }
418
419 return S_OK;
420}
421
422HRESULT NATNetwork::addLocalMapping(const com::Utf8Str &aHostId, LONG aOffset)
423{
424 RTNETADDRIPV4 addr, net, mask;
425
426 int rc = RTNetStrToIPv4Addr(Utf8Str(aHostId).c_str(), &addr);
427 if (RT_FAILURE(rc))
428 return E_INVALIDARG;
429
430 /* check against 127/8 */
431 if ((RT_N2H_U32(addr.u) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)
432 return E_INVALIDARG;
433
434 /* check against networkid vs network mask */
435 rc = RTCidrStrToIPv4(Utf8Str(m->s.strIPv4NetworkCidr).c_str(), &net, &mask);
436 if (RT_FAILURE(rc))
437 return E_INVALIDARG;
438
439 if (((net.u + aOffset) & mask.u) != net.u)
440 return E_INVALIDARG;
441
442 settings::NATLoopbackOffsetList::iterator it;
443
444 it = std::find(m->s.llHostLoopbackOffsetList.begin(),
445 m->s.llHostLoopbackOffsetList.end(),
446 aHostId);
447 if (it != m->s.llHostLoopbackOffsetList.end())
448 {
449 if (aOffset == 0) /* erase */
450 m->s.llHostLoopbackOffsetList.erase(it, it);
451 else /* modify */
452 {
453 settings::NATLoopbackOffsetList::iterator it1;
454 it1 = std::find(m->s.llHostLoopbackOffsetList.begin(),
455 m->s.llHostLoopbackOffsetList.end(),
456 (uint32_t)aOffset);
457 if (it1 != m->s.llHostLoopbackOffsetList.end())
458 return E_INVALIDARG; /* this offset is already registered. */
459
460 (*it).u32Offset = aOffset;
461 }
462
463 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
464 return m->pVirtualBox->i_saveSettings();
465 }
466
467 /* injection */
468 it = std::find(m->s.llHostLoopbackOffsetList.begin(),
469 m->s.llHostLoopbackOffsetList.end(),
470 (uint32_t)aOffset);
471
472 if (it != m->s.llHostLoopbackOffsetList.end())
473 return E_INVALIDARG; /* offset is already registered. */
474
475 settings::NATHostLoopbackOffset off;
476 off.strLoopbackHostAddress = aHostId;
477 off.u32Offset = (uint32_t)aOffset;
478 m->s.llHostLoopbackOffsetList.push_back(off);
479
480 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
481 return m->pVirtualBox->i_saveSettings();
482}
483
484
485HRESULT NATNetwork::getLoopbackIp6(LONG *aLoopbackIp6)
486{
487 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
488
489 *aLoopbackIp6 = m->s.u32HostLoopback6Offset;
490 return S_OK;
491}
492
493
494HRESULT NATNetwork::setLoopbackIp6(LONG aLoopbackIp6)
495{
496 {
497 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
498
499 if (aLoopbackIp6 < 0)
500 return E_INVALIDARG;
501
502 if (static_cast<uint32_t>(aLoopbackIp6) == m->s.u32HostLoopback6Offset)
503 return S_OK;
504
505 m->s.u32HostLoopback6Offset = aLoopbackIp6;
506 }
507
508 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
509 return m->pVirtualBox->i_saveSettings();
510}
511
512
513HRESULT NATNetwork::getPortForwardRules4(std::vector<com::Utf8Str> &aPortForwardRules4)
514{
515 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
516 i_getPortForwardRulesFromMap(aPortForwardRules4,
517 m->s.mapPortForwardRules4);
518 return S_OK;
519}
520
521HRESULT NATNetwork::getPortForwardRules6(std::vector<com::Utf8Str> &aPortForwardRules6)
522{
523 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
524 i_getPortForwardRulesFromMap(aPortForwardRules6,
525 m->s.mapPortForwardRules6);
526 return S_OK;
527}
528
529HRESULT NATNetwork::addPortForwardRule(BOOL aIsIpv6,
530 const com::Utf8Str &aPortForwardRuleName,
531 NATProtocol_T aProto,
532 const com::Utf8Str &aHostIp,
533 USHORT aHostPort,
534 const com::Utf8Str &aGuestIp,
535 USHORT aGuestPort)
536{
537 {
538 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
539 Utf8Str name = aPortForwardRuleName;
540 Utf8Str proto;
541 settings::NATRule r;
542 settings::NATRulesMap &mapRules = aIsIpv6 ? m->s.mapPortForwardRules6 : m->s.mapPortForwardRules4;
543 switch (aProto)
544 {
545 case NATProtocol_TCP:
546 proto = "tcp";
547 break;
548 case NATProtocol_UDP:
549 proto = "udp";
550 break;
551 default:
552 return E_INVALIDARG;
553 }
554 if (name.isEmpty())
555 name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
556 aHostIp.c_str(), aHostPort,
557 aGuestIp.c_str(), aGuestPort);
558
559 for (settings::NATRulesMap::iterator it = mapRules.begin(); it != mapRules.end(); ++it)
560 {
561 r = it->second;
562 if (it->first == name)
563 return setError(E_INVALIDARG,
564 tr("A NAT rule of this name already exists"));
565 if ( r.strHostIP == aHostIp
566 && r.u16HostPort == aHostPort
567 && r.proto == aProto)
568 return setError(E_INVALIDARG,
569 tr("A NAT rule for this host port and this host IP already exists"));
570 }
571
572 r.strName = name.c_str();
573 r.proto = aProto;
574 r.strHostIP = aHostIp;
575 r.u16HostPort = aHostPort;
576 r.strGuestIP = aGuestIp;
577 r.u16GuestPort = aGuestPort;
578 mapRules.insert(std::make_pair(name, r));
579 }
580 {
581 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
582 HRESULT rc = m->pVirtualBox->i_saveSettings();
583 ComAssertComRCRetRC(rc);
584 }
585
586 m->pVirtualBox->i_onNATNetworkPortForward(Bstr(m->s.strNetworkName).raw(), TRUE, aIsIpv6,
587 Bstr(aPortForwardRuleName).raw(), aProto,
588 Bstr(aHostIp).raw(), aHostPort,
589 Bstr(aGuestIp).raw(), aGuestPort);
590
591 /* Notify listerners listening on this network only */
592 fireNATNetworkPortForwardEvent(m->pEventSource, Bstr(m->s.strNetworkName).raw(), TRUE,
593 aIsIpv6, Bstr(aPortForwardRuleName).raw(), aProto,
594 Bstr(aHostIp).raw(), aHostPort,
595 Bstr(aGuestIp).raw(), aGuestPort);
596
597 return S_OK;
598}
599
600HRESULT NATNetwork::removePortForwardRule(BOOL aIsIpv6, const com::Utf8Str &aPortForwardRuleName)
601{
602 Utf8Str strHostIP;
603 Utf8Str strGuestIP;
604 uint16_t u16HostPort;
605 uint16_t u16GuestPort;
606 NATProtocol_T proto;
607
608 {
609 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
610 settings::NATRulesMap &mapRules = aIsIpv6 ? m->s.mapPortForwardRules6 : m->s.mapPortForwardRules4;
611 settings::NATRulesMap::iterator it = mapRules.find(aPortForwardRuleName);
612
613 if (it == mapRules.end())
614 return E_INVALIDARG;
615
616 strHostIP = it->second.strHostIP;
617 strGuestIP = it->second.strGuestIP;
618 u16HostPort = it->second.u16HostPort;
619 u16GuestPort = it->second.u16GuestPort;
620 proto = it->second.proto;
621
622 mapRules.erase(it);
623 }
624
625 {
626 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
627 HRESULT rc = m->pVirtualBox->i_saveSettings();
628 ComAssertComRCRetRC(rc);
629 }
630
631 m->pVirtualBox->i_onNATNetworkPortForward(Bstr(m->s.strNetworkName).raw(), FALSE, aIsIpv6,
632 Bstr(aPortForwardRuleName).raw(), proto,
633 Bstr(strHostIP).raw(), u16HostPort,
634 Bstr(strGuestIP).raw(), u16GuestPort);
635
636 /* Notify listerners listening on this network only */
637 fireNATNetworkPortForwardEvent(m->pEventSource, Bstr(m->s.strNetworkName).raw(), FALSE,
638 aIsIpv6, Bstr(aPortForwardRuleName).raw(), proto,
639 Bstr(strHostIP).raw(), u16HostPort,
640 Bstr(strGuestIP).raw(), u16GuestPort);
641 return S_OK;
642}
643
644
645void NATNetwork::i_updateDomainNameOption(ComPtr<IHost> &host)
646{
647 com::Bstr domain;
648 if (FAILED(host->COMGETTER(DomainName)(domain.asOutParam())))
649 LogRel(("NATNetwork: Failed to get host's domain name\n"));
650 if (domain.isNotEmpty())
651 {
652 HRESULT hrc = m->dhcpServer->AddGlobalOption(DhcpOpt_DomainName, domain.raw());
653 if (FAILED(hrc))
654 LogRel(("NATNetwork: Failed to add domain name option with %Rhrc\n", hrc));
655 }
656 else
657 m->dhcpServer->RemoveGlobalOption(DhcpOpt_DomainName);
658}
659
660void NATNetwork::i_updateDomainNameServerOption(ComPtr<IHost> &host)
661{
662 RTNETADDRIPV4 networkid, netmask;
663
664 int rc = RTCidrStrToIPv4(m->s.strIPv4NetworkCidr.c_str(), &networkid, &netmask);
665 if (RT_FAILURE(rc))
666 {
667 LogRel(("NATNetwork: Failed to parse cidr %s with %Rrc\n", m->s.strIPv4NetworkCidr.c_str(), rc));
668 return;
669 }
670
671 /* XXX: these are returned, surprisingly, in host order */
672 networkid.u = RT_H2N_U32(networkid.u);
673 netmask.u = RT_H2N_U32(netmask.u);
674
675 com::SafeArray<BSTR> nameServers;
676 HRESULT hrc = host->COMGETTER(NameServers)(ComSafeArrayAsOutParam(nameServers));
677 if (FAILED(hrc))
678 {
679 LogRel(("NATNetwork: Failed to get name servers from host with %Rhrc\n", hrc));
680 return;
681 }
682
683 size_t cAddresses = nameServers.size();
684 if (cAddresses)
685 {
686 RTCList<RTCString> lstServers;
687 /* The following code was copied (and adapted a bit) from VBoxNetDhcp::hostDnsServers */
688 /*
689 * Recent fashion is to run dnsmasq on 127.0.1.1 which we
690 * currently can't map. If that's the only nameserver we've got,
691 * we need to use DNS proxy for VMs to reach it.
692 */
693 bool fUnmappedLoopback = false;
694
695 for (size_t i = 0; i < cAddresses; ++i)
696 {
697 RTNETADDRIPV4 addr;
698
699 com::Utf8Str strNameServerAddress(nameServers[i]);
700 rc = RTNetStrToIPv4Addr(strNameServerAddress.c_str(), &addr);
701 if (RT_FAILURE(rc))
702 {
703 LogRel(("NATNetwork: Failed to parse IP address %s with %Rrc\n", strNameServerAddress.c_str(), rc));
704 continue;
705 }
706
707 if (addr.u == INADDR_ANY)
708 {
709 /*
710 * This doesn't seem to be very well documented except for
711 * RTFS of res_init.c, but INADDR_ANY is a valid value for
712 * for "nameserver".
713 */
714 addr.u = RT_H2N_U32_C(INADDR_LOOPBACK);
715 }
716
717 if (addr.au8[0] == 127)
718 {
719 settings::NATLoopbackOffsetList::const_iterator it;
720
721 it = std::find(m->s.llHostLoopbackOffsetList.begin(),
722 m->s.llHostLoopbackOffsetList.end(),
723 strNameServerAddress);
724 if (it == m->s.llHostLoopbackOffsetList.end())
725 {
726 fUnmappedLoopback = true;
727 continue;
728 }
729 addr.u = RT_H2N_U32(RT_N2H_U32(networkid.u) + it->u32Offset);
730 }
731 lstServers.append(RTCStringFmt("%RTnaipv4", addr));
732 }
733
734 if (lstServers.isEmpty() && fUnmappedLoopback)
735 lstServers.append(RTCStringFmt("%RTnaipv4", networkid.u | RT_H2N_U32_C(1U))); /* proxy */
736
737 hrc = m->dhcpServer->AddGlobalOption(DhcpOpt_DomainNameServer, Bstr(RTCString::join(lstServers, " ")).raw());
738 if (FAILED(hrc))
739 LogRel(("NATNetwork: Failed to add domain name server option '%s' with %Rhrc\n", RTCString::join(lstServers, " ").c_str(), hrc));
740 }
741 else
742 m->dhcpServer->RemoveGlobalOption(DhcpOpt_DomainNameServer);
743}
744
745void NATNetwork::i_updateDnsOptions()
746{
747 ComPtr<IHost> host;
748 if (SUCCEEDED(m->pVirtualBox->COMGETTER(Host)(host.asOutParam())))
749 {
750 i_updateDomainNameOption(host);
751 i_updateDomainNameServerOption(host);
752 }
753}
754
755
756HRESULT NATNetwork::start(const com::Utf8Str &aTrunkType)
757{
758#ifdef VBOX_WITH_NAT_SERVICE
759 if (!m->s.fEnabled) return S_OK;
760 AssertReturn(!m->s.strNetworkName.isEmpty(), E_FAIL);
761
762 m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyNetwork, Utf8Str(m->s.strNetworkName).c_str());
763 m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str());
764 m->NATRunner.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPv4Gateway).c_str());
765 m->NATRunner.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->IPv4NetworkMask).c_str());
766
767 /* No portforwarding rules from command-line, all will be fetched via API */
768
769 if (m->s.fNeedDhcpServer)
770 {
771 /*
772 * Just to as idea... via API (on creation user pass the cidr of network and)
773 * and we calculate it's addreses (mutable?).
774 */
775
776 /*
777 * Configuration and running DHCP server:
778 * 1. find server first createDHCPServer
779 * 2. if return status is E_INVALARG => server already exists just find and start.
780 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
781 * 4. if return status S_OK proceed to DHCP server configuration
782 * 5. call setConfiguration() and pass all required parameters
783 * 6. start dhcp server.
784 */
785 HRESULT hrc = m->pVirtualBox->FindDHCPServerByNetworkName(Bstr(m->s.strNetworkName).raw(),
786 m->dhcpServer.asOutParam());
787 switch (hrc)
788 {
789 case E_INVALIDARG:
790 /* server haven't beeen found let create it then */
791 hrc = m->pVirtualBox->CreateDHCPServer(Bstr(m->s.strNetworkName).raw(),
792 m->dhcpServer.asOutParam());
793 if (FAILED(hrc))
794 return E_FAIL;
795 /* breakthrough */
796
797 {
798 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
799 m->IPv4Gateway.c_str(),
800 m->IPv4DhcpServer.c_str(),
801 m->IPv4DhcpServerLowerIp.c_str(),
802 m->IPv4DhcpServerUpperIp.c_str()));
803
804 hrc = m->dhcpServer->COMSETTER(Enabled)(true);
805
806 hrc = m->dhcpServer->SetConfiguration(Bstr(m->IPv4DhcpServer).raw(),
807 Bstr(m->IPv4NetworkMask).raw(),
808 Bstr(m->IPv4DhcpServerLowerIp).raw(),
809 Bstr(m->IPv4DhcpServerUpperIp).raw());
810 }
811 case S_OK:
812 break;
813
814 default:
815 return E_FAIL;
816 }
817
818#ifdef VBOX_WITH_DHCPD
819 i_updateDnsOptions();
820#endif /* VBOX_WITH_DHCPD */
821 /* XXX: AddGlobalOption(DhcpOpt_Router,) - enables attachement of DhcpServer to Main (no longer true with VBoxNetDhcpd). */
822 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, Bstr(m->IPv4Gateway).raw());
823
824 hrc = m->dhcpServer->Start(Bstr(m->s.strNetworkName).raw(), Bstr("").raw(), Bstr(aTrunkType).raw());
825 if (FAILED(hrc))
826 {
827 m->dhcpServer.setNull();
828 return E_FAIL;
829 }
830 }
831
832 if (RT_SUCCESS(m->NATRunner.start(false /* KillProcOnStop */)))
833 {
834 m->pVirtualBox->i_onNATNetworkStartStop(Bstr(m->s.strNetworkName).raw(), TRUE);
835 return S_OK;
836 }
837 /** @todo missing setError()! */
838 return E_FAIL;
839#else
840 NOREF(aTrunkType);
841 ReturnComNotImplemented();
842#endif
843}
844
845HRESULT NATNetwork::stop()
846{
847#ifdef VBOX_WITH_NAT_SERVICE
848 m->pVirtualBox->i_onNATNetworkStartStop(Bstr(m->s.strNetworkName).raw(), FALSE);
849
850 if (!m->dhcpServer.isNull())
851 m->dhcpServer->Stop();
852
853 if (RT_SUCCESS(m->NATRunner.stop()))
854 return S_OK;
855
856 /** @todo missing setError()! */
857 return E_FAIL;
858#else
859 ReturnComNotImplemented();
860#endif
861}
862
863
864void NATNetwork::i_getPortForwardRulesFromMap(std::vector<com::Utf8Str> &aPortForwardRules, settings::NATRulesMap &aRules)
865{
866 aPortForwardRules.resize(aRules.size());
867 size_t i = 0;
868 for (settings::NATRulesMap::const_iterator it = aRules.begin();
869 it != aRules.end(); ++it, ++i)
870 {
871 settings::NATRule r = it->second;
872 aPortForwardRules[i] = Utf8StrFmt("%s:%s:[%s]:%d:[%s]:%d",
873 r.strName.c_str(),
874 (r.proto == NATProtocol_TCP ? "tcp" : "udp"),
875 r.strHostIP.c_str(),
876 r.u16HostPort,
877 r.strGuestIP.c_str(),
878 r.u16GuestPort);
879 }
880}
881
882
883int NATNetwork::i_findFirstAvailableOffset(ADDRESSLOOKUPTYPE addrType, uint32_t *poff)
884{
885 RTNETADDRIPV4 network, netmask;
886
887 int rc = RTCidrStrToIPv4(m->s.strIPv4NetworkCidr.c_str(),
888 &network,
889 &netmask);
890 AssertRCReturn(rc, rc);
891
892 uint32_t off;
893 for (off = 1; off < ~netmask.u; ++off)
894 {
895 bool skip = false;
896 for (settings::NATLoopbackOffsetList::iterator it = m->s.llHostLoopbackOffsetList.begin();
897 it != m->s.llHostLoopbackOffsetList.end();
898 ++it)
899 {
900 if ((*it).u32Offset == off)
901 {
902 skip = true;
903 break;
904 }
905
906 }
907
908 if (skip)
909 continue;
910
911 if (off == m->offGateway)
912 {
913 if (addrType == ADDR_GATEWAY)
914 break;
915 else
916 continue;
917 }
918
919 if (off == m->offDhcp)
920 {
921 if (addrType == ADDR_DHCP)
922 break;
923 else
924 continue;
925 }
926
927 if (!skip)
928 break;
929 }
930
931 if (poff)
932 *poff = off;
933
934 return VINF_SUCCESS;
935}
936
937int NATNetwork::i_recalculateIpv4AddressAssignments()
938{
939 RTNETADDRIPV4 network, netmask;
940 int rc = RTCidrStrToIPv4(m->s.strIPv4NetworkCidr.c_str(),
941 &network,
942 &netmask);
943 AssertRCReturn(rc, rc);
944
945 i_findFirstAvailableOffset(ADDR_GATEWAY, &m->offGateway);
946 if (m->s.fNeedDhcpServer)
947 i_findFirstAvailableOffset(ADDR_DHCP, &m->offDhcp);
948
949 /* I don't remember the reason CIDR calculated on the host. */
950 RTNETADDRIPV4 gateway = network;
951 gateway.u += m->offGateway;
952 gateway.u = RT_H2N_U32(gateway.u);
953 char szTmpIp[16];
954 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", gateway);
955 m->IPv4Gateway = szTmpIp;
956
957 if (m->s.fNeedDhcpServer)
958 {
959 RTNETADDRIPV4 dhcpserver = network;
960 dhcpserver.u += m->offDhcp;
961
962 /* XXX: adding more services should change the math here */
963 RTNETADDRIPV4 dhcplowerip = network;
964 uint32_t offDhcpLowerIp;
965 i_findFirstAvailableOffset(ADDR_DHCPLOWERIP, &offDhcpLowerIp);
966 dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp);
967
968 RTNETADDRIPV4 dhcpupperip;
969 dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1);
970
971 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
972 network.u = RT_H2N_U32(network.u);
973
974 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver);
975 m->IPv4DhcpServer = szTmpIp;
976 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip);
977 m->IPv4DhcpServerLowerIp = szTmpIp;
978 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip);
979 m->IPv4DhcpServerUpperIp = szTmpIp;
980
981 LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
982 network, dhcpserver, dhcplowerip, dhcpupperip));
983 }
984
985 /* we need IPv4NetworkMask for NAT's gw service start */
986 netmask.u = RT_H2N_U32(netmask.u);
987 RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask);
988 m->IPv4NetworkMask = szTmpIp;
989
990 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
991 return VINF_SUCCESS;
992}
993
994
995int NATNetwork::i_recalculateIPv6Prefix()
996{
997 int rc;
998
999 RTNETADDRIPV4 net, mask;
1000 rc = RTCidrStrToIPv4(Utf8Str(m->s.strIPv4NetworkCidr).c_str(), &net, &mask);
1001 if (RT_FAILURE(rc))
1002 return rc;
1003
1004 net.u = RT_H2N_U32(net.u); /* XXX: fix RTCidrStrToIPv4! */
1005
1006 /*
1007 * [fd17:625c:f037:XXXX::/64] - RFC 4193 (ULA) Locally Assigned
1008 * Global ID where XXXX, 16 bit Subnet ID, are two bytes from the
1009 * middle of the IPv4 address, e.g. :dead: for 10.222.173.1
1010 */
1011 RTNETADDRIPV6 prefix;
1012 RT_ZERO(prefix);
1013
1014 prefix.au8[0] = 0xFD;
1015 prefix.au8[1] = 0x17;
1016
1017 prefix.au8[2] = 0x62;
1018 prefix.au8[3] = 0x5C;
1019
1020 prefix.au8[4] = 0xF0;
1021 prefix.au8[5] = 0x37;
1022
1023 prefix.au8[6] = net.au8[1];
1024 prefix.au8[7] = net.au8[2];
1025
1026 char szBuf[32];
1027 RTStrPrintf(szBuf, sizeof(szBuf), "%RTnaipv6/64", &prefix);
1028
1029 m->s.strIPv6Prefix = szBuf;
1030 return VINF_SUCCESS;
1031}
Note: See TracBrowser for help on using the repository browser.

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