VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/NATEngineImpl.cpp@ 64166

Last change on this file since 64166 was 64166, checked in by vboxsync, 8 years ago

NAT: Don't use user supplied port-forwarding rule names as node names
in CFGM. Instead move all rules under new .../Config/PortForwarding/
node, use (transient) rule index as the node name and put the rule
name into the "Name" leaf value. Note that this is a private
interface between components, so nothing else should be affected by
this layout change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/* $Id: NATEngineImpl.cpp 64166 2016-10-06 14:11:46Z vboxsync $ */
2/** @file
3 * Implementation of INATEngine in VBoxSVC.
4 */
5
6/*
7 * Copyright (C) 2010-2016 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 "NATEngineImpl.h"
19#include "AutoCaller.h"
20#include "Logging.h"
21#include "MachineImpl.h"
22#include "GuestOSTypeImpl.h"
23
24#include <iprt/ctype.h>
25#include <iprt/string.h>
26#include <iprt/cpp/utils.h>
27
28#include <VBox/err.h>
29#include <VBox/settings.h>
30#include <VBox/com/array.h>
31
32struct NATEngine::Data
33{
34 Backupable<settings::NAT> m;
35};
36
37
38// constructor / destructor
39////////////////////////////////////////////////////////////////////////////////
40
41NATEngine::NATEngine():mData(NULL), mParent(NULL), mAdapter(NULL) {}
42NATEngine::~NATEngine(){}
43
44HRESULT NATEngine::FinalConstruct()
45{
46 return BaseFinalConstruct();
47}
48
49void NATEngine::FinalRelease()
50{
51 uninit();
52 BaseFinalRelease();
53}
54
55
56HRESULT NATEngine::init(Machine *aParent, INetworkAdapter *aAdapter)
57{
58 AutoInitSpan autoInitSpan(this);
59 AssertReturn(autoInitSpan.isOk(), E_FAIL);
60 autoInitSpan.setSucceeded();
61 mData = new Data();
62 mData->m.allocate();
63 mData->m->strNetwork.setNull();
64 mData->m->strBindIP.setNull();
65 unconst(mParent) = aParent;
66 unconst(mAdapter) = aAdapter;
67 return S_OK;
68}
69
70HRESULT NATEngine::init(Machine *aParent, INetworkAdapter *aAdapter, NATEngine *aThat)
71{
72 AutoInitSpan autoInitSpan(this);
73 AssertReturn(autoInitSpan.isOk(), E_FAIL);
74 Log(("init that:%p this:%p\n", aThat, this));
75
76 AutoCaller thatCaller(aThat);
77 AssertComRCReturnRC(thatCaller.rc());
78
79 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
80
81 mData = new Data();
82 mData->m.share(aThat->mData->m);
83 unconst(mParent) = aParent;
84 unconst(mAdapter) = aAdapter;
85 unconst(mPeer) = aThat;
86 autoInitSpan.setSucceeded();
87 return S_OK;
88}
89
90HRESULT NATEngine::initCopy(Machine *aParent, INetworkAdapter *aAdapter, NATEngine *aThat)
91{
92 AutoInitSpan autoInitSpan(this);
93 AssertReturn(autoInitSpan.isOk(), E_FAIL);
94
95 Log(("initCopy that:%p this:%p\n", aThat, this));
96
97 AutoCaller thatCaller(aThat);
98 AssertComRCReturnRC(thatCaller.rc());
99
100 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
101
102 mData = new Data();
103 mData->m.attachCopy(aThat->mData->m);
104 unconst(mAdapter) = aAdapter;
105 unconst(mParent) = aParent;
106 autoInitSpan.setSucceeded();
107
108 return S_OK;
109}
110
111
112void NATEngine::uninit()
113{
114 AutoUninitSpan autoUninitSpan(this);
115 if (autoUninitSpan.uninitDone())
116 return;
117
118 mData->m.free();
119 delete mData;
120 mData = NULL;
121 unconst(mPeer) = NULL;
122 unconst(mParent) = NULL;
123}
124
125bool NATEngine::i_isModified()
126{
127 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
128 bool fModified = mData->m.isBackedUp();
129 return fModified;
130}
131
132void NATEngine::i_rollback()
133{
134 AutoCaller autoCaller(this);
135 AssertComRCReturnVoid(autoCaller.rc());
136
137 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
138
139 mData->m.rollback();
140}
141
142void NATEngine::i_commit()
143{
144 AutoCaller autoCaller(this);
145 AssertComRCReturnVoid(autoCaller.rc());
146
147 /* sanity too */
148 AutoCaller peerCaller(mPeer);
149 AssertComRCReturnVoid(peerCaller.rc());
150
151 /* lock both for writing since we modify both (mPeer is "master" so locked
152 * first) */
153 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
154 if (mData->m.isBackedUp())
155 {
156 mData->m.commit();
157 if (mPeer)
158 mPeer->mData->m.attach(mData->m);
159 }
160}
161
162void NATEngine::i_copyFrom(NATEngine *aThat)
163{
164 AssertReturnVoid(aThat != NULL);
165
166 /* sanity */
167 AutoCaller autoCaller(this);
168 AssertComRCReturnVoid(autoCaller.rc());
169
170 /* sanity too */
171 AutoCaller thatCaller(aThat);
172 AssertComRCReturnVoid(thatCaller.rc());
173
174 /* peer is not modified, lock it for reading (aThat is "master" so locked
175 * first) */
176 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
177 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
178
179 /* this will back up current data */
180 mData->m.assignCopy(aThat->mData->m);
181}
182
183HRESULT NATEngine::getNetworkSettings(ULONG *aMtu, ULONG *aSockSnd, ULONG *aSockRcv, ULONG *aTcpWndSnd, ULONG *aTcpWndRcv)
184{
185 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
186 if (aMtu)
187 *aMtu = mData->m->u32Mtu;
188 if (aSockSnd)
189 *aSockSnd = mData->m->u32SockSnd;
190 if (aSockRcv)
191 *aSockRcv = mData->m->u32SockRcv;
192 if (aTcpWndSnd)
193 *aTcpWndSnd = mData->m->u32TcpSnd;
194 if (aTcpWndRcv)
195 *aTcpWndRcv = mData->m->u32TcpRcv;
196
197 return S_OK;
198}
199
200HRESULT NATEngine::setNetworkSettings(ULONG aMtu, ULONG aSockSnd, ULONG aSockRcv, ULONG aTcpWndSnd, ULONG aTcpWndRcv)
201{
202 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
203 if ( aMtu || aSockSnd || aSockRcv
204 || aTcpWndSnd || aTcpWndRcv)
205 {
206 mData->m.backup();
207 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
208 }
209 if (aMtu)
210 mData->m->u32Mtu = aMtu;
211 if (aSockSnd)
212 mData->m->u32SockSnd = aSockSnd;
213 if (aSockRcv)
214 mData->m->u32SockRcv = aSockSnd;
215 if (aTcpWndSnd)
216 mData->m->u32TcpSnd = aTcpWndSnd;
217 if (aTcpWndRcv)
218 mData->m->u32TcpRcv = aTcpWndRcv;
219
220 return S_OK;
221}
222
223
224HRESULT NATEngine::getRedirects(std::vector<com::Utf8Str> &aRedirects)
225{
226 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
227
228 aRedirects.resize(mData->m->mapRules.size());
229 size_t i = 0;
230 settings::NATRulesMap::const_iterator it;
231 for (it = mData->m->mapRules.begin(); it != mData->m->mapRules.end(); ++it, ++i)
232 {
233 settings::NATRule r = it->second;
234 aRedirects[i] = Utf8StrFmt("%s,%d,%s,%d,%s,%d",
235 r.strName.c_str(),
236 r.proto,
237 r.strHostIP.c_str(),
238 r.u16HostPort,
239 r.strGuestIP.c_str(),
240 r.u16GuestPort);
241 }
242 return S_OK;
243}
244
245HRESULT NATEngine::addRedirect(const com::Utf8Str &aName, NATProtocol_T aProto, const com::Utf8Str &aHostIP,
246 USHORT aHostPort, const com::Utf8Str &aGuestIP, USHORT aGuestPort)
247{
248 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
249 Utf8Str name = aName;
250 settings::NATRule r;
251 const char *proto;
252 switch (aProto)
253 {
254 case NATProtocol_TCP:
255 proto = "tcp";
256 break;
257 case NATProtocol_UDP:
258 proto = "udp";
259 break;
260 default:
261 return E_INVALIDARG;
262 }
263
264 if (name.isEmpty())
265 name = Utf8StrFmt("%s_%d_%d", proto, aHostPort, aGuestPort);
266 else
267 {
268 const char *s;
269 char c;
270
271 for (s = name.c_str(); (c = *s) != '\0'; ++s)
272 {
273 if (RT_C_IS_SPACE(c))
274 return setError(E_INVALIDARG,
275 tr("Whitespace in NAT rule name"));
276
277 if (c == ',') /* we use csv in several places e.g. GetRedirects or natpf<N> argument */
278 return setError(E_INVALIDARG,
279 tr("'%c' - invalid character in NAT rule name"), c);
280 }
281 }
282
283 settings::NATRulesMap::iterator it;
284 for (it = mData->m->mapRules.begin(); it != mData->m->mapRules.end(); ++it)
285 {
286 r = it->second;
287 if (it->first == name)
288 return setError(E_INVALIDARG,
289 tr("A NAT rule of this name already exists"));
290 if ( r.strHostIP == aHostIP
291 && r.u16HostPort == aHostPort
292 && r.proto == aProto)
293 return setError(E_INVALIDARG,
294 tr("A NAT rule for this host port and this host IP already exists"));
295 }
296
297 mData->m.backup();
298 r.strName = name.c_str();
299 r.proto = aProto;
300 r.strHostIP = aHostIP;
301 r.u16HostPort = aHostPort;
302 r.strGuestIP = aGuestIP;
303 r.u16GuestPort = aGuestPort;
304 mData->m->mapRules.insert(std::make_pair(name, r));
305 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
306
307 ULONG ulSlot;
308 mAdapter->COMGETTER(Slot)(&ulSlot);
309
310 alock.release();
311 mParent->i_onNATRedirectRuleChange(ulSlot, FALSE, Bstr(name).raw(), aProto, Bstr(r.strHostIP).raw(),
312 r.u16HostPort, Bstr(r.strGuestIP).raw(), r.u16GuestPort);
313 return S_OK;
314}
315
316HRESULT NATEngine::removeRedirect(const com::Utf8Str &aName)
317{
318 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
319 settings::NATRulesMap::iterator it = mData->m->mapRules.find(aName);
320 if (it == mData->m->mapRules.end())
321 return E_INVALIDARG;
322 mData->m.backup();
323 /*
324 * NB: "it" may now point to the backup! In that case it's ok to
325 * get data from the backup copy of s.mapRules via it, but we can't
326 * erase(it) from potentially new s.mapRules.
327 */
328 settings::NATRule r = it->second;
329 ULONG ulSlot;
330 mAdapter->COMGETTER(Slot)(&ulSlot);
331
332 mData->m->mapRules.erase(aName); /* NB: erase by key, "it" may not be valid */
333 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
334 alock.release();
335 mParent->i_onNATRedirectRuleChange(ulSlot, TRUE, Bstr(aName).raw(), r.proto, Bstr(r.strHostIP).raw(),
336 r.u16HostPort, Bstr(r.strGuestIP).raw(), r.u16GuestPort);
337 return S_OK;
338}
339
340HRESULT NATEngine::i_loadSettings(const settings::NAT &data)
341{
342 AutoCaller autoCaller(this);
343 AssertComRCReturnRC(autoCaller.rc());
344
345 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
346 mData->m.assignCopy(&data);
347 return S_OK;
348}
349
350
351HRESULT NATEngine::i_saveSettings(settings::NAT &data)
352{
353 AutoCaller autoCaller(this);
354 AssertComRCReturnRC(autoCaller.rc());
355
356 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
357 HRESULT rc = S_OK;
358 data = *mData->m.data();
359 return rc;
360}
361
362HRESULT NATEngine::setNetwork(const com::Utf8Str &aNetwork)
363{
364 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
365 if (mData->m->strNetwork != aNetwork)
366 {
367 mData->m.backup();
368 mData->m->strNetwork = aNetwork;
369 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
370 }
371 return S_OK;
372}
373
374
375HRESULT NATEngine::getNetwork(com::Utf8Str &aNetwork)
376{
377 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
378 if (!mData->m->strNetwork.isEmpty())
379 {
380 aNetwork = mData->m->strNetwork;
381 Log(("Getter (this:%p) Network: %s\n", this, mData->m->strNetwork.c_str()));
382 }
383 return S_OK;
384}
385
386HRESULT NATEngine::setHostIP(const com::Utf8Str &aHostIP)
387{
388 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
389 if (mData->m->strBindIP != aHostIP)
390 {
391 mData->m.backup();
392 mData->m->strBindIP = aHostIP;
393 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
394 }
395 return S_OK;
396}
397
398HRESULT NATEngine::getHostIP(com::Utf8Str &aBindIP)
399{
400 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
401
402 if (!mData->m->strBindIP.isEmpty())
403 aBindIP = mData->m->strBindIP;
404 return S_OK;
405}
406
407HRESULT NATEngine::setTFTPPrefix(const com::Utf8Str &aTFTPPrefix)
408{
409 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
410 if (mData->m->strTFTPPrefix != aTFTPPrefix)
411 {
412 mData->m.backup();
413 mData->m->strTFTPPrefix = aTFTPPrefix;
414 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
415 }
416 return S_OK;
417}
418
419
420HRESULT NATEngine::getTFTPPrefix(com::Utf8Str &aTFTPPrefix)
421{
422 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
423
424 if (!mData->m->strTFTPPrefix.isEmpty())
425 {
426 aTFTPPrefix = mData->m->strTFTPPrefix;
427 Log(("Getter (this:%p) TFTPPrefix: %s\n", this, mData->m->strTFTPPrefix.c_str()));
428 }
429 return S_OK;
430}
431
432HRESULT NATEngine::setTFTPBootFile(const com::Utf8Str &aTFTPBootFile)
433{
434 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
435 if (mData->m->strTFTPBootFile != aTFTPBootFile)
436 {
437 mData->m.backup();
438 mData->m->strTFTPBootFile = aTFTPBootFile;
439 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
440 }
441 return S_OK;
442}
443
444
445HRESULT NATEngine::getTFTPBootFile(com::Utf8Str &aTFTPBootFile)
446{
447 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
448 if (!mData->m->strTFTPBootFile.isEmpty())
449 {
450 aTFTPBootFile = mData->m->strTFTPBootFile;
451 Log(("Getter (this:%p) BootFile: %s\n", this, mData->m->strTFTPBootFile.c_str()));
452 }
453 return S_OK;
454}
455
456
457HRESULT NATEngine::setTFTPNextServer(const com::Utf8Str &aTFTPNextServer)
458{
459 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
460 if (mData->m->strTFTPNextServer != aTFTPNextServer)
461 {
462 mData->m.backup();
463 mData->m->strTFTPNextServer = aTFTPNextServer;
464 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
465 }
466 return S_OK;
467}
468
469HRESULT NATEngine::getTFTPNextServer(com::Utf8Str &aTFTPNextServer)
470{
471 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
472 if (!mData->m->strTFTPNextServer.isEmpty())
473 {
474 aTFTPNextServer = mData->m->strTFTPNextServer;
475 Log(("Getter (this:%p) NextServer: %s\n", this, mData->m->strTFTPNextServer.c_str()));
476 }
477 return S_OK;
478}
479
480/* DNS */
481HRESULT NATEngine::setDNSPassDomain(BOOL aDNSPassDomain)
482{
483 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
484
485 if (mData->m->fDNSPassDomain != RT_BOOL(aDNSPassDomain))
486 {
487 mData->m.backup();
488 mData->m->fDNSPassDomain = RT_BOOL(aDNSPassDomain);
489 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
490 }
491 return S_OK;
492}
493
494HRESULT NATEngine::getDNSPassDomain(BOOL *aDNSPassDomain)
495{
496 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
497 *aDNSPassDomain = mData->m->fDNSPassDomain;
498 return S_OK;
499}
500
501
502HRESULT NATEngine::setDNSProxy(BOOL aDNSProxy)
503{
504 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
505
506 if (mData->m->fDNSProxy != RT_BOOL(aDNSProxy))
507 {
508 mData->m.backup();
509 mData->m->fDNSProxy = RT_BOOL(aDNSProxy);
510 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
511 }
512 return S_OK;
513}
514
515HRESULT NATEngine::getDNSProxy(BOOL *aDNSProxy)
516{
517 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
518 *aDNSProxy = mData->m->fDNSProxy;
519 return S_OK;
520}
521
522
523HRESULT NATEngine::getDNSUseHostResolver(BOOL *aDNSUseHostResolver)
524{
525 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
526 *aDNSUseHostResolver = mData->m->fDNSUseHostResolver;
527 return S_OK;
528}
529
530
531HRESULT NATEngine::setDNSUseHostResolver(BOOL aDNSUseHostResolver)
532{
533 if (mData->m->fDNSUseHostResolver != RT_BOOL(aDNSUseHostResolver))
534 {
535 mData->m.backup();
536 mData->m->fDNSUseHostResolver = RT_BOOL(aDNSUseHostResolver);
537 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
538 }
539 return S_OK;
540}
541
542HRESULT NATEngine::setAliasMode(ULONG aAliasMode)
543{
544 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
545 ULONG uAliasMode = (mData->m->fAliasUseSamePorts ? NATAliasMode_AliasUseSamePorts : 0);
546 uAliasMode |= (mData->m->fAliasLog ? NATAliasMode_AliasLog : 0);
547 uAliasMode |= (mData->m->fAliasProxyOnly ? NATAliasMode_AliasProxyOnly : 0);
548 if (uAliasMode != aAliasMode)
549 {
550 mData->m.backup();
551 mData->m->fAliasUseSamePorts = RT_BOOL(aAliasMode & NATAliasMode_AliasUseSamePorts);
552 mData->m->fAliasLog = RT_BOOL(aAliasMode & NATAliasMode_AliasLog);
553 mData->m->fAliasProxyOnly = RT_BOOL(aAliasMode & NATAliasMode_AliasProxyOnly);
554 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
555 }
556 return S_OK;
557}
558
559HRESULT NATEngine::getAliasMode(ULONG *aAliasMode)
560{
561 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
562 ULONG uAliasMode = (mData->m->fAliasUseSamePorts ? NATAliasMode_AliasUseSamePorts : 0);
563 uAliasMode |= (mData->m->fAliasLog ? NATAliasMode_AliasLog : 0);
564 uAliasMode |= (mData->m->fAliasProxyOnly ? NATAliasMode_AliasProxyOnly : 0);
565 *aAliasMode = uAliasMode;
566 return S_OK;
567}
568
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