VirtualBox

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

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

Introduce option "--need-main(-M) on|off" in network services to emphosize whether network service need to establish connection with Main (by default this optiois off).

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