From a73f1fa7c55923cf13550efe8809e0ac26efaa8f Mon Sep 17 00:00:00 2001 From: subtly Date: Fri, 23 Jan 2015 04:23:55 -0500 Subject: [PATCH] add packet-type. prep for node-discovery interop. --- alethzero/MainWin.cpp | 13 +++++-------- libp2p/Host.h | 11 +++++------ libp2p/NodeTable.cpp | 25 +++++++++++++++---------- libp2p/NodeTable.h | 22 +++++++++++----------- libp2p/UDP.cpp | 14 +++++++++++--- libp2p/UDP.h | 3 ++- 6 files changed, 49 insertions(+), 39 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 7a28948f4..d96c55917 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -938,13 +938,13 @@ void Main::refreshNetwork() if (web3()->haveNetwork()) { - map clients; + map sessions; for (PeerSessionInfo const& i: ps) ui->peers->addItem(QString("[%8 %7] %3 ms - %1:%2 - %4 %5 %6") .arg(QString::fromStdString(i.host)) .arg(i.port) .arg(chrono::duration_cast(i.lastPing).count()) - .arg(clients[i.id] = QString::fromStdString(i.clientVersion)) + .arg(sessions[i.id] = QString::fromStdString(i.clientVersion)) .arg(QString::fromStdString(toString(i.caps))) .arg(QString::fromStdString(toString(i.notes))) .arg(i.socket) @@ -952,15 +952,12 @@ void Main::refreshNetwork() auto ns = web3()->nodes(); for (p2p::Peer const& i: ns) - ui->nodes->insertItem(clients.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") + ui->nodes->insertItem(sessions.count(i.id) ? 0 : ui->nodes->count(), QString("[%1 %3] %2 - ( =%5s | /%4s%6 ) - *%7 $%8") .arg(QString::fromStdString(i.id.abridged())) - .arg(QString::fromStdString(toString(i.address))) - .arg(i.id == web3()->id() ? "self" : clients.count(i.id) ? clients[i.id] : i.secondsSinceLastAttempted() == -1 ? "session-fail" : i.secondsSinceLastAttempted() >= (int)i.fallbackSeconds() ? "retrying..." : "retry-" + QString::number(i.fallbackSeconds() - i.secondsSinceLastAttempted()) + "s") - .arg(i.secondsSinceLastAttempted()) - .arg(i.secondsSinceLastConnected()) + .arg(QString::fromStdString(i.peerEndpoint().address().to_string())) + .arg(i.id == web3()->id() ? "self" : sessions.count(i.id) ? sessions[i.id] : "disconnected") .arg(i.isOffline() ? " | " + QString::fromStdString(reasonOf(i.lastDisconnect)) + " | " + QString::number(i.failedAttempts) + "x" : "") .arg(i.rating) - .arg(0 /* (int)i.idOrigin */) ); } } diff --git a/libp2p/Host.h b/libp2p/Host.h index 1719bac6a..bffc6c39f 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -69,6 +69,7 @@ class Host; * Host of the responsibility. (&& remove save/restoreNodes) * @todo reimplement recording of historical session information on per-transport basis * @todo rebuild nodetable when localNetworking is enabled/disabled + * @todo move attributes into protected */ class Peer: public Node { @@ -79,11 +80,6 @@ public: bi::tcp::endpoint const& peerEndpoint() const { return endpoint.tcp; } -protected: - - /// Used by isOffline() and (todo) for peer to emit session information. - std::weak_ptr m_session; - int score = 0; ///< All time cumulative. int rating = 0; ///< Trending. @@ -93,6 +89,10 @@ protected: std::chrono::system_clock::time_point lastAttempted; unsigned failedAttempts = 0; DisconnectReason lastDisconnect = NoDisconnect; ///< Reason for disconnect that happened last. + +protected: + /// Used by isOffline() and (todo) for peer to emit session information. + std::weak_ptr m_session; }; using Peers = std::vector; @@ -260,7 +260,6 @@ private: std::set m_peerAddresses; ///< Public addresses that peers (can) know us by. - // Our capabilities. std::map> m_capabilities; ///< Each of the capabilities we support. std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 242c1b325..40688f4a5 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -352,24 +352,24 @@ NodeTable::NodeBucket& NodeTable::bucket(NodeEntry const* _n) void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytesConstRef _packet) { - // h256 + Signature + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) - if (_packet.size() < h256::size + Signature::size + 3) + // h256 + Signature + type + RLP (smallest possible packet is empty neighbours packet which is 3 bytes) + if (_packet.size() < h256::size + Signature::size + 1 + 3) { clog(NodeTableMessageSummary) << "Invalid Message size from " << _from.address().to_string() << ":" << _from.port(); return; } - bytesConstRef signedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); - h256 hashSigned(sha3(signedBytes)); + bytesConstRef hashedBytes(_packet.cropped(h256::size, _packet.size() - h256::size)); + h256 hashSigned(sha3(hashedBytes)); if (!_packet.cropped(0, h256::size).contentsEqual(hashSigned.asBytes())) { clog(NodeTableMessageSummary) << "Invalid Message hash from " << _from.address().to_string() << ":" << _from.port(); return; } + + bytesConstRef rlpBytes(hashedBytes.cropped(Signature::size, hashedBytes.size() - Signature::size)); - bytesConstRef rlpBytes(signedBytes.cropped(Signature::size, signedBytes.size() - Signature::size)); - RLP rlp(rlpBytes); - unsigned itemCount = rlp.itemCount(); + // todo: verify sig via known-nodeid and MDC, or, do ping/pong auth if node/endpoint is unknown/untrusted bytesConstRef sigBytes(_packet.cropped(h256::size, Signature::size)); Public nodeid(dev::recover(*(Signature const*)sigBytes.data(), sha3(rlpBytes))); @@ -378,8 +378,13 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes clog(NodeTableMessageSummary) << "Invalid Message signature from " << _from.address().to_string() << ":" << _from.port(); return; } - noteNode(nodeid, _from); + if (rlpBytes[0] && rlpBytes[0] < 4) + noteNode(nodeid, _from); + + // todo: switch packet-type + RLP rlp(rlpBytes.cropped(1, rlpBytes.size() - 1)); + unsigned itemCount = rlp.itemCount(); try { switch (itemCount) { @@ -435,14 +440,14 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes PingNode in = PingNode::fromBytesConstRef(_from, rlpBytes); Pong p(_from); - p.replyTo = sha3(rlpBytes); + p.echo = sha3(rlpBytes); p.sign(m_secret); m_socketPtr->send(p); break; } default: - clog(NodeTableMessageSummary) << "Invalid Message received from " << _from.address().to_string() << ":" << _from.port(); + clog(NodeTableMessageSummary) << "Invalid Message, " << std::hex << rlpBytes[0] << ", received from " << _from.address().to_string() << ":" << _from.port(); return; } } diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index dee10c7ae..acf735f74 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -122,7 +122,7 @@ public: NodeTable(ba::io_service& _io, KeyPair _alias, uint16_t _udpPort = 30303); ~NodeTable(); - /// Constants for Kademlia, mostly derived from address space. + /// Constants for Kademlia, derived from address space. static unsigned const s_addressByteSize = sizeof(NodeId); ///< Size of address type in bytes. static unsigned const s_bits = 8 * s_addressByteSize; ///< Denoted by n in [Kademlia]. @@ -269,6 +269,9 @@ struct PingNode: RLPXDatagram PingNode(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} PingNode(bi::udp::endpoint _ep, std::string _src, uint16_t _srcPort, std::chrono::seconds _expiration = std::chrono::seconds(60)): RLPXDatagram(_ep), ipAddress(_src), port(_srcPort), expiration(futureFromEpoch(_expiration)) {} + uint8_t packetType() { return 1; } + + unsigned version = 1; std::string ipAddress; unsigned port; unsigned expiration; @@ -283,20 +286,17 @@ struct PingNode: RLPXDatagram * RLP Encoded Items: 1 * Minimum Encoded Size: 33 bytes * Maximum Encoded Size: 33 bytes - * - * @todo expiration - * @todo value of replyTo - * @todo create from PingNode (reqs RLPXDatagram verify flag) */ struct Pong: RLPXDatagram { Pong(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} - h256 replyTo; // hash of rlp of PingNode + uint8_t packetType() { return 2; } + h256 echo; ///< MCD of PingNode unsigned expiration; - void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << replyTo; } - void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); replyTo = (h256)r[0]; } + void streamRLP(RLPStream& _s) const { _s.appendList(1); _s << echo; } + void interpretRLP(bytesConstRef _bytes) { RLP r(_bytes); echo = (h256)r[0]; } }; /** @@ -317,6 +317,7 @@ struct FindNode: RLPXDatagram FindNode(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} FindNode(bi::udp::endpoint _ep, NodeId _target, std::chrono::seconds _expiration = std::chrono::seconds(30)): RLPXDatagram(_ep), target(_target), expiration(futureFromEpoch(_expiration)) {} + uint8_t packetType() { return 3; } h512 target; unsigned expiration; @@ -329,8 +330,6 @@ struct FindNode: RLPXDatagram * * RLP Encoded Items: 2 (first item is list) * Minimum Encoded Size: 10 bytes - * - * @todo nonce: Should be replaced with expiration. */ struct Neighbours: RLPXDatagram { @@ -346,7 +345,7 @@ struct Neighbours: RLPXDatagram }; Neighbours(bi::udp::endpoint _ep): RLPXDatagram(_ep) {} - Neighbours(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to) + Neighbours(bi::udp::endpoint _to, std::vector> const& _nearest, unsigned _offset = 0, unsigned _limit = 0): RLPXDatagram(_to), expiration(futureFromEpoch(std::chrono::seconds(30))) { auto limit = _limit ? std::min(_nearest.size(), (size_t)(_offset + _limit)) : _nearest.size(); for (auto i = _offset; i < limit; i++) @@ -359,6 +358,7 @@ struct Neighbours: RLPXDatagram } } + uint8_t packetType() { return 4; } std::list nodes; unsigned expiration = 1; diff --git a/libp2p/UDP.cpp b/libp2p/UDP.cpp index b1f87e409..23a3531ac 100644 --- a/libp2p/UDP.cpp +++ b/libp2p/UDP.cpp @@ -25,9 +25,13 @@ using namespace dev::p2p; h256 RLPXDatagramFace::sign(Secret const& _k) { - RLPStream rlpstream; - streamRLP(rlpstream); - bytes rlpBytes(rlpstream.out()); + assert(packetType()); + + RLPStream rlpxstream; +// rlpxstream.appendRaw(toPublic(_k).asBytes()); // for mdc-based signature + rlpxstream.appendRaw(bytes(1, packetType())); + streamRLP(rlpxstream); + bytes rlpBytes(rlpxstream.out()); bytesConstRef rlp(&rlpBytes); h256 hash(dev::sha3(rlp)); @@ -35,12 +39,16 @@ h256 RLPXDatagramFace::sign(Secret const& _k) data.resize(h256::size + Signature::size + rlp.size()); bytesConstRef packetHash(&data[0], h256::size); + bytesConstRef signedPayload(&data[h256::size], Signature::size + rlp.size()); bytesConstRef payloadSig(&data[h256::size], Signature::size); bytesConstRef payload(&data[h256::size + Signature::size], rlp.size()); sig.ref().copyTo(payloadSig); +// rlp.cropped(Public::size, rlp.size() - Public::size).copyTo(payload); rlp.copyTo(payload); + +// hash.ref().copyTo(packetHash); // for mdc-based signature dev::sha3(signedPayload).ref().copyTo(packetHash); return std::move(hash); diff --git a/libp2p/UDP.h b/libp2p/UDP.h index d048e697c..9451e43f0 100644 --- a/libp2p/UDP.h +++ b/libp2p/UDP.h @@ -63,7 +63,8 @@ struct RLPXDatagramFace: public UDPDatagram static uint64_t futureFromEpoch(std::chrono::milliseconds _ms) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _ms).time_since_epoch()).count(); } static uint64_t futureFromEpoch(std::chrono::seconds _sec) { return std::chrono::duration_cast((std::chrono::system_clock::now() + _sec).time_since_epoch()).count(); } static Public authenticate(bytesConstRef _sig, bytesConstRef _rlp); - + + virtual uint8_t packetType() =0; RLPXDatagramFace(bi::udp::endpoint const& _ep): UDPDatagram(_ep) {} virtual h256 sign(Secret const& _from);