VirtualBox

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

Last change on this file since 55457 was 54705, checked in by vboxsync, 10 years ago

Main: VBoxNetNAT/VBoxNetDHCP: sometimes it's required to kill the runner process (in case of no Main clients)

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