amnezia-client/client/platforms/ios/ipaddress.cpp

313 lines
8.2 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ipaddress.h"
#include "bigintipv6addr.h"
#include <QtMath>
namespace {
quint32 s_allIpV4Ones = static_cast<quint32>(qPow(2, 32) - 1);
BigIntIPv6Addr s_allIPv6Ones;
bool s_ipv6Initialized = false;
void maybeInitialize() {
if (s_ipv6Initialized) return;
s_ipv6Initialized = true;
Q_IPV6ADDR allOnes;
memset((void*)&allOnes, static_cast<quint8>(qPow(2, 8) - 1), sizeof(allOnes));
s_allIPv6Ones = BigIntIPv6Addr(allOnes);
}
} // namespace
// static
IPAddress IPAddress::create(const QString& ip) {
if (ip.contains("/")) {
QPair<QHostAddress, int> p = QHostAddress::parseSubnet(ip);
if (p.first.protocol() == QAbstractSocket::IPv4Protocol) {
if (p.second < 32) {
return IPAddress(p.first, p.second);
}
return IPAddress(p.first);
}
if (p.first.protocol() == QAbstractSocket::IPv6Protocol) {
if (p.second < 128) {
return IPAddress(p.first, p.second);
}
return IPAddress(p.first);
}
Q_ASSERT(false);
}
return IPAddress(QHostAddress(ip));
}
IPAddress::IPAddress() {
maybeInitialize();
}
IPAddress::IPAddress(const IPAddress& other) {
maybeInitialize();
*this = other;
}
IPAddress& IPAddress::operator=(const IPAddress& other) {
if (this == &other) return *this;
m_address = other.m_address;
m_prefixLength = other.m_prefixLength;
m_netmask = other.m_netmask;
m_hostmask = other.m_hostmask;
m_broadcastAddress = other.m_broadcastAddress;
return *this;
}
IPAddress::IPAddress(const QHostAddress& address)
: m_address(address), m_broadcastAddress(address) {
maybeInitialize();
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
m_prefixLength = 32;
m_netmask = QHostAddress(s_allIpV4Ones);
m_hostmask = QHostAddress((quint32)(0));
} else {
Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
m_prefixLength = 128;
m_netmask = QHostAddress(s_allIPv6Ones.value());
{
Q_IPV6ADDR ipv6;
memset((void*)&ipv6, 0, sizeof(ipv6));
m_hostmask = QHostAddress(ipv6);
}
}
}
IPAddress::IPAddress(const QHostAddress& address, int prefixLength)
: m_address(address), m_prefixLength(prefixLength) {
maybeInitialize();
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
Q_ASSERT(prefixLength >= 0 && prefixLength <= 32);
m_netmask = QHostAddress(s_allIpV4Ones ^ (s_allIpV4Ones >> prefixLength));
m_hostmask = QHostAddress(m_netmask.toIPv4Address() ^ s_allIpV4Ones);
m_broadcastAddress =
QHostAddress(address.toIPv4Address() | m_hostmask.toIPv4Address());
} else {
Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
Q_ASSERT(prefixLength >= 0 && prefixLength <= 128);
Q_IPV6ADDR netmask;
{
BigIntIPv6Addr tmp = (s_allIPv6Ones >> prefixLength);
for (int i = 0; i < 16; ++i)
netmask[i] = s_allIPv6Ones.value()[i] ^ tmp.value()[i];
}
m_netmask = QHostAddress(netmask);
{
Q_IPV6ADDR tmp;
for (int i = 0; i < 16; ++i)
tmp[i] = netmask[i] ^ s_allIPv6Ones.value()[i];
m_hostmask = QHostAddress(tmp);
}
{
Q_IPV6ADDR ipv6Address = address.toIPv6Address();
Q_IPV6ADDR ipv6Hostname = m_hostmask.toIPv6Address();
for (int i = 0; i < 16; ++i) ipv6Address[i] |= ipv6Hostname[i];
m_broadcastAddress = QHostAddress(ipv6Address);
}
}
}
IPAddress::~IPAddress() { }
QAbstractSocket::NetworkLayerProtocol IPAddress::type() const {
return m_address.protocol();
}
bool IPAddress::overlaps(const IPAddress& other) const {
return other.contains(m_address) || other.contains(m_broadcastAddress) ||
contains(other.m_address) || contains(other.m_broadcastAddress);
}
bool IPAddress::contains(const QHostAddress& address) const {
if (address.protocol() != m_address.protocol()) {
return false;
}
if (address.protocol() == QAbstractSocket::IPv4Protocol) {
return (m_address.toIPv4Address() <= address.toIPv4Address()) &&
(address.toIPv4Address() <= m_broadcastAddress.toIPv4Address());
}
Q_ASSERT(address.protocol() == QAbstractSocket::IPv6Protocol);
return (BigIntIPv6Addr(m_address.toIPv6Address()) <=
BigIntIPv6Addr(address.toIPv6Address())) &&
(BigIntIPv6Addr(address.toIPv6Address()) <=
BigIntIPv6Addr(m_broadcastAddress.toIPv6Address()));
}
bool IPAddress::operator==(const IPAddress& other) const {
return m_address == other.m_address && m_netmask == other.m_netmask;
}
bool IPAddress::subnetOf(const IPAddress& other) const {
if (other.m_address.protocol() != m_address.protocol()) {
return false;
}
if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
return other.m_address.toIPv4Address() <= m_address.toIPv4Address() &&
other.m_broadcastAddress.toIPv4Address() >=
m_broadcastAddress.toIPv4Address();
}
Q_ASSERT(m_address.protocol() == QAbstractSocket::IPv6Protocol);
return BigIntIPv6Addr(other.m_address.toIPv6Address()) <=
BigIntIPv6Addr(m_address.toIPv6Address()) &&
BigIntIPv6Addr(other.m_broadcastAddress.toIPv6Address()) >=
BigIntIPv6Addr(m_broadcastAddress.toIPv6Address());
}
QList<IPAddress> IPAddress::subnets() const {
QList<IPAddress> list;
if (m_address.protocol() == QAbstractSocket::IPv4Protocol) {
if (m_prefixLength == 32) {
list.append(*this);
return list;
}
quint64 start = m_address.toIPv4Address();
quint64 end = quint64(m_broadcastAddress.toIPv4Address()) + 1;
quint64 step = ((quint64)m_hostmask.toIPv4Address() + 1) >> 1;
while (start < end) {
int newPrefixLength = m_prefixLength + 1;
if (newPrefixLength == 32) {
list.append(IPAddress(QHostAddress(static_cast<quint32>(start))));
} else {
list.append(IPAddress(QHostAddress(static_cast<quint32>(start)),
m_prefixLength + 1));
}
start += step;
}
return list;
}
Q_ASSERT(m_address.protocol() == QAbstractSocket::IPv6Protocol);
if (m_prefixLength == 128) {
list.append(*this);
return list;
}
BigInt start(17);
{
Q_IPV6ADDR addr = m_address.toIPv6Address();
for (int i = 0; i < 16; ++i) {
start.setValueAt(addr[i], i + 1);
}
}
BigInt end(17);
{
Q_IPV6ADDR addr = m_broadcastAddress.toIPv6Address();
for (int i = 0; i < 16; ++i) {
end.setValueAt(addr[i], i + 1);
}
++end;
}
BigInt step(17);
{
Q_IPV6ADDR addr = m_hostmask.toIPv6Address();
for (int i = 0; i < 16; ++i) {
step.setValueAt(addr[i], i + 1);
}
step = (++step) >> 1;
}
while (start < end) {
int newPrefixLength = m_prefixLength + 1;
Q_IPV6ADDR startIPv6;
for (int i = 0; i < 16; ++i) {
startIPv6[i] = start.valueAt(i + 1);
}
if (newPrefixLength == 128) {
list.append(IPAddress(QHostAddress(startIPv6)));
} else {
list.append(IPAddress(QHostAddress(startIPv6), m_prefixLength + 1));
}
start += step;
}
return list;
}
// static
QList<IPAddress> IPAddress::excludeAddresses(
const QList<IPAddress>& sourceList, const QList<IPAddress>& excludeList) {
QList<IPAddress> results = sourceList;
for (const IPAddress& exclude : excludeList) {
QList<IPAddress> newResults;
for (const IPAddress& ip : results) {
if (ip.overlaps(exclude)) {
QList<IPAddress> range = ip.excludeAddresses(exclude);
newResults.append(range);
} else {
newResults.append(ip);
}
}
results = newResults;
}
return results;
}
QList<IPAddress> IPAddress::excludeAddresses(const IPAddress& ip) const {
QList<IPAddress> sn = subnets();
Q_ASSERT(sn.length() >= 2);
QList<IPAddress> result;
while (sn[0] != ip && sn[1] != ip) {
if (ip.subnetOf(sn[0])) {
result.append(sn[1]);
sn = sn[0].subnets();
} else if (ip.subnetOf(sn[1])) {
result.append(sn[0]);
sn = sn[1].subnets();
} else {
Q_ASSERT(false);
}
}
if (sn[0] == ip) {
result.append(sn[1]);
} else if (sn[1] == ip) {
result.append(sn[0]);
} else {
Q_ASSERT(false);
}
return result;
}