NATNetworkImpl.cpp revision 6dd946376d7b56d260db8d3bd66989858c729ce7
/* $Id$ */
/** @file
* INATNetwork implementation.
*/
/*
* Copyright (C) 2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include <string>
#include "NetworkServiceRunner.h"
#include "DHCPServerImpl.h"
#include "NATNetworkImpl.h"
#include "AutoCaller.h"
#include "Logging.h"
#include <VBox/settings.h>
#include "EventImpl.h"
#include "VirtualBoxImpl.h"
#include <algorithm>
#include <list>
#ifndef RT_OS_WINDOWS
#else
# define IN_LOOPBACKNET 127
#endif
// constructor / destructor
/////////////////////////////////////////////////////////////////////////////
struct NATNetwork::Data
{
Data()
, u32LoopbackIp6(0)
, offGateway(0)
, offDhcp(0)
{
}
virtual ~Data(){}
#ifdef VBOX_WITH_NAT_SERVICE
#endif
};
: mVirtualBox(NULL)
{
}
NATNetwork::~NATNetwork()
{
}
{
return BaseFinalConstruct();
}
void NATNetwork::FinalRelease()
{
uninit();
}
void NATNetwork::uninit()
{
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
if (autoUninitSpan.uninitDone())
return;
delete m;
m = NULL;
}
{
AutoInitSpan autoInitSpan(this);
/* share VirtualBox weakly (parent remains NULL so far) */
m = new Data();
m->offGateway = 1;
m->IPv4NetworkCidr = "10.0.2.0/24";
m->IPv6Prefix = "fe80::/64";
/* Confirm a successful initialization */
return S_OK;
}
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* share VirtualBox weakly (parent remains NULL so far) */
m = new Data();
m->maNATLoopbackOffsetList.clear();
/* IPv4 port-forward rules */
{
}
/* IPv6 port-forward rules */
{
}
return S_OK;
}
{
AutoCaller autoCaller(this);
/* saving ipv4 port-forward Rules*/
/* saving ipv6 port-forward Rules*/
m->maNATLoopbackOffsetList.end());
/* Notify listerners listening on this network only */
return S_OK;
}
{
/* event source is const, no need to lock */
return S_OK;
}
{
return S_OK;
}
{
{
if (aNetworkName == mName)
return S_OK;
}
return S_OK;
}
{
return S_OK;
}
{
{
return S_OK;
}
return S_OK;
}
{
aIPv4Gateway = m->IPv4Gateway;
return S_OK;
}
{
aNetwork = m->IPv4NetworkCidr;
return S_OK;
}
{
{
if (aIPv4NetworkCidr == m->IPv4NetworkCidr)
return S_OK;
/* silently ignore network cidr update for now.
* todo: keep internally guest address of port forward rule
* as offset from network id.
*/
if (!m->mapName2PortForwardRule4.empty())
return S_OK;
}
return S_OK;
}
{
*aIPv6Enabled = m->fIPv6Enabled;
return S_OK;
}
{
{
if (aIPv6Enabled == m->fIPv6Enabled)
return S_OK;
m->fIPv6Enabled = aIPv6Enabled;
}
return S_OK;
}
{
aIPv6Prefix = m->IPv6Prefix;
return S_OK;
}
{
{
if (aIPv6Prefix == m->IPv6Prefix)
return S_OK;
/* silently ignore network IPv6 prefix update.
* todo: see similar todo in NATNetwork::COMSETTER(Network)(IN_BSTR)
*/
if (!m->mapName2PortForwardRule6.empty())
return S_OK;
}
return S_OK;
}
{
return S_OK;
}
{
{
return S_OK;
}
return S_OK;
}
{
*aNeedDhcpServer = m->fNeedDhcpServer;
return S_OK;
}
{
{
if (aNeedDhcpServer == m->fNeedDhcpServer)
return S_OK;
}
return S_OK;
}
{
size_t i = 0;
{
}
return S_OK;
}
{
if (RT_FAILURE(rc))
return E_INVALIDARG;
/* check against 127/8 */
return E_INVALIDARG;
/* check against networkid vs network mask */
if (RT_FAILURE(rc))
return E_INVALIDARG;
return E_INVALIDARG;
m->maNATLoopbackOffsetList.end(),
aHostId);
{
if (aOffset == 0) /* erase */
else /* modify */
{
m->maNATLoopbackOffsetList.end(),
return E_INVALIDARG; /* this offset is already registered. */
}
return mVirtualBox->i_saveSettings();
}
/* injection */
m->maNATLoopbackOffsetList.end(),
return E_INVALIDARG; /* offset is already registered. */
return mVirtualBox->i_saveSettings();
}
{
*aLoopbackIp6 = m->u32LoopbackIp6;
return S_OK;
}
{
{
if (aLoopbackIp6 < 0)
return E_INVALIDARG;
return S_OK;
m->u32LoopbackIp6 = aLoopbackIp6;
}
return mVirtualBox->i_saveSettings();
}
{
return S_OK;
}
{
return S_OK;
}
{
{
switch (aProto)
{
case NATProtocol_TCP:
proto = "tcp";
break;
case NATProtocol_UDP:
proto = "udp";
break;
default:
return E_INVALIDARG;
}
{
return setError(E_INVALIDARG,
tr("A NAT rule of this name already exists"));
&& r.u16HostPort == aHostPort
return setError(E_INVALIDARG,
tr("A NAT rule for this host port and this host IP already exists"));
}
r.u16HostPort = aHostPort;
r.strGuestIP = aGuestIp;
r.u16GuestPort = aGuestPort;
}
{
}
/* Notify listerners listening on this network only */
return S_OK;
}
{
{
return E_INVALIDARG;
}
{
}
/* Notify listerners listening on this network only */
return S_OK;
}
{
#ifdef VBOX_WITH_NAT_SERVICE
/* No portforwarding rules from command-line, all will be fetched via API */
if (m->fNeedDhcpServer)
{
/*
* Just to as idea... via API (on creation user pass the cidr of network and)
* and we calculate it's addreses (mutable?).
*/
/*
* Configuration and running DHCP server:
* 1. find server first createDHCPServer
* 2. if return status is E_INVALARG => server already exists just find and start.
* 3. if return status neither E_INVALRG nor S_OK => return E_FAIL
* 4. if return status S_OK proceed to DHCP server configuration
* 5. call setConfiguration() and pass all required parameters
* 6. start dhcp server.
*/
m->dhcpServer.asOutParam());
switch (hrc)
{
case E_INVALIDARG:
/* server haven't beeen found let create it then */
m->dhcpServer.asOutParam());
return E_FAIL;
/* breakthrough */
{
LogFunc(("gateway: %s, dhcpserver:%s, dhcplowerip:%s, dhcpupperip:%s\n",
m->IPv4Gateway.c_str(),
m->IPv4DhcpServer.c_str(),
m->IPv4DhcpServerLowerIp.c_str(),
m->IPv4DhcpServerUpperIp.c_str()));
upperip);
}
case S_OK:
break;
default:
return E_FAIL;
}
/* XXX: AddGlobalOption(DhcpOpt_Router,) - enables attachement of DhcpServer to Main. */
{
m->dhcpServer.setNull();
return E_FAIL;
}
}
{
return S_OK;
}
/** @todo missing setError()! */
return E_FAIL;
#else
#endif
}
{
#ifdef VBOX_WITH_NAT_SERVICE
if (!m->dhcpServer.isNull())
m->dhcpServer->Stop();
return S_OK;
/** @todo missing setError()! */
return E_FAIL;
#else
#endif
}
void NATNetwork::i_getPortForwardRulesFromMap(std::vector<com::Utf8Str> &aPortForwardRules, NATRuleMap& aRules)
{
size_t i = 0;
{
r.u16HostPort,
r.strGuestIP.c_str(),
r.u16GuestPort);
}
}
{
&network,
&netmask);
{
bool skip = false;
++it)
{
{
skip = true;
break;
}
}
if (skip)
continue;
if (off == m->offGateway)
{
if (addrType == ADDR_GATEWAY)
break;
else
continue;
}
{
break;
else
continue;
}
if (!skip)
break;
}
if (poff)
return VINF_SUCCESS;
}
{
&network,
&netmask);
if (m->fNeedDhcpServer)
/* I don't remember the reason CIDR calculated on the host. */
gateway.u += m->offGateway;
char szTmpIp[16];
m->IPv4Gateway = szTmpIp;
if (m->fNeedDhcpServer)
{
dhcpserver.u += m->offDhcp;
/* XXX: adding more services should change the math here */
m->IPv4DhcpServer = szTmpIp;
m->IPv4DhcpServerLowerIp = szTmpIp;
m->IPv4DhcpServerUpperIp = szTmpIp;
LogFunc(("network:%RTnaipv4, dhcpserver:%RTnaipv4, dhcplowerip:%RTnaipv4, dhcpupperip:%RTnaipv4\n",
}
/* we need IPv4NetworkMask for NAT's gw service start */
m->IPv4NetworkMask = szTmpIp;
return VINF_SUCCESS;
}