VirtualBox

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

Last change on this file since 60786 was 60786, checked in by vboxsync, 9 years ago

Main/NATNetwork+NATEngine: simplify settings handling greatly by directly using the structs without tedious translation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.0 KB
Line 
1/* $Id: NATNetworkImpl.cpp 60786 2016-05-02 13:00:02Z vboxsync $ */
2/** @file
3 * INATNetwork implementation.
4 */
5
6/*
7 * Copyright (C) 2013-2016 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 <string>
19#include "NetworkServiceRunner.h"
20#include "DHCPServerImpl.h"
21#include "NATNetworkImpl.h"
22#include "AutoCaller.h"
23#include "Logging.h"
24
25#include <iprt/asm.h>
26#include <iprt/cpp/utils.h>
27#include <iprt/cidr.h>
28#include <iprt/net.h>
29#include <VBox/com/array.h>
30#include <VBox/com/ptr.h>
31#include <VBox/settings.h>
32
33#include "EventImpl.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 AssertReturn(!aName.isEmpty(), E_INVALIDARG);
118
119 AutoInitSpan autoInitSpan(this);
120 AssertReturn(autoInitSpan.isOk(), E_FAIL);
121
122 m = new Data();
123 /* share VirtualBox weakly */
124 unconst(m->pVirtualBox) = aVirtualBox;
125 m->s.strNetworkName = aName;
126 m->s.strIPv4NetworkCidr = "10.0.2.0/24";
127 m->offGateway = 1;
128 i_recalculateIPv6Prefix(); /* set m->strIPv6Prefix based on IPv4 */
129
130 settings::NATHostLoopbackOffset off;
131 off.strLoopbackHostAddress = "127.0.0.1";
132 off.u32Offset = (uint32_t)2;
133 m->s.llHostLoopbackOffsetList.push_back(off);
134
135 i_recalculateIpv4AddressAssignments();
136
137 HRESULT hrc = unconst(m->pEventSource).createObject();
138 if (FAILED(hrc)) throw hrc;
139
140 hrc = m->pEventSource->init();
141 if (FAILED(hrc)) throw hrc;
142
143 /* Confirm a successful initialization */
144 autoInitSpan.setSucceeded();
145
146 return S_OK;
147}
148
149
150HRESULT NATNetwork::i_loadSettings(const settings::NATNetwork &data)
151{
152 AutoCaller autoCaller(this);
153 AssertComRCReturnRC(autoCaller.rc());
154
155 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
156 m->s = data;
157 if ( m->s.strIPv6Prefix.isEmpty()
158 /* also clean up bogus old default */
159 || m->s.strIPv6Prefix == "fe80::/64")
160 i_recalculateIPv6Prefix(); /* set m->strIPv6Prefix based on IPv4 */
161 i_recalculateIpv4AddressAssignments();
162
163 return S_OK;
164}
165
166HRESULT NATNetwork::i_saveSettings(settings::NATNetwork &data)
167{
168 AutoCaller autoCaller(this);
169 if (FAILED(autoCaller.rc())) return autoCaller.rc();
170
171 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
172 data = m->s;
173 alock.release();
174
175 m->pVirtualBox->i_onNATNetworkSetting(Bstr(m->s.strNetworkName).raw(),
176 m->s.fEnabled,
177 Bstr(m->s.strIPv4NetworkCidr).raw(),
178 Bstr(m->IPv4Gateway).raw(),
179 m->s.fAdvertiseDefaultIPv6Route,
180 m->s.fNeedDhcpServer);
181
182 /* Notify listerners listening on this network only */
183 fireNATNetworkSettingEvent(m->pEventSource,
184 Bstr(m->s.strNetworkName).raw(),
185 m->s.fEnabled,
186 Bstr(m->s.strIPv4NetworkCidr).raw(),
187 Bstr(m->IPv4Gateway).raw(),
188 m->s.fAdvertiseDefaultIPv6Route,
189 m->s.fNeedDhcpServer);
190
191 return S_OK;
192}
193
194HRESULT NATNetwork::getEventSource(ComPtr<IEventSource> &aEventSource)
195{
196 /* event source is const, no need to lock */
197 m->pEventSource.queryInterfaceTo(aEventSource.asOutParam());
198 return S_OK;
199}
200
201HRESULT NATNetwork::getNetworkName(com::Utf8Str &aNetworkName)
202{
203 aNetworkName = m->s.strNetworkName;
204 return S_OK;
205}
206
207HRESULT NATNetwork::setNetworkName(const com::Utf8Str &aNetworkName)
208{
209 {
210 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
211 if (aNetworkName == m->s.strNetworkName)
212 return S_OK;
213
214 m->s.strNetworkName = aNetworkName;
215 }
216 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
217 HRESULT rc = m->pVirtualBox->i_saveSettings();
218 ComAssertComRCRetRC(rc);
219
220 return S_OK;
221}
222
223HRESULT NATNetwork::getEnabled(BOOL *aEnabled)
224{
225 *aEnabled = m->s.fEnabled;
226
227 i_recalculateIpv4AddressAssignments();
228 return S_OK;
229}
230
231HRESULT NATNetwork::setEnabled(const BOOL aEnabled)
232{
233 {
234 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
235 if (RT_BOOL(aEnabled) == m->s.fEnabled)
236 return S_OK;
237 m->s.fEnabled = RT_BOOL(aEnabled);
238 }
239
240 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
241 HRESULT rc = m->pVirtualBox->i_saveSettings();
242 ComAssertComRCRetRC(rc);
243 return S_OK;
244}
245
246HRESULT NATNetwork::getGateway(com::Utf8Str &aIPv4Gateway)
247{
248 aIPv4Gateway = m->IPv4Gateway;
249 return S_OK;
250}
251
252HRESULT NATNetwork::getNetwork(com::Utf8Str &aNetwork)
253{
254 aNetwork = m->s.strIPv4NetworkCidr;
255 return S_OK;
256}
257
258
259HRESULT NATNetwork::setNetwork(const com::Utf8Str &aIPv4NetworkCidr)
260{
261 {
262
263 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
264
265 if (aIPv4NetworkCidr == m->s.strIPv4NetworkCidr)
266 return S_OK;
267
268 /* silently ignore network cidr update for now.
269 * todo: keep internally guest address of port forward rule
270 * as offset from network id.
271 */
272 if (!m->s.mapPortForwardRules4.empty())
273 return S_OK;
274
275
276 m->s.strIPv4NetworkCidr = aIPv4NetworkCidr;
277 i_recalculateIpv4AddressAssignments();
278 }
279
280 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
281 HRESULT rc = m->pVirtualBox->i_saveSettings();
282 ComAssertComRCRetRC(rc);
283 return S_OK;
284}
285
286
287HRESULT NATNetwork::getIPv6Enabled(BOOL *aIPv6Enabled)
288{
289 *aIPv6Enabled = m->s.fIPv6Enabled;
290
291 return S_OK;
292}
293
294
295HRESULT NATNetwork::setIPv6Enabled(const BOOL aIPv6Enabled)
296{
297 {
298 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
299
300 if (RT_BOOL(aIPv6Enabled) == m->s.fIPv6Enabled)
301 return S_OK;
302
303 m->s.fIPv6Enabled = RT_BOOL(aIPv6Enabled);
304 }
305
306 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
307 HRESULT rc = m->pVirtualBox->i_saveSettings();
308 ComAssertComRCRetRC(rc);
309
310 return S_OK;
311}
312
313
314HRESULT NATNetwork::getIPv6Prefix(com::Utf8Str &aIPv6Prefix)
315{
316 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
317
318 aIPv6Prefix = m->s.strIPv6Prefix;
319 return S_OK;
320}
321
322HRESULT NATNetwork::setIPv6Prefix(const com::Utf8Str &aIPv6Prefix)
323{
324 {
325 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
326
327 if (aIPv6Prefix == m->s.strIPv6Prefix)
328 return S_OK;
329
330 /* silently ignore network IPv6 prefix update.
331 * todo: see similar todo in NATNetwork::COMSETTER(Network)(IN_BSTR)
332 */
333 if (!m->s.mapPortForwardRules6.empty())
334 return S_OK;
335
336 m->s.strIPv6Prefix = aIPv6Prefix;
337 }
338
339 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
340 HRESULT rc = m->pVirtualBox->i_saveSettings();
341 ComAssertComRCRetRC(rc);
342
343 return S_OK;
344}
345
346
347HRESULT NATNetwork::getAdvertiseDefaultIPv6RouteEnabled(BOOL *aAdvertiseDefaultIPv6Route)
348{
349 *aAdvertiseDefaultIPv6Route = m->s.fAdvertiseDefaultIPv6Route;
350
351 return S_OK;
352}
353
354
355HRESULT NATNetwork::setAdvertiseDefaultIPv6RouteEnabled(const BOOL aAdvertiseDefaultIPv6Route)
356{
357 {
358 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
359
360 if (RT_BOOL(aAdvertiseDefaultIPv6Route) == m->s.fAdvertiseDefaultIPv6Route)
361 return S_OK;
362
363 m->s.fAdvertiseDefaultIPv6Route = RT_BOOL(aAdvertiseDefaultIPv6Route);
364
365 }
366
367 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
368 HRESULT rc = m->pVirtualBox->i_saveSettings();
369 ComAssertComRCRetRC(rc);
370
371 return S_OK;
372}
373
374
375HRESULT NATNetwork::getNeedDhcpServer(BOOL *aNeedDhcpServer)
376{
377 *aNeedDhcpServer = m->s.fNeedDhcpServer;
378
379 return S_OK;
380}
381
382HRESULT NATNetwork::setNeedDhcpServer(const BOOL aNeedDhcpServer)
383{
384 {
385 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
386
387 if (RT_BOOL(aNeedDhcpServer) == m->s.fNeedDhcpServer)
388 return S_OK;
389
390 m->s.fNeedDhcpServer = RT_BOOL(aNeedDhcpServer);
391
392 i_recalculateIpv4AddressAssignments();
393
394 }
395
396 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
397 HRESULT rc = m->pVirtualBox->i_saveSettings();
398 ComAssertComRCRetRC(rc);
399
400 return S_OK;
401}
402
403HRESULT NATNetwork::getLocalMappings(std::vector<com::Utf8Str> &aLocalMappings)
404{
405 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
406
407 aLocalMappings.resize(m->s.llHostLoopbackOffsetList.size());
408 size_t i = 0;
409 for (settings::NATLoopbackOffsetList::const_iterator it = m->s.llHostLoopbackOffsetList.begin();
410 it != m->s.llHostLoopbackOffsetList.end(); ++it, ++i)
411 {
412 aLocalMappings[i] = Utf8StrFmt("%s=%d",
413 (*it).strLoopbackHostAddress.c_str(),
414 (*it).u32Offset);
415 }
416
417 return S_OK;
418}
419
420HRESULT NATNetwork::addLocalMapping(const com::Utf8Str &aHostId, LONG aOffset)
421{
422 RTNETADDRIPV4 addr, net, mask;
423
424 int rc = RTNetStrToIPv4Addr(Utf8Str(aHostId).c_str(), &addr);
425 if (RT_FAILURE(rc))
426 return E_INVALIDARG;
427
428 /* check against 127/8 */
429 if ((RT_N2H_U32(addr.u) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)
430 return E_INVALIDARG;
431
432 /* check against networkid vs network mask */
433 rc = RTCidrStrToIPv4(Utf8Str(m->s.strIPv4NetworkCidr).c_str(), &net, &mask);
434 if (RT_FAILURE(rc))
435 return E_INVALIDARG;
436
437 if (((net.u + aOffset) & mask.u) != net.u)
438 return E_INVALIDARG;
439
440 settings::NATLoopbackOffsetList::iterator it;
441
442 it = std::find(m->s.llHostLoopbackOffsetList.begin(),
443 m->s.llHostLoopbackOffsetList.end(),
444 aHostId);
445 if (it != m->s.llHostLoopbackOffsetList.end())
446 {
447 if (aOffset == 0) /* erase */
448 m->s.llHostLoopbackOffsetList.erase(it, it);
449 else /* modify */
450 {
451 settings::NATLoopbackOffsetList::iterator it1;
452 it1 = std::find(m->s.llHostLoopbackOffsetList.begin(),
453 m->s.llHostLoopbackOffsetList.end(),
454 (uint32_t)aOffset);
455 if (it1 != m->s.llHostLoopbackOffsetList.end())
456 return E_INVALIDARG; /* this offset is already registered. */
457
458 (*it).u32Offset = aOffset;
459 }
460
461 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
462 return m->pVirtualBox->i_saveSettings();
463 }
464
465 /* injection */
466 it = std::find(m->s.llHostLoopbackOffsetList.begin(),
467 m->s.llHostLoopbackOffsetList.end(),
468 (uint32_t)aOffset);
469
470 if (it != m->s.llHostLoopbackOffsetList.end())
471 return E_INVALIDARG; /* offset is already registered. */
472
473 settings::NATHostLoopbackOffset off;
474 off.strLoopbackHostAddress = aHostId;
475 off.u32Offset = (uint32_t)aOffset;
476 m->s.llHostLoopbackOffsetList.push_back(off);
477
478 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
479 return m->pVirtualBox->i_saveSettings();
480}
481
482
483HRESULT NATNetwork::getLoopbackIp6(LONG *aLoopbackIp6)
484{
485 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
486
487 *aLoopbackIp6 = m->s.u32HostLoopback6Offset;
488 return S_OK;
489}
490
491
492HRESULT NATNetwork::setLoopbackIp6(LONG aLoopbackIp6)
493{
494 {
495 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
496
497 if (aLoopbackIp6 < 0)
498 return E_INVALIDARG;
499
500 if (static_cast<uint32_t>(aLoopbackIp6) == m->s.u32HostLoopback6Offset)
501 return S_OK;
502
503 m->s.u32HostLoopback6Offset = aLoopbackIp6;
504 }
505
506 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
507 return m->pVirtualBox->i_saveSettings();
508}
509
510
511HRESULT NATNetwork::getPortForwardRules4(std::vector<com::Utf8Str> &aPortForwardRules4)
512{
513 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
514 i_getPortForwardRulesFromMap(aPortForwardRules4,
515 m->s.mapPortForwardRules4);
516 return S_OK;
517}
518
519HRESULT NATNetwork::getPortForwardRules6(std::vector<com::Utf8Str> &aPortForwardRules6)
520{
521 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
522 i_getPortForwardRulesFromMap(aPortForwardRules6,
523 m->s.mapPortForwardRules6);
524 return S_OK;
525}
526
527HRESULT NATNetwork::addPortForwardRule(BOOL aIsIpv6,
528 const com::Utf8Str &aPortForwardRuleName,
529 NATProtocol_T aProto,
530 const com::Utf8Str &aHostIp,
531 USHORT aHostPort,
532 const com::Utf8Str &aGuestIp,
533 USHORT aGuestPort)
534{
535 {
536 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
537 Utf8Str name = aPortForwardRuleName;
538 Utf8Str proto;
539 settings::NATRule r;
540 settings::NATRulesMap &mapRules = aIsIpv6 ? m->s.mapPortForwardRules6 : m->s.mapPortForwardRules4;
541 switch (aProto)
542 {
543 case NATProtocol_TCP:
544 proto = "tcp";
545 break;
546 case NATProtocol_UDP:
547 proto = "udp";
548 break;
549 default:
550 return E_INVALIDARG;
551 }
552 if (name.isEmpty())
553 name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
554 aHostIp.c_str(), aHostPort,
555 aGuestIp.c_str(), aGuestPort);
556
557 for (settings::NATRulesMap::iterator it = mapRules.begin(); it != mapRules.end(); ++it)
558 {
559 r = it->second;
560 if (it->first == name)
561 return setError(E_INVALIDARG,
562 tr("A NAT rule of this name already exists"));
563 if ( r.strHostIP == aHostIp
564 && r.u16HostPort == aHostPort
565 && r.proto == aProto)
566 return setError(E_INVALIDARG,
567 tr("A NAT rule for this host port and this host IP already exists"));
568 }
569
570 r.strName = name.c_str();
571 r.proto = aProto;
572 r.strHostIP = aHostIp;
573 r.u16HostPort = aHostPort;
574 r.strGuestIP = aGuestIp;
575 r.u16GuestPort = aGuestPort;
576 mapRules.insert(std::make_pair(name, r));
577 }
578 {
579 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
580 HRESULT rc = m->pVirtualBox->i_saveSettings();
581 ComAssertComRCRetRC(rc);
582 }
583
584 m->pVirtualBox->i_onNATNetworkPortForward(Bstr(m->s.strNetworkName).raw(), TRUE, aIsIpv6,
585 Bstr(aPortForwardRuleName).raw(), aProto,
586 Bstr(aHostIp).raw(), aHostPort,
587 Bstr(aGuestIp).raw(), aGuestPort);
588
589 /* Notify listerners listening on this network only */
590 fireNATNetworkPortForwardEvent(m->pEventSource, Bstr(m->s.strNetworkName).raw(), TRUE,
591 aIsIpv6, Bstr(aPortForwardRuleName).raw(), aProto,
592 Bstr(aHostIp).raw(), aHostPort,
593 Bstr(aGuestIp).raw(), aGuestPort);
594
595 return S_OK;
596}
597
598HRESULT NATNetwork::removePortForwardRule(BOOL aIsIpv6, const com::Utf8Str &aPortForwardRuleName)
599{
600 Utf8Str strHostIP;
601 Utf8Str strGuestIP;
602 uint16_t u16HostPort;
603 uint16_t u16GuestPort;
604 NATProtocol_T proto;
605
606 {
607 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
608 settings::NATRulesMap &mapRules = aIsIpv6 ? m->s.mapPortForwardRules6 : m->s.mapPortForwardRules4;
609 settings::NATRulesMap::iterator it = mapRules.find(aPortForwardRuleName);
610
611 if (it == mapRules.end())
612 return E_INVALIDARG;
613
614 strHostIP = it->second.strHostIP;
615 strGuestIP = it->second.strGuestIP;
616 u16HostPort = it->second.u16HostPort;
617 u16GuestPort = it->second.u16GuestPort;
618 proto = it->second.proto;
619
620 mapRules.erase(it);
621 }
622
623 {
624 AutoWriteLock vboxLock(m->pVirtualBox COMMA_LOCKVAL_SRC_POS);
625 HRESULT rc = m->pVirtualBox->i_saveSettings();
626 ComAssertComRCRetRC(rc);
627 }
628
629 m->pVirtualBox->i_onNATNetworkPortForward(Bstr(m->s.strNetworkName).raw(), FALSE, aIsIpv6,
630 Bstr(aPortForwardRuleName).raw(), proto,
631 Bstr(strHostIP).raw(), u16HostPort,
632 Bstr(strGuestIP).raw(), u16GuestPort);
633
634 /* Notify listerners listening on this network only */
635 fireNATNetworkPortForwardEvent(m->pEventSource, Bstr(m->s.strNetworkName).raw(), FALSE,
636 aIsIpv6, Bstr(aPortForwardRuleName).raw(), proto,
637 Bstr(strHostIP).raw(), u16HostPort,
638 Bstr(strGuestIP).raw(), u16GuestPort);
639 return S_OK;
640}
641
642
643HRESULT NATNetwork::start(const com::Utf8Str &aTrunkType)
644{
645#ifdef VBOX_WITH_NAT_SERVICE
646 if (!m->s.fEnabled) return S_OK;
647
648 m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyNetwork, Utf8Str(m->s.strNetworkName).c_str());
649 m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str());
650 m->NATRunner.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPv4Gateway).c_str());
651 m->NATRunner.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->IPv4NetworkMask).c_str());
652
653 /* No portforwarding rules from command-line, all will be fetched via API */
654
655 if (m->s.fNeedDhcpServer)
656 {
657 /*
658 * Just to as idea... via API (on creation user pass the cidr of network and)
659 * and we calculate it's addreses (mutable?).
660 */
661
662 /*
663 * Configuration and running DHCP server:
664 * 1. find server first createDHCPServer
665 * 2. if return status is E_INVALARG => server already exists just find and start.
666 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
667 * 4. if return status S_OK proceed to DHCP server configuration
668 * 5. call setConfiguration() and pass all required parameters
669 * 6. start dhcp server.
670 */
671 HRESULT hrc = m->pVirtualBox->FindDHCPServerByNetworkName(Bstr(m->s.strNetworkName).raw(),
672 m->dhcpServer.asOutParam());
673 switch (hrc)
674 {
675 case E_INVALIDARG:
676 /* server haven't beeen found let create it then */
677 hrc = m->pVirtualBox->CreateDHCPServer(Bstr(m->s.strNetworkName).raw(),
678 m->dhcpServer.asOutParam());
679 if (FAILED(hrc))
680 return E_FAIL;
681 /* breakthrough */
682
683 {
684 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
685 m->IPv4Gateway.c_str(),
686 m->IPv4DhcpServer.c_str(),
687 m->IPv4DhcpServerLowerIp.c_str(),
688 m->IPv4DhcpServerUpperIp.c_str()));
689
690 hrc = m->dhcpServer->COMSETTER(Enabled)(true);
691
692 BSTR dhcpip = NULL;
693 BSTR netmask = NULL;
694 BSTR lowerip = NULL;
695 BSTR upperip = NULL;
696
697 m->IPv4DhcpServer.cloneTo(&dhcpip);
698 m->IPv4NetworkMask.cloneTo(&netmask);
699 m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
700 m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
701 hrc = m->dhcpServer->SetConfiguration(dhcpip,
702 netmask,
703 lowerip,
704 upperip);
705 }
706 case S_OK:
707 break;
708
709 default:
710 return E_FAIL;
711 }
712
713 /* XXX: AddGlobalOption(DhcpOpt_Router,) - enables attachement of DhcpServer to Main. */
714 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, Bstr(m->IPv4Gateway).raw());
715
716 hrc = m->dhcpServer->Start(Bstr(m->s.strNetworkName).raw(), Bstr("").raw(), Bstr(aTrunkType).raw());
717 if (FAILED(hrc))
718 {
719 m->dhcpServer.setNull();
720 return E_FAIL;
721 }
722 }
723
724 if (RT_SUCCESS(m->NATRunner.start(false /* KillProcOnStop */)))
725 {
726 m->pVirtualBox->i_onNATNetworkStartStop(Bstr(m->s.strNetworkName).raw(), TRUE);
727 return S_OK;
728 }
729 /** @todo missing setError()! */
730 return E_FAIL;
731#else
732 NOREF(aTrunkType);
733 ReturnComNotImplemented();
734#endif
735}
736
737HRESULT NATNetwork::stop()
738{
739#ifdef VBOX_WITH_NAT_SERVICE
740 m->pVirtualBox->i_onNATNetworkStartStop(Bstr(m->s.strNetworkName).raw(), FALSE);
741
742 if (!m->dhcpServer.isNull())
743 m->dhcpServer->Stop();
744
745 if (RT_SUCCESS(m->NATRunner.stop()))
746 return S_OK;
747
748 /** @todo missing setError()! */
749 return E_FAIL;
750#else
751 ReturnComNotImplemented();
752#endif
753}
754
755
756void NATNetwork::i_getPortForwardRulesFromMap(std::vector<com::Utf8Str> &aPortForwardRules, settings::NATRulesMap &aRules)
757{
758 aPortForwardRules.resize(aRules.size());
759 size_t i = 0;
760 for (settings::NATRulesMap::const_iterator it = aRules.begin();
761 it != aRules.end(); ++it, ++i)
762 {
763 settings::NATRule r = it->second;
764 aPortForwardRules[i] = Utf8StrFmt("%s:%s:[%s]:%d:[%s]:%d",
765 r.strName.c_str(),
766 (r.proto == NATProtocol_TCP ? "tcp" : "udp"),
767 r.strHostIP.c_str(),
768 r.u16HostPort,
769 r.strGuestIP.c_str(),
770 r.u16GuestPort);
771 }
772}
773
774
775int NATNetwork::i_findFirstAvailableOffset(ADDRESSLOOKUPTYPE addrType, uint32_t *poff)
776{
777 RTNETADDRIPV4 network, netmask;
778
779 int rc = RTCidrStrToIPv4(m->s.strIPv4NetworkCidr.c_str(),
780 &network,
781 &netmask);
782 AssertRCReturn(rc, rc);
783
784 uint32_t off;
785 for (off = 1; off < ~netmask.u; ++off)
786 {
787 bool skip = false;
788 for (settings::NATLoopbackOffsetList::iterator it = m->s.llHostLoopbackOffsetList.begin();
789 it != m->s.llHostLoopbackOffsetList.end();
790 ++it)
791 {
792 if ((*it).u32Offset == off)
793 {
794 skip = true;
795 break;
796 }
797
798 }
799
800 if (skip)
801 continue;
802
803 if (off == m->offGateway)
804 {
805 if (addrType == ADDR_GATEWAY)
806 break;
807 else
808 continue;
809 }
810
811 if (off == m->offDhcp)
812 {
813 if (addrType == ADDR_DHCP)
814 break;
815 else
816 continue;
817 }
818
819 if (!skip)
820 break;
821 }
822
823 if (poff)
824 *poff = off;
825
826 return VINF_SUCCESS;
827}
828
829int NATNetwork::i_recalculateIpv4AddressAssignments()
830{
831 RTNETADDRIPV4 network, netmask;
832 int rc = RTCidrStrToIPv4(m->s.strIPv4NetworkCidr.c_str(),
833 &network,
834 &netmask);
835 AssertRCReturn(rc, rc);
836
837 i_findFirstAvailableOffset(ADDR_GATEWAY, &m->offGateway);
838 if (m->s.fNeedDhcpServer)
839 i_findFirstAvailableOffset(ADDR_DHCP, &m->offDhcp);
840
841 /* I don't remember the reason CIDR calculated on the host. */
842 RTNETADDRIPV4 gateway = network;
843 gateway.u += m->offGateway;
844 gateway.u = RT_H2N_U32(gateway.u);
845 char szTmpIp[16];
846 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", gateway);
847 m->IPv4Gateway = szTmpIp;
848
849 if (m->s.fNeedDhcpServer)
850 {
851 RTNETADDRIPV4 dhcpserver = network;
852 dhcpserver.u += m->offDhcp;
853
854 /* XXX: adding more services should change the math here */
855 RTNETADDRIPV4 dhcplowerip = network;
856 uint32_t offDhcpLowerIp;
857 i_findFirstAvailableOffset(ADDR_DHCPLOWERIP, &offDhcpLowerIp);
858 dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp);
859
860 RTNETADDRIPV4 dhcpupperip;
861 dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1);
862
863 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
864 network.u = RT_H2N_U32(network.u);
865
866 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver);
867 m->IPv4DhcpServer = szTmpIp;
868 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip);
869 m->IPv4DhcpServerLowerIp = szTmpIp;
870 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip);
871 m->IPv4DhcpServerUpperIp = szTmpIp;
872
873 LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
874 network, dhcpserver, dhcplowerip, dhcpupperip));
875 }
876
877 /* we need IPv4NetworkMask for NAT's gw service start */
878 netmask.u = RT_H2N_U32(netmask.u);
879 RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask);
880 m->IPv4NetworkMask = szTmpIp;
881
882 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
883 return VINF_SUCCESS;
884}
885
886
887int NATNetwork::i_recalculateIPv6Prefix()
888{
889 int rc;
890
891 RTNETADDRIPV4 net, mask;
892 rc = RTCidrStrToIPv4(Utf8Str(m->s.strIPv4NetworkCidr).c_str(), &net, &mask);
893 if (RT_FAILURE(rc))
894 return rc;
895
896 net.u = RT_H2N_U32(net.u); /* XXX: fix RTCidrStrToIPv4! */
897
898 /*
899 * [fd17:625c:f037:XXXX::/64] - RFC 4193 (ULA) Locally Assigned
900 * Global ID where XXXX, 16 bit Subnet ID, are two bytes from the
901 * middle of the IPv4 address, e.g. :dead: for 10.222.173.1
902 */
903 RTNETADDRIPV6 prefix;
904 RT_ZERO(prefix);
905
906 prefix.au8[0] = 0xFD;
907 prefix.au8[1] = 0x17;
908
909 prefix.au8[2] = 0x62;
910 prefix.au8[3] = 0x5C;
911
912 prefix.au8[4] = 0xF0;
913 prefix.au8[5] = 0x37;
914
915 prefix.au8[6] = net.au8[1];
916 prefix.au8[7] = net.au8[2];
917
918 char szBuf[32];
919 RTStrPrintf(szBuf, sizeof(szBuf), "%RTnaipv6/64", &prefix);
920
921 m->s.strIPv6Prefix = szBuf;
922 return VINF_SUCCESS;
923}
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