void Peer::recvPeers(StellarMessage const& msg) { for (auto peer : msg.peers()) { stringstream ip; ip << (int)peer.ip[0] << "." << (int)peer.ip[1] << "." << (int)peer.ip[2] << "." << (int)peer.ip[3]; if (peer.port == 0 || peer.port > UINT16_MAX) { CLOG(DEBUG, "Overlay") << "ignoring peer with bad port"; continue; } PeerRecord pr{ip.str(), static_cast<unsigned short>(peer.port), mApp.getClock().now(), peer.numFailures, 1}; if (pr.isPrivateAddress()) { CLOG(DEBUG, "Overlay") << "ignoring flooded private address"; } else { pr.insertIfNew(mApp.getDatabase()); } } }
void Peer::sendHello() { LOG(DEBUG) << "Peer::sendHello " << "@" << mApp.getConfig().PEER_PORT << " to " << mRemoteListeningPort; StellarMessage msg; msg.type(HELLO); msg.hello().protocolVersion = mApp.getConfig().PROTOCOL_VERSION; msg.hello().versionStr = mApp.getConfig().VERSION_STR; msg.hello().listeningPort = mApp.getConfig().PEER_PORT; msg.hello().peerID = mApp.getConfig().PEER_PUBLIC_KEY; sendMessage(msg); }
std::string msgSummary(StellarMessage const& m) { xdr::detail::Printer p(0); xdr::archive(p, m.type(), nullptr); return p.buf_.str() + ":" + hexAbbrev(sha256(xdr::xdr_to_msg(m))); }
void Peer::recvGetSCPState(StellarMessage const& msg) { uint32 seq = msg.getSCPLedgerSeq(); CLOG(TRACE, "Overlay") << "get SCP State " << seq; mApp.getHerder().sendSCPStateToPeer(seq, shared_from_this()); }
void Peer::recvTransaction(StellarMessage const& msg) { TransactionFramePtr transaction = TransactionFrame::makeTransactionFromWire( mApp.getNetworkID(), msg.transaction()); if (transaction) { // add it to our current set // and make sure it is valid auto recvRes = mApp.getHerder().recvTransaction(transaction); if (recvRes == Herder::TX_STATUS_PENDING || recvRes == Herder::TX_STATUS_DUPLICATE) { // record that this peer sent us this transaction mApp.getOverlayManager().recvFloodedMsg(msg, shared_from_this()); if (recvRes == Herder::TX_STATUS_PENDING) { // if it's a new transaction, broadcast it mApp.getOverlayManager().broadcastMessage(msg); } } } }
void Peer::recvGetTxSet(StellarMessage const& msg) { auto self = shared_from_this(); if (auto txSet = mApp.getHerder().getTxSet(msg.txSetHash())) { StellarMessage newMsg; newMsg.type(TX_SET); txSet->toXDR(newMsg.txSet()); self->sendMessage(newMsg); } else { sendDontHave(TX_SET, msg.txSetHash()); } }
void Peer::recvDontHave(StellarMessage const& msg) { switch (msg.dontHave().type) { case TX_SET: mApp.getHerder().doesntHaveTxSet(msg.dontHave().reqHash, shared_from_this()); break; case SCP_QUORUMSET: mApp.getHerder().doesntHaveSCPQuorumSet(msg.dontHave().reqHash, shared_from_this()); break; default: break; } }
void Peer::recvGetTxSet(StellarMessage const& msg) { TxSetFramePtr txSet = mApp.getHerder().fetchTxSet(msg.txSetHash(), false); if (txSet) { StellarMessage newMsg; newMsg.type(TX_SET); txSet->toXDR(newMsg.txSet()); sendMessage(newMsg); } else { sendDontHave(TX_SET, msg.txSetHash()); } }
void Peer::recvGetSCPQuorumSet(StellarMessage const& msg) { SCPQuorumSetPtr qSet = mApp.getHerder().fetchSCPQuorumSet(msg.qSetHash(), false); if (qSet) { sendSCPQuorumSet(qSet); } else { CLOG(TRACE, "Overlay") << "No quorum set: " << hexAbbrev(msg.qSetHash()); sendDontHave(SCP_QUORUMSET, msg.qSetHash()); // do we want to ask other people for it? } }
// copy/pasted from sendHello2 // (to be removed when HELLO is not used) void Peer::sendHello() { CLOG(DEBUG, "Overlay") << "Peer::sendHello to " << toString(); StellarMessage msg; msg.type(HELLO); Hello& elo = msg.hello(); elo.ledgerVersion = mApp.getConfig().LEDGER_PROTOCOL_VERSION; elo.overlayVersion = mApp.getConfig().OVERLAY_PROTOCOL_VERSION; elo.versionStr = mApp.getConfig().VERSION_STR; elo.networkID = mApp.getNetworkID(); elo.listeningPort = mApp.getConfig().PEER_PORT; elo.peerID = mApp.getConfig().NODE_SEED.getPublicKey(); elo.cert = this->getAuthCert(); elo.nonce = mSendNonce; sendMessage(msg); }
void Peer::sendPeers() { // send top 50 peers we know about vector<PeerRecord> peerList; PeerRecord::loadPeerRecords(mApp.getDatabase(), 50, mApp.getClock().now(), peerList); StellarMessage newMsg; newMsg.type(PEERS); newMsg.peers().resize(xdr::size32(peerList.size())); for (size_t n = 0; n < peerList.size(); n++) { if (!peerList[n].isPrivateAddress()) { peerList[n].toXdr(newMsg.peers()[n]); } } sendMessage(newMsg); }
void Peer::sendMessage(StellarMessage const& msg) { CLOG(TRACE, "Overlay") << "(" << binToHex(mApp.getConfig().PEER_PUBLIC_KEY) .substr(0, 6) << ")send: " << msg.type() << " to : " << hexAbbrev(mPeerID); xdr::msg_ptr xdrBytes(xdr::xdr_to_msg(msg)); this->sendMessage(std::move(xdrBytes)); }
void Peer::recvSCPMessage(StellarMessage const& msg) { SCPEnvelope envelope = msg.envelope(); CLOG(TRACE, "Overlay") << "recvSCPMessage qset: " << binToHex(msg.envelope().statement.quorumSetHash) .substr(0, 6); mApp.getOverlayManager().recvFloodedMsg(msg, shared_from_this()); auto cb = [msg, this](SCP::EnvelopeState state) { if (state == SCP::EnvelopeState::VALID) { mApp.getOverlayManager().broadcastMessage(msg); } }; mApp.getHerder().recvSCPEnvelope(envelope, cb); }
void Peer::recvPeers(StellarMessage const& msg) { const uint32 NEW_PEER_WINDOW_SECONDS = 10; for (auto const& peer : msg.peers()) { if (peer.port == 0 || peer.port > UINT16_MAX) { CLOG(WARNING, "Overlay") << "ignoring received peer with bad port " << peer.port; continue; } if (peer.ip.type() == IPv6) { CLOG(WARNING, "Overlay") << "ignoring received IPv6 address" << " (not yet supported)"; continue; } // randomize when we'll try to connect to this peer next if we don't // know it auto defaultNextAttempt = mApp.getClock().now() + std::chrono::seconds(std::rand() % NEW_PEER_WINDOW_SECONDS); stringstream ip; ip << (int)peer.ip.ipv4()[0] << "." << (int)peer.ip.ipv4()[1] << "." << (int)peer.ip.ipv4()[2] << "." << (int)peer.ip.ipv4()[3]; // don't use peer.numFailures here as we may have better luck // (and we don't want to poison our failure count) PeerRecord pr{ip.str(), static_cast<unsigned short>(peer.port), defaultNextAttempt, 0}; if (pr.isPrivateAddress()) { CLOG(WARNING, "Overlay") << "ignoring received private address " << pr.toString(); } else if (pr.isSelfAddressAndPort(getIP(), mApp.getConfig().PEER_PORT)) { CLOG(WARNING, "Overlay") << "ignoring received self-address " << pr.toString(); } else if (pr.isLocalhost() && !mApp.getConfig().ALLOW_LOCALHOST_FOR_TESTING) { CLOG(WARNING, "Overlay") << "ignoring received localhost"; } else { pr.insertIfNew(mApp.getDatabase()); } } }
void Peer::sendMessage(StellarMessage const& msg) { CLOG(TRACE, "Overlay") << "(" << PubKeyUtils::toShortString( mApp.getConfig().NODE_SEED.getPublicKey()) << ") send: " << msg.type() << " to : " << PubKeyUtils::toShortString(mPeerID); AuthenticatedMessage amsg; amsg.v0().message = msg; if (msg.type() != HELLO) { amsg.v0().sequence = mSendMacSeq; amsg.v0().mac = hmacSha256(mSendMacKey, xdr::xdr_to_opaque(mSendMacSeq, msg)); ++mSendMacSeq; } xdr::msg_ptr xdrBytes(xdr::xdr_to_msg(amsg)); this->sendMessage(std::move(xdrBytes)); }
bool Peer::recvHello(StellarMessage const& msg) { if (msg.hello().peerID == mApp.getConfig().PEER_PUBLIC_KEY) { CLOG(DEBUG, "Overlay") << "connecting to self"; drop(); return false; } mRemoteProtocolVersion = msg.hello().protocolVersion; mRemoteVersion = msg.hello().versionStr; if (msg.hello().listeningPort <= 0 || msg.hello().listeningPort > UINT16_MAX) { CLOG(DEBUG, "Overlay") << "bad port in recvHello"; drop(); return false; } mRemoteListeningPort = static_cast<unsigned short>(msg.hello().listeningPort); CLOG(INFO, "Overlay") << "recvHello " << "@" << mApp.getConfig().PEER_PORT << " from: " << mRemoteProtocolVersion << " " << mRemoteVersion << " " << mRemoteListeningPort; mState = GOT_HELLO; mPeerID = msg.hello().peerID; return true; }
bool Peer::recvHello(StellarMessage const& msg) { if (msg.hello().peerID == mApp.getConfig().PEER_PUBLIC_KEY) { CLOG(DEBUG, "Overlay") << "connecting to self"; drop(); return false; } mRemoteOverlayVersion = msg.hello().overlayVersion; mRemoteVersion = msg.hello().versionStr; if (msg.hello().listeningPort <= 0 || msg.hello().listeningPort > UINT16_MAX) { CLOG(DEBUG, "Overlay") << "bad port in recvHello"; drop(); return false; } mRemoteListeningPort = static_cast<unsigned short>(msg.hello().listeningPort); CLOG(DEBUG, "Overlay") << "recvHello from " << toString(); mState = GOT_HELLO; mPeerID = msg.hello().peerID; if (mRole == INITIATOR) { PeerRecord pr(getIP(), mRemoteListeningPort, mApp.getClock().now(), 0, 1); pr.insertIfNew(mApp.getDatabase()); } return true; }
void Peer::sendPeers() { // send top 50 peers we know about vector<PeerRecord> peerList; PeerRecord::loadPeerRecords(mApp.getDatabase(), 50, mApp.getClock().now(), peerList); StellarMessage newMsg; newMsg.type(PEERS); newMsg.peers().reserve(peerList.size()); for (auto const& pr : peerList) { if (pr.isPrivateAddress() || pr.isSelfAddressAndPort(getIP(), mRemoteListeningPort)) { continue; } PeerAddress pa; pr.toXdr(pa); newMsg.peers().push_back(pa); } sendMessage(newMsg); }
void PendingEnvelopes::envelopeReady(SCPEnvelope const& envelope) { StellarMessage msg; msg.type(SCP_MESSAGE); msg.envelope() = envelope; mApp.getOverlayManager().broadcastMessage(msg); mPendingEnvelopes[envelope.statement.slotIndex].push_back(envelope); /* // if envelope is on the right slot send into SCP // TODO.1 : below if(checkFutureCommitted(envelope)) { mIsFutureCommitted.insert(envelope.statement.slotIndex); } */ mApp.getClock().getIOService().post([this]() { mHerder.processSCPQueue(); }); }
bool tryRead(XDRInputFileStream& in, StellarMessage& m) { try { return in.readOne(m); } catch (xdr::xdr_runtime_error& e) { LOG(INFO) << "Caught XDR error '" << e.what() << "' on input substituting HELLO"; m.type(HELLO); return true; } }
void Peer::recvTransaction(StellarMessage const& msg) { TransactionFramePtr transaction = TransactionFrame::makeTransactionFromWire(msg.transaction()); if (transaction) { // add it to our current set // and make sure it is valid if (mApp.getHerder().recvTransaction(transaction)) { mApp.getOverlayManager().recvFloodedMsg(msg, shared_from_this()); mApp.getOverlayManager().broadcastMessage(msg); } } }
void Peer::recvPeers(StellarMessage const& msg) { for (auto const& peer : msg.peers()) { if (peer.port == 0 || peer.port > UINT16_MAX) { CLOG(WARNING, "Overlay") << "ignoring received peer with bad port " << peer.port; continue; } if (peer.ip.type() == IPv6) { CLOG(WARNING, "Overlay") << "ignoring received IPv6 address" << " (not yet supported)"; continue; } stringstream ip; ip << (int)peer.ip.ipv4()[0] << "." << (int)peer.ip.ipv4()[1] << "." << (int)peer.ip.ipv4()[2] << "." << (int)peer.ip.ipv4()[3]; PeerRecord pr{ip.str(), static_cast<unsigned short>(peer.port), mApp.getClock().now(), peer.numFailures}; if (pr.isPrivateAddress()) { CLOG(WARNING, "Overlay") << "ignoring received private address " << pr.toString(); } else if (pr.isSelfAddressAndPort(getIP(), mApp.getConfig().PEER_PORT)) { CLOG(WARNING, "Overlay") << "ignoring received self-address " << pr.toString(); } else { pr.insertIfNew(mApp.getDatabase()); } } }
void Peer::recvTxSet(StellarMessage const& msg) { TxSetFrame frame(msg.txSet()); mApp.getHerder().recvTxSet(frame.getContentsHash(), frame); }
void Peer::recvSCPQuorumSet(StellarMessage const& msg) { SCPQuorumSetPtr qSet = std::make_shared<SCPQuorumSet>(msg.qSet()); mApp.getHerder().recvSCPQuorumSet(qSet); }
void Peer::recvHello(StellarMessage const& msg) { using xdr::operator==; if (mState >= GOT_HELLO) { CLOG(ERROR, "Overlay") << "received unexpected HELLO"; mDropInRecvHelloUnexpectedMeter.Mark(); drop(); return; } auto& peerAuth = mApp.getOverlayManager().getPeerAuth(); if (!peerAuth.verifyRemoteAuthCert(msg.hello().peerID, msg.hello().cert)) { CLOG(ERROR, "Overlay") << "failed to verify remote peer auth cert"; mDropInRecvHelloCertMeter.Mark(); drop(); return; } mRemoteListeningPort = static_cast<unsigned short>(msg.hello().listeningPort); mRemoteOverlayVersion = msg.hello().overlayVersion; mRemoteVersion = msg.hello().versionStr; mPeerID = msg.hello().peerID; mRecvNonce = msg.hello().nonce; mSendMacSeq = 0; mRecvMacSeq = 0; mSendMacKey = peerAuth.getSendingMacKey(msg.hello().cert.pubkey, mSendNonce, mRecvNonce, mRole); mRecvMacKey = peerAuth.getReceivingMacKey(msg.hello().cert.pubkey, mSendNonce, mRecvNonce, mRole); mState = GOT_HELLO; CLOG(DEBUG, "Overlay") << "recvHello from " << toString(); if (mRole == REMOTE_CALLED_US) { // Send a HELLO back, even if it's going to be followed // immediately by ERROR, because ERROR is an authenticated // message type and the caller won't decode it right if // still waiting for an unauthenticated HELLO. sendHello(); } if (msg.hello().overlayVersion != mApp.getConfig().OVERLAY_PROTOCOL_VERSION) { CLOG(ERROR, "Overlay") << "connection from peer with different overlay protocol version"; CLOG(DEBUG, "Overlay") << "Protocol = " << msg.hello().overlayVersion << " expected: " << mApp.getConfig().OVERLAY_PROTOCOL_VERSION; mDropInRecvHelloVersionMeter.Mark(); drop(ERR_CONF, "wrong protocol version"); return; } if (msg.hello().peerID == mApp.getConfig().NODE_SEED.getPublicKey()) { CLOG(WARNING, "Overlay") << "connecting to self"; mDropInRecvHelloSelfMeter.Mark(); drop(ERR_CONF, "connecting to self"); return; } if (msg.hello().networkID != mApp.getNetworkID()) { CLOG(WARNING, "Overlay") << "connection from peer with different NetworkID"; CLOG(DEBUG, "Overlay") << "NetworkID = " << hexAbbrev(msg.hello().networkID) << " expected: " << hexAbbrev(mApp.getNetworkID()); mDropInRecvHelloNetMeter.Mark(); drop(ERR_CONF, "wrong network passphrase"); return; } for (auto const& p : mApp.getOverlayManager().getPeers()) { if (&(p->mPeerID) == &mPeerID) { continue; } if (p->getPeerID() == mPeerID) { CLOG(WARNING, "Overlay") << "connection from already-connected peerID " << PubKeyUtils::toShortString(mPeerID); mDropInRecvHelloPeerIDMeter.Mark(); drop(ERR_CONF, "connecting already-connected peer"); return; } } if (msg.hello().listeningPort <= 0 || msg.hello().listeningPort > UINT16_MAX) { CLOG(WARNING, "Overlay") << "bad port in recvHello"; mDropInRecvHelloPortMeter.Mark(); drop(ERR_CONF, "bad port number"); return; } if (mRole == WE_CALLED_REMOTE) { sendAuth(); } }
void Peer::recvTxSet(StellarMessage const& msg) { TxSetFramePtr txSet = std::make_shared<TxSetFrame>(msg.txSet()); mApp.getHerder().recvTxSet(txSet); }
void Peer::recvMessage(StellarMessage const& stellarMsg) { CLOG(TRACE, "Overlay") << "(" << binToHex(mApp.getConfig().PEER_PUBLIC_KEY) .substr(0, 6) << ")recv: " << stellarMsg.type() << " from:" << hexAbbrev(mPeerID); if (mState < GOT_HELLO && ((stellarMsg.type() != HELLO) && (stellarMsg.type() != PEERS))) { CLOG(WARNING, "Overlay") << "recv: " << stellarMsg.type() << " before hello"; drop(); return; } switch (stellarMsg.type()) { case ERROR_MSG: { recvError(stellarMsg); } break; case HELLO: { this->recvHello(stellarMsg); } break; case DONT_HAVE: { recvDontHave(stellarMsg); } break; case GET_PEERS: { recvGetPeers(stellarMsg); } break; case PEERS: { recvPeers(stellarMsg); } break; case GET_TX_SET: { recvGetTxSet(stellarMsg); } break; case TX_SET: { recvTxSet(stellarMsg); } break; case TRANSACTION: { recvTransaction(stellarMsg); } break; case GET_SCP_QUORUMSET: { recvGetSCPQuorumSet(stellarMsg); } break; case SCP_QUORUMSET: { recvSCPQuorumSet(stellarMsg); } break; case SCP_MESSAGE: { recvSCPMessage(stellarMsg); } break; } }
void fuzz(std::string const& filename, el::Level logLevel, std::vector<std::string> const& metrics) { Logging::setFmt("<fuzz>", false); Logging::setLogLevel(logLevel, nullptr); LOG(INFO) << "Fuzzing stellar-core " << STELLAR_CORE_VERSION; LOG(INFO) << "Fuzz input is in " << filename; Config cfg1, cfg2; cfg1.RUN_STANDALONE = true; cfg1.ARTIFICIALLY_ACCELERATE_TIME_FOR_TESTING = true; cfg1.LOG_FILE_PATH = "fuzz-app-1.log"; cfg1.TMP_DIR_PATH = "fuzz-tmp-1"; cfg1.BUCKET_DIR_PATH = "fuzz-buckets-1"; cfg2.RUN_STANDALONE = true; cfg2.ARTIFICIALLY_ACCELERATE_TIME_FOR_TESTING = true; cfg1.LOG_FILE_PATH = "fuzz-app-2.log"; cfg2.TMP_DIR_PATH = "fuzz-tmp-2"; cfg2.BUCKET_DIR_PATH = "fuzz-buckets-2"; CfgDirGuard g1(cfg1); CfgDirGuard g2(cfg2); restart: { VirtualClock clock; Application::pointer app1 = Application::create(clock, cfg1); Application::pointer app2 = Application::create(clock, cfg2); LoopbackPeerConnection loop(*app1, *app2); while (clock.crank(false) > 0) ; XDRInputFileStream in; in.open(filename); StellarMessage msg; size_t i = 0; while (tryRead(in, msg)) { ++i; if (msg.type() != HELLO) { LOG(INFO) << "Fuzzer injecting message " << i << ": " << msgSummary(msg); loop.getAcceptor()->Peer::sendMessage(msg); } size_t iter = 20; while (clock.crank(false) > 0 && iter-- > 0) ; } } if (getenv("AFL_PERSISTENT") && persist_cnt++ < PERSIST_MAX) { #ifndef _WIN32 raise(SIGSTOP); #endif goto restart; } }
void Peer::recvDontHave(StellarMessage const& msg) { mApp.getHerder().peerDoesntHave(msg.dontHave().type, msg.dontHave().reqHash, shared_from_this()); }
void Peer::recvSCPQuorumSet(StellarMessage const& msg) { Hash hash = sha256(xdr::xdr_to_opaque(msg.qSet())); mApp.getHerder().recvSCPQuorumSet(hash, msg.qSet()); }