VirtualBox

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

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

Main/NATNetworkImpl.cpp: replace explicit autolock releasing with scopping.

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