Skip to content
This repository has been archived by the owner on Sep 1, 2022. It is now read-only.

Commit

Permalink
Reseed: rewrite implementation. Resolves #149.
Browse files Browse the repository at this point in the history
* C++11 (minimum) refactor
* Create/rewrite appropriate classes
  - Improve class Reseed
  - Create classes SU3, ZIP, X509, and HTTP
  - Refactoring: move the mess of local variables into a POD type
  - Use spec-identifiable constants instead of raw numbers
  - Move class ZIP to core/util/ZIP.{h,cpp}
  - Move class X509 to core/crypto/X509.{h,cpp}
* Design rewrite
  - Create better reseed abstraction
    - See constructors, design, and interface of class
      Reseed/SU3/ZIP/X509
  - Separate parsing:
    - Class SU3 parsing from X.509/signature parsing and from class ZIP
      parsing
  - Rewrite/refactor related class NetDb code
  - Refactor: get rid of -1 return values, use bool and adjust related
    code
* Create/implement stream abstraction
  - Stream wrapper for strongly-typed classes
* Abstract CryptoPP from class ZIP and class X509
  - Pimpl ZIP decompression
  - Pimpl X.509 and separate cert processing from decoding
  - Ensure uncaught exceptions are caught
  - Cleanup pimpl-related directory structure
* Feature: manual reseed: create/implement an overloaded --reseed-from
  run-time switch
  - Handles reseeding from file
  - Handles reseeding from specified URL
* Feature: create/implement --reseed-skip-ssl-check run-time switch
  - Allows connecting to servers with certificates not shipped with
    Kovri (such as a local server)
  - Users can still put their self-signed cert in
    KOVRI_DATA_DIR/certificates/su3
    and skip this switch if desired
* HTTP: minor design refactor to accommodate new class Reseed design
  - Download function stores results in member stream, returns bool
  - HTTP response is stored in member variable
  - Logic design refactor to fix erroneous error response and help with
    debugging
* Spec review
  - Ensure that SU3 implementation meets requirements and provides a
    minimal interface to implement future content-types and/or specifications
    (ex. for auto-update or news feed)
  - Ensure that ZIP meets minimum requirements for our use-case
