VirtualBox

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

Last change on this file since 49612 was 49612, checked in by vboxsync, 12 years ago

NATNetworkImpl.cpp: FindDHCPServerByNetworkName() returns HRESULT, but no int.
[-Wc++11-narrowing]

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

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