VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 8 weeks ago

Copyright year updates by scm.

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