Browse Source

Bug fixes and incoming/outgoing packet checking.

cl-refactor
Gav Wood 11 years ago
parent
commit
9f8f2138da
  1. 2
      CMakeLists.txt
  2. 26
      libethereum/Common.h
  3. 72
      libethereum/PeerNetwork.cpp
  4. 3
      libethereum/PeerNetwork.h
  5. 8
      libethereum/RLP.h

2
CMakeLists.txt

@ -5,7 +5,7 @@ set(CMAKE_AUTOMOC ON)
cmake_policy(SET CMP0015 NEW)
set(ETH_VERSION 0.2.4)
set(ETH_VERSION 0.2.5)
set(ETH_BUILD_TYPE ${CMAKE_BUILD_TYPE})
set(TARGET_PLATFORM CACHE STRING "linux")

26
libethereum/Common.h

@ -67,6 +67,18 @@ using u160Set = std::set<u160>;
template <class T, class Out> inline void toBigEndian(T _val, Out& o_out);
template <class T, class In> inline T fromBigEndian(In const& _bytes);
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte.
/// @example asHex("A\x69") == "4169"
template <class _T>
std::string asHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
template <unsigned N>
class FixedHash
{
@ -97,6 +109,8 @@ public:
FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; }
FixedHash& operator~() { for (auto i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; }
std::string abridged() const { return asHex(ref().cropped(0, 4)); }
byte& operator[](unsigned _i) { return m_data[_i]; }
byte operator[](unsigned _i) const { return m_data[_i]; }
@ -252,18 +266,6 @@ inline bytes asBytes(std::string const& _b)
return bytes((byte const*)_b.data(), (byte const*)(_b.data() + _b.size()));
}
/// Convert a series of bytes to the corresponding string of hex duplets.
/// @param _w specifies the width of each of the elements. Defaults to two - enough to represent a byte.
/// @example asHex("A\x69") == "4169"
template <class _T>
std::string asHex(_T const& _data, int _w = 2)
{
std::ostringstream ret;
for (auto i: _data)
ret << std::hex << std::setfill('0') << std::setw(_w) << (int)(typename std::make_unsigned<decltype(i)>::type)i;
return ret.str();
}
/// Trims a given number of elements from the front of a collection.
/// Only works for POD element types.
template <class _T>

72
libethereum/PeerNetwork.cpp

