From 015c1681fb91591bf977ae2a0507616018194448 Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 26 Mar 2015 16:21:25 +0100 Subject: [PATCH] adopt node IP address from udp header when ping.ipAddress isn't public --- libp2p/Host.cpp | 8 ++++---- libp2p/NodeTable.cpp | 42 ++++++++++++++++++++++++++++-------------- test/net.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index b946d9b3e..41c2fbb77 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -592,12 +592,12 @@ void Host::startedWorking() m_run = true; } - // try to open acceptor (todo: ipv6) - m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort); - - // start capability threads + // start capability threads (ready for incoming connections) for (auto const& h: m_capabilities) h.second->onStarting(); + + // try to open acceptor (todo: ipv6) + m_listenPort = Network::tcp4Listen(m_tcp4Acceptor, m_netPrefs.listenPort); // determine public IP, but only if we're able to listen for connections // todo: GUI when listen is unavailable in UI diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 7fe531762..7bdaf3088 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -84,11 +84,14 @@ shared_ptr NodeTable::addNode(Node const& _node) return move(shared_ptr()); } - // ping address if nodeid is empty + // ping address to recover nodeid if nodeid is empty if (!_node.id) { clog(NodeTableConnect) << "Sending public key discovery Ping to" << _node.endpoint.udp << "(Advertising:" << m_node.endpoint.udp << ")"; - m_pubkDiscoverPings[_node.endpoint.udp.address()] = std::chrono::steady_clock::now(); + { + Guard l(x_pubkDiscoverPings); + m_pubkDiscoverPings[_node.endpoint.udp.address()] = std::chrono::steady_clock::now(); + } PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); p.sign(m_secret); m_socketPointer->send(p); @@ -101,7 +104,11 @@ shared_ptr NodeTable::addNode(Node const& _node) return m_nodes[_node.id]; } - shared_ptr ret(new NodeEntry(m_node, _node.id, NodeIPEndpoint(_node.endpoint.udp, _node.endpoint.tcp))); + // TODO: SECURITY - Temporary until packets are updated. + NodeIPEndpoint ep(_node.endpoint.udp, _node.endpoint.tcp); + if (!isPublicAddress(ep.tcp.address())) + ep.tcp.address(_node.endpoint.udp.address()); + shared_ptr ret(new NodeEntry(m_node, _node.id, ep)); m_nodes[_node.id] = ret; PingNode p(_node.endpoint.udp, m_node.endpoint.udp.address().to_string(), m_node.endpoint.udp.port()); p.sign(m_secret); @@ -315,9 +322,13 @@ void NodeTable::noteActiveNode(Public const& _pubk, bi::udp::endpoint const& _en { clog(NodeTableConnect) << "Noting active node:" << _pubk.abridged() << _endpoint.address().to_string() << ":" << _endpoint.port(); - // update udp endpoint + // TODO: SECURITY - Temporary until packets are updated. + // update udp endpoint and override tcp endpoint if tcp endpoint isn't public + // (for the rare case where NAT port is mapped but node->endpoint.udp.address(_endpoint.address()); node->endpoint.udp.port(_endpoint.port()); + if (!isPublicAddress(node->endpoint.tcp.address())) + node->endpoint.tcp.address(_endpoint.address()); shared_ptr contested; { @@ -399,7 +410,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes bytesConstRef signedBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); - // todo: verify sig via known-nodeid and MDC, or, do ping/pong auth if node/endpoint is unknown/untrusted + // todo: verify sig via known-nodeid and MDC bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(signedBytes))); @@ -430,8 +441,7 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes dropNode(n); if (auto n = nodeEntry(it->first.first)) - if (m_nodeEventHandler && n->pending) - n->pending = false; + n->pending = false; it = m_evictions.erase(it); } @@ -441,14 +451,18 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes { if (auto n = nodeEntry(nodeid)) n->pending = false; + else if (m_pubkDiscoverPings.count(_from.address())) + { + { + Guard l(x_pubkDiscoverPings); + m_pubkDiscoverPings.erase(_from.address()); + } + if (!haveNode(nodeid)) + addNode(nodeid, _from, bi::tcp::endpoint(_from.address(), _from.port())); + } + else + return; // unsolicited pong; don't note node as active } - else if (m_pubkDiscoverPings.count(_from.address())) - { - m_pubkDiscoverPings.erase(_from.address()); - addNode(nodeid, _from, bi::tcp::endpoint(_from.address(), _from.port())); - } - else - return; // unsolicited pong; don't note node as active break; } diff --git a/test/net.cpp b/test/net.cpp index a5f973450..ec1efb360 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -145,6 +145,40 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(isIPAddressType) +{ + string wildcard = "0.0.0.0"; + BOOST_REQUIRE(bi::address::from_string(wildcard).is_unspecified()); + + string empty = ""; + BOOST_REQUIRE_THROW(bi::address::from_string(empty).is_unspecified(), std::exception); + + string publicAddress192 = "192.169.0.0"; + BOOST_REQUIRE(isPublicAddress(publicAddress192)); + BOOST_REQUIRE(!isPrivateAddress(publicAddress192)); + BOOST_REQUIRE(!isLocalHostAddress(publicAddress192)); + + string publicAddress172 = "172.32.0.0"; + BOOST_REQUIRE(isPublicAddress(publicAddress172)); + BOOST_REQUIRE(!isPrivateAddress(publicAddress172)); + BOOST_REQUIRE(!isLocalHostAddress(publicAddress172)); + + string privateAddress192 = "192.168.1.0"; + BOOST_REQUIRE(isPrivateAddress(privateAddress192)); + BOOST_REQUIRE(!isPublicAddress(privateAddress192)); + BOOST_REQUIRE(!isLocalHostAddress(privateAddress192)); + + string privateAddress172 = "172.16.0.0"; + BOOST_REQUIRE(isPrivateAddress(privateAddress172)); + BOOST_REQUIRE(!isPublicAddress(privateAddress172)); + BOOST_REQUIRE(!isLocalHostAddress(privateAddress172)); + + string privateAddress10 = "10.0.0.0"; + BOOST_REQUIRE(isPrivateAddress(privateAddress10)); + BOOST_REQUIRE(!isPublicAddress(privateAddress10)); + BOOST_REQUIRE(!isLocalHostAddress(privateAddress10)); +} + BOOST_AUTO_TEST_CASE(v2PingNodePacket) { // test old versino of pingNode packet w/new