VirtualBox

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

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

NATNetwork::saveSettings: fireNATNetworkSettingEvent also for
listerners that listen on this NAT network only.

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