VirtualBox

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

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

Main/NATEngine: Reject rules with names that contain whitespace, slash
(CFGM node path separator) or comma (VBoxManage natpf argument is
comma-separated). ticketref:16002.

  • 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 64142 2016-10-04 12:05: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 == '/' /* CFGM node path separator */
278 || c == ',') /* VBoxManage natpf<N> argument is csv */
279 return setError(E_INVALIDARG,
280 tr("'%c' - invalid character in NAT rule name"), c);
281 }
282 }
283
284 settings::NATRulesMap::iterator it;
285 for (it = mData->m->mapRules.begin(); it != mData->m->mapRules.end(); ++it)
286 {
287 r = it->second;
288 if (it->first == name)
289 return setError(E_INVALIDARG,
290 tr("A NAT rule of this name already exists"));
291 if ( r.strHostIP == aHostIP
292 && r.u16HostPort == aHostPort
293 && r.proto == aProto)
294 return setError(E_INVALIDARG,
295 tr("A NAT rule for this host port and this host IP already exists"));
296 }
297
298 mData->m.backup();
299 r.strName = name.c_str();
300 r.proto = aProto;
301 r.strHostIP = aHostIP;
302 r.u16HostPort = aHostPort;
303 r.strGuestIP = aGuestIP;
304 r.u16GuestPort = aGuestPort;
305 mData->m->mapRules.insert(std::make_pair(name, r));
306 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
307
308 ULONG ulSlot;
309 mAdapter->COMGETTER(Slot)(&ulSlot);
310
311 alock.release();
312 mParent->i_onNATRedirectRuleChange(ulSlot, FALSE, Bstr(name).raw(), aProto, Bstr(r.strHostIP).raw(),
313 r.u16HostPort, Bstr(r.strGuestIP).raw(), r.u16GuestPort);
314 return S_OK;
315}
316
317HRESULT NATEngine::removeRedirect(const com::Utf8Str &aName)
318{
319 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
320 settings::NATRulesMap::iterator it = mData->m->mapRules.find(aName);
321 if (it == mData->m->mapRules.end())
322 return E_INVALIDARG;
323 mData->m.backup();
324 /*
325 * NB: "it" may now point to the backup! In that case it's ok to
326 * get data from the backup copy of s.mapRules via it, but we can't
327 * erase(it) from potentially new s.mapRules.
328 */
329 settings::NATRule r = it->second;
330 ULONG ulSlot;
331 mAdapter->COMGETTER(Slot)(&ulSlot);
332
333 mData->m->mapRules.erase(aName); /* NB: erase by key, "it" may not be valid */
334 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
335 alock.release();
336 mParent->i_onNATRedirectRuleChange(ulSlot, TRUE, Bstr(aName).raw(), r.proto, Bstr(r.strHostIP).raw(),
337 r.u16HostPort, Bstr(r.strGuestIP).raw(), r.u16GuestPort);
338 return S_OK;
339}
340
341HRESULT NATEngine::i_loadSettings(const settings::NAT &data)
342{
343 AutoCaller autoCaller(this);
344 AssertComRCReturnRC(autoCaller.rc());
345
346 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
347 mData->m.assignCopy(&data);
348 return S_OK;
349}
350
351
352HRESULT NATEngine::i_saveSettings(settings::NAT &data)
353{
354 AutoCaller autoCaller(this);
355 AssertComRCReturnRC(autoCaller.rc());
356
357 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
358 HRESULT rc = S_OK;
359 data = *mData->m.data();
360 return rc;
361}
362
363HRESULT NATEngine::setNetwork(const com::Utf8Str &aNetwork)
364{
365 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
366 if (mData->m->strNetwork != aNetwork)
367 {
368 mData->m.backup();
369 mData->m->strNetwork = aNetwork;
370 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
371 }
372 return S_OK;
373}
374
375
376HRESULT NATEngine::getNetwork(com::Utf8Str &aNetwork)
377{
378 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
379 if (!mData->m->strNetwork.isEmpty())
380 {
381 aNetwork = mData->m->strNetwork;
382 Log(("Getter (this:%p) Network: %s\n", this, mData->m->strNetwork.c_str()));
383 }
384 return S_OK;
385}
386
387HRESULT NATEngine::setHostIP(const com::Utf8Str &aHostIP)
388{
389 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
390 if (mData->m->strBindIP != aHostIP)
391 {
392 mData->m.backup();
393 mData->m->strBindIP = aHostIP;
394 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
395 }
396 return S_OK;
397}
398
399HRESULT NATEngine::getHostIP(com::Utf8Str &aBindIP)
400{
401 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
402
403 if (!mData->m->strBindIP.isEmpty())
404 aBindIP = mData->m->strBindIP;
405 return S_OK;
406}
407
408HRESULT NATEngine::setTFTPPrefix(const com::Utf8Str &aTFTPPrefix)
409{
410 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
411 if (mData->m->strTFTPPrefix != aTFTPPrefix)
412 {
413 mData->m.backup();
414 mData->m->strTFTPPrefix = aTFTPPrefix;
415 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
416 }
417 return S_OK;
418}
419
420
421HRESULT NATEngine::getTFTPPrefix(com::Utf8Str &aTFTPPrefix)
422{
423 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
424
425 if (!mData->m->strTFTPPrefix.isEmpty())
426 {
427 aTFTPPrefix = mData->m->strTFTPPrefix;
428 Log(("Getter (this:%p) TFTPPrefix: %s\n", this, mData->m->strTFTPPrefix.c_str()));
429 }
430 return S_OK;
431}
432
433HRESULT NATEngine::setTFTPBootFile(const com::Utf8Str &aTFTPBootFile)
434{
435 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
436 if (mData->m->strTFTPBootFile != aTFTPBootFile)
437 {
438 mData->m.backup();
439 mData->m->strTFTPBootFile = aTFTPBootFile;
440 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
441 }
442 return S_OK;
443}
444
445
446HRESULT NATEngine::getTFTPBootFile(com::Utf8Str &aTFTPBootFile)
447{
448 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
449 if (!mData->m->strTFTPBootFile.isEmpty())
450 {
451 aTFTPBootFile = mData->m->strTFTPBootFile;
452 Log(("Getter (this:%p) BootFile: %s\n", this, mData->m->strTFTPBootFile.c_str()));
453 }
454 return S_OK;
455}
456
457
458HRESULT NATEngine::setTFTPNextServer(const com::Utf8Str &aTFTPNextServer)
459{
460 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
461 if (mData->m->strTFTPNextServer != aTFTPNextServer)
462 {
463 mData->m.backup();
464 mData->m->strTFTPNextServer = aTFTPNextServer;
465 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
466 }
467 return S_OK;
468}
469
470HRESULT NATEngine::getTFTPNextServer(com::Utf8Str &aTFTPNextServer)
471{
472 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
473 if (!mData->m->strTFTPNextServer.isEmpty())
474 {
475 aTFTPNextServer = mData->m->strTFTPNextServer;
476 Log(("Getter (this:%p) NextServer: %s\n", this, mData->m->strTFTPNextServer.c_str()));
477 }
478 return S_OK;
479}
480
481/* DNS */
482HRESULT NATEngine::setDNSPassDomain(BOOL aDNSPassDomain)
483{
484 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
485
486 if (mData->m->fDNSPassDomain != RT_BOOL(aDNSPassDomain))
487 {
488 mData->m.backup();
489 mData->m->fDNSPassDomain = RT_BOOL(aDNSPassDomain);
490 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
491 }
492 return S_OK;
493}
494
495HRESULT NATEngine::getDNSPassDomain(BOOL *aDNSPassDomain)
496{
497 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
498 *aDNSPassDomain = mData->m->fDNSPassDomain;
499 return S_OK;
500}
501
502
503HRESULT NATEngine::setDNSProxy(BOOL aDNSProxy)
504{
505 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
506
507 if (mData->m->fDNSProxy != RT_BOOL(aDNSProxy))
508 {
509 mData->m.backup();
510 mData->m->fDNSProxy = RT_BOOL(aDNSProxy);
511 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
512 }
513 return S_OK;
514}
515
516HRESULT NATEngine::getDNSProxy(BOOL *aDNSProxy)
517{
518 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
519 *aDNSProxy = mData->m->fDNSProxy;
520 return S_OK;
521}
522
523
524HRESULT NATEngine::getDNSUseHostResolver(BOOL *aDNSUseHostResolver)
525{
526 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
527 *aDNSUseHostResolver = mData->m->fDNSUseHostResolver;
528 return S_OK;
529}
530
531
532HRESULT NATEngine::setDNSUseHostResolver(BOOL aDNSUseHostResolver)
533{
534 if (mData->m->fDNSUseHostResolver != RT_BOOL(aDNSUseHostResolver))
535 {
536 mData->m.backup();
537 mData->m->fDNSUseHostResolver = RT_BOOL(aDNSUseHostResolver);
538 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
539 }
540 return S_OK;
541}
542
543HRESULT NATEngine::setAliasMode(ULONG aAliasMode)
544{
545 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
546 ULONG uAliasMode = (mData->m->fAliasUseSamePorts ? NATAliasMode_AliasUseSamePorts : 0);
547 uAliasMode |= (mData->m->fAliasLog ? NATAliasMode_AliasLog : 0);
548 uAliasMode |= (mData->m->fAliasProxyOnly ? NATAliasMode_AliasProxyOnly : 0);
549 if (uAliasMode != aAliasMode)
550 {
551 mData->m.backup();
552 mData->m->fAliasUseSamePorts = RT_BOOL(aAliasMode & NATAliasMode_AliasUseSamePorts);
553 mData->m->fAliasLog = RT_BOOL(aAliasMode & NATAliasMode_AliasLog);
554 mData->m->fAliasProxyOnly = RT_BOOL(aAliasMode & NATAliasMode_AliasProxyOnly);
555 mParent->i_setModified(Machine::IsModified_NetworkAdapters);
556 }
557 return S_OK;
558}
559
560HRESULT NATEngine::getAliasMode(ULONG *aAliasMode)
561{
562 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
563 ULONG uAliasMode = (mData->m->fAliasUseSamePorts ? NATAliasMode_AliasUseSamePorts : 0);
564 uAliasMode |= (mData->m->fAliasLog ? NATAliasMode_AliasLog : 0);
565 uAliasMode |= (mData->m->fAliasProxyOnly ? NATAliasMode_AliasProxyOnly : 0);
566 *aAliasMode = uAliasMode;
567 return S_OK;
568}
569
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