From c4d5621f679fef246bce8ffb28fcd23d679cf815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= Date: Fri, 10 Feb 2017 00:10:11 -0500 Subject: [PATCH] network: treat loopback address as sender address When learning about nodes in an answer, we used to drop nodes with loopback address. Address is now replaced by the packet sender address and the port is preserved. --- include/opendht/network_engine.h | 2 +- src/network_engine.cpp | 81 ++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 36 deletions(-) diff --git a/include/opendht/network_engine.h b/include/opendht/network_engine.h index fb64499e..3920a7ab 100644 --- a/include/opendht/network_engine.h +++ b/include/opendht/network_engine.h @@ -542,7 +542,7 @@ private: const std::string& message, bool include_id=false); - void deserializeNodes(ParsedMessage& msg); + void deserializeNodes(ParsedMessage& msg, const SockAddr& from); /* DHT info */ const InfoHash& myid; diff --git a/src/network_engine.cpp b/src/network_engine.cpp index 37049905..ed23933b 100644 --- a/src/network_engine.cpp +++ b/src/network_engine.cpp @@ -307,32 +307,25 @@ NetworkEngine::rateLimit(const SockAddr& addr) bool NetworkEngine::isMartian(const SockAddr& addr) { - // Check that sa_family can be accessed safely - if (addr.second < sizeof(sockaddr_in)) + if (addr.getPort() == 0) return true; - - switch(addr.first.ss_family) { + switch(addr.getFamily()) { case AF_INET: { - sockaddr_in *sin = (sockaddr_in*)&addr.first; - const uint8_t *address = (const uint8_t*)&sin->sin_addr; - return sin->sin_port == 0 || - (address[0] == 0) || - (address[0] == 127) || - ((address[0] & 0xE0) == 0xE0); + const auto& sin = addr.getIPv4(); + const uint8_t* address = (const uint8_t*)&sin.sin_addr; + return (address[0] == 0) || + ((address[0] & 0xE0) == 0xE0); } case AF_INET6: { if (addr.second < sizeof(sockaddr_in6)) return true; - sockaddr_in6 *sin6 = (sockaddr_in6*)&addr.first; - const uint8_t *address = (const uint8_t*)&sin6->sin6_addr; - return sin6->sin6_port == 0 || - (address[0] == 0xFF) || - (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) || - (memcmp(address, zeroes.data(), 15) == 0 && - (address[15] == 0 || address[15] == 1)) || - (memcmp(address, v4prefix, 12) == 0); + const auto& sin6 = addr.getIPv6(); + const uint8_t* address = (const uint8_t*)&sin6.sin6_addr; + return address[0] == 0xFF || + (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) || + memcmp(address, zeroes.data(), 16) == 0 || + memcmp(address, v4prefix, 12) == 0; } - default: return true; } @@ -516,11 +509,11 @@ NetworkEngine::process(std::unique_ptr&& msg, const SockAddr& fro requests.erase(req_it); req->reply_time = scheduler.time(); - deserializeNodes(*msg); + deserializeNodes(*msg, from); req->setDone(std::move(*msg)); break; } else { /* request socket data */ - deserializeNodes(*msg); + deserializeNodes(*msg, from); rsocket->on_receive(rsocket->node, std::move(*msg)); } default: @@ -784,25 +777,43 @@ NetworkEngine::sendGetValues(Sp n, const InfoHash& info_hash, const Query& return req; } +SockAddr deserializeIPv4(const uint8_t* ni) { + SockAddr addr; + auto& sin = addr.getIPv4(); + std::fill_n((uint8_t*)&sin, sizeof(sockaddr_in), 0); + addr.setFamily(AF_INET); + memcpy(&sin.sin_addr, ni, 4); + memcpy(&sin.sin_port, ni + 4, 2); + return addr; +} +SockAddr deserializeIPv6(const uint8_t* ni) { + SockAddr addr; + auto& sin6 = addr.getIPv6(); + std::fill_n((uint8_t*)&sin6, sizeof(sockaddr_in6), 0); + addr.setFamily(AF_INET6); + memcpy(&sin6.sin6_addr, ni, 16); + memcpy(&sin6.sin6_port, ni + 16, 2); + return addr; +} + void -NetworkEngine::deserializeNodes(ParsedMessage& msg) { +NetworkEngine::deserializeNodes(ParsedMessage& msg, const SockAddr& from) { if (msg.nodes4_raw.size() % NODE4_INFO_BUF_LEN != 0 || msg.nodes6_raw.size() % NODE6_INFO_BUF_LEN != 0) { throw DhtProtocolException {DhtProtocolException::WRONG_NODE_INFO_BUF_LEN}; } else { // deserialize nodes const auto& now = scheduler.time(); - SockAddr addr; for (unsigned i = 0; i < msg.nodes4_raw.size() / NODE4_INFO_BUF_LEN; i++) { uint8_t *ni = msg.nodes4_raw.data() + i * NODE4_INFO_BUF_LEN; const InfoHash& ni_id = *reinterpret_cast(ni); if (ni_id == myid) continue; - auto sin = (sockaddr_in*)&addr.first; - std::fill_n((uint8_t*)sin, sizeof(sockaddr_in), 0); - sin->sin_family = AF_INET; - memcpy(&sin->sin_addr, ni + ni_id.size(), 4); - memcpy(&sin->sin_port, ni + ni_id.size() + 4, 2); - addr.second = sizeof(sockaddr_in); + SockAddr addr = deserializeIPv4(ni + ni_id.size()); + if (addr.isLoopback() and from.getFamily() == AF_INET) { + auto port = addr.getPort(); + addr = from; + addr.setPort(port); + } if (isMartian(addr) || isNodeBlacklisted(addr)) continue; msg.nodes4.emplace_back(cache.getNode(ni_id, addr, now, false)); @@ -813,12 +824,12 @@ NetworkEngine::deserializeNodes(ParsedMessage& msg) { const InfoHash& ni_id = *reinterpret_cast(ni); if (ni_id == myid) continue; - auto sin6 = (sockaddr_in6*)&addr.first; - std::fill_n((uint8_t*)sin6, sizeof(sockaddr_in6), 0); - sin6->sin6_family = AF_INET6; - memcpy(&sin6->sin6_addr, ni + HASH_LEN, 16); - memcpy(&sin6->sin6_port, ni + HASH_LEN + 16, 2); - addr.second = sizeof(sockaddr_in6); + SockAddr addr = deserializeIPv6(ni + ni_id.size()); + if (addr.isLoopback() and from.getFamily() == AF_INET6) { + auto port = addr.getPort(); + addr = from; + addr.setPort(port); + } if (isMartian(addr) || isNodeBlacklisted(addr)) continue; msg.nodes6.emplace_back(cache.getNode(ni_id, addr, now, false));