Rank private/UL addresses lower than global ones

Also adds some tests. Yay tests!
alut-include-path
Lukas Werling 2017-02-28 22:15:29 +01:00
parent d7e71d8362
commit 3ebedd0c5f
4 changed files with 113 additions and 4 deletions

View File

@ -273,6 +273,25 @@ bool C4NetIO::HostAddress::IsLocal() const
return false;
}
bool C4NetIO::HostAddress::IsPrivate() const
{
// IPv6 unique local address
if (gen.sa_family == AF_INET6)
return (v6.sin6_addr.s6_addr[0] & 0xfe) == 0xfc;
if (gen.sa_family == AF_INET)
{
uint32_t addr = ntohl(v4.sin_addr.s_addr);
uint32_t s = (addr >> 16) & 0xff;
switch (addr >> 24)
{
case 10: return true;
case 172: return s >= 16 && s <= 31;
case 192: return s == 168;
}
}
return false;
}
void C4NetIO::HostAddress::SetScopeId(int scopeId)
{
if (gen.sa_family != AF_INET6) return;

View File

@ -113,7 +113,8 @@ public:
bool IsNull() const;
bool IsMulticast() const;
bool IsLoopback() const;
bool IsLocal() const;
bool IsLocal() const; // IPv6 link-local address
bool IsPrivate() const; // IPv6 ULA or IPv4 private address range
// bool IsBroadcast() const;
StdStrBuf ToString(int flags = 0) const;

View File

@ -217,7 +217,7 @@ static void SortAddresses(std::vector<C4Network2Address>& addrs)
bool haveIPv6 = false;
for (auto& addr : localAddrs)
{
if (addr.GetFamily() == C4NetIO::HostAddress::IPv6 && !addr.IsLocal())
if (addr.GetFamily() == C4NetIO::HostAddress::IPv6 && !addr.IsLocal() && !addr.IsPrivate())
{
haveIPv6 = true;
break;
@ -235,13 +235,17 @@ static void SortAddresses(std::vector<C4Network2Address>& addrs)
case C4NetIO::HostAddress::IPv6:
if (addr.IsLocal())
rank = 100;
else if (addr.IsPrivate())
rank = 150;
else if (haveIPv6)
// TODO: Rank public IPv6 addresses by longest matching prefix with local addresses.
rank = 300;
break;
case C4NetIO::HostAddress::IPv4:
// TODO: Maybe rank IPv4 addresses from private address ranges differently.
rank = 200;
if (addr.IsPrivate())
rank = 150;
else
rank = 200;
break;
default:
assert(!"Unexpected address family");

View File

@ -0,0 +1,85 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2017, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
#include <C4Include.h>
#include "network/C4NetIO.h"
#include <gtest/gtest.h>
class C4NetIOTest : public ::testing::Test
{
protected:
C4NetIOTest()
{
#ifdef HAVE_WINSOCK
AcquireWinSock();
#endif
}
~C4NetIOTest()
{
#ifdef HAVE_WINSOCK
ReleaseWinSock();
#endif
}
};
TEST_F(C4NetIOTest, HostAddressCategories)
{
static struct TestAddr
{
const char *addr;
bool null, multicast, loopback, linklocal, priv;
} addrs[] =
{
// null mc loopb ll priv
{"0.0.0.0", true, false, false, false, false},
{"192.168.0.1", false, false, false, false, true},
{"10.168.0.1", false, false, false, false, true},
{"172.16.10.1", false, false, false, false, true},
{"127.0.0.1", false, false, true, false, false},
{"239.1.1.1", false, true, false, false, false},
// null mc loopb ll priv
{"::", true, false, false, false, false},
{"::1", false, false, true, false, false},
{"ff02::1", false, true, false, false, false},
{"ff15::1234", false, true, false, false, false},
{"fe80::1234:abcd:def:1234", false, false, false, true, false},
{"fe80::1234:abcd:def:1234", false, false, false, true, false},
{"fd12::1234:abcd:def:1234", false, false, false, false, true},
{"fc12::1234:abcd:def:1234", false, false, false, false, true},
{nullptr, false, false, false, false, false},
};
for (auto t = addrs; t->addr; t++)
{
// TODO: While this produces better error messages than EXPECT_EQ, failures are still super confusing.
auto check = [&](bool a, bool b)
{
if (a == b)
return ::testing::AssertionSuccess();
else
return ::testing::AssertionFailure() << "addr = " << t->addr << " expected: " << b;
};
C4NetIO::HostAddress addr(StdStrBuf(t->addr));
EXPECT_TRUE(check(addr.IsNull(), t->null));
EXPECT_TRUE(check(addr.IsMulticast(), t->multicast));
EXPECT_TRUE(check(addr.IsLoopback(), t->loopback));
EXPECT_TRUE(check(addr.IsLocal(), t->linklocal));
EXPECT_TRUE(check(addr.IsPrivate(), t->priv));
}
}