bool IsBehindIPv4Nat() { ULONG len = 0; int ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME, 0, 0, &len); if (ret != ERROR_BUFFER_OVERFLOW) { return false; } bool has_ipv4 = false; bool has_public_ipv4 = false; auto buf = std::unique_ptr<char[]>(new char[len]); IP_ADAPTER_ADDRESSES *addrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(buf.get()); ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME, 0, addrs, &len); if (ret == ERROR_SUCCESS) { for (auto addr = addrs; addr; addr = addr->Next) { for (auto ip = addr->FirstUnicastAddress; ip; ip = ip->Next) { if (ip->Flags & IP_ADAPTER_ADDRESS_TRANSIENT) { continue; } if (ip->Address.lpSockaddr && ip->Address.lpSockaddr->sa_family == AF_INET) { has_ipv4 = true; CStdString ipStr = inet_ntoa(reinterpret_cast<SOCKADDR_IN*>(ip->Address.lpSockaddr)->sin_addr); if (!ipStr.IsEmpty()) { has_public_ipv4 = has_public_ipv4 || IsRoutableAddress(ipStr); } } } } } return has_ipv4 && !has_public_ipv4; }
bool IsRoutableAddress(const wxString& address, CSocket::address_family family) { if (family == CSocket::ipv6) { wxString long_address = GetIPV6LongForm(address); if (long_address.size() != 39) return false; if (long_address[0] == '0') { // ::/128 if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0000")) return false; // ::1/128 if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0001")) return false; if (long_address.Left(30) == _T("0000:0000:0000:0000:0000:ffff:")) { // IPv4 mapped wxString ipv4 = wxString::Format(_T("%d.%d.%d.%d"), DigitHexToDecNum(long_address[30]) * 16 + DigitHexToDecNum(long_address[31]), DigitHexToDecNum(long_address[32]) * 16 + DigitHexToDecNum(long_address[33]), DigitHexToDecNum(long_address[35]) * 16 + DigitHexToDecNum(long_address[36]), DigitHexToDecNum(long_address[37]) * 16 + DigitHexToDecNum(long_address[38])); return IsRoutableAddress(ipv4, CSocket::ipv4); } return true; } if (long_address[0] == 'f') { if (long_address[1] == 'e') { // fe80::/10 (link local) const wxChar& c = long_address[2]; int v; if (c >= 'a') v = c - 'a' + 10; else v = c - '0'; if ((v & 0xc) == 0x8) return false; return true; } else if (long_address[1] == 'c' || long_address[1] == 'd') { // fc00::/7 (site local) return false; } } return true; } else { // Assumes address is already a valid IP address if (address.Left(3) == _T("127") || address.Left(3) == _T("10.") || address.Left(7) == _T("192.168") || address.Left(7) == _T("169.254")) return false; if (address.Left(3) == _T("172")) { wxString middle = address.Mid(4); int pos = address.Find(_T(".")); wxASSERT(pos != -1); long part; middle.Left(pos).ToLong(&part); if (part >= 16 && part <= 31) return false; } return true; } }
void CIPAddressTest::testIsRoutableAddress4() { // 127.0.0.0/8 CPPUNIT_ASSERT(IsRoutableAddress(_T("126.255.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("127.0.0.0"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("127.255.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(IsRoutableAddress(_T("128.0.0.0"), CSocket::ipv4)); // 10.0.0.0/8 CPPUNIT_ASSERT(IsRoutableAddress(_T("9.255.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("10.0.0.0"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("10.255.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(IsRoutableAddress(_T("11.0.0.0"), CSocket::ipv4)); // 169.254.0.0/16 CPPUNIT_ASSERT(IsRoutableAddress(_T("169.253.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("169.254.0.0"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("169.254.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(IsRoutableAddress(_T("169.255.0.0"), CSocket::ipv4)); // 192.168.0.0/16 CPPUNIT_ASSERT(IsRoutableAddress(_T("192.167.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("192.168.0.0"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("192.168.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(IsRoutableAddress(_T("102.169.0.0"), CSocket::ipv4)); // 172.16.0.0/20 CPPUNIT_ASSERT(IsRoutableAddress(_T("172.15.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("172.16.0.0"), CSocket::ipv4)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("172.31.255.255"), CSocket::ipv4)); CPPUNIT_ASSERT(IsRoutableAddress(_T("172.32.0.0"), CSocket::ipv4)); }
void CIPAddressTest::testIsRoutableAddress6() { CPPUNIT_ASSERT(!IsRoutableAddress(_T("::1"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::0"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("::2"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("1234:ABCD::1234:ef01"), CSocket::ipv6)); // fe80::/10 (link local) CPPUNIT_ASSERT(IsRoutableAddress(_T("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("fe80:0000:0000:0000:0000:0000:0000:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("fec0:0000:0000:0000:0000:0000:0000:0000"), CSocket::ipv6)); // fc00::/7 (site local) CPPUNIT_ASSERT(IsRoutableAddress(_T("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("fc00:0000:0000:0000:0000:0000:0000:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("fe00:0000:0000:0000:0000:0000:0000:0000"), CSocket::ipv6)); // IPv4 mapped // 127.0.0.0/8 CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:7eff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:7f00:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:7fff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:8000:0000"), CSocket::ipv6)); // 10.0.0.0/8 CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:9ff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:0a00:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:0aff:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:0b00:0000"), CSocket::ipv6)); // 169.254.0.0/16 CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:a9fd:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:a9fe:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:a9fe:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:a9ff:0000"), CSocket::ipv6)); // 192.168.0.0/16 CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:c0a7:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:c0a8:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:c0a8:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:c0a9:0000"), CSocket::ipv6)); // 172.16.0.0/20 CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:ac0f:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:ac10:0000"), CSocket::ipv6)); CPPUNIT_ASSERT(!IsRoutableAddress(_T("::ffff:ac1f:ffff"), CSocket::ipv6)); CPPUNIT_ASSERT(IsRoutableAddress(_T("::ffff:ac20:0000"), CSocket::ipv6)); }
bool IsRoutableAddress(const CStdString& address) { if (address.Find(_T(":")) != -1) { CStdString long_address = GetIPV6LongForm(address); if (long_address.IsEmpty()) return false; if (long_address[0] == '0') { // ::/128 if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0000")) return false; // ::1/128 if (long_address == _T("0000:0000:0000:0000:0000:0000:0000:0001")) return false; if (long_address.Left(30) == _T("0000:0000:0000:0000:0000:ffff:")) { // IPv4 mapped CStdString ipv4; ipv4.Format(_T("%d.%d.%d.%d"), DigitHexToDecNum(long_address[30]) * 16 + DigitHexToDecNum(long_address[31]), DigitHexToDecNum(long_address[32]) * 16 + DigitHexToDecNum(long_address[33]), DigitHexToDecNum(long_address[35]) * 16 + DigitHexToDecNum(long_address[36]), DigitHexToDecNum(long_address[37]) * 16 + DigitHexToDecNum(long_address[38])); return IsRoutableAddress(ipv4); } return true; } if (long_address[0] == 'f') { if (long_address[1] == 'e') { // fe80::/10 (link local) const TCHAR& c = long_address[2]; int v; if (c >= 'a') v = c - 'a' + 10; else v = c - '0'; if ((v & 0xc) == 0x8) return false; return true; } else if (long_address[1] == 'c' || long_address[1] == 'd') { // fc00::/7 (site local) return false; } } return true; } else { // Assumes address is already a valid IP address if (address.Left(3) == _T("127") || address.Left(3) == _T("10.") || address.Left(7) == _T("192.168") || address.Left(7) == _T("169.254")) return false; if (address.Left(3) == _T("172")) { CStdString middle = address.Mid(4); int pos = address.Find(_T(".")); if (pos == -1) return false; int part = _ttoi(middle.Left(pos)); if (part >= 16 && part <= 31) return false; } return true; } }