VirtualBox

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

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

since r90752 VBoxNetNAT always connects to VBoxSVC, so there're no reasons to explicitly add '--need-main' to VBoxNetNAT's argument list.

  • 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 49614 2013-11-21 16:43:35Z 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(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::kNsrKeyNetwork, Utf8Str(mName).c_str());
873 m->NATRunner.setOption(NetworkServiceRunner::kNsrKeyTrunkType, Utf8Str(aTrunkType).c_str());
874 m->NATRunner.setOption(NetworkServiceRunner::kNsrIpAddress, Utf8Str(m->IPv4Gateway).c_str());
875 m->NATRunner.setOption(NetworkServiceRunner::kNsrIpNetmask, Utf8Str(m->IPv4NetworkMask).c_str());
876
877 /* No portforwarding rules from command-line, all will be fetched via API */
878
879 if (m->fNeedDhcpServer)
880 {
881 /*
882 * Just to as idea... via API (on creation user pass the cidr of network and)
883 * and we calculate it's addreses (mutable?).
884 */
885
886 /*
887 * Configuration and running DHCP server:
888 * 1. find server first createDHCPServer
889 * 2. if return status is E_INVALARG => server already exists just find and start.
890 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
891 * 4. if return status S_OK proceed to DHCP server configuration
892 * 5. call setConfiguration() and pass all required parameters
893 * 6. start dhcp server.
894 */
895 HRESULT hrc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(),
896 m->dhcpServer.asOutParam());
897 switch (hrc)
898 {
899 case E_INVALIDARG:
900 /* server haven't beeen found let create it then */
901 hrc = mVirtualBox->CreateDHCPServer(mName.raw(),
902 m->dhcpServer.asOutParam());
903 if (FAILED(hrc))
904 return E_FAIL;
905 /* breakthrough */
906
907 {
908 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
909 Utf8Str(m->IPv4Gateway.raw()).c_str(),
910 Utf8Str(m->IPv4DhcpServer.raw()).c_str(),
911 Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(),
912 Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str()));
913
914 hrc = m->dhcpServer->COMSETTER(Enabled)(true);
915
916 BSTR dhcpip = NULL;
917 BSTR netmask = NULL;
918 BSTR lowerip = NULL;
919 BSTR upperip = NULL;
920
921 m->IPv4DhcpServer.cloneTo(&dhcpip);
922 m->IPv4NetworkMask.cloneTo(&netmask);
923 m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
924 m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
925 hrc = m->dhcpServer->SetConfiguration(dhcpip,
926 netmask,
927 lowerip,
928 upperip);
929 }
930 case S_OK:
931 break;
932
933 default:
934 return E_FAIL;
935 }
936
937 /* XXX: AddGlobalOption(DhcpOpt_Router,) - enables attachement of DhcpServer to Main. */
938 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw());
939
940 hrc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType);
941 if (FAILED(hrc))
942 {
943 m->dhcpServer.setNull();
944 return E_FAIL;
945 }
946 }
947
948 if (RT_SUCCESS(m->NATRunner.start()))
949 {
950 mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE);
951 return S_OK;
952 }
953 /** @todo missing setError()! */
954 return E_FAIL;
955#else
956 NOREF(aTrunkType);
957 ReturnComNotImplemented();
958#endif
959}
960
961
962STDMETHODIMP NATNetwork::Stop()
963{
964#ifdef VBOX_WITH_NAT_SERVICE
965 if (!m->dhcpServer.isNull())
966 m->dhcpServer->Stop();
967
968 if (RT_SUCCESS(m->NATRunner.stop()))
969 {
970 mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE);
971 return S_OK;
972 }
973 /** @todo missing setError()! */
974 return E_FAIL;
975#else
976 ReturnComNotImplemented();
977#endif
978}
979
980
981void NATNetwork::GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules)
982{
983 com::SafeArray<BSTR> sf(aRules.size());
984 size_t i = 0;
985 NATRuleMap::const_iterator it;
986 for (it = aRules.begin();
987 it != aRules.end(); ++it, ++i)
988 {
989 settings::NATRule r = it->second;
990 BstrFmt bstr("%s:%s:[%s]:%d:[%s]:%d",
991 r.strName.c_str(),
992 (r.proto == NATProtocol_TCP? "tcp" : "udp"),
993 r.strHostIP.c_str(),
994 r.u16HostPort,
995 r.strGuestIP.c_str(),
996 r.u16GuestPort);
997 bstr.detachTo(&sf[i]);
998 }
999 sf.detachTo(ComSafeArrayOutArg(aPortForwardRules));
1000}
1001
1002
1003int NATNetwork::findFirstAvailableOffset(ADDRESSLOOKUPTYPE addrType, uint32_t *poff)
1004{
1005 RTNETADDRIPV4 network, netmask;
1006
1007 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
1008 &network,
1009 &netmask);
1010 AssertRCReturn(rc, rc);
1011
1012 uint32_t off;
1013 settings::NATLoopbackOffsetList::iterator it;
1014 for (off = 1; off < ~netmask.u; ++off)
1015 {
1016
1017 bool skip = false;
1018 for (it = m->llNATLoopbackOffsetList.begin();
1019 it != m->llNATLoopbackOffsetList.end();
1020 ++it)
1021 {
1022 if ((*it).u32Offset == off)
1023 {
1024 skip = true;
1025 break;
1026 }
1027
1028 }
1029
1030 if (skip)
1031 continue;
1032
1033 if (off == m->offGateway)
1034 {
1035 if (addrType == ADDR_GATEWAY)
1036 break;
1037 else
1038 continue;
1039 }
1040
1041 if (off == m->offDhcp)
1042 {
1043 if (addrType == ADDR_DHCP)
1044 break;
1045 else
1046 continue;
1047 }
1048
1049 if (!skip)
1050 break;
1051 }
1052
1053 if (poff)
1054 *poff = off;
1055
1056 return VINF_SUCCESS;
1057}
1058
1059
1060int NATNetwork::recalculateIpv4AddressAssignments()
1061{
1062 RTNETADDRIPV4 network, netmask;
1063 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
1064 &network,
1065 &netmask);
1066 AssertRCReturn(rc, rc);
1067
1068 findFirstAvailableOffset(ADDR_GATEWAY, &m->offGateway);
1069 if (m->fNeedDhcpServer)
1070 findFirstAvailableOffset(ADDR_DHCP, &m->offDhcp);
1071
1072 /* I don't remember the reason CIDR calculated on the host. */
1073 RTNETADDRIPV4 gateway = network;
1074 gateway.u += m->offGateway;
1075 gateway.u = RT_H2N_U32(gateway.u);
1076 char szTmpIp[16];
1077 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", gateway);
1078 m->IPv4Gateway = szTmpIp;
1079
1080 if (m->fNeedDhcpServer)
1081 {
1082 RTNETADDRIPV4 dhcpserver = network;
1083 dhcpserver.u += m->offDhcp;
1084
1085 /* XXX: adding more services should change the math here */
1086 RTNETADDRIPV4 dhcplowerip = network;
1087 uint32_t offDhcpLowerIp;
1088 findFirstAvailableOffset(ADDR_DHCPLOWERIP, &offDhcpLowerIp);
1089 dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp);
1090
1091 RTNETADDRIPV4 dhcpupperip;
1092 dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1);
1093
1094 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
1095 network.u = RT_H2N_U32(network.u);
1096
1097 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver);
1098 m->IPv4DhcpServer = szTmpIp;
1099 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip);
1100 m->IPv4DhcpServerLowerIp = szTmpIp;
1101 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip);
1102 m->IPv4DhcpServerUpperIp = szTmpIp;
1103
1104 LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
1105 network, dhcpserver, dhcplowerip, dhcpupperip));
1106 }
1107
1108 /* we need IPv4NetworkMask for NAT's gw service start */
1109 netmask.u = RT_H2N_U32(netmask.u);
1110 RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask);
1111 m->IPv4NetworkMask = szTmpIp;
1112
1113 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
1114 return VINF_SUCCESS;
1115}
Note: See TracBrowser for help on using the repository browser.

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