VirtualBox

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

Last change on this file since 48366 was 48107, checked in by vboxsync, 11 years ago

NATNetwork windows build fix. Fixed memory leak in recalculateIpv4AddressAssignments due to confusing string handling and simplified the code there a little (~20 lines shorter). Fixed indentation and some other nits.

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