// Copyright 2005-2016 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "murmur_pch.h" #include "Net.h" HostAddress::HostAddress() { addr[0] = addr[1] = 0ULL; } HostAddress::HostAddress(const Q_IPV6ADDR &address) { memcpy(qip6.c, address.c, 16); } HostAddress::HostAddress(const std::string &address) { if (address.length() != 16) addr[0] = addr[1] = 0ULL; else for (int i=0;i<16;++i) qip6[i] = address[i]; } HostAddress::HostAddress(const QByteArray &address) { if (address.length() != 16) addr[0] = addr[1] = 0ULL; else for (int i=0;i<16;++i) qip6[i] = address[i]; } HostAddress::HostAddress(const QHostAddress &address) { if (address.protocol() == QAbstractSocket::IPv6Protocol) { const Q_IPV6ADDR &a = address.toIPv6Address(); memcpy(qip6.c, a.c, 16); } else { addr[0] = 0ULL; shorts[4] = 0; shorts[5] = 0xffff; hash[3] = htonl(address.toIPv4Address()); } } HostAddress::HostAddress(const sockaddr_storage &address) { if (address.ss_family == AF_INET) { const struct sockaddr_in *in = reinterpret_cast(&address); addr[0] = 0ULL; shorts[4] = 0; shorts[5] = 0xffff; hash[3] = in->sin_addr.s_addr; } else if (address.ss_family == AF_INET6) { const struct sockaddr_in6 *in6 = reinterpret_cast(&address); memcpy(qip6.c, in6->sin6_addr.s6_addr, 16); } else { addr[0] = addr[1] = 0ULL; } } bool HostAddress::operator < (const HostAddress &other) const { return memcmp(qip6.c, other.qip6.c, 16) < 0; } bool HostAddress::operator == (const HostAddress &other) const { return ((addr[0] == other.addr[0]) && (addr[1] == other.addr[1])); } bool HostAddress::match(const HostAddress &netmask, int bits) const { quint64 mask[2]; if (bits == 128) { mask[0] = mask[1] = 0xffffffffffffffffULL; } else if (bits > 64) { mask[0] = 0xffffffffffffffffULL; mask[1] = SWAP64(~((1ULL << (128-bits)) - 1)); } else { mask[0] = SWAP64(~((1ULL << (64-bits)) - 1)); mask[1] = 0ULL; } return ((addr[0] & mask[0]) == (netmask.addr[0] & mask[0])) && ((addr[1] & mask[1]) == (netmask.addr[1] & mask[1])); } std::string HostAddress::toStdString() const { return std::string(reinterpret_cast(qip6.c), 16); } bool HostAddress::isV6() const { return (addr[0] != 0ULL) || (shorts[4] != 0) || (shorts[5] != 0xffff); } bool HostAddress::isValid() const { return (addr[0] != 0ULL) || (addr[1] != 0ULL); } QHostAddress HostAddress::toAddress() const { if (isV6()) return QHostAddress(qip6); else { return QHostAddress(ntohl(hash[3])); } } QByteArray HostAddress::toByteArray() const { return QByteArray(reinterpret_cast(qip6.c), 16); } void HostAddress::toSockaddr(sockaddr_storage *dst) const { memset(dst, 0, sizeof(*dst)); if (isV6()) { struct sockaddr_in6 *in6 = reinterpret_cast(dst); dst->ss_family = AF_INET6; memcpy(in6->sin6_addr.s6_addr, qip6.c, 16); } else { struct sockaddr_in *in = reinterpret_cast(dst); dst->ss_family = AF_INET; in->sin_addr.s_addr = hash[3]; } } quint32 qHash(const HostAddress &ha) { return (ha.hash[0] ^ ha.hash[1] ^ ha.hash[2] ^ ha.hash[3]); } QString HostAddress::toString() const { if (isV6()) { if (isValid()) { QString qs; qs.sprintf("[%x:%x:%x:%x:%x:%x:%x:%x]", ntohs(shorts[0]), ntohs(shorts[1]), ntohs(shorts[2]), ntohs(shorts[3]), ntohs(shorts[4]), ntohs(shorts[5]), ntohs(shorts[6]), ntohs(shorts[7])); return qs.replace(QRegExp(QLatin1String("(:0)+")),QLatin1String(":")); } else { return QLatin1String("[::]"); } } else { return QHostAddress(ntohl(hash[3])).toString(); } } bool Ban::isExpired() const { return (iDuration > 0) && static_cast(iDuration - qdtStart.secsTo(QDateTime::currentDateTime().toUTC())) < 0; } bool Ban::operator <(const Ban &other) const { // Compare username primarily and address secondarily const int unameDifference = qsUsername.localeAwareCompare(other.qsUsername); if (unameDifference == 0) return haAddress < other.haAddress; else return unameDifference < 0; } bool Ban::operator ==(const Ban &other) const { return (haAddress == other.haAddress) && (iMask == other.iMask) && (qsUsername == other.qsUsername) && (qsHash == other.qsHash) && (qsReason == other.qsReason) && (qdtStart == other.qdtStart) && (iDuration == other.iDuration); } bool Ban::isValid() const { return haAddress.isValid() && (iMask >= 8) && (iMask <= 128); } QString Ban::toString() const { return QString(QLatin1String("Hash: \"%1\", Host: \"%2\", Mask: \"%3\", Username: \"%4\", Reason: \"%5\", BanStart: \"%6\", BanEnd: \"%7\" %8")).arg( qsHash, haAddress.toString(), haAddress.isV6() ? QString::number(iMask) : QString::number(iMask-96), qsUsername, qsReason, qdtStart.toLocalTime().toString(QLatin1String("yyyy-MM-dd hh:mm:ss")), qdtStart.toLocalTime().addSecs(iDuration).toString(QLatin1String("yyyy-MM-dd hh:mm:ss")), iDuration == 0 ? QLatin1String("(permanent)") : QLatin1String("(temporary)") ); } quint32 qHash(const Ban &b) { return qHash(b.qsHash) ^ qHash(b.haAddress) ^ qHash(b.qsUsername) ^ qHash(b.iMask); }