VirtualBox

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

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

Main/NetworkServices: no zombies on shutdown.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.7 KB
Line 
1/* $Id: NATNetworkImpl.cpp 47447 2013-07-29 04:16:10Z 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
39
40// constructor / destructor
41/////////////////////////////////////////////////////////////////////////////
42
43struct NATNetwork::Data
44{
45 Data() :
46
47 fEnabled(FALSE),
48 fIPv6Enabled(FALSE),
49 fAdvertiseDefaultIPv6Route(FALSE),
50 fNeedDhcpServer(FALSE)
51 {
52 IPv4Gateway.setNull();
53 IPv4NetworkCidr.setNull();
54 IPv6Prefix.setNull();
55 IPv4DhcpServer.setNull();
56 IPv4NetworkMask.setNull();
57 IPv4DhcpServerLowerIp.setNull();
58 IPv4DhcpServerUpperIp.setNull();
59 }
60 virtual ~Data(){}
61 const ComObjPtr<EventSource> pEventSource;
62#ifdef VBOX_WITH_NAT_SERVICE
63 NATNetworkServiceRunner NATRunner;
64 ComObjPtr<IDHCPServer> dhcpServer;
65#endif
66 Bstr IPv4Gateway;
67 Bstr IPv4NetworkCidr;
68 Bstr IPv4NetworkMask;
69 Bstr IPv4DhcpServer;
70 Bstr IPv4DhcpServerLowerIp;
71 Bstr IPv4DhcpServerUpperIp;
72 BOOL fEnabled;
73 BOOL fIPv6Enabled;
74 Bstr IPv6Prefix;
75 BOOL fAdvertiseDefaultIPv6Route;
76 BOOL fNeedDhcpServer;
77 NATRuleMap mapName2PortForwardRule4;
78 NATRuleMap mapName2PortForwardRule6;
79};
80
81NATNetwork::NATNetwork()
82 : mVirtualBox(NULL)
83{
84}
85
86NATNetwork::~NATNetwork()
87{
88}
89
90HRESULT NATNetwork::FinalConstruct()
91{
92 return BaseFinalConstruct();
93}
94
95void NATNetwork::FinalRelease()
96{
97 uninit ();
98
99 BaseFinalRelease();
100}
101
102void NATNetwork::uninit()
103{
104 /* Enclose the state transition Ready->InUninit->NotReady */
105 AutoUninitSpan autoUninitSpan(this);
106 if (autoUninitSpan.uninitDone())
107 return;
108 delete m;
109 m = NULL;
110 unconst(mVirtualBox) = NULL;
111}
112
113HRESULT NATNetwork::init(VirtualBox *aVirtualBox, IN_BSTR aName)
114{
115 AssertReturn(aName != NULL, E_INVALIDARG);
116
117 AutoInitSpan autoInitSpan(this);
118 AssertReturn(autoInitSpan.isOk(), E_FAIL);
119
120 /* share VirtualBox weakly (parent remains NULL so far) */
121 unconst(mVirtualBox) = aVirtualBox;
122 unconst(mName) = aName;
123 m = new Data();
124 m->IPv4Gateway = "10.0.2.2";
125 m->IPv4NetworkCidr = "10.0.2.0/24";
126 m->IPv6Prefix = "fe80::/64";
127 m->fEnabled = FALSE;
128
129
130
131 RecalculateIpv4AddressAssignments();
132
133 HRESULT hrc = unconst(m->pEventSource).createObject();
134 if (FAILED(hrc)) throw hrc;
135
136 hrc = m->pEventSource->init(static_cast<INATNetwork *>(this));
137 if (FAILED(hrc)) throw hrc;
138
139 /* Confirm a successful initialization */
140 autoInitSpan.setSucceeded();
141
142 return S_OK;
143}
144
145
146HRESULT NATNetwork::init(VirtualBox *aVirtualBox,
147 const settings::NATNetwork &data)
148{
149 /* Enclose the state transition NotReady->InInit->Ready */
150 AutoInitSpan autoInitSpan(this);
151 AssertReturn(autoInitSpan.isOk(), E_FAIL);
152
153 /* share VirtualBox weakly (parent remains NULL so far) */
154 unconst(mVirtualBox) = aVirtualBox;
155
156 unconst(mName) = data.strNetworkName;
157 m = new Data();
158 m->IPv4NetworkCidr = data.strNetwork;
159 m->fEnabled = data.fEnabled;
160 m->fAdvertiseDefaultIPv6Route = data.fAdvertiseDefaultIPv6Route;
161 m->fNeedDhcpServer = data.fNeedDhcpServer;
162
163 RecalculateIpv4AddressAssignments();
164
165 /* IPv4 port-forward rules */
166 m->mapName2PortForwardRule4.clear();
167 for (settings::NATRuleList::const_iterator it = data.llPortForwardRules4.begin();
168 it != data.llPortForwardRules4.end(); ++it)
169 {
170 m->mapName2PortForwardRule4.insert(std::make_pair(it->strName.c_str(), *it));
171 }
172
173 /* IPv6 port-forward rules */
174 m->mapName2PortForwardRule6.clear();
175 for (settings::NATRuleList::const_iterator it = data.llPortForwardRules6.begin();
176 it != data.llPortForwardRules6.end(); ++it)
177 {
178 m->mapName2PortForwardRule6.insert(std::make_pair(it->strName, *it));
179 }
180
181 HRESULT hrc = unconst(m->pEventSource).createObject();
182 if (FAILED(hrc)) throw hrc;
183
184 hrc = m->pEventSource->init(static_cast<INATNetwork *>(this));
185 if (FAILED(hrc)) throw hrc;
186
187 autoInitSpan.setSucceeded();
188
189 return S_OK;
190}
191
192#ifdef NAT_XML_SERIALIZATION
193HRESULT NATNetwork::saveSettings(settings::NATNetwork &data)
194{
195 AutoCaller autoCaller(this);
196 if (FAILED(autoCaller.rc())) return autoCaller.rc();
197
198 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
199
200 data.strNetworkName = mName;
201 data.strNetwork = m->IPv4NetworkCidr;
202 data.fEnabled = RT_BOOL(m->fEnabled);
203 data.fAdvertiseDefaultIPv6Route = RT_BOOL(m->fAdvertiseDefaultIPv6Route);
204 data.fNeedDhcpServer = RT_BOOL(m->fNeedDhcpServer);
205 data.fIPv6 = RT_BOOL(m->fIPv6Enabled);
206 data.strIPv6Prefix = m->IPv6Prefix;
207
208 /* saving ipv4 port-forward Rules*/
209 data.llPortForwardRules4.clear();
210 for (NATRuleMap::iterator it = m->mapName2PortForwardRule4.begin();
211 it != m->mapName2PortForwardRule4.end(); ++it)
212 data.llPortForwardRules4.push_back(it->second);
213
214 /* saving ipv6 port-forward Rules*/
215 data.llPortForwardRules6.clear();
216 for (NATRuleMap::iterator it = m->mapName2PortForwardRule6.begin();
217 it != m->mapName2PortForwardRule6.end(); ++it)
218 data.llPortForwardRules4.push_back(it->second);
219
220 /* XXX: should we do here a copy of params */
221 /* XXX: should we unlock here? */
222 mVirtualBox->onNATNetworkSetting(mName.raw(),
223 data.fEnabled ? TRUE : FALSE,
224 m->IPv4NetworkCidr.raw(),
225 m->IPv4Gateway.raw(),
226 data.fAdvertiseDefaultIPv6Route ? TRUE : FALSE,
227 data.fNeedDhcpServer ? TRUE : FALSE);
228 return S_OK;
229}
230#endif
231
232STDMETHODIMP NATNetwork::COMGETTER(EventSource)(IEventSource ** aEventSource)
233{
234 CheckComArgOutPointerValid(aEventSource);
235
236 AutoCaller autoCaller(this);
237 if (FAILED(autoCaller.rc())) return autoCaller.rc();
238
239 /* event source is const, no need to lock */
240 m->pEventSource.queryInterfaceTo(aEventSource);
241
242 return S_OK;
243}
244
245STDMETHODIMP NATNetwork::COMGETTER(NetworkName) (BSTR *aName)
246{
247 CheckComArgOutPointerValid(aName);
248
249 AutoCaller autoCaller(this);
250 if (FAILED(autoCaller.rc())) return autoCaller.rc();
251
252 mName.cloneTo(aName);
253
254 return S_OK;
255}
256
257STDMETHODIMP NATNetwork::COMSETTER(NetworkName) (IN_BSTR aName)
258{
259 CheckComArgOutPointerValid(aName);
260
261 HRESULT rc = S_OK;
262 AutoCaller autoCaller(this);
263 if (FAILED(autoCaller.rc())) return autoCaller.rc();
264 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
265 unconst(mName) = aName;
266
267 alock.release();
268
269#ifdef NAT_XML_SERIALIZATION
270 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
271 rc = mVirtualBox->saveSettings();
272#endif
273 return rc;
274}
275
276
277STDMETHODIMP NATNetwork::COMGETTER(Enabled) (BOOL *aEnabled)
278{
279 CheckComArgOutPointerValid(aEnabled);
280
281 AutoCaller autoCaller(this);
282 if (FAILED(autoCaller.rc())) return autoCaller.rc();
283
284 *aEnabled = m->fEnabled;
285 RecalculateIpv4AddressAssignments();
286
287 return S_OK;
288}
289
290STDMETHODIMP NATNetwork::COMSETTER(Enabled) (BOOL aEnabled)
291{
292 AutoCaller autoCaller(this);
293 if (FAILED(autoCaller.rc())) return autoCaller.rc();
294 HRESULT rc = S_OK;
295 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
296 m->fEnabled = aEnabled;
297
298 // save the global settings; for that we should hold only the VirtualBox lock
299 alock.release();
300#ifdef NAT_XML_SERIALIZATION
301 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
302 rc = mVirtualBox->saveSettings();
303#endif
304 return rc;
305}
306
307STDMETHODIMP NATNetwork::COMGETTER(Gateway) (BSTR *aIPv4Gateway)
308{
309 CheckComArgOutPointerValid(aIPv4Gateway);
310
311 AutoCaller autoCaller(this);
312 if (FAILED(autoCaller.rc())) return autoCaller.rc();
313
314 m->IPv4Gateway.cloneTo(aIPv4Gateway);
315
316 return S_OK;
317}
318
319STDMETHODIMP NATNetwork::COMGETTER(Network) (BSTR *aIPv4NetworkCidr)
320{
321 CheckComArgOutPointerValid(aIPv4NetworkCidr);
322
323 AutoCaller autoCaller(this);
324 if (FAILED(autoCaller.rc())) return autoCaller.rc();
325 m->IPv4NetworkCidr.cloneTo(aIPv4NetworkCidr);
326 return S_OK;
327}
328
329STDMETHODIMP NATNetwork::COMSETTER(Network) (IN_BSTR aIPv4NetworkCidr)
330{
331 CheckComArgOutPointerValid(aIPv4NetworkCidr);
332
333 HRESULT rc = S_OK;
334 AutoCaller autoCaller(this);
335 if (FAILED(autoCaller.rc())) return autoCaller.rc();
336 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
337 /* silently ignore network cidr update */
338 if (m->mapName2PortForwardRule4.empty())
339 {
340
341 unconst(m->IPv4NetworkCidr) = Bstr(aIPv4NetworkCidr);
342 RecalculateIpv4AddressAssignments();
343 alock.release();
344
345#ifdef NAT_XML_SERIALIZATION
346 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
347 rc = mVirtualBox->saveSettings();
348#endif
349 }
350 return rc;
351}
352
353STDMETHODIMP NATNetwork::COMGETTER(IPv6Enabled)(BOOL *aAdvertiseDefaultIPv6Route)
354{
355 CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route);
356
357 AutoCaller autoCaller(this);
358 if (FAILED(autoCaller.rc())) return autoCaller.rc();
359
360 *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route;
361
362 return S_OK;
363}
364
365STDMETHODIMP NATNetwork::COMSETTER(IPv6Enabled)(BOOL aAdvertiseDefaultIPv6Route)
366{
367 AutoCaller autoCaller(this);
368 if (FAILED(autoCaller.rc())) return autoCaller.rc();
369 HRESULT rc = S_OK;
370 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
371 m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route;
372
373 // save the global settings; for that we should hold only the VirtualBox lock
374 alock.release();
375
376#ifdef NAT_XML_SERIALIZATION
377 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
378 rc = mVirtualBox->saveSettings();
379#endif
380 return rc;
381}
382
383STDMETHODIMP NATNetwork::COMGETTER(IPv6Prefix) (BSTR *aIPv6Prefix)
384{
385 CheckComArgOutPointerValid(aIPv6Prefix);
386
387 AutoCaller autoCaller(this);
388 if (FAILED(autoCaller.rc())) return autoCaller.rc();
389 return S_OK;
390}
391
392STDMETHODIMP NATNetwork::COMSETTER(IPv6Prefix) (IN_BSTR aIPv6Prefix)
393{
394 CheckComArgOutPointerValid(aIPv6Prefix);
395
396 HRESULT rc = S_OK;
397 AutoCaller autoCaller(this);
398 if (FAILED(autoCaller.rc())) return autoCaller.rc();
399 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
400 /* silently ignore network cidr update */
401 if (m->mapName2PortForwardRule6.empty())
402 {
403
404 unconst(m->IPv6Prefix) = Bstr(aIPv6Prefix);
405 /* @todo: do we need recalculation ? */
406 alock.release();
407
408#ifdef NAT_XML_SERIALIZATION
409 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
410 rc = mVirtualBox->saveSettings();
411#endif
412 }
413 return rc;
414}
415
416STDMETHODIMP NATNetwork::COMGETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL *aAdvertiseDefaultIPv6Route)
417{
418 CheckComArgOutPointerValid(aAdvertiseDefaultIPv6Route);
419
420 AutoCaller autoCaller(this);
421 if (FAILED(autoCaller.rc())) return autoCaller.rc();
422
423 *aAdvertiseDefaultIPv6Route = m->fAdvertiseDefaultIPv6Route;
424
425 return S_OK;
426}
427
428STDMETHODIMP NATNetwork::COMSETTER(AdvertiseDefaultIPv6RouteEnabled)(BOOL aAdvertiseDefaultIPv6Route)
429{
430 AutoCaller autoCaller(this);
431 if (FAILED(autoCaller.rc())) return autoCaller.rc();
432 HRESULT rc = S_OK;
433 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
434 m->fAdvertiseDefaultIPv6Route = aAdvertiseDefaultIPv6Route;
435
436 // save the global settings; for that we should hold only the VirtualBox lock
437 alock.release();
438
439#ifdef NAT_XML_SERIALIZATION
440 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
441 rc = mVirtualBox->saveSettings();
442#endif
443 return rc;
444}
445
446STDMETHODIMP NATNetwork::COMGETTER(NeedDhcpServer)(BOOL *aNeedDhcpServer)
447{
448 CheckComArgOutPointerValid(aNeedDhcpServer);
449
450 AutoCaller autoCaller(this);
451 if (FAILED(autoCaller.rc())) return autoCaller.rc();
452
453 *aNeedDhcpServer = m->fNeedDhcpServer;
454
455 return S_OK;
456}
457
458STDMETHODIMP NATNetwork::COMSETTER(NeedDhcpServer)(BOOL aNeedDhcpServer)
459{
460 AutoCaller autoCaller(this);
461 if (FAILED(autoCaller.rc())) return autoCaller.rc();
462 HRESULT rc = S_OK;
463 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
464 m->fNeedDhcpServer = aNeedDhcpServer;
465
466 RecalculateIpv4AddressAssignments();
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(PortForwardRules4)(ComSafeArrayOut(BSTR, aPortForwardRules4))
479{
480 CheckComArgOutSafeArrayPointerValid(aPortForwardRules4);
481
482 AutoCaller autoCaller(this);
483 if (FAILED(autoCaller.rc())) return autoCaller.rc();
484
485 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
486 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules4),
487 m->mapName2PortForwardRule4);
488 alock.release();
489 return S_OK;
490}
491
492STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules6)(ComSafeArrayOut(BSTR,
493 aPortForwardRules6))
494{
495 CheckComArgOutSafeArrayPointerValid(aPortForwardRules6);
496
497 AutoCaller autoCaller(this);
498 if (FAILED(autoCaller.rc())) return autoCaller.rc();
499
500 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
501 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules6), m->mapName2PortForwardRule6);
502 return S_OK;
503}
504
505STDMETHODIMP NATNetwork::AddPortForwardRule(BOOL aIsIpv6,
506 IN_BSTR aPortForwardRuleName,
507 NATProtocol_T aProto,
508 IN_BSTR aHostIp,
509 USHORT aHostPort,
510 IN_BSTR aGuestIp,
511 USHORT aGuestPort)
512{
513 int rc = S_OK;
514 AutoCaller autoCaller(this);
515 if (FAILED(autoCaller.rc())) return autoCaller.rc();
516
517 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
518 Utf8Str name = aPortForwardRuleName;
519 Utf8Str proto;
520 settings::NATRule r;
521 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
522 switch (aProto)
523 {
524 case NATProtocol_TCP:
525 proto = "tcp";
526 break;
527 case NATProtocol_UDP:
528 proto = "udp";
529 break;
530 default:
531 return E_INVALIDARG;
532 }
533 if (name.isEmpty())
534 name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
535 Utf8Str(aHostIp).c_str(), aHostPort,
536 Utf8Str(aGuestIp).c_str(), aGuestPort);
537
538 NATRuleMap::iterator it;
539
540 for (it = mapRules.begin(); it != mapRules.end(); ++it)
541 {
542 r = it->second;
543 if (it->first == name)
544 return setError(E_INVALIDARG,
545 tr("A NAT rule of this name already exists"));
546 if ( r.strHostIP == Utf8Str(aHostIp)
547 && r.u16HostPort == aHostPort
548 && r.proto == aProto)
549 return setError(E_INVALIDARG,
550 tr("A NAT rule for this host port and this host IP already exists"));
551 }
552
553 r.strName = name.c_str();
554 r.proto = aProto;
555 r.strHostIP = aHostIp;
556 r.u16HostPort = aHostPort;
557 r.strGuestIP = aGuestIp;
558 r.u16GuestPort = aGuestPort;
559 mapRules.insert(std::make_pair(name, r));
560
561 alock.release();
562 mVirtualBox->onNATNetworkPortForward(mName.raw(), TRUE, aIsIpv6,
563 aPortForwardRuleName, aProto,
564 aHostIp, aHostPort,
565 aGuestIp, aGuestPort);
566
567 /* Notify listerners listening on this network only */
568 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), TRUE,
569 aIsIpv6, aPortForwardRuleName, aProto,
570 aHostIp, aHostPort,
571 aGuestIp, aGuestPort);
572
573#ifdef NAT_XML_SERIALIZATION
574 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
575 rc = mVirtualBox->saveSettings();
576#endif
577 return rc;
578}
579
580STDMETHODIMP NATNetwork::RemovePortForwardRule(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName)
581{
582 int rc = S_OK;
583 Utf8Str strHostIP, strGuestIP;
584 uint16_t u16HostPort, u16GuestPort;
585 NATProtocol_T proto = NATProtocol_TCP;
586
587 AutoCaller autoCaller(this);
588 if (FAILED(autoCaller.rc())) return autoCaller.rc();
589
590 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
591 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
592 NATRuleMap::iterator it = mapRules.find(aPortForwardRuleName);
593
594 if (it == mapRules.end())
595 return E_INVALIDARG;
596
597 strHostIP = it->second.strHostIP;
598 strGuestIP = it->second.strGuestIP;
599 u16HostPort = it->second.u16HostPort;
600 u16GuestPort = it->second.u16GuestPort;
601 proto = it->second.proto;
602
603 mapRules.erase(it);
604
605 alock.release();
606
607 mVirtualBox->onNATNetworkPortForward(mName.raw(), FALSE, aIsIpv6,
608 aPortForwardRuleName, proto,
609 Bstr(strHostIP).raw(), u16HostPort,
610 Bstr(strGuestIP).raw(), u16GuestPort);
611
612 /* Notify listerners listening on this network only */
613 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), FALSE,
614 aIsIpv6, aPortForwardRuleName, proto,
615 Bstr(strHostIP).raw(), u16HostPort,
616 Bstr(strGuestIP).raw(), u16GuestPort);
617#ifdef NAT_XML_SERIALIZATION
618 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
619 rc = mVirtualBox->saveSettings();
620#endif
621
622 return rc;
623}
624
625
626STDMETHODIMP NATNetwork::Start(IN_BSTR aTrunkType)
627{
628#ifdef VBOX_WITH_NAT_SERVICE
629 AutoCaller autoCaller(this);
630 if (FAILED(autoCaller.rc())) return autoCaller.rc();
631
632 if (!m->fEnabled) return S_OK;
633
634 m->NATRunner.setOption(NETCFG_NETNAME, mName, true);
635 m->NATRunner.setOption(NETCFG_TRUNKTYPE, Utf8Str(aTrunkType), true);
636 m->NATRunner.setOption(NETCFG_IPADDRESS, m->IPv4Gateway, true);
637 m->NATRunner.setOption(NETCFG_NETMASK, m->IPv4NetworkMask, true);
638
639 /* No portforwarding rules from command-line, all will be fetched via API */
640
641 if (m->fNeedDhcpServer)
642 {
643 /**
644 * Just to as idea... via API (on creation user pass the cidr of network and)
645 * and we calculate it's addreses (mutable?).
646 */
647
648 /*
649 * Configuration and running DHCP server:
650 * 1. find server first createDHCPServer
651 * 2. if return status is E_INVALARG => server already exists just find and start.
652 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
653 * 4. if return status S_OK proceed to DHCP server configuration
654 * 5. call setConfiguration() and pass all required parameters
655 * 6. start dhcp server.
656 */
657 int rc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(),
658 m->dhcpServer.asOutParam());
659 switch (rc)
660 {
661 case E_INVALIDARG:
662 /* server haven't beeen found let create it then */
663 rc = mVirtualBox->CreateDHCPServer(mName.raw(),
664 m->dhcpServer.asOutParam());
665 if (FAILED(rc))
666 return E_FAIL;
667 /* breakthrough */
668
669 {
670 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
671 Utf8Str(m->IPv4Gateway.raw()).c_str(),
672 Utf8Str(m->IPv4DhcpServer.raw()).c_str(),
673 Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(),
674 Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str()));
675
676 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw());
677
678 rc = m->dhcpServer->SetEnabled(true);
679
680 BSTR dhcpip = NULL;
681 BSTR netmask = NULL;
682 BSTR lowerip = NULL;
683 BSTR upperip = NULL;
684
685 m->IPv4DhcpServer.cloneTo(&dhcpip);
686 m->IPv4NetworkMask.cloneTo(&netmask);
687 m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
688 m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
689 rc = m->dhcpServer->SetConfiguration(dhcpip,
690 netmask,
691 lowerip,
692 upperip);
693 }
694 case S_OK:
695 break;
696
697 default:
698 return E_FAIL;
699 }
700
701 rc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType);
702 if (FAILED(rc))
703 {
704 m->dhcpServer.setNull();
705 return E_FAIL;
706 }
707 }
708
709 if (RT_SUCCESS(m->NATRunner.start()))
710 {
711 mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE);
712 return S_OK;
713 }
714 else return E_FAIL;
715#else
716 NOREF(aTrunkType);
717 ReturnComNotImplemented();
718#endif
719}
720
721STDMETHODIMP NATNetwork::Stop()
722{
723#ifdef VBOX_WITH_NAT_SERVICE
724 if (!m->dhcpServer.isNull())
725 m->dhcpServer->Stop();
726
727 if (RT_SUCCESS(m->NATRunner.stop()))
728 {
729 mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE);
730 return S_OK;
731 }
732 else return E_FAIL;
733#else
734 ReturnComNotImplemented();
735#endif
736}
737
738void NATNetwork::GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules)
739{
740 com::SafeArray<BSTR> sf(aRules.size());
741 size_t i = 0;
742 NATRuleMap::const_iterator it;
743 for (it = aRules.begin();
744 it != aRules.end(); ++it, ++i)
745 {
746 settings::NATRule r = it->second;
747 BstrFmt bstr("%s:%s:[%s]:%d:[%s]:%d",
748 r.strName.c_str(),
749 (r.proto == NATProtocol_TCP? "tcp" : "udp"),
750 r.strHostIP.c_str(),
751 r.u16HostPort,
752 r.strGuestIP.c_str(),
753 r.u16GuestPort);
754 bstr.detachTo(&sf[i]);
755 }
756 sf.detachTo(ComSafeArrayOutArg(aPortForwardRules));
757}
758
759int NATNetwork::RecalculateIpv4AddressAssignments()
760{
761 RTNETADDRIPV4 network, netmask, gateway;
762 char aszGatewayIp[16], aszNetmask[16];
763 RT_ZERO(aszNetmask);
764 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
765 &network,
766 &netmask);
767 AssertRCReturn(rc, rc);
768
769 /* I don't remember the reason CIDR calcualted in host */
770 gateway.u = network.u;
771
772 gateway.u += 1;
773 gateway.u = RT_H2N_U32(gateway.u);
774 RTStrPrintf(aszGatewayIp, 16, "%RTnaipv4", gateway);
775 m->IPv4Gateway = RTStrDup(aszGatewayIp);
776 if (m->fNeedDhcpServer)
777 {
778 RTNETADDRIPV4 dhcpserver,
779 dhcplowerip,
780 dhcpupperip;
781 char aszNetwork[16],
782 aszDhcpIp[16],
783 aszDhcpLowerIp[16],
784 aszDhcpUpperIp[16];
785 RT_ZERO(aszNetwork);
786
787 RT_ZERO(aszDhcpIp);
788 RT_ZERO(aszDhcpLowerIp);
789 RT_ZERO(aszDhcpUpperIp);
790
791 dhcpserver.u = network.u;
792 dhcpserver.u += 2;
793
794
795 /* XXX: adding more services should change the math here */
796 dhcplowerip.u = RT_H2N_U32(dhcpserver.u + 1);
797 dhcpupperip.u = RT_H2N_U32((network.u | (~netmask.u)) -1);
798 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
799 network.u = RT_H2N_U32(network.u);
800
801 RTStrPrintf(aszNetwork, 16, "%RTnaipv4", network);
802 RTStrPrintf(aszDhcpLowerIp, 16, "%RTnaipv4", dhcplowerip);
803 RTStrPrintf(aszDhcpUpperIp, 16, "%RTnaipv4", dhcpupperip);
804 RTStrPrintf(aszDhcpIp, 16, "%RTnaipv4", dhcpserver);
805
806 m->IPv4DhcpServer = aszDhcpIp;
807 m->IPv4DhcpServerLowerIp = aszDhcpLowerIp;
808 m->IPv4DhcpServerUpperIp = aszDhcpUpperIp;
809
810 LogFunc(("network: %RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
811 network,
812 dhcpserver,
813 dhcplowerip,
814 dhcpupperip));
815 }
816 /* we need IPv4NetworkMask for NAT's gw service start */
817 netmask.u = RT_H2N_U32(netmask.u);
818 RTStrPrintf(aszNetmask, 16, "%RTnaipv4", netmask);
819 m->IPv4NetworkMask = aszNetmask;
820 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
821 return VINF_SUCCESS;
822}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette