VirtualBox

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

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

Main/NATNework: Assign to dhcplowerip not next to the dhcpserver but next available.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 KB
Line 
1/* $Id: NATNetworkImpl.cpp 48415 2013-09-10 15:17:46Z 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 < ~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 = network;
976 uint32_t offDhcpLowerIp;
977 findFirstAvailableOffset(&offDhcpLowerIp);
978 dhcplowerip.u = RT_H2N_U32(dhcplowerip.u + offDhcpLowerIp);
979
980 RTNETADDRIPV4 dhcpupperip;
981 dhcpupperip.u = RT_H2N_U32((network.u | ~netmask.u) - 1);
982
983 dhcpserver.u = RT_H2N_U32(dhcpserver.u);
984 network.u = RT_H2N_U32(network.u);
985
986 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpserver);
987 m->IPv4DhcpServer = szTmpIp;
988 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcplowerip);
989 m->IPv4DhcpServerLowerIp = szTmpIp;
990 RTStrPrintf(szTmpIp, sizeof(szTmpIp), "%RTnaipv4", dhcpupperip);
991 m->IPv4DhcpServerUpperIp = szTmpIp;
992
993 LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
994 network, dhcpserver, dhcplowerip, dhcpupperip));
995 }
996
997 /* we need IPv4NetworkMask for NAT's gw service start */
998 netmask.u = RT_H2N_U32(netmask.u);
999 RTStrPrintf(szTmpIp, 16, "%RTnaipv4", netmask);
1000 m->IPv4NetworkMask = szTmpIp;
1001
1002 LogFlowFunc(("getaway:%RTnaipv4, netmask:%RTnaipv4\n", gateway, netmask));
1003 return VINF_SUCCESS;
1004}
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