@ -45,8 +45,8 @@ using namespace eth;
static const int c_protocolVersion = 4;
static const eth::uint c_maxHashes = 64; ///< Maximum number of hashes GetChain will ever send.
static const eth::uint c_maxBlocks = 32; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.
static const eth::uint c_maxHashes = 512; ///< Maximum number of hashes GetChain will ever send.
static const eth::uint c_maxBlocks = 256; ///< Maximum number of blocks Blocks will ever send. BUG: if this gets too big (e.g. 2048) stuff starts going wrong.
static const eth::uint c_maxBlocksAsk = 256; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain).
// Addresses we will skip during network interface discovery
@ -140,14 +140,14 @@ bool PeerSession::interpret(RLP const& _r)
m_listenPort = _r[5].toInt<short>();
m_id = _r[6].toHash<h512>();
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << asHex(m_id.ref().cropped(0, 4)) << showbase << hex << m_caps << dec << m_listenPort;
clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "/" << m_networkId << "]" << m_id.abridged() << showbase << hex << m_caps << dec << m_listenPort;
if (m_server->m_peers.count(m_id))
if (auto l = m_server->m_peers[m_id].lock())
if (l.get() != this && l->isOpen())
{
// Already connected.
cwarn << "Already have peer id" << m_id << "at" << l->endpoint() << "rather than" << endpoint();
cwarn << "Already have peer id" << m_id.abridged() << "at" << l->endpoint() << "rather than" << endpoint();
disconnect(DuplicatePeer);
return false;
}
@ -356,8 +356,13 @@ bool PeerSession::interpret(RLP const& _r)
uint n = latestNumber;
for (; n > startNumber; n--, h = m_server->m_chain->details(h).parent) {}
for (uint i = 0; h != parent && n > endNumber && i < count; ++i, --n, h = m_server->m_chain->details(h).parent)
for (uint i = 0; i < count; ++i, --n, h = m_server->m_chain->details(h).parent)
{
if (h == parent || n == endNumber)
{
cwarn << "BUG! Couldn't create the reply for GetChain!";
return true;
}
clogS(NetAllDetail) << " " << dec << i << " " << h;
s.appendRaw(m_server->m_chain->block(h));
}
@ -459,12 +464,31 @@ void PeerSession::sealAndSend(RLPStream& _s)
sendDestroy(b);
}
bool PeerSession::checkPacket(bytesConstRef _msg)
{
if (_msg.size() < 8)
return false;
if (!(_msg[0] == 0x22 && _msg[1] == 0x40 && _msg[2] == 0x08 && _msg[3] == 0x91))
return false;
uint32_t len = ((_msg[4] * 256 + _msg[5]) * 256 + _msg[6]) * 256 + _msg[7];
if (_msg.size() != len + 8)
return false;
RLP r(_msg.cropped(8));
if (r.actualSize() != len)
return false;
return true;
}
void PeerSession::sendDestroy(bytes& _msg)
{
clogS(NetLeft) << RLP(bytesConstRef(&_msg).cropped(8));
std::shared_ptr<bytes> buffer = std::make_shared<bytes>();
swap(*buffer, _msg);
assert((*buffer)[0] == 0x22);
if (!checkPacket(bytesConstRef(&*buffer)))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length)
{
if (ec)
@ -480,7 +504,10 @@ void PeerSession::send(bytesConstRef _msg)
{
clogS(NetLeft) << RLP(_msg.cropped(8));
std::shared_ptr<bytes> buffer = std::make_shared<bytes>(_msg.toBytes());
assert((*buffer)[0] == 0x22);
if (!checkPacket(_msg))
{
cwarn << "INVALID PACKET CONSTRUCTED!";
}
ba::async_write(m_socket, ba::buffer(*buffer), [=](boost::system::error_code ec, std::size_t length)
{
if (ec)
@ -516,7 +543,7 @@ void PeerSession::disconnect(int _reason)
{
RLPStream s;
prep(s);
s.appendList(1) << DisconnectPacket << _reason;
s.appendList(2) << DisconnectPacket << _reason;
sealAndSend(s);
m_disconnect = chrono::steady_clock::now();
}
@ -529,7 +556,7 @@ void PeerSession::start()
{
RLPStream s;
prep(s);
s.appendList(m_server->m_public.port() ? 6 : 5) << HelloPacket << (uint)c_protocolVersion << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub();
s.appendList(7) << HelloPacket << (uint)c_protocolVersion << (uint)m_server->m_requiredNetworkId << m_server->m_clientVersion << (m_server->m_mode == NodeMode::Full ? 0x07 : m_server->m_mode == NodeMode::PeerServer ? 0x01 : 0) << m_server->m_public.port() << m_server->m_key.pub();
sealAndSend(s);
ping();
@ -564,20 +591,31 @@ void PeerSession::doRead()
else
{
uint32_t len = fromBigEndian<uint32_t>(bytesConstRef(m_incoming.data() + 4, 4));
if (m_incoming.size() - 8 < len)
uint32_t tlen = len + 8;
if (m_incoming.size() < tlen)
break;
// enough has come in.
// cerr << "Received " << len << ": " << asHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
RLP r(bytesConstRef(m_incoming.data() + 8, len));
if (!interpret(r))
auto data = bytesConstRef(m_incoming.data(), tlen);
if (!checkPacket(data))
{
cerr << "Received " << len << ": " << asHex(bytesConstRef(m_incoming.data() + 8, len)) << endl;
cwarn << "INVALID MESSAGE RECEIVED";
disconnect(BadProtocol);
}
else
{
// error
dropped();
return;
RLP r(data.cropped(8));
if (!interpret(r))
{
// error
dropped();
return;
}
}
memmove(m_incoming.data(), m_incoming.data() + len + 8, m_incoming.size() - (len + 8));
m_incoming.resize(m_incoming.size() - (len + 8));
memmove(m_incoming.data(), m_incoming.data() + tlen, m_incoming.size() - tlen);
m_incoming.resize(m_incoming.size() - tlen);
}
}
doRead();

3
libethereum/PeerNetwork.h

@ -109,6 +109,9 @@ private:
void doWrite(std::size_t length);
bool interpret(RLP const& _r);
/// @returns true iff the _msg forms a valid message for sending or receiving on the network.
static bool checkPacket(bytesConstRef _msg);
static RLPStream& prep(RLPStream& _s);
void sealAndSend(RLPStream& _s);
void sendDestroy(bytes& _msg);

8
libethereum/RLP.h

@ -229,14 +229,14 @@ public:
/// @returns the data payload. Valid for all types.
bytesConstRef payload() const { return isSingleByte() ? m_data.cropped(0, 1) : m_data.cropped(1 + lengthSize()); }
/// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
uint actualSize() const;
private:
/// Single-byte data payload.
bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; }
/// @returns the theoretical size of this item; if it's a list, will require a deep traversal which could take a while.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
uint actualSize() const;
/// @returns the bytes used to encode the length of the data. Valid for all types.
uint lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; }

Loading…
Cancel
Save