diff --git a/Config.cpp b/Config.cpp index 8e212360..81c2a2ce 100644 --- a/Config.cpp +++ b/Config.cpp @@ -113,7 +113,8 @@ namespace config { ("log", value()->default_value(""), "Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") - ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") + ("family", value()->default_value(""), "Specify a family, router belongs to") + ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") diff --git a/Daemon.cpp b/Daemon.cpp index 242f4bbf..0687d0b9 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -120,7 +120,7 @@ namespace i2p i2p::context.SetHighBandwidth (); else i2p::context.SetLowBandwidth (); - } + } else if (isFloodfill) { LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'"); @@ -132,6 +132,11 @@ namespace i2p i2p::context.SetLowBandwidth (); } + std::string family; i2p::config::GetOption("family", family); + i2p::context.SetFamily (family); + if (family.length () > 0) + LogPrint(eLogInfo, "Daemon: family set to ", family); + return true; } diff --git a/Family.cpp b/Family.cpp index 8db0723c..d83adf2a 100644 --- a/Family.cpp +++ b/Family.cpp @@ -122,6 +122,51 @@ namespace data return true; } + std::string CreateFamilySignature (const std::string& family, const IdentHash& ident) + { + std::string sig; + auto filename = i2p::util::filesystem::GetDefaultDataDir() / "family" / (family + ".key"); + SSL_CTX * ctx = SSL_CTX_new (TLSv1_method ()); + int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.string ().c_str (), SSL_FILETYPE_PEM); + if (ret) + { + SSL * ssl = SSL_new (ctx); + EVP_PKEY * pkey = SSL_get_privatekey (ssl); + EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey); + if (ecKey) + { + auto group = EC_KEY_get0_group (ecKey); + if (group) + { + int curve = EC_GROUP_get_curve_name (group); + if (curve == NID_X9_62_prime256v1) + { + uint8_t signingPrivateKey[32], buf[50], signature[64]; + i2p::crypto::bn2buf (EC_KEY_get0_private_key (ecKey), signingPrivateKey, 32); + i2p::crypto::ECDSAP256Signer signer (signingPrivateKey); + size_t len = family.length (); + memcpy (buf, family.c_str (), len); + memcpy (buf + len, (const uint8_t *)ident, 32); + len += 32; + signer.Sign (buf, len, signature); + len = Base64EncodingBufferSize (64); + char * b64 = new char[len+1]; + len = ByteStreamToBase64 (signature, 64, b64, len); + b64[len] = 0; + sig = b64; + delete[] b64; + } + else + LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); + } + } + SSL_free (ssl); + } + else + LogPrint (eLogError, "Family: Can't open keys file ", filename.string ()); + SSL_CTX_free (ctx); + return sig; + } } } diff --git a/Family.h b/Family.h index 51cf6bf5..42a37292 100644 --- a/Family.h +++ b/Family.h @@ -1,5 +1,5 @@ #ifndef FAMILY_H__ -#define FAMILY_H_ +#define FAMILY_H__ #include #include @@ -29,6 +29,9 @@ namespace data std::map > m_SigningKeys; }; + + std::string CreateFamilySignature (const std::string& family, const IdentHash& ident); + // return base64 signature of empty string in case of failure } } diff --git a/RouterContext.cpp b/RouterContext.cpp index 90961948..070e52ad 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -8,6 +8,7 @@ #include "util.h" #include "version.h" #include "Log.h" +#include "Family.h" #include "RouterContext.h" namespace i2p @@ -141,12 +142,29 @@ namespace i2p { m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill); // we don't publish number of routers and leaseset for non-floodfill - m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_LEASESETS); - m_RouterInfo.DeleteProperty (ROUTER_INFO_PROPERTY_ROUTERS); + m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS); + m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS); } UpdateRouterInfo (); } + void RouterContext::SetFamily (const std::string& family) + { + std::string signature; + if (family.length () > 0) + signature = i2p::data::CreateFamilySignature (family, GetIdentHash ()); + if (signature.length () > 0) + { + m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY, family); + m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG, signature); + } + else + { + m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY); + m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_FAMILY_SIG); + } + } + void RouterContext::SetHighBandwidth () { if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ()) @@ -284,8 +302,8 @@ namespace i2p if (m_IsFloodfill) { // update routers and leasesets - m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast(i2p::data::netdb.GetNumLeaseSets ())); - m_RouterInfo.SetProperty (ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast(i2p::data::netdb.GetNumRouters ())); + m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS, boost::lexical_cast(i2p::data::netdb.GetNumLeaseSets ())); + m_RouterInfo.SetProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS, boost::lexical_cast(i2p::data::netdb.GetNumRouters ())); UpdateRouterInfo (); } } diff --git a/RouterContext.h b/RouterContext.h index 8c07b17f..bc1ee836 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -15,9 +15,6 @@ namespace i2p const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes - - const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets"; - const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters"; enum RouterStatus { @@ -60,6 +57,7 @@ namespace i2p void SetReachable (); bool IsFloodfill () const { return m_IsFloodfill; }; void SetFloodfill (bool floodfill); + void SetFamily (const std::string& family); void SetHighBandwidth (); void SetLowBandwidth (); void SetExtraBandwidth (); diff --git a/RouterInfo.cpp b/RouterInfo.cpp index ec9a4acd..1bf05a99 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -263,18 +263,18 @@ namespace data if (!strcmp (key, "caps")) ExtractCaps (value); // check netId - else if (!strcmp (key, "netId") && atoi (value) != I2PD_NET_ID) + else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != I2PD_NET_ID) { - LogPrint (eLogError, "Unexpected netid=", value); + LogPrint (eLogError, "Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value); m_IsUnreachable = true; } // family - else if (!strcmp (key, "family")) + else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY)) { m_Family = value; boost::to_lower (m_Family); } - else if (!strcmp (key, "family.sig")) + else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY_SIG)) { if (!netdb.GetFamilies ().VerifyFamily (m_Family, GetIdentHash (), value)) { diff --git a/RouterInfo.h b/RouterInfo.h index 57212be9..5b77e170 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -14,6 +14,12 @@ namespace i2p { namespace data { + const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets"; + const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters"; + const char ROUTER_INFO_PROPERTY_NETID[] = "netId"; + const char ROUTER_INFO_PROPERTY_FAMILY[] = "family"; + const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig"; + const char CAPS_FLAG_FLOODFILL = 'f'; const char CAPS_FLAG_HIDDEN = 'H'; const char CAPS_FLAG_REACHABLE = 'R';