VirtualBox

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

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

Main/NATNetworkImpl.cpp: G/c -line.

  • 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 49136 2013-10-16 12:27:10Z 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 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
430 HRESULT rc = mVirtualBox->saveSettings();
431 ComAssertComRCRetRC(rc);
432
433 return S_OK;
434}
435
436STDMETHODIMP NATNetwork::COMGETTER(IPv6Prefix) (BSTR *aIPv6Prefix)
437{
438 CheckComArgOutPointerValid(aIPv6Prefix);
439
440 AutoCaller autoCaller(this);
441 if (FAILED(autoCaller.rc())) return autoCaller.rc();
442 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
443
444 m->IPv6Prefix.cloneTo(aIPv6Prefix);
445
446 return S_OK;
447}
448
449STDMETHODIMP NATNetwork::COMSETTER(IPv6Prefix) (IN_BSTR aIPv6Prefix)
450{
451 CheckComArgOutPointerValid(aIPv6Prefix);
452
453 AutoCaller autoCaller(this);
454 if (FAILED(autoCaller.rc()))
455 return autoCaller.rc();
456
457 {
458 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
459
460 if (aIPv6Prefix == m->IPv6Prefix)
461 return S_OK;
462
463 /* silently ignore network IPv6 prefix update.
464 * todo: see similar todo in NATNetwork::COMSETTER(Network)(IN_BSTR)
465 */
466 if (!m->mapName2PortForwardRule6.empty())
467 return S_OK;
468
469 unconst(m->IPv6Prefix) = Bstr(aIPv6Prefix);
470 }
471
472 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
473 HRESULT rc = mVirtualBox->saveSettings();
474 ComAssertComRCRetRC(rc);
475
476 return S_OK;
477}
478
479STDMETHODIMP NATNetwork::COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL *aAdvertiseDefaultIPv6Route)
480{
481 CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route);
482
483 AutoCaller autoCaller(this);
484 if (FAILED(autoCaller.rc())) return autoCaller.rc();
485
486 *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route;
487
488 return S_OK;
489}
490
491STDMETHODIMP NATNetwork::COMSETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL aAdvertiseDefaultIPv6Route)
492{
493 AutoCaller autoCaller(this);
494 if (FAILED(autoCaller.rc()))
495 return autoCaller.rc();
496
497 {
498 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
499
500 if (aAdvertiseDefaultIPv6Route == m->fAdvertiseDefaultIPv6Route)
501 return S_OK;
502
503 m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route;
504
505 }
506
507 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
508 HRESULT rc = mVirtualBox->saveSettings();
509 ComAssertComRCRetRC(rc);
510
511 return S_OK;
512}
513
514STDMETHODIMP NATNetwork::COMGETTER(NeedDhcpServer)(BOOL *aNeedDhcpServer)
515{
516 CheckComArgOutPointerValid(aNeedDhcpServer);
517
518 AutoCaller autoCaller(this);
519 if (FAILED(autoCaller.rc())) return autoCaller.rc();
520
521 *aNeedDhcpServer = m->fNeedDhcpServer;
522
523 return S_OK;
524}
525
526STDMETHODIMP NATNetwork::COMSETTER(NeedDhcpServer)(BOOL aNeedDhcpServer)
527{
528 AutoCaller autoCaller(this);
529 if (FAILED(autoCaller.rc()))
530 return autoCaller.rc();
531
532 {
533 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
534
535 if (aNeedDhcpServer == m->fNeedDhcpServer)
536 return S_OK;
537
538 m->fNeedDhcpServer = aNeedDhcpServer;
539
540 recalculateIpv4AddressAssignments();
541
542 }
543
544 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
545 HRESULT rc = mVirtualBox->saveSettings();
546 ComAssertComRCRetRC(rc);
547
548 return S_OK;
549}
550
551
552STDMETHODIMP NATNetwork::COMGETTER(LocalMappings)(ComSafeArrayOut(BSTR, aLocalMappings))
553{
554 CheckComArgOutSafeArrayPointerValid(aLocalMappings);
555
556 AutoCaller autoCaller(this);
557 if (FAILED(autoCaller.rc())) return autoCaller.rc();
558 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
559
560 com::SafeArray<BSTR> sf(m->llNATLoopbackOffsetList.size());
561
562 size_t i = 0;
563 settings::NATLoopbackOffsetList::const_iterator it;
564
565 for (it = m->llNATLoopbackOffsetList.begin();
566 it != m->llNATLoopbackOffsetList.end(); ++it, ++i)
567 {
568 BstrFmt bstr("%s=%d",
569 (*it).strLoopbackHostAddress.c_str(),
570 (*it).u32Offset);
571 bstr.detachTo(&sf[i]);
572 }
573 sf.detachTo(ComSafeArrayOutArg(aLocalMappings));
574
575 return S_OK;
576}
577
578
579STDMETHODIMP NATNetwork::AddLocalMapping(IN_BSTR aHostId, LONG aOffset)
580{
581 AutoCaller autoCaller(this);
582 if (FAILED(autoCaller.rc())) return autoCaller.rc();
583
584 //AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
585
586 RTNETADDRIPV4 addr, net, mask;
587
588 int rc = RTNetStrToIPv4Addr(Utf8Str(aHostId).c_str(), &addr);
589 if (RT_FAILURE(rc))
590 return E_INVALIDARG;
591
592 /* check against 127/8 */
593 if ((RT_N2H_U32(addr.u) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)
594 return E_INVALIDARG;
595
596 /* check against networkid vs network mask */
597 rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr).c_str(), &net, &mask);
598 if (RT_FAILURE(rc))
599 return E_INVALIDARG;
600
601 if (((net.u + aOffset) & mask.u) != net.u)
602 return E_INVALIDARG;
603
604 settings::NATLoopbackOffsetList::iterator it;
605
606 it = std::find(m->llNATLoopbackOffsetList.begin(),
607 m->llNATLoopbackOffsetList.end(),
608 Utf8Str(aHostId).c_str());
609
610 if (it != m->llNATLoopbackOffsetList.end())
611 {
612 if (aOffset == 0) /* erase */
613 m->llNATLoopbackOffsetList.erase(it, it);
614 else /* modify */
615 {
616 settings::NATLoopbackOffsetList::iterator it1;
617 it1 = std::find(m->llNATLoopbackOffsetList.begin(),
618 m->llNATLoopbackOffsetList.end(),
619 (uint32_t)aOffset);
620 if (it1 != m->llNATLoopbackOffsetList.end())
621 return E_INVALIDARG; /* this offset is already registered. */
622
623 (*it).u32Offset = aOffset;
624 }
625
626 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
627 return mVirtualBox->saveSettings();
628 }
629
630 /* injection */
631 it = std::find(m->llNATLoopbackOffsetList.begin(),
632 m->llNATLoopbackOffsetList.end(),
633 (uint32_t)aOffset);
634
635 if (it != m->llNATLoopbackOffsetList.end())
636 return E_INVALIDARG; /* offset is already registered. */
637
638 settings::NATHostLoopbackOffset off;
639 off.strLoopbackHostAddress = aHostId;
640 off.u32Offset = (uint32_t)aOffset;
641 m->llNATLoopbackOffsetList.push_back(off);
642
643 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
644 return mVirtualBox->saveSettings();
645}
646
647
648STDMETHODIMP NATNetwork::COMGETTER(LoopbackIp6)(LONG *aLoopbackIp6)
649{
650 AutoCaller autoCaller(this);
651 if (FAILED(autoCaller.rc())) return autoCaller.rc();
652 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
653
654 *aLoopbackIp6 = m->u32LoopbackIp6;
655 return S_OK;
656}
657
658
659STDMETHODIMP NATNetwork::COMSETTER(LoopbackIp6)(LONG aLoopbackIp6)
660{
661 AutoCaller autoCaller(this);
662 if (FAILED(autoCaller.rc()))
663 return autoCaller.rc();
664
665 {
666 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
667
668 if (aLoopbackIp6 < 0)
669 return E_INVALIDARG;
670
671 if (static_cast<uint32_t>(aLoopbackIp6) == m->u32LoopbackIp6)
672 return S_OK;
673
674 m->u32LoopbackIp6 = aLoopbackIp6;
675 }
676
677 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
678 return mVirtualBox->saveSettings();
679}
680
681STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules4)(ComSafeArrayOut(BSTR, aPortForwardRules4))
682{
683 CheckComArgOutSafeArrayPointerValid(aPortForwardRules4);
684
685 AutoCaller autoCaller(this);
686 if (FAILED(autoCaller.rc())) return autoCaller.rc();
687
688 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
689 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules4),
690 m->mapName2PortForwardRule4);
691 return S_OK;
692}
693
694STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules6)(ComSafeArrayOut(BSTR,
695 aPortForwardRules6))
696{
697 CheckComArgOutSafeArrayPointerValid(aPortForwardRules6);
698
699 AutoCaller autoCaller(this);
700 if (FAILED(autoCaller.rc())) return autoCaller.rc();
701
702 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
703 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules6), m->mapName2PortForwardRule6);
704 return S_OK;
705}
706
707STDMETHODIMP NATNetwork::AddPortForwardRule(BOOL aIsIpv6,
708 IN_BSTR aPortForwardRuleName,
709 NATProtocol_T aProto,
710 IN_BSTR aHostIp,
711 USHORT aHostPort,
712 IN_BSTR aGuestIp,
713 USHORT aGuestPort)
714{
715 AutoCaller autoCaller(this);
716 if (FAILED(autoCaller.rc()))
717 return autoCaller.rc();
718
719 {
720 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
721 Utf8Str name = aPortForwardRuleName;
722 Utf8Str proto;
723 settings::NATRule r;
724 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
725 switch (aProto)
726 {
727 case NATProtocol_TCP:
728 proto = "tcp";
729 break;
730 case NATProtocol_UDP:
731 proto = "udp";
732 break;
733 default:
734 return E_INVALIDARG;
735 }
736 if (name.isEmpty())
737 name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
738 Utf8Str(aHostIp).c_str(), aHostPort,
739 Utf8Str(aGuestIp).c_str(), aGuestPort);
740
741 NATRuleMap::iterator it;
742
743 for (it = mapRules.begin(); it != mapRules.end(); ++it)
744 {
745 r = it->second;
746 if (it->first == name)
747 return setError(E_INVALIDARG,
748 tr("A NAT rule of this name already exists"));
749 if ( r.strHostIP == Utf8Str(aHostIp)
750 && r.u16HostPort == aHostPort
751 && r.proto == aProto)
752 return setError(E_INVALIDARG,
753 tr("A NAT rule for this host port and this host IP already exists"));
754 }
755
756 r.strName = name.c_str();
757 r.proto = aProto;
758 r.strHostIP = aHostIp;
759 r.u16HostPort = aHostPort;
760 r.strGuestIP = aGuestIp;
761 r.u16GuestPort = aGuestPort;
762 mapRules.insert(std::make_pair(name, r));
763 }
764
765 {
766 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
767 HRESULT rc = mVirtualBox->saveSettings();
768 ComAssertComRCRetRC(rc);
769 }
770
771 mVirtualBox->onNATNetworkPortForward(mName.raw(), TRUE, aIsIpv6,
772 aPortForwardRuleName, aProto,
773 aHostIp, aHostPort,
774 aGuestIp, aGuestPort);
775
776 /* Notify listerners listening on this network only */
777 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), TRUE,
778 aIsIpv6, aPortForwardRuleName, aProto,
779 aHostIp, aHostPort,
780 aGuestIp, aGuestPort);
781 return S_OK;
782}
783
784STDMETHODIMP NATNetwork::RemovePortForwardRule(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName)
785{
786 AutoCaller autoCaller(this);
787 if (FAILED(autoCaller.rc()))
788 return autoCaller.rc();
789
790 Utf8Str strHostIP;
791 Utf8Str strGuestIP;
792 uint16_t u16HostPort;
793 uint16_t u16GuestPort;
794 NATProtocol_T proto;
795
796
797 {
798 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
799 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6
800 : m->mapName2PortForwardRule4;
801
802 NATRuleMap::iterator it = mapRules.find(aPortForwardRuleName);
803
804 if (it == mapRules.end())
805 return E_INVALIDARG;
806
807 strHostIP = it->second.strHostIP;
808 strGuestIP = it->second.strGuestIP;
809 u16HostPort = it->second.u16HostPort;
810 u16GuestPort = it->second.u16GuestPort;
811 proto = it->second.proto;
812
813 mapRules.erase(it);
814 }
815
816 {
817 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
818 HRESULT rc = mVirtualBox->saveSettings();
819 ComAssertComRCRetRC(rc);
820 }
821
822 mVirtualBox->onNATNetworkPortForward(mName.raw(), FALSE, aIsIpv6,
823 aPortForwardRuleName, proto,
824 Bstr(strHostIP).raw(), u16HostPort,
825 Bstr(strGuestIP).raw(), u16GuestPort);
826
827 /* Notify listerners listening on this network only */
828 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), FALSE,
829 aIsIpv6, aPortForwardRuleName, proto,
830 Bstr(strHostIP).raw(), u16HostPort,
831 Bstr(strGuestIP).raw(), u16GuestPort);
832 return S_OK;
833}
834
835
836STDMETHODIMP NATNetwork::Start(IN_BSTR aTrunkType)
837{
838#ifdef VBOX_WITH_NAT_SERVICE
839 AutoCaller autoCaller(this);
840 if (FAILED(autoCaller.rc())) return autoCaller.rc();
841
842 if (!m->fEnabled) return S_OK;
843
844 m->NATRunner.setOption(NETCFG_NETNAME, mName, true);
845 m->NATRunner.setOption(NETCFG_TRUNKTYPE, Utf8Str(aTrunkType), true);
846 m->NATRunner.setOption(NETCFG_IPADDRESS, m->IPv4Gateway, true);
847 m->NATRunner.setOption(NETCFG_NETMASK, m->IPv4NetworkMask, true);
848
849 /* No portforwarding rules from command-line, all will be fetched via API */
850
851 if (m->fNeedDhcpServer)
852 {
853 /*
854 * Just to as idea... via API (on creation user pass the cidr of network and)
855 * and we calculate it's addreses (mutable?).
856 */
857
858 /*
859 * Configuration and running DHCP server:
860 * 1. find server first createDHCPServer
861 * 2. if return status is E_INVALARG => server already exists just find and start.
862 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
863 * 4. if return status S_OK proceed to DHCP server configuration
864 * 5. call setConfiguration() and pass all required parameters
865 * 6. start dhcp server.
866 */
867 int rc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(),
868 m->dhcpServer.asOutParam());
869 switch (rc)
870 {
871 case E_INVALIDARG:
872 /* server haven't beeen found let create it then */
873 rc = mVirtualBox->CreateDHCPServer(mName.raw(),
874 m->dhcpServer.asOutParam());
875 if (FAILED(rc))
876 return E_FAIL;
877 /* breakthrough */
878
879 {
880 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
881 Utf8Str(m->IPv4Gateway.raw()).c_str(),
882 Utf8Str(m->IPv4DhcpServer.raw()).c_str(),
883 Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(),
884 Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str()));
885
886 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw());
887
888 rc = m->dhcpServer->COMSETTER(Enabled)(true);
889
890 BSTR dhcpip = NULL;
891 BSTR netmask = NULL;
892 BSTR lowerip = NULL;
893 BSTR upperip = NULL;
894
895 m->IPv4DhcpServer.cloneTo(&dhcpip);
896 m->IPv4NetworkMask.cloneTo(&netmask);
897 m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
898 m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
899 rc = m->dhcpServer->SetConfiguration(dhcpip,
900 netmask,
901 lowerip,
902 upperip);
903 }
904 case S_OK:
905 break;
906
907 default:
908 return E_FAIL;
909 }
910
911 rc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType);
912 if (FAILED(rc))
913 {
914 m->dhcpServer.setNull();
915 return E_FAIL;
916 }
917 }
918
919 if (RT_SUCCESS(m->NATRunner.start()))
920 {
921 mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE);
922 return S_OK;
923 }
924 /** @todo missing setError()! */
925 return E_FAIL;
926#else
927 NOREF(aTrunkType);
928 ReturnComNotImplemented();
929#endif
930}
931
932STDMETHODIMP NATNetwork::Stop()
933{
934#ifdef VBOX_WITH_NAT_SERVICE
935 if (!m->dhcpServer.isNull())
936 m->dhcpServer->Stop();
937
938 if (RT_SUCCESS(m->NATRunner.stop()))
939 {
940 mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE);
941 return S_OK;
942 }
943 /** @todo missing setError()! */
944 return E_FAIL;
945#else
946 ReturnComNotImplemented();
947#endif
948}
949
950void NATNetwork::GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules)
951{
952 com::SafeArray<BSTR> sf(aRules.size());
953 size_t i = 0;
954 NATRuleMap::const_iterator it;
955 for (it = aRules.begin();
956 it != aRules.end(); ++it, ++i)
957 {
958 settings::NATRule r = it->second;
959 BstrFmt bstr("%s:%s:[%s]:%d:[%s]:%d",
960 r.strName.c_str(),
961 (r.proto == NATProtocol_TCP? "tcp" : "udp"),
962 r.strHostIP.c_str(),
963 r.u16HostPort,
964 r.strGuestIP.c_str(),
965 r.u16GuestPort);
966 bstr.detachTo(&sf[i]);
967 }
968 sf.detachTo(ComSafeArrayOutArg(aPortForwardRules));
969}
970
971
972int NATNetwork::findFirstAvailableOffset(ADDRESSLOOKUPTYPE addrType, uint32_t *poff)
973{
974 RTNETADDRIPV4 network, netmask;
975
976 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
977 &network,
978 &netmask);
979 AssertRCReturn(rc, rc);
980
981 uint32_t off;
982 settings::NATLoopbackOffsetList::iterator it;
983 for (off = 1; off < ~netmask.u; ++off)
984 {
985
986 bool skip = false;
987 for (it = m->llNATLoopbackOffsetList.begin();
988 it != m->llNATLoopbackOffsetList.end();
989 ++it)
990 {
991 if ((*it).u32Offset == off)
992 {
993 skip = true;
994 break;
995 }
996
997 }
998
999 if (skip)
1000 continue;
1001
1002 if (off == m->offGateway)
1003 {
1004 if (addrType == ADDR_GATEWAY)
1005 break;
1006 else
1007 continue;
1008 }
1009
1010 if (off == m->offDhcp)
1011 {
1012 if (addrType == ADDR_DHCP)
1013 break;
1014 else
1015 continue;
1016 }
1017
1018 if (!skip)
1019 break;
1020 }
1021
1022 if (poff)
1023 *poff = off;
1024
1025 return VINF_SUCCESS;
1026}
1027
1028int NATNetwork::recalculateIpv4AddressAssignments()
1029{
1030 RTNETADDRIPV4 network, netmask;
1031 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
1032 &network,
1033 &netmask);
1034 AssertRCReturn(rc, rc);
1035
1036 findFirstAvailableOffset(ADDR_GATEWAY, &m->offGateway);
1037 if (m->fNeedDhcpServer)
1038 findFirstAvailableOffset(ADDR_DHCP, &m->offDhcp);
1039
1040 /* I don't remember the reason CIDR calculated on the host. */
1041 RTNETADDRIPV4 gateway = network;
1042 gateway.u += m->offGateway;
1043 gateway.u = RT_H2N_U32(gateway.u);
1044 char szTmpIp[16];
1045 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", gateway);
1046 m->IPv4Gateway = szTmpIp;
1047
1048 if (m->fNeedDhcpServer)
1049 {
1050 RTNETADDRIPV4 dhcpserver = network;
1051 dhcpserver.u += m->offDhcp;
1052
1053 /* XXX: adding more services should change the math here */
1054 RTNETADDRIPV4 dhcplowerip = network;
1055 uint32_t offDhcpLowerIp;
1056 findFirstAvailableOffset(ADDR_DHCPLOWERIP, &offDhcpLowerIp);
1057 dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp);
1058
1059 RTNETADDRIPV4 dhcpupperip;
1060 dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1);
1061
1062 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
1063 network.u = RT_H2N_U32(network.u);
1064
1065 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver);
1066 m->IPv4DhcpServer = szTmpIp;
1067 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip);
1068 m->IPv4DhcpServerLowerIp = szTmpIp;
1069 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip);
1070 m->IPv4DhcpServerUpperIp = szTmpIp;
1071
1072 LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
1073 network, dhcpserver, dhcplowerip, dhcpupperip));
1074 }
1075
1076 /* we need IPv4NetworkMask for NAT's gw service start */
1077 netmask.u = RT_H2N_U32(netmask.u);
1078 RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask);
1079 m->IPv4NetworkMask = szTmpIp;
1080
1081 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
1082 return VINF_SUCCESS;
1083}
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