Fix host connections on link-local IPv6 addresses

Link-local IPv6 addresses are valid on all interfaces and thus need an
interface specifier / scope id, e.g. fe80::1%eth0.

This commit adds scope ids for initial host connections only. While not
optimal, this is probably enough in practise as the link-local addresses
are likely only important when there is no internet connectivity. In
this case, connecting clients directly is less of an advantage.
ipv6
Lukas Werling 2017-01-06 13:51:51 +01:00
parent 5d803d3be3
commit 0137c5f929
5 changed files with 38 additions and 2 deletions

View File

@ -244,6 +244,16 @@ bool C4NetIO::HostAddress::IsLoopback() const
return false;
}
bool C4NetIO::HostAddress::IsLocal() const
{
if (gen.sa_family == AF_INET6)
return IN6_IS_ADDR_LINKLOCAL(&v6.sin6_addr) != 0;
// We don't really care about local 169.256.0.0/16 addresses here as users will either have a
// router doing DHCP (which will prevent usage of these addresses) or have a network that
// doesn't care about IP and IPv6 link-local addresses will work.
return false;
}
void C4NetIO::HostAddress::SetScopeId(int scopeId)
{
if (gen.sa_family != AF_INET6) return;

View File

@ -111,6 +111,7 @@ public:
bool IsNull() const;
bool IsMulticast() const;
bool IsLoopback() const;
bool IsLocal() const;
// bool IsBroadcast() const;
StdStrBuf ToString(int flags = 0) const;

View File

@ -310,9 +310,25 @@ C4Network2::InitResult C4Network2::InitClient(const class C4Network2Address *pAd
for (int i = 0; i < iAddrCount; i++)
if (!pAddrs[i].isIPNull())
{
auto addr = pAddrs[i].getAddr();
std::vector<C4NetIO::addr_t> addrs;
if (addr.IsLocal())
{
// Local IPv6 addresses need a scope id.
for (auto& id : Clients.GetLocal()->getInterfaceIDs())
{
addr.SetScopeId(id);
addrs.push_back(addr);
}
}
else
addrs.push_back(addr);
// connection
if (!NetIO.Connect(pAddrs[i].getAddr(), pAddrs[i].getProtocol(), HostCore, szPassword))
continue;
int cnt = 0;
for (auto& a : addrs)
if (NetIO.Connect(a, pAddrs[i].getProtocol(), HostCore, szPassword))
cnt++;
if (cnt == 0) continue;
// format for message
if (strAddresses.getLength())
strAddresses.Append(", ");

View File

@ -231,6 +231,8 @@ void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP)
addr.SetPort(iPortUDP);
AddAddr(C4Network2Address(addr, P_UDP), false);
}
if (addr.GetScopeId())
InterfaceIDs.insert(addr.GetScopeId());
}
}
}
@ -257,6 +259,8 @@ void C4Network2Client::AddLocalAddrs(int16_t iPortTCP, int16_t iPortUDP)
addr.SetPort(iPortUDP);
AddAddr(C4Network2Address(addr, P_UDP), false);
}
if (addr.GetScopeId())
InterfaceIDs.insert(addr.GetScopeId());
}
}
freeifaddrs(addrs);

View File

@ -57,6 +57,9 @@ protected:
int32_t AddrAttempts[C4ClientMaxAddr];
int32_t iAddrCnt;
// interface ids
std::set<int> InterfaceIDs;
// status
C4Network2ClientStatus eStatus;
@ -88,6 +91,8 @@ public:
int32_t getAddrCnt() const { return iAddrCnt; }
const C4Network2Address &getAddr(int32_t i) const { return Addr[i]; }
const std::set<int> &getInterfaceIDs() const { return InterfaceIDs; }
C4Network2ClientStatus getStatus() const { return eStatus; }
bool hasJoinData() const { return getStatus() != NCS_Joining; }
bool isChasing() const { return getStatus() == NCS_Chasing; }