Skip to content

Commit

Permalink
Add methods for IP selection.
Browse files Browse the repository at this point in the history
This adds a mechanism to determine a list of addresses that servers
should listen to, based off those defined for the machine. If
BackendServerIP or BackendServerIP6 are defined for that host, only
those and localhost addresses are selected.  If otherwise, any
link-local addresses are filtered out, and IPv4 is limited to only
RFC1918 private ranges. If users wish to listen on an internet
accessible address, they will need to force that with those settings.

Also added is a GetBackendServerIP convenience function, replacing the
existing GetSettingOnHost calls, and returning an IPv4 or IPv6 address
as is available.
  • Loading branch information
wagnerrp committed Feb 12, 2012
1 parent 6f6e34d commit c895f45
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 19 deletions.
136 changes: 118 additions & 18 deletions mythtv/libs/libmythbase/mythcorecontext.cpp
Expand Up @@ -6,7 +6,9 @@
#include <QMutex>
#include <QWaitCondition>
#include <QNetworkInterface>
#include <QAbstractSocket>
#include <QHostAddress>
#include <QNetworkInterface>

#include <cmath>

Expand Down Expand Up @@ -67,7 +69,8 @@ class MythCoreContextPrivate : public QObject
bool m_WOLInProgress;

bool m_backend;
bool m_hasIPv6;
QList<QHostAddress> m_IPv4;
QList<QHostAddress> m_IPv6;

MythDB *m_database;

Expand All @@ -93,7 +96,6 @@ MythCoreContextPrivate::MythCoreContextPrivate(MythCoreContext *lparent,
m_serverSock(NULL), m_eventSock(NULL),
m_WOLInProgress(false),
m_backend(false),
m_hasIPv6(false),
m_database(GetMythDB()),
m_UIThread(QThread::currentThread()),
m_locale(NULL),
Expand Down Expand Up @@ -226,18 +228,7 @@ bool MythCoreContext::Init(void)
"(such as 'en_US.UTF-8').").arg(lang_variables));
#endif

// If any of the IPs on any interfaces look like IPv6 addresses, assume IPv6
// is available
QNetworkInterface qtinterface;
QList<QHostAddress> IpList = qtinterface.allAddresses();
for (int i = 0; i < IpList.size(); i++)
{
if (IpList.at(i).toString().contains(":"))
{
d->m_hasIPv6 = true;
break;
}
}
ConfigureHostAddress();

return true;
}
Expand Down Expand Up @@ -585,9 +576,10 @@ bool MythCoreContext::IsBackend(void) const
bool MythCoreContext::IsMasterHost(void)
{
QString myip = GetSetting("BackendServerIP");
QString myip6 = GetSetting("BackendServerIP6");
QString masterip = GetSetting("MasterServerIP");

return (masterip == myip);
return ((masterip == myip) || (masterip == myip6));
}

bool MythCoreContext::IsMasterBackend(void)
Expand Down Expand Up @@ -629,10 +621,92 @@ bool MythCoreContext::IsFrontendOnly(void)
return !backendOnLocalhost;
}

QHostAddress MythCoreContext::MythHostAddressAny(void)
void MythCoreContext::ConfigureHostAddress(void)
{
// populate stored IPv4 and IPv6 addresses
// if address is not defined, QHostAddress will be invalid and Null
QHostAddress config_v4(GetSetting("BackendServerIP"));
#if !defined(QT_NO_IPV6)
QHostAddress config_v6(GetSetting("BackendServerIP6"));
#endif

// loop through all available addresses to populate lists
QList<QHostAddress> IPs = QNetworkInterface::allAddresses();
QList<QHostAddress>::const_iterator it;
for (it = IPs.begin(); it != IPs.end(); ++it)
{
if (d->m_IPv4.contains(*it))
// already defined, skip
continue;
else if (*it == QHostAddress::LocalHost)
// always listen on LocalHost
d->m_IPv4.append(*it);
else if (!config_v4.isNull() && (*it == config_v4))
// IPv4 address is defined, add it
d->m_IPv4.append(*it);
else if (config_v4.isNull() &&
(it->protocol() == QAbstractSocket::IPv4Protocol))
{
// IPv4 address is not defined, populate one
// restrict autoconfiguration to RFC1918 private networks
if (it->isInSubnet(QHostAddress::parseSubnet("10.0.0.0/8")) ||
it->isInSubnet(QHostAddress::parseSubnet("172.16.0.0/12")) ||
it->isInSubnet(QHostAddress::parseSubnet("192.168.0.0/16")))
d->m_IPv4.append(*it);
}
#if !defined(QT_NO_IPV6)
else if (d->m_IPv6.contains(*it))
// already defined, skip
continue;
else if (*it == QHostAddress::LocalHostIPv6)
// always listen on LocalHost
d->m_IPv6.append(*it);
else if (!config_v6.isNull() && (*it == config_v6))
// IPv6 address is defined, add it
d->m_IPv6.append(*it);
else if (config_v6.isNull() &&
(it->protocol() == QAbstractSocket::IPv6Protocol))
// IPv6 address is not defined, populate one
// put in additional block filtering here?
if (!it->isInSubnet(QHostAddress::parseSubnet("fe80::/10")))
d->m_IPv6.append(*it);
#endif
}

if (!config_v4.isNull() && d->m_IPv4.contains(config_v4))
{
LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
"on %1, but address is not used on any local network "
"interfaces.").arg(config_v4.toString()));
}
#if !defined(QT_NO_IPV6)

