VirtualBox

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

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

Main/NATNetworkImpl.cpp: update comment in NATNetwork::COMSETTER(Network)(IN_BSTR) and NATNetwork::COMSETTER(IPv6Prefix) (IN_BSTR) about ignoring new value if there're registered port-forwarding rules. in TODO part of the comment how to resolve the conflict with different internal representation (guest address should be offset from network id, insted direct address, albeit additional check against network bounds should be added then).

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