VirtualBox

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

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

Main/NATNetwork: cut'n'paste typo: u32GatewayOffset -> u32DhcpOffset.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.4 KB
Line 
1/* $Id: NATNetworkImpl.cpp 48103 2013-08-27 18:42:30Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2013 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "NetworkServiceRunner.h"
21#include "DHCPServerImpl.h"
22#include "NATNetworkImpl.h"
23#include "AutoCaller.h"
24#include "Logging.h"
25
26#include <iprt/asm.h>
27#include <iprt/cpp/utils.h>
28#include <iprt/cidr.h>
29#include <iprt/net.h>
30#include <VBox/com/array.h>
31#include <VBox/com/ptr.h>
32#include <VBox/settings.h>
33
34#include "EventImpl.h"
35#include "VBoxEvents.h"
36
37#include "VirtualBoxImpl.h"
38#include <algorithm>
39#include <list>
40
41#ifndef RT_OS_WINDOWS
42#include <netinet/in.h>
43#else
44# include <ws2def.h>
45# define IN_LOOPBACKNET 127
46#endif
47
48
49// constructor / destructor
50/////////////////////////////////////////////////////////////////////////////
51
52struct NATNetwork::Data
53{
54 Data() :
55
56 fEnabled(FALSE),
57 fIPv6Enabled(FALSE),
58 fAdvertiseDefaultIPv6Route(FALSE),
59 fNeedDhcpServer(FALSE)
60 {
61 IPv4Gateway.setNull();
62 IPv4NetworkCidr.setNull();
63 IPv6Prefix.setNull();
64 IPv4DhcpServer.setNull();
65 IPv4NetworkMask.setNull();
66 IPv4DhcpServerLowerIp.setNull();
67 IPv4DhcpServerUpperIp.setNull();
68 }
69 virtual ~Data(){}
70 const ComObjPtr<EventSource> pEventSource;
71#ifdef VBOX_WITH_NAT_SERVICE
72 NATNetworkServiceRunner NATRunner;
73 ComObjPtr<IDHCPServer> dhcpServer;
74#endif
75 Bstr IPv4Gateway;
76 Bstr IPv4NetworkCidr;
77 Bstr IPv4NetworkMask;
78 Bstr IPv4DhcpServer;
79 Bstr IPv4DhcpServerLowerIp;
80 Bstr IPv4DhcpServerUpperIp;
81 BOOL fEnabled;
82 BOOL fIPv6Enabled;
83 Bstr IPv6Prefix;
84 BOOL fAdvertiseDefaultIPv6Route;
85 BOOL fNeedDhcpServer;
86 NATRuleMap mapName2PortForwardRule4;
87 NATRuleMap mapName2PortForwardRule6;
88 settings::NATLoopbackOffsetList llNATLoopbackOffsetList;
89 uint32_t u32LoopbackIp6;
90 uint32_t u32GatewayOffset;
91 uint32_t u32DhcpOffset;
92};
93
94NATNetwork::NATNetwork()
95 : mVirtualBox(NULL)
96{
97}
98
99NATNetwork::~NATNetwork()
100{
101}
102
103HRESULT NATNetwork::FinalConstruct()
104{
105 return BaseFinalConstruct();
106}
107
108void NATNetwork::FinalRelease()
109{
110 uninit ();
111
112 BaseFinalRelease();
113}
114
115void NATNetwork::uninit()
116{
117 /* Enclose the state transition Ready->InUninit->NotReady */
118 AutoUninitSpan autoUninitSpan(this);
119 if (autoUninitSpan.uninitDone())
120 return;
121 delete m;
122 m = NULL;
123 unconst(mVirtualBox) = NULL;
124}
125
126HRESULT NATNetwork::init(VirtualBox *aVirtualBox, IN_BSTR aName)
127{
128 AssertReturn(aName != NULL, E_INVALIDARG);
129
130 AutoInitSpan autoInitSpan(this);
131 AssertReturn(autoInitSpan.isOk(), E_FAIL);
132
133 /* share VirtualBox weakly (parent remains NULL so far) */
134 unconst(mVirtualBox) = aVirtualBox;
135 unconst(mName) = aName;
136 m = new Data();
137 m->u32GatewayOffset = 1;
138 m->IPv4NetworkCidr = "10.0.2.0/24";
139 m->IPv6Prefix = "fe80::/64";
140 m->fEnabled = FALSE;
141
142 settings::NATHostLoopbackOffset off;
143 off.strLoopbackHostAddress = "127.0.0.1";
144 off.u32Offset = (uint32_t)2;
145 m->llNATLoopbackOffsetList.push_back(off);
146
147 RecalculateIpv4AddressAssignments();
148
149 HRESULT hrc = unconst(m->pEventSource).createObject();
150 if (FAILED(hrc)) throw hrc;
151
152 hrc = m->pEventSource->init(static_cast<INATNetwork *>(this));
153 if (FAILED(hrc)) throw hrc;
154
155 /* Confirm a successful initialization */
156 autoInitSpan.setSucceeded();
157
158 return S_OK;
159}
160
161
162HRESULT NATNetwork::init(VirtualBox *aVirtualBox,
163 const settings::NATNetwork &data)
164{
165 /* Enclose the state transition NotReady->InInit->Ready */
166 AutoInitSpan autoInitSpan(this);
167 AssertReturn(autoInitSpan.isOk(), E_FAIL);
168
169 /* share VirtualBox weakly (parent remains NULL so far) */
170 unconst(mVirtualBox) = aVirtualBox;
171
172 unconst(mName) = data.strNetworkName;
173 m = new Data();
174 m->IPv4NetworkCidr = data.strNetwork;
175 m->fEnabled = data.fEnabled;
176 m->fAdvertiseDefaultIPv6Route = data.fAdvertiseDefaultIPv6Route;
177 m->fNeedDhcpServer = data.fNeedDhcpServer;
178
179 m->u32LoopbackIp6 = data.u32HostLoopback6Offset;
180
181 m->llNATLoopbackOffsetList.clear();
182 m->llNATLoopbackOffsetList.assign(data.llHostLoopbackOffsetList.begin(),
183 data.llHostLoopbackOffsetList.end());
184
185 RecalculateIpv4AddressAssignments();
186
187 /* IPv4 port-forward rules */
188 m->mapName2PortForwardRule4.clear();
189 for (settings::NATRuleList::const_iterator it = data.llPortForwardRules4.begin();
190 it != data.llPortForwardRules4.end(); ++it)
191 {
192 m->mapName2PortForwardRule4.insert(std::make_pair(it->strName.c_str(), *it));
193 }
194
195 /* IPv6 port-forward rules */
196 m->mapName2PortForwardRule6.clear();
197 for (settings::NATRuleList::const_iterator it = data.llPortForwardRules6.begin();
198 it != data.llPortForwardRules6.end(); ++it)
199 {
200 m->mapName2PortForwardRule6.insert(std::make_pair(it->strName, *it));
201 }
202
203 HRESULT hrc = unconst(m->pEventSource).createObject();
204 if (FAILED(hrc)) throw hrc;
205
206 hrc = m->pEventSource->init(static_cast<INATNetwork *>(this));
207 if (FAILED(hrc)) throw hrc;
208
209 autoInitSpan.setSucceeded();
210
211 return S_OK;
212}
213
214#ifdef NAT_XML_SERIALIZATION
215HRESULT NATNetwork::saveSettings(settings::NATNetwork &data)
216{
217 AutoCaller autoCaller(this);
218 if (FAILED(autoCaller.rc())) return autoCaller.rc();
219
220 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
221
222 data.strNetworkName = mName;
223 data.strNetwork = m->IPv4NetworkCidr;
224 data.fEnabled = RT_BOOL(m->fEnabled);
225 data.fAdvertiseDefaultIPv6Route = RT_BOOL(m->fAdvertiseDefaultIPv6Route);
226 data.fNeedDhcpServer = RT_BOOL(m->fNeedDhcpServer);
227 data.fIPv6 = RT_BOOL(m->fIPv6Enabled);
228 data.strIPv6Prefix = m->IPv6Prefix;
229
230 /* saving ipv4 port-forward Rules*/
231 data.llPortForwardRules4.clear();
232 for (NATRuleMap::iterator it = m->mapName2PortForwardRule4.begin();
233 it != m->mapName2PortForwardRule4.end(); ++it)
234 data.llPortForwardRules4.push_back(it->second);
235
236 /* saving ipv6 port-forward Rules*/
237 data.llPortForwardRules6.clear();
238 for (NATRuleMap::iterator it = m->mapName2PortForwardRule6.begin();
239 it != m->mapName2PortForwardRule6.end(); ++it)
240 data.llPortForwardRules4.push_back(it->second);
241
242 data.u32HostLoopback6Offset = m->u32LoopbackIp6;
243
244 data.llHostLoopbackOffsetList.clear();
245 data.llHostLoopbackOffsetList.assign(m->llNATLoopbackOffsetList.begin(),
246 m->llNATLoopbackOffsetList.end());
247
248 mVirtualBox->onNATNetworkSetting(mName.raw(),
249 data.fEnabled ? TRUE : FALSE,
250 m->IPv4NetworkCidr.raw(),
251 m->IPv4Gateway.raw(),
252 data.fAdvertiseDefaultIPv6Route ? TRUE : FALSE,
253 data.fNeedDhcpServer ? TRUE : FALSE);
254
255 return S_OK;
256}
257#endif
258
259STDMETHODIMP NATNetwork::COMGETTER(EventSource)(IEventSource ** aEventSource)
260{
261 CheckComArgOutPointerValid(aEventSource);
262
263 AutoCaller autoCaller(this);
264 if (FAILED(autoCaller.rc())) return autoCaller.rc();
265
266 /* event source is const, no need to lock */
267 m->pEventSource.queryInterfaceTo(aEventSource);
268
269 return S_OK;
270}
271
272STDMETHODIMP NATNetwork::COMGETTER(NetworkName) (BSTR *aName)
273{
274 CheckComArgOutPointerValid(aName);
275
276 AutoCaller autoCaller(this);
277 if (FAILED(autoCaller.rc())) return autoCaller.rc();
278
279 mName.cloneTo(aName);
280
281 return S_OK;
282}
283
284STDMETHODIMP NATNetwork::COMSETTER(NetworkName) (IN_BSTR aName)
285{
286 CheckComArgOutPointerValid(aName);
287
288 HRESULT rc = S_OK;
289 AutoCaller autoCaller(this);
290 if (FAILED(autoCaller.rc())) return autoCaller.rc();
291 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
292 unconst(mName) = aName;
293
294 alock.release();
295
296#ifdef NAT_XML_SERIALIZATION
297 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
298 rc = mVirtualBox->saveSettings();
299#endif
300 return rc;
301}
302
303
304STDMETHODIMP NATNetwork::COMGETTER(Enabled) (BOOL *aEnabled)
305{
306 CheckComArgOutPointerValid(aEnabled);
307
308 AutoCaller autoCaller(this);
309 if (FAILED(autoCaller.rc())) return autoCaller.rc();
310
311 *aEnabled = m->fEnabled;
312 RecalculateIpv4AddressAssignments();
313
314 return S_OK;
315}
316
317STDMETHODIMP NATNetwork::COMSETTER(Enabled) (BOOL aEnabled)
318{
319 AutoCaller autoCaller(this);
320 if (FAILED(autoCaller.rc())) return autoCaller.rc();
321 HRESULT rc = S_OK;
322 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
323 m->fEnabled = aEnabled;
324
325 // save the global settings; for that we should hold only the VirtualBox lock
326 alock.release();
327#ifdef NAT_XML_SERIALIZATION
328 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
329 rc = mVirtualBox->saveSettings();
330#endif
331 return rc;
332}
333
334STDMETHODIMP NATNetwork::COMGETTER(Gateway) (BSTR *aIPv4Gateway)
335{
336 CheckComArgOutPointerValid(aIPv4Gateway);
337
338 AutoCaller autoCaller(this);
339 if (FAILED(autoCaller.rc())) return autoCaller.rc();
340
341 m->IPv4Gateway.cloneTo(aIPv4Gateway);
342
343 return S_OK;
344}
345
346STDMETHODIMP NATNetwork::COMGETTER(Network) (BSTR *aIPv4NetworkCidr)
347{
348 CheckComArgOutPointerValid(aIPv4NetworkCidr);
349
350 AutoCaller autoCaller(this);
351 if (FAILED(autoCaller.rc())) return autoCaller.rc();
352 m->IPv4NetworkCidr.cloneTo(aIPv4NetworkCidr);
353 return S_OK;
354}
355
356STDMETHODIMP NATNetwork::COMSETTER(Network) (IN_BSTR aIPv4NetworkCidr)
357{
358 CheckComArgOutPointerValid(aIPv4NetworkCidr);
359
360 HRESULT rc = S_OK;
361 AutoCaller autoCaller(this);
362 if (FAILED(autoCaller.rc())) return autoCaller.rc();
363 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
364 /* silently ignore network cidr update */
365 if (m->mapName2PortForwardRule4.empty())
366 {
367
368 unconst(m->IPv4NetworkCidr) = Bstr(aIPv4NetworkCidr);
369 RecalculateIpv4AddressAssignments();
370 alock.release();
371
372#ifdef NAT_XML_SERIALIZATION
373 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
374 rc = mVirtualBox->saveSettings();
375#endif
376 }
377 return rc;
378}
379
380STDMETHODIMP NATNetwork::COMGETTER(IPv6Enabled)(BOOL *aAdvertiseDefaultIPv6Route)
381{
382 CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route);
383
384 AutoCaller autoCaller(this);
385 if (FAILED(autoCaller.rc())) return autoCaller.rc();
386
387 *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route;
388
389 return S_OK;
390}
391
392STDMETHODIMP NATNetwork::COMSETTER(IPv6Enabled)(BOOL aAdvertiseDefaultIPv6Route)
393{
394 AutoCaller autoCaller(this);
395 if (FAILED(autoCaller.rc())) return autoCaller.rc();
396 HRESULT rc = S_OK;
397 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
398 m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route;
399
400 // save the global settings; for that we should hold only the VirtualBox lock
401 alock.release();
402
403#ifdef NAT_XML_SERIALIZATION
404 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
405 rc = mVirtualBox->saveSettings();
406#endif
407 return rc;
408}
409
410STDMETHODIMP NATNetwork::COMGETTER(IPv6Prefix) (BSTR *aIPv6Prefix)
411{
412 CheckComArgOutPointerValid(aIPv6Prefix);
413
414 AutoCaller autoCaller(this);
415 if (FAILED(autoCaller.rc())) return autoCaller.rc();
416 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
417
418 m->IPv6Prefix.cloneTo(aIPv6Prefix);
419
420 return S_OK;
421}
422
423STDMETHODIMP NATNetwork::COMSETTER(IPv6Prefix) (IN_BSTR aIPv6Prefix)
424{
425 CheckComArgOutPointerValid(aIPv6Prefix);
426
427 HRESULT rc = S_OK;
428 AutoCaller autoCaller(this);
429 if (FAILED(autoCaller.rc())) return autoCaller.rc();
430 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
431
432 /* silently ignore network cidr update */
433 if (m->mapName2PortForwardRule6.empty())
434 {
435
436 unconst(m->IPv6Prefix) = Bstr(aIPv6Prefix);
437 /* @todo: do we need recalculation ? */
438 alock.release();
439
440#ifdef NAT_XML_SERIALIZATION
441 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
442 rc = mVirtualBox->saveSettings();
443#endif
444 }
445 return rc;
446}
447
448STDMETHODIMP NATNetwork::COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL *aAdvertiseDefaultIPv6Route)
449{
450 CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route);
451
452 AutoCaller autoCaller(this);
453 if (FAILED(autoCaller.rc())) return autoCaller.rc();
454
455 *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route;
456
457 return S_OK;
458}
459
460STDMETHODIMP NATNetwork::COMSETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL aAdvertiseDefaultIPv6Route)
461{
462 AutoCaller autoCaller(this);
463 if (FAILED(autoCaller.rc())) return autoCaller.rc();
464 HRESULT rc = S_OK;
465 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
466 m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route;
467
468 // save the global settings; for that we should hold only the VirtualBox lock
469 alock.release();
470
471#ifdef NAT_XML_SERIALIZATION
472 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
473 rc = mVirtualBox->saveSettings();
474#endif
475 return rc;
476}
477
478STDMETHODIMP NATNetwork::COMGETTER(NeedDhcpServer)(BOOL *aNeedDhcpServer)
479{
480 CheckComArgOutPointerValid(aNeedDhcpServer);
481
482 AutoCaller autoCaller(this);
483 if (FAILED(autoCaller.rc())) return autoCaller.rc();
484
485 *aNeedDhcpServer = m->fNeedDhcpServer;
486
487 return S_OK;
488}
489
490STDMETHODIMP NATNetwork::COMSETTER(NeedDhcpServer)(BOOL aNeedDhcpServer)
491{
492 AutoCaller autoCaller(this);
493 if (FAILED(autoCaller.rc())) return autoCaller.rc();
494 HRESULT rc = S_OK;
495 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
496 m->fNeedDhcpServer = aNeedDhcpServer;
497
498 RecalculateIpv4AddressAssignments();
499
500 // save the global settings; for that we should hold only the VirtualBox lock
501 alock.release();
502
503#ifdef NAT_XML_SERIALIZATION
504 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
505 rc = mVirtualBox->saveSettings();
506#endif
507 return rc;
508}
509
510
511STDMETHODIMP NATNetwork::COMGETTER(LocalMappings)(ComSafeArrayOut(BSTR, aLocalMappings))
512{
513 CheckComArgOutSafeArrayPointerValid(aLocalMappings);
514
515 AutoCaller autoCaller(this);
516 if (FAILED(autoCaller.rc())) return autoCaller.rc();
517 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
518
519 com::SafeArray<BSTR> sf(m->llNATLoopbackOffsetList.size());
520
521 size_t i = 0;
522 settings::NATLoopbackOffsetList::const_iterator it;
523
524 for (it = m->llNATLoopbackOffsetList.begin();
525 it != m->llNATLoopbackOffsetList.end(); ++it, ++i)
526 {
527 BstrFmt bstr("%s;%d",
528 (*it).strLoopbackHostAddress.c_str(),
529 (*it).u32Offset);
530 bstr.detachTo(&sf[i]);
531 }
532 sf.detachTo(ComSafeArrayOutArg(aLocalMappings));
533
534 return S_OK;
535}
536
537
538STDMETHODIMP NATNetwork::AddLocalMapping(IN_BSTR aHostId, LONG aOffset)
539{
540 AutoCaller autoCaller(this);
541 if (FAILED(autoCaller.rc())) return autoCaller.rc();
542
543 //AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
544
545 RTNETADDRIPV4 addr, net, mask;
546
547 int rc = RTNetStrToIPv4Addr(Utf8Str(aHostId).c_str(), &addr);
548 if (RT_FAILURE(rc))
549 return E_INVALIDARG;
550
551 /* check against 127/8 */
552 if ((RT_N2H_U32(addr.u) >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)
553 return E_INVALIDARG;
554
555 /* check against networkid vs network mask */
556 rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr).c_str(), &net, &mask);
557 if (RT_FAILURE(rc))
558 return E_INVALIDARG;
559
560 if (((net.u + aOffset) & mask.u) != net.u)
561 return E_INVALIDARG;
562
563 settings::NATLoopbackOffsetList::iterator it;
564
565 it = std::find(m->llNATLoopbackOffsetList.begin(),
566 m->llNATLoopbackOffsetList.end(),
567 Utf8Str(aHostId).c_str());
568
569 if (it != m->llNATLoopbackOffsetList.end())
570 {
571 if (aOffset == 0) /* erase */
572 m->llNATLoopbackOffsetList.erase(it, it);
573 else /* modify */
574 {
575 settings::NATLoopbackOffsetList::iterator it1;
576 it1 = std::find(m->llNATLoopbackOffsetList.begin(),
577 m->llNATLoopbackOffsetList.end(),
578 (uint32_t)aOffset);
579 if (it1 != m->llNATLoopbackOffsetList.end())
580 return E_INVALIDARG; /* this offset is already registered. */
581
582 (*it).u32Offset = aOffset;
583 }
584
585 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
586 return mVirtualBox->saveSettings();
587 }
588
589 /* injection */
590 it = std::find(m->llNATLoopbackOffsetList.begin(),
591 m->llNATLoopbackOffsetList.end(),
592 (uint32_t)aOffset);
593
594 if (it != m->llNATLoopbackOffsetList.end())
595 return E_INVALIDARG; /* offset is already registered. */
596
597 settings::NATHostLoopbackOffset off;
598 off.strLoopbackHostAddress = aHostId;
599 off.u32Offset = (uint32_t)aOffset;
600 m->llNATLoopbackOffsetList.push_back(off);
601
602 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
603 return mVirtualBox->saveSettings();
604}
605
606
607STDMETHODIMP NATNetwork::COMGETTER(LoopbackIp6)(LONG *aLoopbackIp6)
608{
609 AutoCaller autoCaller(this);
610 if (FAILED(autoCaller.rc())) return autoCaller.rc();
611 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
612
613 *aLoopbackIp6 = m->u32LoopbackIp6;
614 return S_OK;
615}
616
617
618STDMETHODIMP NATNetwork::COMSETTER(LoopbackIp6)(LONG aLoopbackIp6)
619{
620 AutoCaller autoCaller(this);
621 if (FAILED(autoCaller.rc())) return autoCaller.rc();
622 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
623
624 m->u32LoopbackIp6 = aLoopbackIp6;
625
626 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
627 return mVirtualBox->saveSettings();
628}
629
630STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules4)(ComSafeArrayOut(BSTR, aPortForwardRules4))
631{
632 CheckComArgOutSafeArrayPointerValid(aPortForwardRules4);
633
634 AutoCaller autoCaller(this);
635 if (FAILED(autoCaller.rc())) return autoCaller.rc();
636
637 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
638 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules4),
639 m->mapName2PortForwardRule4);
640 alock.release();
641 return S_OK;
642}
643
644STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules6)(ComSafeArrayOut(BSTR,
645 aPortForwardRules6))
646{
647 CheckComArgOutSafeArrayPointerValid(aPortForwardRules6);
648
649 AutoCaller autoCaller(this);
650 if (FAILED(autoCaller.rc())) return autoCaller.rc();
651
652 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
653 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules6), m->mapName2PortForwardRule6);
654 return S_OK;
655}
656
657STDMETHODIMP NATNetwork::AddPortForwardRule(BOOL aIsIpv6,
658 IN_BSTR aPortForwardRuleName,
659 NATProtocol_T aProto,
660 IN_BSTR aHostIp,
661 USHORT aHostPort,
662 IN_BSTR aGuestIp,
663 USHORT aGuestPort)
664{
665 int rc = S_OK;
666 AutoCaller autoCaller(this);
667 if (FAILED(autoCaller.rc())) return autoCaller.rc();
668
669 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
670 Utf8Str name = aPortForwardRuleName;
671 Utf8Str proto;
672 settings::NATRule r;
673 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
674 switch (aProto)
675 {
676 case NATProtocol_TCP:
677 proto = "tcp";
678 break;
679 case NATProtocol_UDP:
680 proto = "udp";
681 break;
682 default:
683 return E_INVALIDARG;
684 }
685 if (name.isEmpty())
686 name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
687 Utf8Str(aHostIp).c_str(), aHostPort,
688 Utf8Str(aGuestIp).c_str(), aGuestPort);
689
690 NATRuleMap::iterator it;
691
692 for (it = mapRules.begin(); it != mapRules.end(); ++it)
693 {
694 r = it->second;
695 if (it->first == name)
696 return setError(E_INVALIDARG,
697 tr("A NAT rule of this name already exists"));
698 if ( r.strHostIP == Utf8Str(aHostIp)
699 && r.u16HostPort == aHostPort
700 && r.proto == aProto)
701 return setError(E_INVALIDARG,
702 tr("A NAT rule for this host port and this host IP already exists"));
703 }
704
705 r.strName = name.c_str();
706 r.proto = aProto;
707 r.strHostIP = aHostIp;
708 r.u16HostPort = aHostPort;
709 r.strGuestIP = aGuestIp;
710 r.u16GuestPort = aGuestPort;
711 mapRules.insert(std::make_pair(name, r));
712
713 alock.release();
714 mVirtualBox->onNATNetworkPortForward(mName.raw(), TRUE, aIsIpv6,
715 aPortForwardRuleName, aProto,
716 aHostIp, aHostPort,
717 aGuestIp, aGuestPort);
718
719 /* Notify listerners listening on this network only */
720 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), TRUE,
721 aIsIpv6, aPortForwardRuleName, aProto,
722 aHostIp, aHostPort,
723 aGuestIp, aGuestPort);
724
725#ifdef NAT_XML_SERIALIZATION
726 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
727 rc = mVirtualBox->saveSettings();
728#endif
729 return rc;
730}
731
732STDMETHODIMP NATNetwork::RemovePortForwardRule(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName)
733{
734 int rc = S_OK;
735 Utf8Str strHostIP, strGuestIP;
736 uint16_t u16HostPort, u16GuestPort;
737 NATProtocol_T proto = NATProtocol_TCP;
738
739 AutoCaller autoCaller(this);
740 if (FAILED(autoCaller.rc())) return autoCaller.rc();
741
742 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
743 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
744 NATRuleMap::iterator it = mapRules.find(aPortForwardRuleName);
745
746 if (it == mapRules.end())
747 return E_INVALIDARG;
748
749 strHostIP = it->second.strHostIP;
750 strGuestIP = it->second.strGuestIP;
751 u16HostPort = it->second.u16HostPort;
752 u16GuestPort = it->second.u16GuestPort;
753 proto = it->second.proto;
754
755 mapRules.erase(it);
756
757 alock.release();
758
759 mVirtualBox->onNATNetworkPortForward(mName.raw(), FALSE, aIsIpv6,
760 aPortForwardRuleName, proto,
761 Bstr(strHostIP).raw(), u16HostPort,
762 Bstr(strGuestIP).raw(), u16GuestPort);
763
764 /* Notify listerners listening on this network only */
765 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), FALSE,
766 aIsIpv6, aPortForwardRuleName, proto,
767 Bstr(strHostIP).raw(), u16HostPort,
768 Bstr(strGuestIP).raw(), u16GuestPort);
769#ifdef NAT_XML_SERIALIZATION
770 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
771 rc = mVirtualBox->saveSettings();
772#endif
773
774 return rc;
775}
776
777
778STDMETHODIMP NATNetwork::Start(IN_BSTR aTrunkType)
779{
780#ifdef VBOX_WITH_NAT_SERVICE
781 AutoCaller autoCaller(this);
782 if (FAILED(autoCaller.rc())) return autoCaller.rc();
783
784 if (!m->fEnabled) return S_OK;
785
786 m->NATRunner.setOption(NETCFG_NETNAME, mName, true);
787 m->NATRunner.setOption(NETCFG_TRUNKTYPE, Utf8Str(aTrunkType), true);
788 m->NATRunner.setOption(NETCFG_IPADDRESS, m->IPv4Gateway, true);
789 m->NATRunner.setOption(NETCFG_NETMASK, m->IPv4NetworkMask, true);
790
791 /* No portforwarding rules from command-line, all will be fetched via API */
792
793 if (m->fNeedDhcpServer)
794 {
795 /**
796 * Just to as idea... via API (on creation user pass the cidr of network and)
797 * and we calculate it's addreses (mutable?).
798 */
799
800 /*
801 * Configuration and running DHCP server:
802 * 1. find server first createDHCPServer
803 * 2. if return status is E_INVALARG => server already exists just find and start.
804 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
805 * 4. if return status S_OK proceed to DHCP server configuration
806 * 5. call setConfiguration() and pass all required parameters
807 * 6. start dhcp server.
808 */
809 int rc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(),
810 m->dhcpServer.asOutParam());
811 switch (rc)
812 {
813 case E_INVALIDARG:
814 /* server haven't beeen found let create it then */
815 rc = mVirtualBox->CreateDHCPServer(mName.raw(),
816 m->dhcpServer.asOutParam());
817 if (FAILED(rc))
818 return E_FAIL;
819 /* breakthrough */
820
821 {
822 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
823 Utf8Str(m->IPv4Gateway.raw()).c_str(),
824 Utf8Str(m->IPv4DhcpServer.raw()).c_str(),
825 Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(),
826 Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str()));
827
828 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw());
829
830 rc = m->dhcpServer->COMSETTER(Enabled)(true);
831
832 BSTR dhcpip = NULL;
833 BSTR netmask = NULL;
834 BSTR lowerip = NULL;
835 BSTR upperip = NULL;
836
837 m->IPv4DhcpServer.cloneTo(&dhcpip);
838 m->IPv4NetworkMask.cloneTo(&netmask);
839 m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
840 m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
841 rc = m->dhcpServer->SetConfiguration(dhcpip,
842 netmask,
843 lowerip,
844 upperip);
845 }
846 case S_OK:
847 break;
848
849 default:
850 return E_FAIL;
851 }
852
853 rc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType);
854 if (FAILED(rc))
855 {
856 m->dhcpServer.setNull();
857 return E_FAIL;
858 }
859 }
860
861 if (RT_SUCCESS(m->NATRunner.start()))
862 {
863 mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE);
864 return S_OK;
865 }
866 else return E_FAIL;
867#else
868 NOREF(aTrunkType);
869 ReturnComNotImplemented();
870#endif
871}
872
873STDMETHODIMP NATNetwork::Stop()
874{
875#ifdef VBOX_WITH_NAT_SERVICE
876 if (!m->dhcpServer.isNull())
877 m->dhcpServer->Stop();
878
879 if (RT_SUCCESS(m->NATRunner.stop()))
880 {
881 mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE);
882 return S_OK;
883 }
884 else 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(uint32_t *pu32Offset)
913{
914 uint32_t offset;
915 RTNETADDRIPV4 network, netmask;
916
917 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
918 &network,
919 &netmask);
920 AssertRCReturn(rc, rc);
921
922 settings::NATLoopbackOffsetList::iterator it;
923 for (offset = 1; offset < (network.u & (~netmask.u)); ++offset)
924 {
925 bool skip = false;
926
927 if (offset == m->u32GatewayOffset)
928 continue;
929
930 if (offset == m->u32DhcpOffset)
931 continue;
932
933 for (it = m->llNATLoopbackOffsetList.begin();
934 it != m->llNATLoopbackOffsetList.end();
935 ++it)
936 {
937 if ((*it).u32Offset == offset)
938 {
939 skip = true;
940 break;
941 }
942
943 }
944
945 if(!skip)
946 break;
947 }
948
949 if (pu32Offset)
950 *pu32Offset = offset;
951
952 return VINF_SUCCESS;
953}
954
955int NATNetwork::RecalculateIpv4AddressAssignments()
956{
957 RTNETADDRIPV4 network, netmask, gateway;
958 char aszGatewayIp[16], aszNetmask[16];
959 RT_ZERO(aszNetmask);
960 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
961 &network,
962 &netmask);
963 AssertRCReturn(rc, rc);
964
965 findFirstAvailableOffset(&m->u32GatewayOffset);
966 if (m->fNeedDhcpServer)
967 findFirstAvailableOffset(&m->u32DhcpOffset);
968
969 /* I don't remember the reason CIDR calcualted in host */
970 gateway.u = network.u;
971
972 gateway.u += m->u32GatewayOffset;
973 gateway.u = RT_H2N_U32(gateway.u);
974 RTStrPrintf(aszGatewayIp, 16, "%RTnaipv4", gateway);
975
976 m->IPv4Gateway = RTStrDup(aszGatewayIp);
977
978 if (m->fNeedDhcpServer)
979 {
980 RTNETADDRIPV4 dhcpserver,
981 dhcplowerip,
982 dhcpupperip;
983 char aszNetwork[16],
984 aszDhcpIp[16],
985 aszDhcpLowerIp[16],
986 aszDhcpUpperIp[16];
987 RT_ZERO(aszNetwork);
988
989 RT_ZERO(aszDhcpIp);
990 RT_ZERO(aszDhcpLowerIp);
991 RT_ZERO(aszDhcpUpperIp);
992
993 dhcpserver.u = network.u;
994 dhcpserver.u += m->u32DhcpOffset;
995
996
997 /* XXX: adding more services should change the math here */
998 dhcplowerip.u = RT_H2N_U32(dhcpserver.u + 1);
999 dhcpupperip.u = RT_H2N_U32((network.u | (~netmask.u)) -1);
1000 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
1001 network.u = RT_H2N_U32(network.u);
1002
1003 RTStrPrintf(aszNetwork, 16, "%RTnaipv4", network);
1004 RTStrPrintf(aszDhcpLowerIp, 16, "%RTnaipv4", dhcplowerip);
1005 RTStrPrintf(aszDhcpUpperIp, 16, "%RTnaipv4", dhcpupperip);
1006 RTStrPrintf(aszDhcpIp, 16, "%RTnaipv4", dhcpserver);
1007
1008 m->IPv4DhcpServer = aszDhcpIp;
1009 m->IPv4DhcpServerLowerIp = aszDhcpLowerIp;
1010 m->IPv4DhcpServerUpperIp = aszDhcpUpperIp;
1011
1012 LogFunc(("network: %RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
1013 network,
1014 dhcpserver,
1015 dhcplowerip,
1016 dhcpupperip));
1017 }
1018 /* we need IPv4NetworkMask for NAT's gw service start */
1019 netmask.u = RT_H2N_U32(netmask.u);
1020 RTStrPrintf(aszNetmask, 16, "%RTnaipv4", netmask);
1021 m->IPv4NetworkMask = aszNetmask;
1022 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
1023 return VINF_SUCCESS;
1024}
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