I2P: End-to-End encrypted and anonymous Internet https://i2pd.website/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
8.5 KiB

#ifndef I2PCONTROL_H__
#define I2PCONTROL_H__
#include <boost/property_tree/ptree.hpp>
#include <string>
#include <map>
#include <functional>
#include <mutex>
#include <boost/asio.hpp>
namespace i2p {
// Forward declaration
namespace tunnel { class Tunnel; }
namespace client {
namespace i2pcontrol {
namespace constants {
const char DEFAULT_PASSWORD[] = "itoopie";
const uint64_t TOKEN_LIFETIME = 600; // Token lifetime in seconds
const std::size_t TOKEN_SIZE = 8; // Token size in bytes
const char PROPERTY_ID[] = "id";
const char PROPERTY_METHOD[] = "method";
const char PROPERTY_PARAMS[] = "params";
const char PROPERTY_RESULT[] = "result";
// methods
const char METHOD_AUTHENTICATE[] = "Authenticate";
const char METHOD_ECHO[] = "Echo";
const char METHOD_I2PCONTROL[] = "I2PControl";
const char METHOD_ROUTER_INFO[] = "RouterInfo";
const char METHOD_ROUTER_MANAGER[] = "RouterManager";
const char METHOD_NETWORK_SETTING[] = "NetworkSetting";
// params
const char PARAM_API[] = "API";
const char PARAM_PASSWORD[] = "Password";
const char PARAM_TOKEN[] = "Token";
const char PARAM_ECHO[] = "Echo";
const char PARAM_RESULT[] = "Result";
// I2PControl
const char I2PCONTROL_ADDRESS[] = "i2pcontrol.address";
const char I2PCONTROL_PASSWORD[] = "i2pcontrol.password";
const char I2PCONTROL_PORT[] = "i2pcontrol.port";
// RouterInfo requests
const char ROUTER_INFO_UPTIME[] = "i2p.router.uptime";
const char ROUTER_INFO_VERSION[] = "i2p.router.version";
const char ROUTER_INFO_STATUS[] = "i2p.router.status";
const char ROUTER_INFO_DATAPATH[] = "i2p.router.datapath";
const char ROUTER_INFO_NETDB_KNOWNPEERS[] = "i2p.router.netdb.knownpeers";
const char ROUTER_INFO_NETDB_ACTIVEPEERS[] = "i2p.router.netdb.activepeers";
const char ROUTER_INFO_NETDB_FLOODFILLS[] = "i2p.router.netdb.floodfills";
const char ROUTER_INFO_NETDB_LEASESETS[] = "i2p.router.netdb.leasesets";
const char ROUTER_INFO_NET_STATUS[] = "i2p.router.net.status";
const char ROUTER_INFO_TUNNELS_PARTICIPATING[] = "i2p.router.net.tunnels.participating";
// TODO: Probably better to use the standard GetRate instead
const char ROUTER_INFO_TUNNELS_CREATION_SUCCESS[] = "i2p.router.net.tunnels.creationsuccessrate";
const char ROUTER_INFO_TUNNELS_IN_LIST[] = "i2p.router.net.tunnels.inbound.list";
const char ROUTER_INFO_TUNNELS_OUT_LIST[] = "i2p.router.net.tunnels.outbound.list";
const char ROUTER_INFO_BW_IB_1S[] = "i2p.router.net.bw.inbound.1s";
const char ROUTER_INFO_BW_OB_1S[] = "i2p.router.net.bw.outbound.1s";
// RouterManager requests
const char ROUTER_MANAGER_SHUTDOWN[] = "Shutdown";
const char ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
const char ROUTER_MANAGER_RESEED[] = "Reseed";
} // constants
/**
* Represents a Json object, provides functionality to convert to string.
*/
class JsonObject {
public:
JsonObject() = default;
JsonObject(const std::string& value);
JsonObject(int value);
JsonObject(double value);
JsonObject& operator[](const std::string& key);
std::string toString() const;
private:
std::map<std::string, JsonObject> children;
std::string value;
};
JsonObject tunnelToJsonObject(i2p::tunnel::Tunnel* tunnel);
/**
* "Null" I2P control implementation, does not do actual networking.
* @note authentication tokens are per-session
* @note I2PControlSession must always be used as a std::shared_ptr
* @warning an I2PControlSession must be destroyed before its io_service
*/
class I2PControlSession : public std::enable_shared_from_this<I2PControlSession> {
public:
enum class ErrorCode {
None = 0,
// JSON-RPC2
MethodNotFound = 32601,
InvalidParameters = 32602,
InvalidRequest = 32600,
InternalError = 32603,
ParseError = 32700,
// I2PControl specific
InvalidPassword = 32001,
NoToken = 32002,
NonexistentToken = 32003,
ExpiredToken = 32004,
UnspecifiedVersion = 32005,
UnsupportedVersion = 32006
};
class Response {
std::string id;
std::string version;
ErrorCode error;
std::map<std::string, std::string> parameters;
public:
Response(const std::string& version = "2.0");
std::string toJsonString() const;
/**
* Set an output parameter to a specified string.
* @todo escape quotes
*/
void setParam(const std::string& param, const std::string& value);
/**
* Set an output parameter to a specified integer.
*/
void setParam(const std::string& param, int value);
/**
* Set an output parameter to a specified double.
*/
void setParam(const std::string& param, double value);
/**
* Set an output parameter to a specified Json object.
*/
void setParam(const std::string& param, const JsonObject& value);
void setError(ErrorCode code);
void setId(const std::string& identifier);
std::string getErrorMsg() const;
};
/**
* Sets up the appropriate handlers.
* @param pass the password required to authenticate (i.e. obtains a token)
* @param ios the parent io_service object, must remain valid throughout
* the lifetime of this I2PControlSession.
*/
I2PControlSession(boost::asio::io_service& ios,
const std::string& pass = constants::DEFAULT_PASSWORD);
/**
* Starts the I2PControlSession.
* In essence, this starts the expireTokensTimer.
* @note should always be called after construction
*/
void start();
/**
* Cancels all operations that are waiting.
* @note it's a good idea to call this before destruction (shared_ptr reset)
*/
void stop();
/**
* Handle a json string with I2PControl instructions.
*/
Response handleRequest(std::stringstream& request);
private:
// For convenience
typedef boost::property_tree::ptree PropertyTree;
// Handler types
typedef void (I2PControlSession::*MethodHandler)(
const PropertyTree& pt, Response& results
);
typedef void (I2PControlSession::*RequestHandler)(Response& results);
/**
* Tries to authenticate by checking whether the given token is valid.
* Sets the appropriate error code in the given response.
*/
bool authenticate(const PropertyTree& pt, Response& response);
/**
* Generate a random authentication token.
* @return 8 random bytes as a hexadecimal string
*/
std::string generateToken() const;
void startExpireTokensJob();
/**
* Expire tokens that are too old.
*/
void expireTokens(const boost::system::error_code& error);
// Method handlers
void handleAuthenticate(const PropertyTree& pt, Response& response);
void handleEcho(const PropertyTree& pt, Response& response);
void handleI2PControl(const PropertyTree& pt, Response& response);
void handleRouterInfo(const PropertyTree& pt, Response& response);
void handleRouterManager(const PropertyTree& pt, Response& response);
void handleNetworkSetting(const PropertyTree& pt, Response& response);
// RouterInfo handlers
void handleUptime(Response& response);
void handleVersion(Response& response);
void handleStatus(Response& response);
void handleDatapath(Response& response);
void handleNetDbKnownPeers(Response& response);
void handleNetDbActivePeers(Response& response);
void handleNetDbFloodfills(Response& response);
void handleNetDbLeaseSets(Response& response);
void handleNetStatus(Response& response);
void handleTunnelsParticipating(Response& response);
void handleTunnelsCreationSuccess(Response& response);
void handleTunnelsInList(Response& response);
void handleTunnelsOutList(Response& response);
void handleInBandwidth1S(Response& response);
void handleOutBandwidth1S(Response& response);
// RouterManager handlers
void handleShutdown(Response& response);
void handleShutdownGraceful(Response& response);
void handleReseed(Response& response);
std::string password;
std::map<std::string, uint64_t> tokens;
std::mutex tokensMutex;
std::map<std::string, MethodHandler> methodHandlers;
std::map<std::string, RequestHandler> routerInfoHandlers;
std::map<std::string, RequestHandler> routerManagerHandlers;
std::map<std::string, RequestHandler> networkSettingHandlers;
boost::asio::io_service& service;
boost::asio::deadline_timer shutdownTimer;
boost::asio::deadline_timer expireTokensTimer;
};
}
}
}
#endif // I2PCONTROL_H__