VirtualBox

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

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

Main/NATNetworkImpl.h: G/c drops NAT_XML_SERIALIZATION and do serialization unconditionally.

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