VirtualBox

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

Last change on this file since 93920 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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