* Create secure sanity checks
* Create unit tests (referencing #7)
  - Tests for class SU3, ZIP, and X509
  - Cleanup unit-test directory structure and rename appropriate files
  - Adjust CMake accordingly
* Document code
  - Extensive documentation where possible
* Resolve any preexisting TODO's
* General improvements and rewrites
  • Loading branch information
anonimal committed Apr 9, 2016
1 parent 8c61f5d commit 8d63e4d
Show file tree
Hide file tree
Showing 38 changed files with 2,423 additions and 618 deletions.
6 changes: 5 additions & 1 deletion src/app/Daemon.cpp
Expand Up @@ -74,7 +74,6 @@ bool Daemon_Singleton::Init() {
i2p::util::config::var_map["host"].as<std::string>(),
i2p::util::config::var_map["port"].as<int>(),
i2p::util::filesystem::GetDataPath());

m_IsDaemon = i2p::util::config::var_map["daemon"].as<bool>();
m_IsLogging = i2p::util::config::var_map["log"].as<bool>();
int port = i2p::util::config::var_map["port"].as<int>();
Expand All @@ -93,6 +92,11 @@ bool Daemon_Singleton::Init() {
else
i2p::context.SetLowBandwidth();
}
// Set reseed options
i2p::context.ReseedFrom(
i2p::util::config::var_map["reseed-from"].as<std::string>());
i2p::context.ReseedSkipSSLCheck(
i2p::util::config::var_map["reseed-skip-ssl-check"].as<bool>());
// Initialize the ClientContext
InitClientContext();
return true;
Expand Down
26 changes: 25 additions & 1 deletion src/app/util/Config.cpp
Expand Up @@ -78,7 +78,7 @@ bool ParseArgs(

"all | basic | system\n"
"network | proxy | i2pcs\n"
"config\n\n"
"reseed | config\n\n"

"Examples\n"
"========\n\n"
Expand Down Expand Up @@ -161,6 +161,27 @@ bool ParseArgs(
("i2pcontrolpassword", bpo::value<std::string>()->default_value("itoopie"),
"I2P control service password\n");

bpo::options_description reseed("\nReseed");
reseed.add_options()
("reseed-from,r", bpo::value<std::string>()->default_value(""),
"File or URL from which to reseed\n"
"Examples:\n"
"./kovri -r ~/local/path/to/i2pseeds.su3\n"
"./kovri -r https://my.server.tld/i2pseeds.su3\n"
"Note: if the server in your URL is not one of the "
"hard-coded reseed servers, either use --reseed-skip-ssl-check"
"or put your server's certificate in with the others. "
"They are located in the .kovri data directory\n")

("reseed-skip-ssl-check", bpo::value<bool>()->default_value(false),
"Skip SSL check for reseed host. Useful for custom reseed servers\n"
"Examples:\n"
"./kovri --reseed-skip-ssl-check -r https://my.server.tld/i2pseeds.su3\n");

//("reseed-to", bpo::value<std::string>()->default_value(""),
// "Creates a reseed file for you to share\n"
// "Example: ~/path/to/new/i2pseeds.su3\n")

bpo::options_description config("\nConfiguration");
config.add_options()
("kovriconf,c", bpo::value<std::string>(&kovri_config)->default_value(
Expand Down Expand Up @@ -196,6 +217,7 @@ bool ParseArgs(
.add(network)
.add(proxy)
.add(i2pcs)
.add(reseed)
.add(config);
// Map and store cli options
bpo::store(bpo::parse_command_line(argc, argv, cli_options), var_map);
Expand Down Expand Up @@ -223,6 +245,8 @@ bool ParseArgs(
std::cout << proxy;
} else if (s == "i2pcs") {
std::cout << i2pcs;
} else if (s == "reseed") {
std::cout << reseed;
} else if (s == "config") {
std::cout << config;
} else {
Expand Down
17 changes: 9 additions & 8 deletions src/client/AddressBook.cpp
Expand Up @@ -505,13 +505,14 @@ void AddressBookSubscription::Request() {
}
if (leaseSet) {
std::stringstream request, response;
// standard header
request << i2p::util::http::HttpHeader(uri.m_Path, uri.m_Host, "1.1");
// Standard header
i2p::util::http::HTTP http;
request << http.Header(uri.m_Path, uri.m_Host, "1.1");
if (m_Etag.length () > 0) // etag
request << i2p::util::http::IF_NONE_MATCH
request << http.IF_NONE_MATCH
<< ": \"" << m_Etag << "\"\r\n";
if (m_LastModified.length () > 0) // if modified since
request << i2p::util::http::IF_MODIFIED_SINCE
request << http.IF_MODIFIED_SINCE
<< ": " << m_LastModified << "\r\n";
request << "\r\n"; // end of header
auto stream =
Expand Down Expand Up @@ -562,11 +563,11 @@ void AddressBookSubscription::Request() {
if (colon != std::string::npos) {
std::string field = header.substr(0, colon);
header.resize(header.length() - 1); // delete \r
if (field == i2p::util::http::ETAG)
if (field == http.ETAG)
m_Etag = header.substr(colon + 1);
else if (field == i2p::util::http::LAST_MODIFIED)
else if (field == http.LAST_MODIFIED)
m_LastModified = header.substr(colon + 1);
else if (field == i2p::util::http::TRANSFER_ENCODING)
else if (field == http.TRANSFER_ENCODING)
isChunked =
!header.compare(colon + 1, std::string::npos, "chunked");
}
Expand All @@ -582,7 +583,7 @@ void AddressBookSubscription::Request() {
} else {
// merge chunks
std::stringstream merged;
i2p::util::http::MergeChunkedResponse(response, merged);
http.MergeChunkedResponse(response, merged);
m_Book.LoadHostsFromStream(merged);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/client/I2PTunnel/HTTPProxy.cpp
Expand Up @@ -222,7 +222,8 @@ void HTTPProxyHandler::HandleJumpServices() {
}
auto base64 = m_path.substr(addressHelperPos + strlen(helpermark1));
// Some of the symbols may be urlencoded
base64 = i2p::util::http::DecodeURI(base64);
i2p::util::http::URI uri;
base64 = uri.Decode(base64);
LogPrint(eLogDebug, "Jump service for ", m_address,
" found at ", base64, ". Inserting to address book");
// TODO(anonimal): this is very dangerous and broken.
Expand Down
9 changes: 7 additions & 2 deletions src/core/CMakeLists.txt
Expand Up @@ -33,7 +33,12 @@ set(CORE_SRC
"util/HTTP.cpp"
"util/Log.cpp"
"util/MTU.cpp"
"util/Filesystem.cpp")
"util/Filesystem.cpp"
"util/ZIP.cpp")

set(CRYPTO_PIMPL_SRC
"crypto/pimpl/cryptopp/ZIP.cpp"
"crypto/pimpl/cryptopp/X509.cpp")

set(EDDSA_SRC
"crypto/ed25519/fe_0.cpp"
Expand Down Expand Up @@ -89,7 +94,7 @@ add_subdirectory(crypto/ed25519)

# Library building
if(WITH_LIBRARY)
add_library(${CORE_NAME} ${CORE_SRC} ${EDDSA_SRC})
add_library(${CORE_NAME} ${CORE_SRC} ${CRYPTO_PIMPL_SRC} ${EDDSA_SRC})
target_link_libraries(
${CORE_NAME}
${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${OPENSSL_LIBRARIES}
Expand Down
2 changes: 1 addition & 1 deletion src/core/Identity.cpp
Expand Up @@ -45,7 +45,7 @@
#include "Identity.h"
#include "RouterContext.h"
#include "crypto/CryptoConst.h"
#include "crypto/CryptoPP_Rand.h"
#include "crypto/pimpl/cryptopp/Rand.h"
#include "crypto/ElGamal.h"
#include "crypto/Rand.h"
#include "crypto/Signature.h"
Expand Down
5 changes: 2 additions & 3 deletions src/core/Identity.h
Expand Up @@ -52,10 +52,9 @@ class Verifier;

namespace data {
template<int SZ>
class Tag {
class Tag { // TODO(anonimal): review/consider moving this class into core/util
public:
Tag(
const uint8_t * buf) {
Tag(const uint8_t* buf) {
memcpy(m_Buf, buf, SZ);
}
Tag(const Tag<SZ>&) = default;
Expand Down
57 changes: 24 additions & 33 deletions src/core/NetworkDatabase.cpp
Expand Up @@ -64,23 +64,20 @@ NetDb netdb;
NetDb::NetDb()
: m_IsRunning(false),
m_Thread(nullptr),
m_Reseeder(nullptr) {}
m_Reseed(nullptr) {}

NetDb::~NetDb() {
Stop();
if (m_Reseeder) {
delete m_Reseeder;
m_Reseeder = nullptr;
if (m_Reseed) {
delete m_Reseed;
m_Reseed = nullptr;
}
}

bool NetDb::Start() {
Load();
if (m_RouterInfos.size() < 25) { // reseed if # of router less than 50
// try SU3 first
if (!Reseed()) {
// reseed failed
LogPrint(eLogError, "Reseed failed");
return false;
}
}
Expand Down Expand Up @@ -132,8 +129,8 @@ void NetDb::Run() {
LogPrint("DatabaseLookup");
HandleDatabaseLookupMsg(msg);
break;
default: // WTF?
// TODO(unassigned): ???
default:
// TODO(unassigned): error handling
LogPrint(eLogError,
"NetDb: unexpected message type ", msg->GetTypeID());
// i2p::HandleI2NPMessage(msg);
Expand Down Expand Up @@ -185,12 +182,16 @@ void NetDb::Run() {
}
}

void NetDb::AddRouterInfo(
bool NetDb::AddRouterInfo(
const uint8_t* buf,
int len) {
IdentityEx identity;
if (identity.FromBuffer(buf, len))
AddRouterInfo(identity.GetIdentHash(), buf, len);
if (!identity.FromBuffer(buf, len)) {
LogPrint(eLogError, "NetDb: unable to add router info");
return false;
}
AddRouterInfo(identity.GetIdentHash(), buf, len);
return true;
}

void NetDb::AddRouterInfo(
Expand All @@ -202,9 +203,9 @@ void NetDb::AddRouterInfo(
auto ts = r->GetTimestamp();
r->Update(buf, len);
if (r->GetTimestamp() > ts)
LogPrint("RouterInfo updated");
LogPrint("NetDb: RouterInfo updated");
} else {
LogPrint("New RouterInfo added");
LogPrint(eLogDebug, "NetDb: new RouterInfo added");
r = std::make_shared<RouterInfo> (buf, len); {
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
m_RouterInfos[r->GetIdentHash()] = r;
Expand Down Expand Up @@ -299,34 +300,24 @@ bool NetDb::CreateNetDb(
}

bool NetDb::Reseed() {
if (m_Reseeder == nullptr) {
m_Reseeder = new Reseeder();
if (!m_Reseeder->LoadSU3Certs()) {
delete m_Reseeder;
m_Reseeder = nullptr;
LogPrint(eLogError, "Failed to load reseed certificates");
// we need to die hard if this happens
if (m_Reseed == nullptr) {
m_Reseed = new i2p::data::Reseed(i2p::context.ReseedFrom());
if (!m_Reseed->ReseedImpl()) {
delete m_Reseed;
m_Reseed = nullptr;
LogPrint(eLogError, "NetDb: reseed failed");
return false;
}
}
int reseedRetries = 0;
while (reseedRetries < 10) {
int result = m_Reseeder->ReseedNowSU3();
if (result <= 0)
reseedRetries++;
else
break;
}
if (reseedRetries >= 10)
LogPrint(eLogWarning, "Failed to reseed after 10 attempts");
return reseedRetries < 10;
return true;
}

void NetDb::Load() {
boost::filesystem::path p(i2p::context.GetDataPath() / m_NetDbPath);
if (!boost::filesystem::exists(p)) {
// seems netDb doesn't exist yet
if (!CreateNetDb(p)) return;
if (!CreateNetDb(p))
return;
}
// make sure we cleanup netDb from previous attempts
m_RouterInfos.clear();
Expand Down
6 changes: 4 additions & 2 deletions src/core/NetworkDatabase.h
Expand Up @@ -67,9 +67,11 @@ class NetDb {
bool Start();
void Stop();

void AddRouterInfo(
/// @return False on failure
bool AddRouterInfo(
const uint8_t* buf,
int len);

void AddRouterInfo(
const IdentHash& ident,
const uint8_t* buf,
Expand Down Expand Up @@ -170,7 +172,7 @@ class NetDb {
// of I2NPDatabaseStoreMsg
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue;

Reseeder* m_Reseeder;
i2p::data::Reseed* m_Reseed;

friend class NetDbRequests;
NetDbRequests m_Requests;
Expand Down

0 comments on commit 8d63e4d

Please sign in to comment.