if (!config_v6.isNull() && d->m_IPv6.contains(config_v6))
{
LOG(VB_GENERAL, LOG_CRIT, LOC + QString("Host is configured to listen "
"on %1, but address is not used on any local network "
"interfaces.").arg(config_v6.toString()));
}
#endif
}

QList<QHostAddress> MythCoreContext::MythHostAddress(void)
{
QList<QHostAddress> alist(d->m_IPv4);
alist << d->m_IPv6;
return alist;
}

QList<QHostAddress> MythCoreContext::MythHostAddress4(void)
{
QList<QHostAddress> alist(d->m_IPv4);
return alist;
}

QList<QHostAddress> MythCoreContext::MythHostAddress6(void)
{
return QHostAddress(
(d->m_hasIPv6) ? QHostAddress::AnyIPv6 : QHostAddress::Any);
QList<QHostAddress> alist(d->m_IPv6);
return alist;
}

QString MythCoreContext::GenMythURL(QString host, QString port, QString path, QString storageGroup)
Expand Down Expand Up @@ -839,6 +913,32 @@ double MythCoreContext::GetFloatSettingOnHost(const QString &key,
return d->m_database->GetFloatSettingOnHost(key, host, defaultval);
}

QString MythCoreContext::GetBackendServerIP(void)
{
return GetBackendServerIP(d->m_localHostname);
}

QString MythCoreContext::GetBackendServerIP(const QString &host)
{
#if !defined(QT_NO_IPV6)
// prefer IPv6 address if optional
if (!d->m_IPv6.empty())
{
// we have IPv6 addresses, assume we can connect to them
QString address = GetSettingOnHost("BackendServerIP6", host, "");
if (!address.isEmpty())
return address;
}
#endif
// fall back to IPv4 address
QString address = GetSettingOnHost("BackendServerIP", host, "");
if (!address.isEmpty())
return address;

LOG(VB_GENERAL, LOG_WARNING, "No address defined for host: "+host);
return "";
}

void MythCoreContext::SetSetting(const QString &key, const QString &newValue)
{
d->m_database->SetSetting(key, newValue);
Expand Down
8 changes: 7 additions & 1 deletion mythtv/libs/libmythbase/mythcorecontext.h
Expand Up @@ -76,7 +76,10 @@ class MBASE_PUBLIC MythCoreContext : public MythObservable, public MythSocketCBs
uint timeout_ms = kMythSocketLongTimeout,
bool error_dialog_desired = false);

QHostAddress MythHostAddressAny(void);
void ConfigureHostAddress(void);
QList<QHostAddress> MythHostAddress(void);
QList<QHostAddress> MythHostAddress4(void);
QList<QHostAddress> MythHostAddress6(void);

QString GenMythURL(QString host = QString(), QString port = QString(),
QString path = QString(), QString storageGroup = QString());
Expand Down Expand Up @@ -145,6 +148,9 @@ class MBASE_PUBLIC MythCoreContext : public MythObservable, public MythSocketCBs
double GetFloatSettingOnHost(const QString &key, const QString &host,
double defaultval = 0.0);

QString GetBackendServerIP(void);
QString GetBackendServerIP(const QString &host);

void SetSetting(const QString &key, const QString &newValue);

void ClearSettingsCache(const QString &myKey = QString(""));
Expand Down

0 comments on commit c895f45

Please sign in to comment.