VirtualBox

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

Last change on this file since 74897 was 72919, checked in by vboxsync, 6 years ago

Main/*: From now on any valid UTF8 string is considered a valid guest OS type. Of course not all of them are known, so the API clients must be prepared to deal with not having a matching IGuestOSType object.
Frontends/VBoxManage+VBoxShell: adjust to deal with the change

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