VirtualBox

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

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

Main/NATNetwork.cpp: replace implicit call of autolock release, with scope.

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