VirtualBox

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

Last change on this file since 48015 was 47965, checked in by vboxsync, 11 years ago

burn fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.3 KB
Line 
1/* $Id: NATNetworkImpl.cpp 47965 2013-08-21 13:14:21Z 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(LocalMappings)(ComSafeArrayOut(BSTR, aLocalMappings))
479{
480 NOREF(aLocalMappings);
481#ifndef RT_OS_WINDOWS
482 NOREF(aLocalMappingsSize);
483#endif
484 return E_NOTIMPL;
485}
486
487STDMETHODIMP NATNetwork::AddLocalMapping(IN_BSTR aHostId, LONG aOffset)
488{
489 NOREF(aHostId); NOREF(aOffset);
490 return E_NOTIMPL;
491}
492
493STDMETHODIMP NATNetwork::COMGETTER(LoopbackIp6)(LONG *aLoopbackIp6)
494{
495 NOREF(aLoopbackIp6);
496 return E_NOTIMPL;
497}
498
499STDMETHODIMP NATNetwork::COMSETTER(LoopbackIp6)(LONG aLoopbackIp6)
500{
501 NOREF(aLoopbackIp6);
502 return E_NOTIMPL;
503}
504
505STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules4)(ComSafeArrayOut(BSTR, aPortForwardRules4))
506{
507 CheckComArgOutSafeArrayPointerValid(aPortForwardRules4);
508
509 AutoCaller autoCaller(this);
510 if (FAILED(autoCaller.rc())) return autoCaller.rc();
511
512 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
513 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules4),
514 m->mapName2PortForwardRule4);
515 alock.release();
516 return S_OK;
517}
518
519STDMETHODIMP NATNetwork::COMGETTER(PortForwardRules6)(ComSafeArrayOut(BSTR,
520 aPortForwardRules6))
521{
522 CheckComArgOutSafeArrayPointerValid(aPortForwardRules6);
523
524 AutoCaller autoCaller(this);
525 if (FAILED(autoCaller.rc())) return autoCaller.rc();
526
527 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
528 GetPortForwardRulesFromMap(ComSafeArrayInArg(aPortForwardRules6), m->mapName2PortForwardRule6);
529 return S_OK;
530}
531
532STDMETHODIMP NATNetwork::AddPortForwardRule(BOOL aIsIpv6,
533 IN_BSTR aPortForwardRuleName,
534 NATProtocol_T aProto,
535 IN_BSTR aHostIp,
536 USHORT aHostPort,
537 IN_BSTR aGuestIp,
538 USHORT aGuestPort)
539{
540 int rc = S_OK;
541 AutoCaller autoCaller(this);
542 if (FAILED(autoCaller.rc())) return autoCaller.rc();
543
544 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
545 Utf8Str name = aPortForwardRuleName;
546 Utf8Str proto;
547 settings::NATRule r;
548 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
549 switch (aProto)
550 {
551 case NATProtocol_TCP:
552 proto = "tcp";
553 break;
554 case NATProtocol_UDP:
555 proto = "udp";
556 break;
557 default:
558 return E_INVALIDARG;
559 }
560 if (name.isEmpty())
561 name = Utf8StrFmt("%s_[%s]%%%d_[%s]%%%d", proto.c_str(),
562 Utf8Str(aHostIp).c_str(), aHostPort,
563 Utf8Str(aGuestIp).c_str(), aGuestPort);
564
565 NATRuleMap::iterator it;
566
567 for (it = mapRules.begin(); it != mapRules.end(); ++it)
568 {
569 r = it->second;
570 if (it->first == name)
571 return setError(E_INVALIDARG,
572 tr("A NAT rule of this name already exists"));
573 if ( r.strHostIP == Utf8Str(aHostIp)
574 && r.u16HostPort == aHostPort
575 && r.proto == aProto)
576 return setError(E_INVALIDARG,
577 tr("A NAT rule for this host port and this host IP already exists"));
578 }
579
580 r.strName = name.c_str();
581 r.proto = aProto;
582 r.strHostIP = aHostIp;
583 r.u16HostPort = aHostPort;
584 r.strGuestIP = aGuestIp;
585 r.u16GuestPort = aGuestPort;
586 mapRules.insert(std::make_pair(name, r));
587
588 alock.release();
589 mVirtualBox->onNATNetworkPortForward(mName.raw(), TRUE, aIsIpv6,
590 aPortForwardRuleName, aProto,
591 aHostIp, aHostPort,
592 aGuestIp, aGuestPort);
593
594 /* Notify listerners listening on this network only */
595 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), TRUE,
596 aIsIpv6, aPortForwardRuleName, aProto,
597 aHostIp, aHostPort,
598 aGuestIp, aGuestPort);
599
600#ifdef NAT_XML_SERIALIZATION
601 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
602 rc = mVirtualBox->saveSettings();
603#endif
604 return rc;
605}
606
607STDMETHODIMP NATNetwork::RemovePortForwardRule(BOOL aIsIpv6, IN_BSTR aPortForwardRuleName)
608{
609 int rc = S_OK;
610 Utf8Str strHostIP, strGuestIP;
611 uint16_t u16HostPort, u16GuestPort;
612 NATProtocol_T proto = NATProtocol_TCP;
613
614 AutoCaller autoCaller(this);
615 if (FAILED(autoCaller.rc())) return autoCaller.rc();
616
617 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
618 NATRuleMap& mapRules = aIsIpv6 ? m->mapName2PortForwardRule6 : m->mapName2PortForwardRule4;
619 NATRuleMap::iterator it = mapRules.find(aPortForwardRuleName);
620
621 if (it == mapRules.end())
622 return E_INVALIDARG;
623
624 strHostIP = it->second.strHostIP;
625 strGuestIP = it->second.strGuestIP;
626 u16HostPort = it->second.u16HostPort;
627 u16GuestPort = it->second.u16GuestPort;
628 proto = it->second.proto;
629
630 mapRules.erase(it);
631
632 alock.release();
633
634 mVirtualBox->onNATNetworkPortForward(mName.raw(), FALSE, aIsIpv6,
635 aPortForwardRuleName, proto,
636 Bstr(strHostIP).raw(), u16HostPort,
637 Bstr(strGuestIP).raw(), u16GuestPort);
638
639 /* Notify listerners listening on this network only */
640 fireNATNetworkPortForwardEvent(m->pEventSource, mName.raw(), FALSE,
641 aIsIpv6, aPortForwardRuleName, proto,
642 Bstr(strHostIP).raw(), u16HostPort,
643 Bstr(strGuestIP).raw(), u16GuestPort);
644#ifdef NAT_XML_SERIALIZATION
645 AutoWriteLock vboxLock(mVirtualBox COMMA_LOCKVAL_SRC_POS);
646 rc = mVirtualBox->saveSettings();
647#endif
648
649 return rc;
650}
651
652
653STDMETHODIMP NATNetwork::Start(IN_BSTR aTrunkType)
654{
655#ifdef VBOX_WITH_NAT_SERVICE
656 AutoCaller autoCaller(this);
657 if (FAILED(autoCaller.rc())) return autoCaller.rc();
658
659 if (!m->fEnabled) return S_OK;
660
661 m->NATRunner.setOption(NETCFG_NETNAME, mName, true);
662 m->NATRunner.setOption(NETCFG_TRUNKTYPE, Utf8Str(aTrunkType), true);
663 m->NATRunner.setOption(NETCFG_IPADDRESS, m->IPv4Gateway, true);
664 m->NATRunner.setOption(NETCFG_NETMASK, m->IPv4NetworkMask, true);
665
666 /* No portforwarding rules from command-line, all will be fetched via API */
667
668 if (m->fNeedDhcpServer)
669 {
670 /**
671 * Just to as idea... via API (on creation user pass the cidr of network and)
672 * and we calculate it's addreses (mutable?).
673 */
674
675 /*
676 * Configuration and running DHCP server:
677 * 1. find server first createDHCPServer
678 * 2. if return status is E_INVALARG => server already exists just find and start.
679 * 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
680 * 4. if return status S_OK proceed to DHCP server configuration
681 * 5. call setConfiguration() and pass all required parameters
682 * 6. start dhcp server.
683 */
684 int rc = mVirtualBox->FindDHCPServerByNetworkName(mName.raw(),
685 m->dhcpServer.asOutParam());
686 switch (rc)
687 {
688 case E_INVALIDARG:
689 /* server haven't beeen found let create it then */
690 rc = mVirtualBox->CreateDHCPServer(mName.raw(),
691 m->dhcpServer.asOutParam());
692 if (FAILED(rc))
693 return E_FAIL;
694 /* breakthrough */
695
696 {
697 LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
698 Utf8Str(m->IPv4Gateway.raw()).c_str(),
699 Utf8Str(m->IPv4DhcpServer.raw()).c_str(),
700 Utf8Str(m->IPv4DhcpServerLowerIp.raw()).c_str(),
701 Utf8Str(m->IPv4DhcpServerUpperIp.raw()).c_str()));
702
703 m->dhcpServer->AddGlobalOption(DhcpOpt_Router, m->IPv4Gateway.raw());
704
705 rc = m->dhcpServer->COMSETTER(Enabled)(true);
706
707 BSTR dhcpip = NULL;
708 BSTR netmask = NULL;
709 BSTR lowerip = NULL;
710 BSTR upperip = NULL;
711
712 m->IPv4DhcpServer.cloneTo(&dhcpip);
713 m->IPv4NetworkMask.cloneTo(&netmask);
714 m->IPv4DhcpServerLowerIp.cloneTo(&lowerip);
715 m->IPv4DhcpServerUpperIp.cloneTo(&upperip);
716 rc = m->dhcpServer->SetConfiguration(dhcpip,
717 netmask,
718 lowerip,
719 upperip);
720 }
721 case S_OK:
722 break;
723
724 default:
725 return E_FAIL;
726 }
727
728 rc = m->dhcpServer->Start(mName.raw(), Bstr("").raw(), aTrunkType);
729 if (FAILED(rc))
730 {
731 m->dhcpServer.setNull();
732 return E_FAIL;
733 }
734 }
735
736 if (RT_SUCCESS(m->NATRunner.start()))
737 {
738 mVirtualBox->onNATNetworkStartStop(mName.raw(), TRUE);
739 return S_OK;
740 }
741 else return E_FAIL;
742#else
743 NOREF(aTrunkType);
744 ReturnComNotImplemented();
745#endif
746}
747
748STDMETHODIMP NATNetwork::Stop()
749{
750#ifdef VBOX_WITH_NAT_SERVICE
751 if (!m->dhcpServer.isNull())
752 m->dhcpServer->Stop();
753
754 if (RT_SUCCESS(m->NATRunner.stop()))
755 {
756 mVirtualBox->onNATNetworkStartStop(mName.raw(), FALSE);
757 return S_OK;
758 }
759 else return E_FAIL;
760#else
761 ReturnComNotImplemented();
762#endif
763}
764
765void NATNetwork::GetPortForwardRulesFromMap(ComSafeArrayOut(BSTR, aPortForwardRules), NATRuleMap& aRules)
766{
767 com::SafeArray<BSTR> sf(aRules.size());
768 size_t i = 0;
769 NATRuleMap::const_iterator it;
770 for (it = aRules.begin();
771 it != aRules.end(); ++it, ++i)
772 {
773 settings::NATRule r = it->second;
774 BstrFmt bstr("%s:%s:[%s]:%d:[%s]:%d",
775 r.strName.c_str(),
776 (r.proto == NATProtocol_TCP? "tcp" : "udp"),
777 r.strHostIP.c_str(),
778 r.u16HostPort,
779 r.strGuestIP.c_str(),
780 r.u16GuestPort);
781 bstr.detachTo(&sf[i]);
782 }
783 sf.detachTo(ComSafeArrayOutArg(aPortForwardRules));
784}
785
786int NATNetwork::RecalculateIpv4AddressAssignments()
787{
788 RTNETADDRIPV4 network, netmask, gateway;
789 char aszGatewayIp[16], aszNetmask[16];
790 RT_ZERO(aszNetmask);
791 int rc = RTCidrStrToIPv4(Utf8Str(m->IPv4NetworkCidr.raw()).c_str(),
792 &network,
793 &netmask);
794 AssertRCReturn(rc, rc);
795
796 /* I don't remember the reason CIDR calcualted in host */
797 gateway.u = network.u;
798
799 gateway.u += 1;
800 gateway.u = RT_H2N_U32(gateway.u);
801 RTStrPrintf(aszGatewayIp, 16, "%RTnaipv4", gateway);
802 m->IPv4Gateway = RTStrDup(aszGatewayIp);
803 if (m->fNeedDhcpServer)
804 {
805 RTNETADDRIPV4 dhcpserver,
806 dhcplowerip,
807 dhcpupperip;
808 char aszNetwork[16],
809 aszDhcpIp[16],
810 aszDhcpLowerIp[16],
811 aszDhcpUpperIp[16];
812 RT_ZERO(aszNetwork);
813
814 RT_ZERO(aszDhcpIp);
815 RT_ZERO(aszDhcpLowerIp);
816 RT_ZERO(aszDhcpUpperIp);
817
818 dhcpserver.u = network.u;
819 dhcpserver.u += 2;
820
821
822 /* XXX: adding more services should change the math here */
823 dhcplowerip.u = RT_H2N_U32(dhcpserver.u + 1);
824 dhcpupperip.u = RT_H2N_U32((network.u | (~netmask.u)) -1);
825 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
826 network.u = RT_H2N_U32(network.u);
827
828 RTStrPrintf(aszNetwork, 16, "%RTnaipv4", network);
829 RTStrPrintf(aszDhcpLowerIp, 16, "%RTnaipv4", dhcplowerip);
830 RTStrPrintf(aszDhcpUpperIp, 16, "%RTnaipv4", dhcpupperip);
831 RTStrPrintf(aszDhcpIp, 16, "%RTnaipv4", dhcpserver);
832
833 m->IPv4DhcpServer = aszDhcpIp;
834 m->IPv4DhcpServerLowerIp = aszDhcpLowerIp;
835 m->IPv4DhcpServerUpperIp = aszDhcpUpperIp;
836
837 LogFunc(("network: %RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
838 network,
839 dhcpserver,
840 dhcplowerip,
841 dhcpupperip));
842 }
843 /* we need IPv4NetworkMask for NAT's gw service start */
844 netmask.u = RT_H2N_U32(netmask.u);
845 RTStrPrintf(aszNetmask, 16, "%RTnaipv4", netmask);
846 m->IPv4NetworkMask = aszNetmask;
847 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
848 return VINF_SUCCESS;
849}
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