diff --git a/.gitignore b/.gitignore index b6cffd15..73297488 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ netDb autom4te.cache .deps stamp-h1 -Makefile +#Makefile config.h config.h.in~ config.log @@ -238,3 +238,11 @@ pip-log.txt # Sphinx docs/_build /androidIdea/ + + +# emacs files +*~ +*\#* + +# gdb files +.gdb_history \ No newline at end of file diff --git a/AddressBook.cpp b/AddressBook.cpp index b993f456..db424308 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Base.h" #include "util.h" #include "Identity.h" @@ -15,6 +16,7 @@ #include "NetDb.h" #include "ClientContext.h" #include "AddressBook.h" +#include "Config.h" namespace i2p { @@ -404,9 +406,21 @@ namespace client m_Subscriptions.push_back (std::make_shared (*this, s)); } LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); + LogPrint (eLogWarning, "Addressbook: subscriptions.txt usage is deprecated, use config file instead"); } - else - LogPrint (eLogWarning, "Addressbook: subscriptions.txt not found in datadir"); + else if (!i2p::config::IsDefault("addressbook.subscriptions")) + { + // using config file items + std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs); + std::vector subsList; + boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on); + + for (size_t i = 0; i < subsList.size (); i++) + { + m_Subscriptions.push_back (std::make_shared (*this, subsList[i])); + } + LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); + } } else LogPrint (eLogError, "Addressbook: subscriptions already loaded"); @@ -511,10 +525,11 @@ namespace client { if (!m_IsLoaded) { - // download it from http://i2p-projekt.i2p/hosts.txt + // download it from default subscription LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription."); + std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL); if (!m_DefaultSubscription) - m_DefaultSubscription = std::make_shared(*this, DEFAULT_SUBSCRIPTION_ADDRESS); + m_DefaultSubscription = std::make_shared(*this, defaultSubURL); m_IsDownloading = true; std::thread load_hosts(std::bind (&AddressBookSubscription::CheckUpdates, m_DefaultSubscription)); load_hosts.detach(); // TODO: use join diff --git a/AddressBook.h b/AddressBook.h index 7f559cd0..a1cb3def 100644 --- a/AddressBook.h +++ b/AddressBook.h @@ -18,11 +18,6 @@ namespace i2p { namespace client { -#ifdef MESHNET - const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://i42ofzetmgicvui5sshinfckpijix2udewbam4sjo6x5fbukltia.b32.i2p/hosts.txt"; -#else - const char DEFAULT_SUBSCRIPTION_ADDRESS[] = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt"; -#endif const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) diff --git a/BOB.cpp b/BOB.cpp index 8ffffba6..d68c798f 100644 --- a/BOB.cpp +++ b/BOB.cpp @@ -437,8 +437,11 @@ namespace client void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: getkeys"); - SendReplyOK (m_Keys.ToBase64 ().c_str ()); - } + if (m_Keys.GetPublic ()) // keys are set ? + SendReplyOK (m_Keys.ToBase64 ().c_str ()); + else + SendReplyError ("keys are not set"); + } void BOBCommandSession::GetdestCommandHandler (const char * operand, size_t len) { @@ -501,12 +504,12 @@ namespace client { LogPrint (eLogDebug, "BOB: lookup ", operand); i2p::data::IdentHash ident; - if (!context.GetAddressBook ().GetIdentHash (operand, ident) || !m_CurrentDestination) + if (!context.GetAddressBook ().GetIdentHash (operand, ident)) { SendReplyError ("Address Not found"); return; } - auto localDestination = m_CurrentDestination->GetLocalDestination (); + auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination (); auto leaseSet = localDestination->FindLeaseSet (ident); if (leaseSet) SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ()); @@ -568,10 +571,15 @@ namespace client { std::stringstream s; s << "DATA"; s << " NICKNAME: "; s << m_Nickname; - if (m_CurrentDestination->GetLocalDestination ()->IsReady ()) - s << " STARTING: false RUNNING: true STOPPING: false"; + if (m_CurrentDestination) + { + if (m_CurrentDestination->GetLocalDestination ()->IsReady ()) + s << " STARTING: false RUNNING: true STOPPING: false"; + else + s << " STARTING: true RUNNING: false STOPPING: false"; + } else - s << " STARTING: true RUNNING: false STOPPING: false"; + s << " STARTING: false RUNNING: false STOPPING: false"; s << " KEYS: true"; s << " QUIET: "; s << (m_IsQuiet ? "true":"false"); if (m_InPort) { diff --git a/Config.cpp b/Config.cpp index 33231aa4..924f244b 100644 --- a/Config.cpp +++ b/Config.cpp @@ -49,6 +49,7 @@ namespace config { ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", value()->zero_tokens()->default_value(true), "Enable communication through ipv4") ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") + ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("daemon", value()->zero_tokens()->default_value(false), "Router will go to background after start") ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") ("notransit", value()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup") @@ -150,6 +151,7 @@ namespace config { options_description reseed("Reseed options"); reseed.add_options() + ("reseed.verify", value()->default_value(false), "Verify .su3 signature") ("reseed.file", value()->default_value(""), "Path to .su3 file") #ifdef MESHNET ("reseed.urls", value()->default_value("https://reseed.i2p.rocks:8443/"), "Reseed URLs, separated by comma") @@ -163,19 +165,27 @@ namespace config { "https://i2p.manas.ca:8443/," "https://i2p-0.manas.ca:8443/," "https://reseed.i2p.vzaws.com:8443/," - "https://user.mx24.eu/," "https://download.xxlspeed.com/," - "https://reseed-ru.lngserv.ru/" + "https://reseed-ru.lngserv.ru/," + "https://reseed.atomike.ninja/" ), "Reseed URLs, separated by comma") #endif ; + options_description addressbook("AddressBook options"); + addressbook.add_options() + ("addressbook.defaulturl", value()->default_value( + "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt" + ), "AddressBook subscription URL for initial setup") + ("addressbook.subscriptions", value()->default_value(""), + "AddressBook subscriptions URLs, separated by comma"); + options_description trust("Trust options"); trust.add_options() ("trust.enabled", value()->default_value(false), "enable explicit trust options") ("trust.family", value()->default_value(""), "Router Familiy to trust for first hops") ("trust.hidden", value()->default_value(false), "should we hide our router from other routers?"); - + m_OptionsDesc .add(general) .add(limits) @@ -189,6 +199,7 @@ namespace config { .add(upnp) .add(precomputation) .add(reseed) + .add(addressbook) .add(trust) ; } diff --git a/Datagram.cpp b/Datagram.cpp index b9188864..d0b0737a 100644 --- a/Datagram.cpp +++ b/Datagram.cpp @@ -12,8 +12,10 @@ namespace i2p namespace datagram { DatagramDestination::DatagramDestination (std::shared_ptr owner): - m_Owner (owner.get()), m_Receiver (nullptr) + m_Owner (owner.get()), + m_Receiver (nullptr) { + m_Identity.FromBase64 (owner->GetIdentity()->ToBase64()); } DatagramDestination::~DatagramDestination () @@ -24,16 +26,16 @@ namespace datagram void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort) { auto owner = m_Owner; - auto i = owner->GetIdentity(); - uint8_t buf[MAX_DATAGRAM_SIZE]; - auto identityLen = i->ToBuffer (buf, MAX_DATAGRAM_SIZE); + std::vector v(MAX_DATAGRAM_SIZE); + uint8_t * buf = v.data(); + auto identityLen = m_Identity.ToBuffer (buf, MAX_DATAGRAM_SIZE); uint8_t * signature = buf + identityLen; - auto signatureLen = i->GetSignatureLen (); + auto signatureLen = m_Identity.GetSignatureLen (); uint8_t * buf1 = signature + signatureLen; size_t headerLen = identityLen + signatureLen; memcpy (buf1, payload, len); - if (i->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + if (m_Identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { uint8_t hash[32]; SHA256(buf1, len, hash); @@ -48,7 +50,7 @@ namespace datagram } - void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) + void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len) { i2p::data::IdentityEx identity; size_t identityLen = identity.FromBuffer (buf, len); @@ -93,7 +95,7 @@ namespace datagram uint8_t uncompressed[MAX_DATAGRAM_SIZE]; size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE); if (uncompressedLen) - HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); + HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); } std::shared_ptr DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) @@ -121,7 +123,7 @@ namespace datagram if (m_Sessions.empty ()) return; auto now = i2p::util::GetMillisecondsSinceEpoch(); LogPrint(eLogDebug, "DatagramDestination: clean up sessions"); - std::lock_guard lock(m_SessionsMutex); + std::unique_lock lock(m_SessionsMutex); // for each session ... for (auto it = m_Sessions.begin (); it != m_Sessions.end (); ) { @@ -270,13 +272,16 @@ namespace datagram bool DatagramSession::ShouldUpdateRoutingPath() const { + bool dead = m_RoutingSession == nullptr || m_RoutingSession->GetSharedRoutingPath () == nullptr; auto now = i2p::util::GetMillisecondsSinceEpoch (); // we need to rotate paths becuase the routing path is too old - if (now - m_LastPathChange >= DATAGRAM_SESSION_PATH_SWITCH_INTERVAL) return true; + // if (now - m_LastPathChange >= DATAGRAM_SESSION_PATH_SWITCH_INTERVAL) return true; + // too fast switching paths + if (now - m_LastPathChange < DATAGRAM_SESSION_PATH_MIN_LIFETIME ) return false; // our path looks dead so we need to rotate paths - if (now - m_LastSuccess >= DATAGRAM_SESSION_PATH_TIMEOUT) return true; + if (now - m_LastSuccess >= DATAGRAM_SESSION_PATH_TIMEOUT) return !dead; // if we have a routing session and routing path we don't need to switch paths - return m_RoutingSession != nullptr && m_RoutingSession->GetSharedRoutingPath () != nullptr; + return dead; } @@ -291,7 +296,7 @@ namespace datagram if(currentLease) // if we have a lease return true if it's about to expire otherwise return false return currentLease->ExpiresWithin( DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW, DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE ); // we have no current lease, we should switch - return true; + return currentLease == nullptr; } std::shared_ptr DatagramSession::GetNextRoutingPath() diff --git a/Datagram.h b/Datagram.h index f3aae6f9..dc63cccb 100644 --- a/Datagram.h +++ b/Datagram.h @@ -22,14 +22,15 @@ namespace datagram // milliseconds for max session idle time const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000; // milliseconds for how long we try sticking to a dead routing path before trying to switch - const uint64_t DATAGRAM_SESSION_PATH_TIMEOUT = 5000; + const uint64_t DATAGRAM_SESSION_PATH_TIMEOUT = 10 * 1000; // milliseconds interval a routing path is used before switching - const uint64_t DATAGRAM_SESSION_PATH_SWITCH_INTERVAL = 60 * 1000; + const uint64_t DATAGRAM_SESSION_PATH_SWITCH_INTERVAL = 20 * 60 * 1000; // milliseconds before lease expire should we try switching leases const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW = 10 * 1000; // milliseconds fudge factor for leases handover const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000; - + // milliseconds minimum time between path switches + const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000; class DatagramSession { @@ -133,13 +134,14 @@ namespace datagram std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); - void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); + void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); /** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */ Receiver FindReceiver(uint16_t port); private: i2p::client::ClientDestination * m_Owner; + i2p::data::IdentityEx m_Identity; Receiver m_Receiver; // default std::mutex m_SessionsMutex; std::map > m_Sessions; diff --git a/Destination.cpp b/Destination.cpp index 48717f5f..d400259c 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -171,28 +171,35 @@ namespace client std::shared_ptr LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) { - std::lock_guard lock(m_RemoteLeaseSetsMutex); - auto it = m_RemoteLeaseSets.find (ident); - if (it != m_RemoteLeaseSets.end ()) + std::shared_ptr remoteLS; { - if (!it->second->IsExpired ()) + std::lock_guard lock(m_RemoteLeaseSetsMutex); + auto it = m_RemoteLeaseSets.find (ident); + if (it != m_RemoteLeaseSets.end ()) + remoteLS = it->second; + } + + if (remoteLS) + { + if (!remoteLS->IsExpired ()) { - if (it->second->ExpiresSoon()) + if (remoteLS->ExpiresSoon()) { LogPrint(eLogDebug, "Destination: Lease Set expires soon, updating before expire"); // update now before expiration for smooth handover - RequestDestination(ident, [this, ident] (std::shared_ptr ls) { + auto s = shared_from_this (); + RequestDestination(ident, [s, ident] (std::shared_ptr ls) { if(ls && !ls->IsExpired()) { ls->PopulateLeases(); { - std::lock_guard _lock(m_RemoteLeaseSetsMutex); - m_RemoteLeaseSets[ident] = ls; + std::lock_guard _lock(s->m_RemoteLeaseSetsMutex); + s->m_RemoteLeaseSets[ident] = ls; } } }); } - return it->second; + return remoteLS; } else LogPrint (eLogWarning, "Destination: remote LeaseSet expired"); @@ -203,15 +210,13 @@ namespace client if (ls && !ls->IsExpired ()) { ls->PopulateLeases (); // since we don't store them in netdb - { - std::lock_guard lock(m_RemoteLeaseSetsMutex); - m_RemoteLeaseSets[ident] = ls; - } + std::lock_guard _lock(m_RemoteLeaseSetsMutex); + m_RemoteLeaseSets[ident] = ls; return ls; } } return nullptr; - } + } std::shared_ptr LeaseSetDestination::GetLeaseSet () { diff --git a/I2CP.cpp b/I2CP.cpp index 41f81155..e0139b9f 100644 --- a/I2CP.cpp +++ b/I2CP.cpp @@ -66,12 +66,19 @@ namespace client memcpy (buf + 4, payload, len); msg->len += len + 4; msg->FillI2NPMessageHeader (eI2NPData); + auto s = GetSharedFromThis (); auto remote = FindLeaseSet (ident); if (remote) - GetService ().post (std::bind (&I2CPDestination::SendMsg, GetSharedFromThis (), msg, remote)); + { + GetService ().post ( + [s, msg, remote, nonce]() + { + bool sent = s->SendMsg (msg, remote); + s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); + }); + } else { - auto s = GetSharedFromThis (); RequestDestination (ident, [s, msg, nonce](std::shared_ptr ls) { diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index cbd4c3fc..cdc4fb9b 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -102,7 +102,7 @@ namespace i2p { RAND_bytes ((uint8_t *)&msgID, 4); htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); - htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, I2PD_NET_ID); + htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::context.GetNetID ()); } m->len += DELIVERY_STATUS_SIZE; m->FillI2NPMessageHeader (eI2NPDeliveryStatus); diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index 0c58ba9d..be48b83a 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -559,23 +559,23 @@ namespace client } /** create new udp session */ boost::asio::ip::udp::endpoint ep(m_LocalAddress, 0); - m_Sessions.push_back(new UDPSession(ep, m_LocalDest, m_RemoteEndpoint, ih, localPort, remotePort)); + m_Sessions.push_back(new UDPSession(ep, m_LocalDest, m_RemoteEndpoint, &ih, localPort, remotePort)); return m_Sessions.back(); } UDPSession::UDPSession(boost::asio::ip::udp::endpoint localEndpoint, const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash to, + boost::asio::ip::udp::endpoint endpoint, const i2p::data::IdentHash * to, uint16_t ourPort, uint16_t theirPort) : m_Destination(localDestination->GetDatagramDestination()), m_Service(localDestination->GetService()), IPSocket(localDestination->GetService(), localEndpoint), - Identity(to), SendEndpoint(endpoint), LastActivity(i2p::util::GetMillisecondsSinceEpoch()), LocalPort(ourPort), RemotePort(theirPort) { + memcpy(Identity, to->data(), 32); Receive(); } @@ -592,13 +592,7 @@ namespace client { LogPrint(eLogDebug, "UDPSession: forward ", len, "B from ", FromEndpoint); LastActivity = i2p::util::GetMillisecondsSinceEpoch(); - uint8_t * data = new uint8_t[len]; - memcpy(data, m_Buffer, len); - m_Service.post([&,len, data] () { - m_Destination->SendDatagramTo(data, len, Identity, 0, 0); - delete [] data; - }); - + m_Destination->SendDatagramTo(m_Buffer, len, Identity, 0, 0); Receive(); } else { LogPrint(eLogError, "UDPSession: ", ecode.message()); @@ -727,7 +721,7 @@ namespace client if(m_Session) delete m_Session; boost::asio::ip::udp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 0); - m_Session = new UDPSession(m_LocalEndpoint, m_LocalDest, ep, *m_RemoteIdent, LocalPort, RemotePort); + m_Session = new UDPSession(m_LocalEndpoint, m_LocalDest, ep, m_RemoteIdent, LocalPort, RemotePort); } void I2PUDPClientTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) diff --git a/I2PTunnel.h b/I2PTunnel.h index dce9f812..e6f0e84f 100644 --- a/I2PTunnel.h +++ b/I2PTunnel.h @@ -155,7 +155,7 @@ namespace client UDPSession(boost::asio::ip::udp::endpoint localEndpoint, const std::shared_ptr & localDestination, - boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash ident, + boost::asio::ip::udp::endpoint remote, const i2p::data::IdentHash * ident, uint16_t ourPort, uint16_t theirPort); void HandleReceived(const boost::system::error_code & ecode, std::size_t len); void Receive(); diff --git a/Identity.cpp b/Identity.cpp index 6d37d34e..99da059e 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -35,11 +35,12 @@ namespace data } IdentityEx::IdentityEx (): - m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { } - IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type) + IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type): + m_IsVerifierCreated (false) { memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey)); if (type != SIGNING_KEY_TYPE_DSA_SHA1) @@ -135,19 +136,19 @@ namespace data } IdentityEx::IdentityEx (const uint8_t * buf, size_t len): - m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { FromBuffer (buf, len); } IdentityEx::IdentityEx (const IdentityEx& other): - m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { *this = other; } IdentityEx::IdentityEx (const Identity& standard): - m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { *this = standard; } @@ -173,6 +174,7 @@ namespace data m_ExtendedBuffer = nullptr; m_Verifier = nullptr; + m_IsVerifierCreated = false; return *this; } @@ -187,6 +189,7 @@ namespace data m_ExtendedLen = 0; m_Verifier = nullptr; + m_IsVerifierCreated = false; return *this; } @@ -373,8 +376,17 @@ namespace data void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const { - if (!m_Verifier || !verifier) - m_Verifier.reset (verifier); + if (!m_Verifier) + { + auto created = m_IsVerifierCreated.exchange (true); + if (!created) + m_Verifier.reset (verifier); + else + { + delete verifier; + while (!m_Verifier) ; // spin lock + } + } else delete verifier; } @@ -382,7 +394,8 @@ namespace data void IdentityEx::DropVerifier () const { // TODO: potential race condition with Verify - m_Verifier = nullptr; + m_IsVerifierCreated = false; + m_Verifier = nullptr; } PrivateKeys& PrivateKeys::operator=(const Keys& keys) @@ -457,8 +470,8 @@ namespace data void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const { if (!m_Signer) - CreateSigner(); - m_Signer->Sign (buf, len, signature); + CreateSigner(); + m_Signer->Sign (buf, len, signature); } void PrivateKeys::CreateSigner () const diff --git a/Identity.h b/Identity.h index 8f3e9e9d..49dada48 100644 --- a/Identity.h +++ b/Identity.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "Base.h" #include "Signature.h" @@ -104,6 +105,7 @@ namespace data Identity m_StandardIdentity; IdentHash m_IdentHash; mutable std::unique_ptr m_Verifier; + mutable std::atomic_bool m_IsVerifierCreated; // make sure we don't create twice size_t m_ExtendedLen; uint8_t * m_ExtendedBuffer; }; diff --git a/Makefile.mingw b/Makefile.mingw index 85b6b455..e2dae747 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -37,11 +37,17 @@ ifeq ($(USE_WIN32_APP), yes) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif +# don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) CPU_FLAGS = -maes -DAESNI else CPU_FLAGS = -msse endif +ifeq ($(USE_ASLR),yes) + LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va \ + -Wl,--dynamicbase,--export-all-symbols +endif + obj/%.o : %.rc $(WINDRES) -i $< -o $@ diff --git a/README.md b/README.md index f5ce9624..1fbf6c43 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,26 @@ i2pd ==== -i2pd is a full-featured C++ implementation of -[I2P](https://geti2p.net/en/about/intro) client. +i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client. -I2P (Invisible Internet Project) is anonymous network which works on top of -public Internet. Privacy and anonymity are achieved by strong encryption and -bouncing your traffic through thousands of I2P nodes all around the world. +I2P (Invisible Internet Protocol) is a universal anonymous network layer. +All communications over I2P are anonymous and end-to-end encrypted, participants +don't reveal their real IP addresses. -We are building network which helps people to communicate and share information +I2P client is a software used for building and using anonymous I2P +networks. Such networks are commonly used for anonymous peer-to-peer +applications (filesharing, cryptocurrencies) and anonymous client-server +applications (websites, instant messengers, chat-servers). + +I2P allows people from all around the world to communicate and share information without restrictions. * [Website](http://i2pd.website) * [Documentation](https://i2pd.readthedocs.io/en/latest/) * [Wiki](https://github.com/PurpleI2P/i2pd/wiki) * [Tickets/Issues](https://github.com/PurpleI2P/i2pd/issues) -* [Twitter](https://twitter.com/i2porignal) +* [Specifications](https://geti2p.net/spec) +* [Twitter](https://twitter.com/hashtag/i2pd) Installing ---------- diff --git a/Reseed.cpp b/Reseed.cpp index a51dcad4..d8a265db 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -131,52 +131,64 @@ namespace data s.read (signerID, signerIDLength); // signerID signerID[signerIDLength] = 0; - //try to verify signature - auto it = m_SigningKeys.find (signerID); - if (it != m_SigningKeys.end ()) - { - // TODO: implement all signature types - if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096) + bool verify; i2p::config::GetOption("reseed.verify", verify); + if (verify) + { + //try to verify signature + auto it = m_SigningKeys.find (signerID); + if (it != m_SigningKeys.end ()) { - size_t pos = s.tellg (); - size_t tbsLen = pos + contentLength; - uint8_t * tbs = new uint8_t[tbsLen]; - s.seekg (0, std::ios::beg); - s.read ((char *)tbs, tbsLen); - uint8_t * signature = new uint8_t[signatureLength]; - s.read ((char *)signature, signatureLength); - // RSA-raw + // TODO: implement all signature types + if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096) { - // calculate digest - uint8_t digest[64]; - SHA512 (tbs, tbsLen, digest); - // encrypt signature - BN_CTX * bnctx = BN_CTX_new (); - BIGNUM * s = BN_new (), * n = BN_new (); - BN_bin2bn (signature, signatureLength, s); - BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n); - BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n - uint8_t * enSigBuf = new uint8_t[signatureLength]; - i2p::crypto::bn2buf (s, enSigBuf, signatureLength); - // digest is right aligned - // we can't use RSA_verify due wrong padding in SU3 - if (memcmp (enSigBuf + (signatureLength - 64), digest, 64)) - LogPrint (eLogWarning, "Reseed: SU3 signature verification failed"); - delete[] enSigBuf; - BN_free (s); BN_free (n); - BN_CTX_free (bnctx); - } + size_t pos = s.tellg (); + size_t tbsLen = pos + contentLength; + uint8_t * tbs = new uint8_t[tbsLen]; + s.seekg (0, std::ios::beg); + s.read ((char *)tbs, tbsLen); + uint8_t * signature = new uint8_t[signatureLength]; + s.read ((char *)signature, signatureLength); + // RSA-raw + { + // calculate digest + uint8_t digest[64]; + SHA512 (tbs, tbsLen, digest); + // encrypt signature + BN_CTX * bnctx = BN_CTX_new (); + BIGNUM * s = BN_new (), * n = BN_new (); + BN_bin2bn (signature, signatureLength, s); + BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n); + BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n + uint8_t * enSigBuf = new uint8_t[signatureLength]; + i2p::crypto::bn2buf (s, enSigBuf, signatureLength); + // digest is right aligned + // we can't use RSA_verify due wrong padding in SU3 + if (memcmp (enSigBuf + (signatureLength - 64), digest, 64)) + LogPrint (eLogWarning, "Reseed: SU3 signature verification failed"); + else + verify = false; // verified + delete[] enSigBuf; + BN_free (s); BN_free (n); + BN_CTX_free (bnctx); + } - delete[] signature; - delete[] tbs; - s.seekg (pos, std::ios::beg); + delete[] signature; + delete[] tbs; + s.seekg (pos, std::ios::beg); + } + else + LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported"); } else - LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported"); + LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded"); } - else - LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded"); - + + if (verify) // not verified + { + LogPrint (eLogError, "Reseed: SU3 verification failed"); + return 0; + } + // handle content int numFiles = 0; size_t contentPos = s.tellg (); diff --git a/RouterContext.cpp b/RouterContext.cpp index 6824adb8..b4bbefb6 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -18,7 +18,8 @@ namespace i2p RouterContext::RouterContext (): m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), - m_StartupTime (0), m_Status (eRouterStatusOK), m_Error (eRouterErrorNone) + m_StartupTime (0), m_Status (eRouterStatusOK), m_Error (eRouterErrorNone), + m_NetID (I2PD_NET_ID) { } @@ -76,7 +77,8 @@ namespace i2p } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC - routerInfo.SetProperty ("netId", std::to_string (I2PD_NET_ID)); + i2p::config::GetOption("netid", m_NetID); + routerInfo.SetProperty ("netId", std::to_string (m_NetID)); routerInfo.SetProperty ("router.version", I2P_VERSION); routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); diff --git a/RouterContext.h b/RouterContext.h index b89b3140..7ce310ee 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -58,7 +58,9 @@ namespace i2p void SetStatus (RouterStatus status); RouterError GetError () const { return m_Error; }; void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; - + int GetNetID () const { return m_NetID; }; + void SetNetID (int netID) { m_NetID = netID; }; + void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); @@ -117,6 +119,7 @@ namespace i2p uint32_t m_BandwidthLimit; // allowed bandwidth RouterStatus m_Status; RouterError m_Error; + int m_NetID; std::mutex m_GarlicMutex; }; diff --git a/RouterInfo.cpp b/RouterInfo.cpp index ff08286a..b570d6c2 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -13,6 +13,7 @@ #include "Timestamp.h" #include "Log.h" #include "NetDb.h" +#include "RouterContext.h" #include "RouterInfo.h" namespace i2p @@ -286,7 +287,7 @@ namespace data if (!strcmp (key, "caps")) ExtractCaps (value); // check netId - else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != I2PD_NET_ID) + else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ()) { LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value); m_IsUnreachable = true; @@ -771,7 +772,11 @@ namespace data std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const { +#if (BOOST_VERSION >= 105300) + auto addresses = boost::atomic_load (&m_Addresses); +#else auto addresses = m_Addresses; +#endif for (const auto& address : *addresses) { if (address->transportStyle == s) diff --git a/Tag.h b/Tag.h index 92e2f1a5..30dfa654 100644 --- a/Tag.h +++ b/Tag.h @@ -1,3 +1,6 @@ +#ifndef TAG_H__ +#define TAG_H__ + /* * Copyright (c) 2013-2016, The PurpleI2P Project * @@ -6,92 +9,80 @@ * See full license text in LICENSE file at top of project tree */ -#ifndef TAG_H__ -#define TAG_H__ - -#include /* memcpy */ - +#include +#include #include "Base.h" namespace i2p { namespace data { - template - class Tag + +template +class Tag +{ + BOOST_STATIC_ASSERT_MSG(sz % 8 == 0, "Tag size must be multiple of 8 bytes"); + +public: + + Tag () = default; + Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); } + + bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); } + bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; } + + uint8_t * operator()() { return m_Buf; } + const uint8_t * operator()() const { return m_Buf; } + + operator uint8_t * () { return m_Buf; } + operator const uint8_t * () const { return m_Buf; } + + const uint8_t * data() const { return m_Buf; } + const uint64_t * GetLL () const { return ll; } + + bool IsZero () const { - public: + for (size_t i = 0; i < sz/8; ++i) + if (ll[i]) return false; + return true; + } - Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }; - Tag (const Tag& ) = default; -#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it - Tag (Tag&& ) = default; -#endif - Tag () = default; - - Tag& operator= (const Tag& ) = default; -#ifndef _WIN32 - Tag& operator= (Tag&& ) = default; -#endif - - uint8_t * operator()() { return m_Buf; }; - const uint8_t * operator()() const { return m_Buf; }; - - operator uint8_t * () { return m_Buf; }; - operator const uint8_t * () const { return m_Buf; }; - - const uint64_t * GetLL () const { return ll; }; - - bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; - bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; - - bool IsZero () const - { - for (int i = 0; i < sz/8; i++) - if (ll[i]) return false; - return true; - } - - const uint8_t * data() const { return m_Buf; } - - /** fill with a value */ - void Fill(uint8_t c) - { - memset(m_Buf, c, sz); - } + void Fill(uint8_t c) + { + memset(m_Buf, c, sz); + } - std::string ToBase64 () const - { - char str[sz*2]; - int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); - str[l] = 0; - return std::string (str); - } + std::string ToBase64 () const + { + char str[sz*2]; + size_t l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); + return std::string (str, str + l); + } - std::string ToBase32 () const - { - char str[sz*2]; - int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); - str[l] = 0; - return std::string (str); - } + std::string ToBase32 () const + { + char str[sz*2]; + size_t l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); + return std::string (str, str + l); + } - void FromBase32 (const std::string& s) - { - i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); - } + void FromBase32 (const std::string& s) + { + i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } - void FromBase64 (const std::string& s) - { - i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); - } + void FromBase64 (const std::string& s) + { + i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } - private: +private: - union // 8 bytes alignment - { - uint8_t m_Buf[sz]; - uint64_t ll[sz/8]; - }; + union // 8 bytes aligned + { + uint8_t m_Buf[sz]; + uint64_t ll[sz/8]; }; +}; + } // data } // i2p diff --git a/appveyor.yml b/appveyor.yml index bb81757b..be16e890 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -142,9 +142,9 @@ install: - if not defined msvc ( C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy bash pacman pacman-mirrors msys2-runtime msys2-runtime-devel cmake" && if "%x64%" == "1" ( - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc" + C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc mingw-w64-x86_64-extra-cmake-modules" ) else ( - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-openssl mingw-w64-i686-boost mingw-w64-i686-miniupnpc" + C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-openssl mingw-w64-i686-boost mingw-w64-i686-miniupnpc mingw-w64-i686-extra-cmake-modules" ) ) cache: diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 95f223ef..00048942 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -16,7 +16,8 @@ option(WITH_UPNP "Include support for UPnP client" OFF) option(WITH_PCH "Use precompiled header" OFF) option(WITH_GUI "Include GUI (currently MS Windows only)" ON) option(WITH_MESHNET "Build for cjdns test network" OFF) -option(WITH_ADDRSANITIZER "Build with address sanitizer (linux only)" OFF) +option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF) +option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF) # paths set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) @@ -190,10 +191,22 @@ if (WITH_ADDRSANITIZER) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer" ) set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address" ) else () - error ("MSVC does not support address sanitizer option") + message( SEND_ERROR "MSVC does not support address sanitizer option") endif() endif() +if (WITH_THREADSANITIZER) + if (WITH_ADDRSANITIZER) + message( FATAL_ERROR "thread sanitizer option cannot be combined with address sanitizer") + elseif (NOT MSVC) + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread" ) + set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread" ) + else () + message( SEND_ERROR "MSVC does not support address sanitizer option") + endif() +endif() + + # libraries # TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826 # use imported Threads::Threads instead @@ -347,6 +360,7 @@ message(STATUS " UPnP : ${WITH_UPNP}") message(STATUS " PCH : ${WITH_PCH}") message(STATUS " MESHNET : ${WITH_MESHNET}") message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}") +message(STATUS " THEADSANITIZER : ${WITH_THREADSANITIZER}") message(STATUS "---------------------------------------") #Handle paths nicely diff --git a/contrib/certificates/reseed/atomike_at_mail.i2p.crt b/contrib/certificates/reseed/atomike_at_mail.i2p.crt new file mode 100644 index 00000000..1e724f00 --- /dev/null +++ b/contrib/certificates/reseed/atomike_at_mail.i2p.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +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 +cGpnw4a2u9sHZIUNHzoGq32+7UWXsBI5Ow== +-----END CERTIFICATE----- diff --git a/docs/build_notes_windows.md b/docs/build_notes_windows.md index a217d80d..2b4b96b6 100644 --- a/docs/build_notes_windows.md +++ b/docs/build_notes_windows.md @@ -87,7 +87,19 @@ You should be able to run ./i2pd . If you need to start from the new shell, consider starting *MinGW-w64 Win32 Shell* instead of *MSYS2 Shell* as it adds`/minw32/bin` to the PATH. +### UPnP +You can install it through the MSYS2 +and build with USE_UPNP key. +```bash +pacman -S mingw-w64-i686-miniupnpc +make USE_UPNP=yes +``` +or +```bash +pacman -S mingw-w64-x86_64-miniupnpc +make USE_UPNP=yes +``` Using Visual Studio ------------------- @@ -160,20 +172,7 @@ port. You'd want to have include headers around to build i2pd with support for this. Unpack client source code in a sibling folder, e.g. C:\dev\miniupnpc . You may want to remove version number from folder name included in downloaded archive. - -You can also install it through the MSYS2 -and build with USE_UPNP key. - -```bash -pacman -S mingw-w64-i686-miniupnpc -make USE_UPNP=yes -``` -or -```bash -pacman -S mingw-x86_64-miniupnpc -make USE_UPNP=yes -``` - + ### Creating Visual Studio project Start CMake GUI, navigate to i2pd directory, choose building directory, e.g. ./out, and configure options. diff --git a/docs/configuration.md b/docs/configuration.md index 31082dc2..49d8c98d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -25,6 +25,7 @@ If you are upgrading your very old router (< 2.3.0) see also [this](config_opts_ * --floodfill - Router will be floodfill. false by default * --bandwidth= - Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000) * --family= - Name of a family, router belongs to +* --netid= - Network ID, router belongs to. Main I2P is 2. Windows-specific options: @@ -72,8 +73,11 @@ All options below still possible in cmdline, but better write it in config file: * --upnp.name= - Name i2pd appears in UPnP forwardings list. I2Pd by default * --precomputation.elgamal= - Use ElGamal precomputated tables. false for x64 and true for other platforms by default -* --reseed.file - Full path to SU3 file to reseed from -* --reseed.urls - Reseed URLs, separated by comma +* --reseed.verify= - Request SU3 signature verification +* --reseed.file= - Full path to SU3 file to reseed from +* --reseed.urls= - Reseed URLs, separated by comma +* --addressbook.defaulturl= - AddressBook subscription URL for initial setup +* --addressbook.subscriptions= - AddressBook subscriptions URLs, separated by comma * --limits.transittunnels= - Override maximum number of transit tunnels. 2500 by default diff --git a/docs/i2pd.conf b/docs/i2pd.conf index 94287bd0..9ade3663 100644 --- a/docs/i2pd.conf +++ b/docs/i2pd.conf @@ -92,8 +92,18 @@ ipv6 = false # name = I2Pd [reseed] -## Path to reseed .su3 file (if ) -# file = +## URLs to request reseed data from, separated by comma +## Default: "mainline" I2P Network reseeds +# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ +## Path to reseed data file (.su3) for manual reseeding +# file = /path/to/i2pseeds.su3 + +[addressbook] +## AddressBook subscription URL for initial setup +## Default: inr.i2p at "mainline" I2P Network +# defaulturl = http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt +## Optional subscriptions URLs, separated by comma +# subscriptions = http://inr.i2p/export/alive-hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt [http] ## Uncomment and set to 'false' to disable Web Console diff --git a/docs/index.rst b/docs/index.rst index 5507b075..8cfddb24 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -32,7 +32,9 @@ Contents: build_requirements build_notes_unix build_notes_windows + build_notes_cross build_notes_android + build_notes_ios configuration family usage