bool ConnectHandouts::try_insert (beast::IP::Endpoint const& endpoint) { if (full ()) return false; // Make sure the address isn't already in our list if (std::any_of (m_list.begin(), m_list.end(), [&endpoint](beast::IP::Endpoint const& other) { // Ignore port for security reasons return other.address() == endpoint.address(); })) { return false; } // Add to squelch list so we don't try it too often. // If its already there, then make try_insert fail. auto const result (m_squelches.insert ( endpoint.address())); if (! result.second) return false; m_list.push_back (endpoint); return true; }
Role requestRole (Role const& required, HTTP::Port const& port, Json::Value const& params, beast::IP::Endpoint const& remoteIp) { Role role (Role::GUEST); if (isAdmin(port, params, remoteIp.address ())) role = Role::ADMIN; if (required == Role::ADMIN && role != required) role = Role::FORBID; return role; }
// VFALCO ARGH! returning a single std::string for the entire response? std::string ServerHandlerImp::processRequest (std::string const& request, beast::IP::Endpoint const& remoteIPAddress) { Json::Value jvRequest; { Json::Reader reader; if ((request.size () > 1000000) || ! reader.parse (request, jvRequest) || jvRequest.isNull () || ! jvRequest.isObject ()) { return createResponse (400, "Unable to parse request"); } } auto const role = getConfig ().getAdminRole (jvRequest, remoteIPAddress); Resource::Consumer usage; if (role == Config::ADMIN) usage = m_resourceManager.newAdminEndpoint (remoteIPAddress.to_string()); else usage = m_resourceManager.newInboundEndpoint(remoteIPAddress); if (usage.disconnect ()) return createResponse (503, "Server is overloaded"); // Parse id now so errors from here on will have the id // // VFALCO NOTE Except that "id" isn't included in the following errors. // Json::Value const id = jvRequest ["id"]; Json::Value const method = jvRequest ["method"]; if (method.isNull ()) return createResponse (400, "Null method"); if (! method.isString ()) return createResponse (400, "method is not string"); std::string strMethod = method.asString (); if (strMethod.empty()) return createResponse (400, "method is empty"); // Parse params Json::Value params = jvRequest ["params"]; if (params.isNull ()) params = Json::Value (Json::arrayValue); else if (!params.isArray ()) return HTTPReply (400, "params unparseable"); // VFALCO TODO Shouldn't we handle this earlier? // if (role == Config::FORBID) { // VFALCO TODO Needs implementing // FIXME Needs implementing // XXX This needs rate limiting to prevent brute forcing password. return HTTPReply (403, "Forbidden"); } std::string response; RPCHandler rpcHandler (m_networkOPs); Resource::Charge loadType = Resource::feeReferenceRPC; m_journal.debug << "Query: " << strMethod << params; Json::Value const result (rpcHandler.doRpcCommand ( strMethod, params, role, loadType)); m_journal.debug << "Reply: " << result; usage.charge (loadType); response = JSONRPCReply (result, Json::Value (), id); return createResponse (200, response); }
Config::Role Config::getAdminRole (Json::Value const& params, beast::IP::Endpoint const& remoteIp) const { Config::Role role (Config::FORBID); bool const bPasswordSupplied = params.isMember ("admin_user") || params.isMember ("admin_password"); bool const bPasswordRequired = ! this->RPC_ADMIN_USER.empty () || ! this->RPC_ADMIN_PASSWORD.empty (); bool bPasswordWrong; if (bPasswordSupplied) { if (bPasswordRequired) { // Required, and supplied, check match bPasswordWrong = (this->RPC_ADMIN_USER != (params.isMember ("admin_user") ? params["admin_user"].asString () : "")) || (this->RPC_ADMIN_PASSWORD != (params.isMember ("admin_user") ? params["admin_password"].asString () : "")); } else { // Not required, but supplied bPasswordWrong = false; } } else { // Required but not supplied, bPasswordWrong = bPasswordRequired; } // Meets IP restriction for admin. beast::IP::Endpoint const remote_addr (remoteIp.at_port (0)); bool bAdminIP = false; for (auto const& allow_addr : RPC_ADMIN_ALLOW) { if (allow_addr == remote_addr) { bAdminIP = true; break; } } if (bPasswordWrong // Wrong || (bPasswordSupplied && !bAdminIP)) // Supplied and doesn't meet IP filter. { role = Config::FORBID; } // If supplied, password is correct. else { // Allow admin, if from admin IP and no password is required or it was supplied and correct. role = bAdminIP && (!bPasswordRequired || bPasswordSupplied) ? Config::ADMIN : Config::GUEST; } return role; }