Browse Source

Merge pull request #743 from PurpleI2P/openssl

2.11.0
pull/63/merge
orignal 8 years ago committed by GitHub
parent
commit
fc08d15a79
  1. 2
      AddressBook.cpp
  2. 69
      BloomFilter.cpp
  3. 31
      BloomFilter.h
  4. 23
      ChangeLog
  5. 2
      Config.cpp
  6. 58
      Crypto.cpp
  7. 13
      Crypto.h
  8. 334
      Datagram.cpp
  9. 60
      Datagram.h
  10. 7
      Destination.cpp
  11. 10
      Garlic.cpp
  12. 2
      Garlic.h
  13. 50
      HTTPServer.cpp
  14. 18
      HTTPServer.h
  15. 18
      I2PTunnel.cpp
  16. 14
      Identity.cpp
  17. 2
      LeaseSet.cpp
  18. 1
      Makefile
  19. 9
      Makefile.linux
  20. 8
      Makefile.mingw
  21. 13
      Makefile.osx
  22. 39
      NetDb.cpp
  23. 2
      NetDb.h
  24. 44
      RouterInfo.cpp
  25. 107
      SAM.cpp
  26. 13
      SAM.h
  27. 2
      SSUSession.cpp
  28. 9
      TunnelEndpoint.cpp
  29. 1
      TunnelEndpoint.h
  30. 2
      Win32/installer.iss
  31. 2
      android/AndroidManifest.xml
  32. 1
      android/jni/Android.mk
  33. 1
      build/CMakeLists.txt
  34. 12
      debian/changelog
  35. 6
      debian/patches/01-tune-build-opts.patch
  36. 2
      filelist.mk
  37. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  38. 5
      qt/i2pd_qt/i2pd_qt.pro
  39. 6
      version.h

2
AddressBook.cpp

@ -842,7 +842,7 @@ namespace client
else else
memset (response + 8, 0, 32); // not found memset (response + 8, 0, 32); // not found
memset (response + 40, 0, 4); // set expiration time to zero memset (response + 40, 0, 4); // set expiration time to zero
m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 44, from.GetIdentHash (), toPort, fromPort); m_LocalDestination->GetDatagramDestination ()->SendDatagramTo (response, 44, from.GetIdentHash(), toPort, fromPort);
} }
void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident) void AddressResolver::AddAddress (const std::string& name, const i2p::data::IdentHash& ident)

69
BloomFilter.cpp

@ -0,0 +1,69 @@
#include "BloomFilter.h"
#include "I2PEndian.h"
#include <array>
#include <openssl/sha.h>
namespace i2p
{
namespace util
{
/** @brief decaying bloom filter implementation */
class DecayingBloomFilter : public IBloomFilter
{
public:
DecayingBloomFilter(const std::size_t size)
{
m_Size = size;
m_Data = new uint8_t[size];
}
/** @brief implements IBloomFilter::~IBloomFilter */
~DecayingBloomFilter()
{
delete [] m_Data;
}
/** @brief implements IBloomFilter::Add */
bool Add(const uint8_t * data, std::size_t len)
{
std::size_t idx;
uint8_t mask;
Get(data, len, idx, mask);
if(m_Data[idx] & mask) return false; // filter hit
m_Data[idx] |= mask;
return true;
}
/** @brief implements IBloomFilter::Decay */
void Decay()
{
// reset bloom filter buffer
memset(m_Data, 0, m_Size);
}
private:
/** @brief get bit index for for data */
void Get(const uint8_t * data, std::size_t len, std::size_t & idx, uint8_t & bm)
{
bm = 1;
uint8_t digest[32];
// TODO: use blake2 because it's faster
SHA256(data, len, digest);
uint64_t i = buf64toh(digest);
idx = i % m_Size;
bm <<= (i % 8);
}
uint8_t * m_Data;
std::size_t m_Size;
};
BloomFilterPtr BloomFilter(std::size_t capacity)
{
return std::make_shared<DecayingBloomFilter>(capacity);
}
}
}

31
BloomFilter.h

@ -0,0 +1,31 @@
#ifndef BLOOM_FILTER_H_
#define BLOOM_FILTER_H_
#include <memory>
#include <cstdint>
namespace i2p
{
namespace util
{
/** @brief interface for bloom filter */
struct IBloomFilter
{
/** @brief destructor */
virtual ~IBloomFilter() {};
/** @brief add entry to bloom filter, return false if filter hit otherwise return true */
virtual bool Add(const uint8_t * data, std::size_t len) = 0;
/** @brief optionally decay old entries */
virtual void Decay() = 0;
};
typedef std::shared_ptr<IBloomFilter> BloomFilterPtr;
/** @brief create bloom filter */
BloomFilterPtr BloomFilter(std::size_t capacity = 1024 * 8);
}
}
#endif

23
ChangeLog

@ -1,6 +1,29 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.11.0] - 2016-12-18
### Added
- Websockets support
- Reseed through a floodfill
- Tunnel configuration for HTTP and SOCKS proxy
- Zero-hops tunnels for destinations
- Multiple acceptors for SAM
### Changed
- Reseed servers list
- DHT uses AVX if applicable
- New logo
- LeaseSet lookups
### Fixed
- HTTP Proxy connection reset for Windows
- Crash upon SAM session termination
- Can't connect to a destination for a longer time after restart
- Mass packet loss for UDP tunnels
## [2.10.2] - 2016-12-04
### Fixed
- Fixes UPnP discovery bug, producing excessive CPU usage
- Fixes sudden SSU thread stop for Windows.
## [2.10.1] - 2016-11-07 ## [2.10.1] - 2016-11-07
### Fixed ### Fixed
- Fixed some performance issues for Windows and Android - Fixed some performance issues for Windows and Android

2
Config.cpp

@ -171,7 +171,7 @@ namespace config {
"https://i2p.mooo.com/netDb/," "https://i2p.mooo.com/netDb/,"
"https://netdb.i2p2.no/," "https://netdb.i2p2.no/,"
"https://us.reseed.i2p2.no:444/," "https://us.reseed.i2p2.no:444/,"
"https://uk.reseed.i2p2.no:444/," // "https://uk.reseed.i2p2.no:444/," // mamoth's shit
"https://i2p-0.manas.ca:8443/," "https://i2p-0.manas.ca:8443/,"
"https://reseed.i2p.vzaws.com:8443/," "https://reseed.i2p.vzaws.com:8443/,"
"https://download.xxlspeed.com/," "https://download.xxlspeed.com/,"

58
Crypto.cpp

@ -387,12 +387,38 @@ namespace crypto
const uint64_t IPAD = 0x3636363636363636; const uint64_t IPAD = 0x3636363636363636;
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
#if defined(__AVX__)
static const uint64_t ipads[] = { IPAD, IPAD, IPAD, IPAD };
static const uint64_t opads[] = { OPAD, OPAD, OPAD, OPAD };
#endif
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest) void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
// key is 32 bytes // key is 32 bytes
// digest is 16 bytes // digest is 16 bytes
// block size is 64 bytes // block size is 64 bytes
{ {
uint64_t buf[256]; uint64_t buf[256];
uint64_t hash[12]; // 96 bytes
#if defined(__AVX__) // for AVX
__asm__
(
"vmovups %[key], %%ymm0 \n"
"vmovups %[ipad], %%ymm1 \n"
"vmovups %%ymm1, 32(%[buf]) \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, (%[buf]) \n"
"vmovups %[opad], %%ymm1 \n"
"vmovups %%ymm1, 32(%[hash]) \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, (%[hash]) \n"
"vzeroall \n" // end of AVX
"movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes
:
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
[buf]"r"(buf), [hash]"r"(hash)
: "memory", "%xmm0" // TODO: change to %ymm0 later
);
#else
// ikeypad // ikeypad
buf[0] = key.GetLL ()[0] ^ IPAD; buf[0] = key.GetLL ()[0] ^ IPAD;
buf[1] = key.GetLL ()[1] ^ IPAD; buf[1] = key.GetLL ()[1] ^ IPAD;
@ -402,28 +428,26 @@ namespace crypto
buf[5] = IPAD; buf[5] = IPAD;
buf[6] = IPAD; buf[6] = IPAD;
buf[7] = IPAD; buf[7] = IPAD;
// okeypad
hash[0] = key.GetLL ()[0] ^ OPAD;
hash[1] = key.GetLL ()[1] ^ OPAD;
hash[2] = key.GetLL ()[2] ^ OPAD;
hash[3] = key.GetLL ()[3] ^ OPAD;
hash[4] = OPAD;
hash[5] = OPAD;
hash[6] = OPAD;
hash[7] = OPAD;
// fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
memset (hash + 10, 0, 16);
#endif
// concatenate with msg // concatenate with msg
memcpy (buf + 8, msg, len); memcpy (buf + 8, msg, len);
// calculate first hash // calculate first hash
uint8_t hash[16]; // MD5 MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
MD5((uint8_t *)buf, len + 64, hash);
// okeypad
buf[0] = key.GetLL ()[0] ^ OPAD;
buf[1] = key.GetLL ()[1] ^ OPAD;
buf[2] = key.GetLL ()[2] ^ OPAD;
buf[3] = key.GetLL ()[3] ^ OPAD;
buf[4] = OPAD;
buf[5] = OPAD;
buf[6] = OPAD;
buf[7] = OPAD;
// copy first hash after okeypad
memcpy (buf + 8, hash, 16);
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
memset (buf + 10, 0, 16);
// calculate digest // calculate digest
MD5((uint8_t *)buf, 96, digest); MD5((uint8_t *)hash, 96, digest);
} }
// AES // AES

13
Crypto.h

@ -76,7 +76,18 @@ namespace crypto
void operator^=(const ChipherBlock& other) // XOR void operator^=(const ChipherBlock& other) // XOR
{ {
#if defined(__x86_64__) || defined(__SSE__) // for Intel x84 or with SSE #if defined(__AVX__) // AVX
__asm__
(
"vmovups (%[buf]), %%xmm0 \n"
"vmovups (%[other]), %%xmm1 \n"
"vxorps %%xmm0, %%xmm1, %%xmm0 \n"
"vmovups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory"
);
#elif defined(__SSE__) // SSE
__asm__ __asm__
( (
"movups (%[buf]), %%xmm0 \n" "movups (%[buf]), %%xmm0 \n"

334
Datagram.cpp

@ -23,7 +23,7 @@ namespace datagram
m_Sessions.clear(); m_Sessions.clear();
} }
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort) void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
{ {
auto owner = m_Owner; auto owner = m_Owner;
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE); std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
@ -45,8 +45,7 @@ namespace datagram
owner->Sign (buf1, len, signature); owner->Sign (buf1, len, signature);
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort); auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
auto session = ObtainSession(ident); ObtainSession(identity)->SendMsg(msg);
session->SendMsg(msg);
} }
@ -69,6 +68,8 @@ namespace datagram
if (verified) if (verified)
{ {
auto h = identity.GetIdentHash();
ObtainSession(h)->Ack();
auto r = FindReceiver(toPort); auto r = FindReceiver(toPort);
if(r) if(r)
r(identity, fromPort, toPort, buf + headerLen, len -headerLen); r(identity, fromPort, toPort, buf + headerLen, len -headerLen);
@ -138,15 +139,15 @@ namespace datagram
} }
} }
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & ident) std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity)
{ {
std::shared_ptr<DatagramSession> session = nullptr; std::shared_ptr<DatagramSession> session = nullptr;
std::lock_guard<std::mutex> lock(m_SessionsMutex); std::lock_guard<std::mutex> lock(m_SessionsMutex);
auto itr = m_Sessions.find(ident); auto itr = m_Sessions.find(identity);
if (itr == m_Sessions.end()) { if (itr == m_Sessions.end()) {
// not found, create new session // not found, create new session
session = std::make_shared<DatagramSession>(m_Owner, ident); session = std::make_shared<DatagramSession>(m_Owner, identity);
m_Sessions[ident] = session; m_Sessions[identity] = session;
} else { } else {
session = itr->second; session = itr->second;
} }
@ -166,11 +167,11 @@ namespace datagram
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination, DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
const i2p::data::IdentHash & remoteIdent) : const i2p::data::IdentHash & remoteIdent) :
m_LocalDestination(localDestination), m_LocalDestination(localDestination),
m_RemoteIdentity(remoteIdent), m_RemoteIdent(remoteIdent),
m_LastUse(i2p::util::GetMillisecondsSinceEpoch ()), m_SendQueueTimer(localDestination->GetService())
m_LastPathChange(0),
m_LastSuccess(0)
{ {
m_LastUse = i2p::util::GetMillisecondsSinceEpoch ();
ScheduleFlushSendQueue();
} }
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg) void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg)
@ -184,262 +185,149 @@ namespace datagram
DatagramSession::Info DatagramSession::GetSessionInfo() const DatagramSession::Info DatagramSession::GetSessionInfo() const
{ {
if(!m_RoutingSession) if(!m_RoutingSession)
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
auto routingPath = m_RoutingSession->GetSharedRoutingPath(); auto routingPath = m_RoutingSession->GetSharedRoutingPath();
if (!routingPath) if (!routingPath)
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
auto lease = routingPath->remoteLease; auto lease = routingPath->remoteLease;
auto tunnel = routingPath->outboundTunnel; auto tunnel = routingPath->outboundTunnel;
if(lease) if(lease)
{ {
if(tunnel) if(tunnel)
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse, m_LastSuccess); return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse);
else else
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse, m_LastSuccess); return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse);
} }
else if(tunnel) else if(tunnel)
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse, m_LastSuccess); return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse);
else else
return DatagramSession::Info(nullptr, nullptr, m_LastUse, m_LastSuccess); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
} }
void DatagramSession::HandleSend(std::shared_ptr<I2NPMessage> msg) void DatagramSession::Ack()
{
if(!m_RoutingSession)
{
// try to get one
if(m_RemoteLeaseSet) m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
else
{
UpdateLeaseSet(msg);
return;
}
}
// do we have a routing session?
if(m_RoutingSession)
{
// should we switch paths?
if(ShouldUpdateRoutingPath ())
{ {
LogPrint(eLogDebug, "DatagramSession: try getting new routing path"); m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
// try switching paths auto path = GetSharedRoutingPath();
auto path = GetNextRoutingPath();
if(path) if(path)
UpdateRoutingPath (path); path->updateTime = i2p::util::GetSecondsSinceEpoch ();
else
ResetRoutingPath();
} }
auto routingPath = m_RoutingSession->GetSharedRoutingPath ();
// make sure we have a routing path std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
if (routingPath)
{
auto outboundTunnel = routingPath->outboundTunnel;
if (outboundTunnel)
{
if(outboundTunnel->IsEstablished())
{ {
m_LastSuccess = i2p::util::GetMillisecondsSinceEpoch (); if(!m_RoutingSession) {
// we have a routing path and routing session and the outbound tunnel we are using is good if(!m_RemoteLeaseSet) {
// wrap message with routing session and send down routing path's outbound tunnel wrapped for the IBGW m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
auto m = m_RoutingSession->WrapSingleMessage(msg);
routingPath->outboundTunnel->SendTunnelDataMsg({i2p::tunnel::TunnelMessageBlock{
i2p::tunnel::eDeliveryTypeTunnel,
routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID,
m
}});
return;
} }
if(!m_RemoteLeaseSet) {
// no remote lease set
m_LocalDestination->RequestDestination(m_RemoteIdent, std::bind(&DatagramSession::HandleLeaseSetUpdated, this, std::placeholders::_1));
return nullptr;
} }
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
} }
auto path = m_RoutingSession->GetSharedRoutingPath();
if(path) {
if (m_CurrentOutboundTunnel && !m_CurrentOutboundTunnel->IsEstablished()) {
// bad outbound tunnel, switch outbound tunnel
m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
path->outboundTunnel = m_CurrentOutboundTunnel;
}
if(m_CurrentRemoteLease && ! m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
// bad lease, switch to next one
if(m_RemoteLeaseSet) {
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&](const i2p::data::Lease& l) -> bool {
return l.tunnelGateway == m_CurrentRemoteLease->tunnelGateway || l.endDate <= m_CurrentRemoteLease->endDate;
});
auto sz = ls.size();
if (sz) {
auto idx = rand() % sz;
m_CurrentRemoteLease = ls[idx];
} }
auto now = i2p::util::GetMillisecondsSinceEpoch (); } else {
// if this path looks dead reset the routing path since we didn't seem to be able to get a path in time // no remote lease set?
if (m_LastPathChange && now - m_LastPathChange >= DATAGRAM_SESSION_PATH_TIMEOUT ) ResetRoutingPath(); LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ", m_RemoteIdent.ToBase32());
UpdateLeaseSet(msg);
} }
path->remoteLease = m_CurrentRemoteLease;
void DatagramSession::UpdateRoutingPath(const std::shared_ptr<i2p::garlic::GarlicRoutingPath> & path)
{
if(m_RoutingSession == nullptr && m_RemoteLeaseSet)
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
if(!m_RoutingSession) return;
// set routing path and update time we last updated the routing path
m_RoutingSession->SetSharedRoutingPath (path);
m_LastPathChange = i2p::util::GetMillisecondsSinceEpoch ();
} }
} else {
bool DatagramSession::ShouldUpdateRoutingPath() const // no current path, make one
{ path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
bool dead = m_RoutingSession == nullptr || m_RoutingSession->GetSharedRoutingPath () == nullptr; // switch outbound tunnel if bad
auto now = i2p::util::GetMillisecondsSinceEpoch (); if(m_CurrentOutboundTunnel == nullptr || ! m_CurrentOutboundTunnel->IsEstablished()) {
// we need to rotate paths becuase the routing path is too old m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
// if (now - m_LastPathChange >= DATAGRAM_SESSION_PATH_SWITCH_INTERVAL) return true; }
// too fast switching paths // switch lease if bad
if (now - m_LastPathChange < DATAGRAM_SESSION_PATH_MIN_LIFETIME ) return false; if(m_CurrentRemoteLease == nullptr || m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
// our path looks dead so we need to rotate paths if(!m_RemoteLeaseSet) {
if (now - m_LastSuccess >= DATAGRAM_SESSION_PATH_TIMEOUT) return !dead; m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
// if we have a routing session and routing path we don't need to switch paths }
return dead; if(m_RemoteLeaseSet) {
// pick random next good lease
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&] (const i2p::data::Lease & l) -> bool {
if(m_CurrentRemoteLease)
return l.tunnelGateway == m_CurrentRemoteLease->tunnelGateway;
return false;
});
auto sz = ls.size();
if(sz) {
auto idx = rand() % sz;
m_CurrentRemoteLease = ls[idx];
} }
} else {
// no remote lease set currently, bail
bool DatagramSession::ShouldSwitchLease() const LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
{ return nullptr;
std::shared_ptr<i2p::garlic::GarlicRoutingPath> routingPath = nullptr;
std::shared_ptr<const i2p::data::Lease> currentLease = nullptr;
if(m_RoutingSession)
routingPath = m_RoutingSession->GetSharedRoutingPath ();
if(routingPath)
currentLease = routingPath->remoteLease;
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 currentLease == nullptr;
} }
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetNextRoutingPath()
{
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel = nullptr;
std::shared_ptr<i2p::garlic::GarlicRoutingPath> routingPath = nullptr;
// get existing routing path if we have one
if(m_RoutingSession)
routingPath = m_RoutingSession->GetSharedRoutingPath();
// do we have an existing outbound tunnel and routing path?
if(routingPath && routingPath->outboundTunnel)
{
// is the outbound tunnel we are using good?
if (routingPath->outboundTunnel->IsEstablished())
{
// ya so let's stick with it
outboundTunnel = routingPath->outboundTunnel;
} }
else path->outboundTunnel = m_CurrentOutboundTunnel;
outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(routingPath->outboundTunnel); // no so we'll switch outbound tunnels path->remoteLease = m_CurrentRemoteLease;
m_RoutingSession->SetSharedRoutingPath(path);
} }
// do we have an outbound tunnel that works already ? return path;
if(!outboundTunnel)
outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(); // no, let's get a new outbound tunnel as we probably just started
if(outboundTunnel)
{
std::shared_ptr<const i2p::data::Lease> lease = nullptr;
// should we switch leases ?
if (ShouldSwitchLease ())
{
// yes, get next available lease
lease = GetNextLease();
}
else if (routingPath)
{
if(routingPath->remoteLease)
{
if(routingPath->remoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW, DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE))
lease = GetNextLease();
else
lease = routingPath->remoteLease;
}
} }
else
lease = GetNextLease(); void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)
if(lease)
{ {
// we have a valid lease to use and an outbound tunnel if(!ls) return;
// create new routing path // only update lease set if found and newer than previous lease set
uint32_t now = i2p::util::GetSecondsSinceEpoch(); uint64_t oldExpire = 0;
routingPath = std::make_shared<i2p::garlic::GarlicRoutingPath>(i2p::garlic::GarlicRoutingPath{ if(m_RemoteLeaseSet) oldExpire = m_RemoteLeaseSet->GetExpirationTime();
outboundTunnel, if(ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
lease,
0,
now,
0
});
}
else // we don't have a new routing path to give
routingPath = nullptr;
}
return routingPath;
} }
void DatagramSession::ResetRoutingPath() void DatagramSession::HandleSend(std::shared_ptr<I2NPMessage> msg)
{
if(m_RoutingSession)
{
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
if(routingPath && routingPath->remoteLease) // we have a remote lease already specified and a routing path
{ {
// get outbound tunnel on this path m_SendQueue.push_back(msg);
auto outboundTunnel = routingPath->outboundTunnel; // flush queue right away if full
// is this outbound tunnel there and established if(m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE) FlushSendQueue();
if (outboundTunnel && outboundTunnel->IsEstablished())
m_InvalidIBGW.push_back(routingPath->remoteLease->tunnelGateway); // yes, let's mark remote lease as dead because the outbound tunnel seems fine
}
// reset the routing path
UpdateRoutingPath(nullptr);
}
} }
std::shared_ptr<const i2p::data::Lease> DatagramSession::GetNextLease() void DatagramSession::FlushSendQueue ()
{ {
auto now = i2p::util::GetMillisecondsSinceEpoch ();
std::shared_ptr<const i2p::data::Lease> next = nullptr; std::vector<i2p::tunnel::TunnelMessageBlock> send;
if(m_RemoteLeaseSet) auto routingPath = GetSharedRoutingPath();
{ // if we don't have a routing path we will drop all queued messages
std::vector<i2p::data::IdentHash> exclude; if(routingPath && routingPath->outboundTunnel && routingPath->remoteLease)
for(const auto & ident : m_InvalidIBGW)
exclude.push_back(ident);
// find get all leases that are not in our ban list and are not going to expire within our lease set handover window + fudge
auto leases = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding( [&exclude, now] (const i2p::data::Lease & l) -> bool {
if(exclude.size())
{ {
auto end = std::end(exclude); for (const auto & msg : m_SendQueue)
return std::find_if(exclude.begin(), end, [l, now] ( const i2p::data::IdentHash & ident) -> bool {
return ident == l.tunnelGateway;
}) != end;
}
else
return false;
});
if(leases.size())
{ {
// pick random valid next lease auto m = m_RoutingSession->WrapSingleMessage(msg);
uint32_t idx = rand() % leases.size(); send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m});
next = leases[idx];
}
else
LogPrint(eLogWarning, "DatagramDestination: no leases to use");
} }
return next; routingPath->outboundTunnel->SendTunnelDataMsg(send);
} }
m_SendQueue.clear();
void DatagramSession::UpdateLeaseSet(std::shared_ptr<I2NPMessage> msg) ScheduleFlushSendQueue();
{
LogPrint(eLogInfo, "DatagramSession: updating lease set");
m_LocalDestination->RequestDestination(m_RemoteIdentity, std::bind(&DatagramSession::HandleGotLeaseSet, this, std::placeholders::_1, msg));
} }
void DatagramSession::HandleGotLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> remoteIdent, std::shared_ptr<I2NPMessage> msg) void DatagramSession::ScheduleFlushSendQueue()
{
if(remoteIdent)
{ {
// update routing session boost::posix_time::milliseconds dlt(100);
if(m_RoutingSession) m_SendQueueTimer.expires_from_now(dlt);
m_RoutingSession = nullptr; m_SendQueueTimer.async_wait([&](const boost::system::error_code & ec) { if(ec) return; FlushSendQueue(); });
m_RoutingSession = m_LocalDestination->GetRoutingSession(remoteIdent, true);
// clear invalid IBGW as we have a new lease set
m_InvalidIBGW.clear();
m_RemoteLeaseSet = remoteIdent;
// update routing path
auto path = GetNextRoutingPath();
if (path)
UpdateRoutingPath(path);
else
ResetRoutingPath();
// send the message that was queued if it was provided
if(msg)
HandleSend(msg);
}
} }
} }
} }

60
Datagram.h

@ -31,6 +31,8 @@ namespace datagram
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000; const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000;
// milliseconds minimum time between path switches // milliseconds minimum time between path switches
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000; const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
// max 64 messages buffered in send queue for each datagram session
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
class DatagramSession class DatagramSession
{ {
@ -38,22 +40,24 @@ namespace datagram
DatagramSession(i2p::client::ClientDestination * localDestination, DatagramSession(i2p::client::ClientDestination * localDestination,
const i2p::data::IdentHash & remoteIdent); const i2p::data::IdentHash & remoteIdent);
/** @brief ack the garlic routing path */
void Ack();
/** send an i2np message to remote endpoint for this session */ /** send an i2np message to remote endpoint for this session */
void SendMsg(std::shared_ptr<I2NPMessage> msg); void SendMsg(std::shared_ptr<I2NPMessage> msg);
/** get the last time in milliseconds for when we used this datagram session */ /** get the last time in milliseconds for when we used this datagram session */
uint64_t LastActivity() const { return m_LastUse; } uint64_t LastActivity() const { return m_LastUse; }
/** get the last time in milliseconds when we successfully sent data */
uint64_t LastSuccess() const { return m_LastSuccess; }
struct Info struct Info
{ {
std::shared_ptr<const i2p::data::IdentHash> IBGW; std::shared_ptr<const i2p::data::IdentHash> IBGW;
std::shared_ptr<const i2p::data::IdentHash> OBEP; std::shared_ptr<const i2p::data::IdentHash> OBEP;
const uint64_t activity; const uint64_t activity;
const uint64_t success;
Info() : IBGW(nullptr), OBEP(nullptr), activity(0), success(0) {} Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a, const uint64_t s) : Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) :
activity(a), activity(a) {
success(s) {
if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw); if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
else IBGW = nullptr; else IBGW = nullptr;
if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep); if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
@ -63,44 +67,28 @@ namespace datagram
Info GetSessionInfo() const; Info GetSessionInfo() const;
private: private:
/** update our routing path we are using, mark that we have changed paths */ void FlushSendQueue();
void UpdateRoutingPath(const std::shared_ptr<i2p::garlic::GarlicRoutingPath> & path); void ScheduleFlushSendQueue();
/** return true if we should switch routing paths because of path lifetime or timeout otherwise false */
bool ShouldUpdateRoutingPath() const;
/** return true if we should switch the lease for out routing path otherwise return false */ void HandleSend(std::shared_ptr<I2NPMessage> msg);
bool ShouldSwitchLease() const;
/** get next usable routing path, try reusing outbound tunnels */
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetNextRoutingPath();
/**
* mark current routing path as invalid and clear it
* if the outbound tunnel we were using was okay don't use the IBGW in the routing path's lease next time
*/
void ResetRoutingPath();
/** get next usable lease, does not fetch or update if expired or have no lease set */ std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
std::shared_ptr<const i2p::data::Lease> GetNextLease();
void HandleSend(std::shared_ptr<I2NPMessage> msg); void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
void HandleGotLeaseSet(std::shared_ptr<const i2p::data::LeaseSet> remoteIdent,
std::shared_ptr<I2NPMessage> msg);
void UpdateLeaseSet(std::shared_ptr<I2NPMessage> msg=nullptr);
private: private:
i2p::client::ClientDestination * m_LocalDestination; i2p::client::ClientDestination * m_LocalDestination;
i2p::data::IdentHash m_RemoteIdentity; i2p::data::IdentHash m_RemoteIdent;
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
// Ident hash of IBGW that are invalid
std::vector<i2p::data::IdentHash> m_InvalidIBGW;
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet; std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
boost::asio::deadline_timer m_SendQueueTimer;
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
uint64_t m_LastUse; uint64_t m_LastUse;
uint64_t m_LastPathChange;
uint64_t m_LastSuccess;
}; };
const size_t MAX_DATAGRAM_SIZE = 32768; const size_t MAX_DATAGRAM_SIZE = 32768;
@ -114,7 +102,7 @@ namespace datagram
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner); DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
~DatagramDestination (); ~DatagramDestination ();
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };

7
Destination.cpp

@ -544,12 +544,15 @@ namespace client
else // duplicate else // duplicate
{ {
LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already"); LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
// TODO: implement it properly
//ret.first->second->requestComplete.push_back (requestComplete);
if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT)
{
// something went wrong
m_LeaseSetRequests.erase (ret.first); m_LeaseSetRequests.erase (ret.first);
if (requestComplete) requestComplete (nullptr); if (requestComplete) requestComplete (nullptr);
} }
else if (requestComplete)
ret.first->second->requestComplete.push_back (requestComplete);
}
} }
else else
{ {

10
Garlic.cpp

@ -20,8 +20,7 @@ namespace garlic
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet): std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
m_Owner (owner), m_Destination (destination), m_NumTags (numTags), m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
m_LeaseSetUpdateMsgID (0), m_LeaseSetUpdateMsgID (0)
m_ElGamalEncryption (new i2p::crypto::ElGamalEncryption (destination->GetEncryptionPublicKey ()))
{ {
// create new session tags and session key // create new session tags and session key
RAND_bytes (m_SessionKey, 32); RAND_bytes (m_SessionKey, 32);
@ -29,7 +28,7 @@ namespace garlic
} }
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
{ {
memcpy (m_SessionKey, sessionKey, 32); memcpy (m_SessionKey, sessionKey, 32);
m_Encryption.SetKey (m_SessionKey); m_Encryption.SetKey (m_SessionKey);
@ -188,7 +187,8 @@ namespace garlic
RAND_bytes (elGamal.preIV, 32); // Pre-IV RAND_bytes (elGamal.preIV, 32); // Pre-IV
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv); SHA256(elGamal.preIV, 32, iv);
m_ElGamalEncryption->Encrypt ((uint8_t *)&elGamal, buf, true); i2p::crypto::ElGamalEncryption elGamalEncryption (m_Destination->GetEncryptionPublicKey ());
elGamalEncryption.Encrypt ((uint8_t *)&elGamal, buf, true);
m_Encryption.SetIV (iv); m_Encryption.SetIV (iv);
buf += 514; buf += 514;
len += 514; len += 514;
@ -315,7 +315,7 @@ namespace garlic
{ {
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
size_t size = 0; size_t size = 0;
if (isDestination && m_Destination) if (isDestination)
{ {
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
size++; size++;

2
Garlic.h

@ -128,6 +128,7 @@ namespace garlic
GarlicDestination * m_Owner; GarlicDestination * m_Owner;
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination; std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
i2p::crypto::AESKey m_SessionKey; i2p::crypto::AESKey m_SessionKey;
std::list<SessionTag> m_SessionTags; std::list<SessionTag> m_SessionTags;
int m_NumTags; int m_NumTags;
@ -138,7 +139,6 @@ namespace garlic
uint64_t m_LeaseSetSubmissionTime; // in milliseconds uint64_t m_LeaseSetSubmissionTime; // in milliseconds
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption;
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath; std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;

50
HTTPServer.cpp

@ -451,26 +451,26 @@ namespace http {
s << "<br>\r\n"; s << "<br>\r\n";
} }
static void ShowCommands (std::stringstream& s) static void ShowCommands (std::stringstream& s, uint32_t token)
{ {
/* commands */ /* commands */
s << "<b>Router Commands</b><br>\r\n"; s << "<b>Router Commands</b><br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "\">Run peer test</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n";
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n"; //s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
if (i2p::context.AcceptsTunnels ()) if (i2p::context.AcceptsTunnels ())
s << " <a href=\"/?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "\">Decline transit tunnels</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n";
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "\">Accept transit tunnels</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n";
#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) #if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID))
if (Daemon.gracefulShutdownInterval) if (Daemon.gracefulShutdownInterval)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "\">Cancel graceful shutdown</a><br>"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Start graceful shutdown</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
#endif #endif
#ifdef WIN32_APP #ifdef WIN32_APP
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "\">Graceful shutdown</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif #endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "\">Force shutdown</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
} }
static void ShowTransitTunnels (std::stringstream& s) static void ShowTransitTunnels (std::stringstream& s)
@ -709,11 +709,15 @@ namespace http {
char b64_creds[64]; char b64_creds[64];
std::size_t len = 0; std::size_t len = 0;
len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds)); len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds));
/* if we decoded properly then check credentials */
if(len) {
b64_creds[len] = '\0'; b64_creds[len] = '\0';
expected = "Basic "; expected = "Basic ";
expected += b64_creds; expected += b64_creds;
if (provided == expected) return expected == provided;
return true; }
/** we decoded wrong so it's not a correct login credential */
return false;
} }
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ()); LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ());
@ -752,6 +756,7 @@ namespace http {
SendReply (res, content); SendReply (res, content);
} }
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s) void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
{ {
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
@ -767,7 +772,20 @@ namespace http {
else if (page == HTTP_PAGE_TUNNELS) else if (page == HTTP_PAGE_TUNNELS)
ShowTunnels (s); ShowTunnels (s);
else if (page == HTTP_PAGE_COMMANDS) else if (page == HTTP_PAGE_COMMANDS)
ShowCommands (s); {
uint32_t token;
RAND_bytes ((uint8_t *)&token, 4);
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
{
if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
it = m_Tokens.erase (it);
else
++it;
}
m_Tokens[token] = ts;
ShowCommands (s, token);
}
else if (page == HTTP_PAGE_TRANSIT_TUNNELS) else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
ShowTransitTunnels (s); ShowTransitTunnels (s);
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS) else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
@ -794,13 +812,19 @@ namespace http {
void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s) void HTTPConnection::HandleCommand (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
{ {
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
std::string cmd("");
URL url; URL url;
url.parse(req.uri); url.parse(req.uri);
url.parse_query(params); url.parse_query(params);
cmd = params["cmd"];
std::string token = params["token"];
if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
{
ShowError(s, "Invalid token");
return;
}
std::string cmd = params["cmd"];
if (cmd == HTTP_COMMAND_RUN_PEER_TEST) if (cmd == HTTP_COMMAND_RUN_PEER_TEST)
i2p::transport::transports.PeerTest (); i2p::transport::transports.PeerTest ();
else if (cmd == HTTP_COMMAND_RELOAD_CONFIG) else if (cmd == HTTP_COMMAND_RELOAD_CONFIG)

18
HTTPServer.h

@ -1,10 +1,20 @@
#ifndef HTTP_SERVER_H__ #ifndef HTTP_SERVER_H__
#define HTTP_SERVER_H__ #define HTTP_SERVER_H__
namespace i2p { #include <inttypes.h>
namespace http { #include <string>
extern const char *itoopieFavicon; #include <memory>
#include <map>
#include <thread>
#include <boost/asio.hpp>
#include "HTTP.h"
namespace i2p
{
namespace http
{
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection> class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{ {
@ -35,6 +45,8 @@ namespace http {
bool needAuth; bool needAuth;
std::string user; std::string user;
std::string pass; std::string pass;
static std::map<uint32_t, uint32_t> m_Tokens; // token->timestamp in seconds
}; };
class HTTPServer class HTTPServer

18
I2PTunnel.cpp

@ -92,7 +92,9 @@ namespace client
m_Stream->Close (); m_Stream->Close ();
m_Stream.reset (); m_Stream.reset ();
} }
m_Socket->shutdown(boost::asio::ip::tcp::socket::shutdown_send); // avoid RST
m_Socket->close (); m_Socket->close ();
Done(shared_from_this ()); Done(shared_from_this ());
} }
@ -107,10 +109,12 @@ namespace client
{ {
if (ecode) if (ecode)
{ {
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
Terminate (); Terminate ();
} }
}
else else
{ {
if (m_Stream) if (m_Stream)
@ -173,6 +177,8 @@ namespace client
{ {
if (bytes_transferred > 0) if (bytes_transferred > 0)
Write (m_StreamBuffer, bytes_transferred); // postpone termination Write (m_StreamBuffer, bytes_transferred); // postpone termination
else if (ecode == boost::asio::error::timed_out && m_Stream->IsOpen ())
StreamReceive ();
else else
Terminate (); Terminate ();
} }
@ -540,9 +546,13 @@ namespace client
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) { void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
std::lock_guard<std::mutex> lock(m_SessionsMutex); std::lock_guard<std::mutex> lock(m_SessionsMutex);
uint64_t now = i2p::util::GetMillisecondsSinceEpoch(); uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
std::remove_if(m_Sessions.begin(), m_Sessions.end(), [now, delta](const UDPSession * u) -> bool { auto itr = m_Sessions.begin();
return now - u->LastActivity >= delta; while(itr != m_Sessions.end()) {
}); if(now - (*itr)->LastActivity >= delta )
itr = m_Sessions.erase(itr);
else
++itr;
}
} }
UDPSession * I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort) UDPSession * I2PUDPServerTunnel::ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort)

14
Identity.cpp

@ -593,11 +593,25 @@ namespace data
XORMetric operator^(const IdentHash& key1, const IdentHash& key2) XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
{ {
XORMetric m; XORMetric m;
#if defined(__AVX__) // for AVX
__asm__
(
"vmovups %1, %%ymm0 \n"
"vmovups %2, %%ymm1 \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, %0 \n"
: "=m"(*m.metric)
: "m"(*key1), "m"(*key2)
: "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler
);
#else
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
m.metric_ll[0] = hash1[0] ^ hash2[0]; m.metric_ll[0] = hash1[0] ^ hash2[0];
m.metric_ll[1] = hash1[1] ^ hash2[1]; m.metric_ll[1] = hash1[1] ^ hash2[1];
m.metric_ll[2] = hash1[2] ^ hash2[2]; m.metric_ll[2] = hash1[2] ^ hash2[2];
m.metric_ll[3] = hash1[3] ^ hash2[3]; m.metric_ll[3] = hash1[3] ^ hash2[3];
#endif
return m; return m;
} }
} }

2
LeaseSet.cpp

@ -91,7 +91,7 @@ namespace data
if (m_StoreLeases) if (m_StoreLeases)
{ {
auto ret = m_Leases.insert (std::make_shared<Lease>(lease)); auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
if (!ret.second) *(*ret.first) = lease; // update existing if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
(*ret.first)->isUpdated = true; (*ret.first)->isUpdated = true;
// check if lease's gateway is in our netDb // check if lease's gateway is in our netDb
if (!netdb.FindRouter (lease.tunnelGateway)) if (!netdb.FindRouter (lease.tunnelGateway))

1
Makefile

@ -10,6 +10,7 @@ DEPS := obj/make.dep
include filelist.mk include filelist.mk
USE_AESNI := yes USE_AESNI := yes
USE_AVX := yes
USE_STATIC := no USE_STATIC := no
USE_MESHNET := no USE_MESHNET := no
USE_UPNP := no USE_UPNP := no

9
Makefile.linux

@ -60,7 +60,14 @@ ifeq ($(USE_AESNI),yes)
ifeq ($(IS_64),1) ifeq ($(IS_64),1)
#check if AES-NI is supported by CPU #check if AES-NI is supported by CPU
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
CPU_FLAGS = -maes -DAESNI CPU_FLAGS += -maes -DAESNI
endif endif
endif endif
endif endif
ifeq ($(USE_AVX),yes)
#check if AVX supported by CPU
ifneq ($(shell $(GREP) -c avx /proc/cpuinfo),0)
CPU_FLAGS += -mavx
endif
endif

8
Makefile.mingw

@ -39,9 +39,13 @@ endif
# don't change following line to ifeq ($(USE_AESNI),yes) !!! # don't change following line to ifeq ($(USE_AESNI),yes) !!!
ifeq ($(USE_AESNI),1) ifeq ($(USE_AESNI),1)
CPU_FLAGS = -maes -DAESNI CPU_FLAGS += -maes -DAESNI
else else
CPU_FLAGS = -msse CPU_FLAGS += -msse
endif
ifeq ($(USE_AVX),1)
CPU_FLAGS += -mavx
endif endif
ifeq ($(USE_ASLR),yes) ifeq ($(USE_ASLR),yes)

13
Makefile.osx vendored

@ -3,21 +3,26 @@ CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11 #CXXFLAGS = -g -O2 -Wall -std=c++11
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib
ifeq ($(USE_STATIC),yes)
LDLIBS = -lz -lcrypto -lssl /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
else
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
endif
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
LDFLAGS += -ldl LDFLAGS += -ldl
CXXFLAGS += -DUSE_UPNP CXXFLAGS += -DUSE_UPNP
endif endif
# OSX Notes
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
CXXFLAGS += -maes -DAESNI CXXFLAGS += -maes -DAESNI
endif endif
ifeq ($(USE_AVX),yes)
CXXFLAGS += -mavx
endif
# Disabled, since it will be the default make rule. I think its better # Disabled, since it will be the default make rule. I think its better
# to define the default rule in Makefile and not Makefile.<ostype> - torkel # to define the default rule in Makefile and not Makefile.<ostype> - torkel
#install: all #install: all

39
NetDb.cpp

@ -118,7 +118,6 @@ namespace data
{ {
SaveUpdated (); SaveUpdated ();
ManageLeaseSets (); ManageLeaseSets ();
ManageLookupResponses ();
} }
lastSave = ts; lastSave = ts;
} }
@ -857,21 +856,6 @@ namespace data
} }
if (!replyMsg) if (!replyMsg)
{
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
// find or cleate response
std::vector<IdentHash> closestFloodfills;
bool found = false;
if (!numExcluded)
{
auto it = m_LookupResponses.find (ident);
if (it != m_LookupResponses.end ())
{
closestFloodfills = it->second.first;
found = true;
}
}
if (!found)
{ {
std::set<IdentHash> excludedRouters; std::set<IdentHash> excludedRouters;
const uint8_t * exclude_ident = excluded; const uint8_t * exclude_ident = excluded;
@ -880,10 +864,9 @@ namespace data
excludedRouters.insert (exclude_ident); excludedRouters.insert (exclude_ident);
exclude_ident += 32; exclude_ident += 32;
} }
closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true); auto closestFloodfills = GetClosestFloodfills (ident, 3, excludedRouters, true);
if (!numExcluded) // save if no excluded if (closestFloodfills.empty ())
m_LookupResponses[ident] = std::make_pair(closestFloodfills, i2p::util::GetSecondsSinceEpoch ()); LogPrint (eLogWarning, "NetDb: Requested ", key, " not found, ", numExcluded, " peers excluded");
}
replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills); replyMsg = CreateDatabaseSearchReply (ident, closestFloodfills);
} }
} }
@ -929,7 +912,6 @@ namespace data
uint8_t randomHash[32]; uint8_t randomHash[32];
std::vector<i2p::tunnel::TunnelMessageBlock> msgs; std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
std::set<const RouterInfo *> floodfills;
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ..."); LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
for (int i = 0; i < numDestinations; i++) for (int i = 0; i < numDestinations; i++)
{ {
@ -941,9 +923,8 @@ namespace data
return; return;
} }
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once if (floodfill)
{ {
floodfills.insert (floodfill.get ());
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
throughTunnels = false; throughTunnels = false;
if (throughTunnels) if (throughTunnels)
@ -1191,17 +1172,5 @@ namespace data
++it; ++it;
} }
} }
void NetDb::ManageLookupResponses ()
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_LookupResponses.begin (); it != m_LookupResponses.end ();)
{
if (ts > it->second.second + 180) // 3 minutes
it = m_LookupResponses.erase (it);
else
++it;
}
}
} }
} }

2
NetDb.h

@ -112,7 +112,6 @@ namespace data
void Publish (); void Publish ();
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
void ManageLookupResponses ();
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
@ -144,7 +143,6 @@ namespace data
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/ /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
std::map<IdentHash, std::pair<std::vector<IdentHash>, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp)
/** true if in hidden mode */ /** true if in hidden mode */
bool m_HiddenMode; bool m_HiddenMode;

44
RouterInfo.cpp

@ -167,19 +167,19 @@ namespace data
{ {
uint8_t supportedTransports = 0; uint8_t supportedTransports = 0;
bool isValidAddress = true; bool isValidAddress = true;
Address address; auto address = std::make_shared<Address>();
s.read ((char *)&address.cost, sizeof (address.cost)); s.read ((char *)&address->cost, sizeof (address->cost));
s.read ((char *)&address.date, sizeof (address.date)); s.read ((char *)&address->date, sizeof (address->date));
char transportStyle[5]; char transportStyle[5];
ReadString (transportStyle, 5, s); ReadString (transportStyle, 5, s);
if (!strcmp (transportStyle, "NTCP")) if (!strcmp (transportStyle, "NTCP"))
address.transportStyle = eTransportNTCP; address->transportStyle = eTransportNTCP;
else if (!strcmp (transportStyle, "SSU")) else if (!strcmp (transportStyle, "SSU"))
address.transportStyle = eTransportSSU; address->transportStyle = eTransportSSU;
else else
address.transportStyle = eTransportUnknown; address->transportStyle = eTransportUnknown;
address.port = 0; address->port = 0;
address.mtu = 0; address->mtu = 0;
uint16_t size, r = 0; uint16_t size, r = 0;
s.read ((char *)&size, sizeof (size)); if (!s) return; s.read ((char *)&size, sizeof (size)); if (!s) return;
size = be16toh (size); size = be16toh (size);
@ -194,35 +194,35 @@ namespace data
if (!strcmp (key, "host")) if (!strcmp (key, "host"))
{ {
boost::system::error_code ecode; boost::system::error_code ecode;
address.host = boost::asio::ip::address::from_string (value, ecode); address->host = boost::asio::ip::address::from_string (value, ecode);
if (ecode) if (ecode)
{ {
if (address.transportStyle == eTransportNTCP) if (address->transportStyle == eTransportNTCP)
{ {
supportedTransports |= eNTCPV4; // TODO: supportedTransports |= eNTCPV4; // TODO:
address.addressString = value; address->addressString = value;
} }
else else
{ {
supportedTransports |= eSSUV4; // TODO: supportedTransports |= eSSUV4; // TODO:
address.addressString = value; address->addressString = value;
} }
} }
else else
{ {
// add supported protocol // add supported protocol
if (address.host.is_v4 ()) if (address->host.is_v4 ())
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4; supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
else else
supportedTransports |= (address.transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6; supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
} }
} }
else if (!strcmp (key, "port")) else if (!strcmp (key, "port"))
address.port = boost::lexical_cast<int>(value); address->port = boost::lexical_cast<int>(value);
else if (!strcmp (key, "mtu")) else if (!strcmp (key, "mtu"))
address.mtu = boost::lexical_cast<int>(value); address->mtu = boost::lexical_cast<int>(value);
else if (!strcmp (key, "key")) else if (!strcmp (key, "key"))
Base64ToByteStream (value, strlen (value), address.key, 32); Base64ToByteStream (value, strlen (value), address->key, 32);
else if (!strcmp (key, "caps")) else if (!strcmp (key, "caps"))
ExtractCaps (value); ExtractCaps (value);
else if (key[0] == 'i') else if (key[0] == 'i')
@ -237,9 +237,9 @@ namespace data
LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped"); LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
if (s) continue; else return; if (s) continue; else return;
} }
if (index >= address.introducers.size ()) if (index >= address->introducers.size ())
address.introducers.resize (index + 1); address->introducers.resize (index + 1);
Introducer& introducer = address.introducers.at (index); Introducer& introducer = address->introducers.at (index);
if (!strcmp (key, "ihost")) if (!strcmp (key, "ihost"))
{ {
boost::system::error_code ecode; boost::system::error_code ecode;
@ -256,7 +256,7 @@ namespace data
} }
if (isValidAddress) if (isValidAddress)
{ {
addresses->push_back(std::make_shared<Address>(address)); addresses->push_back(address);
m_SupportedTransports |= supportedTransports; m_SupportedTransports |= supportedTransports;
} }
} }

107
SAM.cpp

@ -54,11 +54,7 @@ namespace client
case eSAMSocketTypeAcceptor: case eSAMSocketTypeAcceptor:
{ {
if (m_Session) if (m_Session)
{
m_Session->DelSocket (shared_from_this ()); m_Session->DelSocket (shared_from_this ());
if (m_Session->localDestination)
m_Session->localDestination->StopAcceptingStreams ();
}
break; break;
} }
default: default:
@ -289,6 +285,11 @@ namespace client
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (), dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
} }
else
{
// start accepting streams because we're not a datagram session
m_Session->localDestination->AcceptStreams (std::bind (&SAMSession::AcceptI2P, m_Session, std::placeholders::_1));
}
if (m_Session->localDestination->IsReady ()) if (m_Session->localDestination->IsReady ())
SendSessionCreateReplyOk (); SendSessionCreateReplyOk ();
@ -400,21 +401,26 @@ namespace client
m_ID = id; m_ID = id;
m_Session = m_Owner.FindSession (id); m_Session = m_Owner.FindSession (id);
if (m_Session) if (m_Session)
{
if (!m_Session->localDestination->IsAcceptingStreams ())
{ {
m_SocketType = eSAMSocketTypeAcceptor; m_SocketType = eSAMSocketTypeAcceptor;
m_Session->AddSocket (shared_from_this ()); m_Session->AddSocket (shared_from_this ());
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
else
SendMessageReply (SAM_STREAM_STATUS_I2P_ERROR, strlen(SAM_STREAM_STATUS_I2P_ERROR), true);
}
else else
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
} }
void SAMSocket::Accept(std::shared_ptr<i2p::stream::Stream> stream)
{
if(stream) {
m_SocketType = eSAMSocketTypeStream;
HandleI2PAccept(stream);
} else {
SendMessageReply (SAM_STREAM_STATUS_I2P_ERROR, strlen(SAM_STREAM_STATUS_I2P_ERROR), true);
auto s = shared_from_this ();
m_Owner.GetService ().post ([s] { s->Terminate (); });
}
}
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data) size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
{ {
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len); LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
@ -578,7 +584,7 @@ namespace client
if (!ecode) if (!ecode)
s->Receive (); s->Receive ();
else else
s->Terminate (); s->m_Owner.GetService ().post ([s] { s->Terminate (); });
}); });
} }
} }
@ -622,10 +628,16 @@ namespace client
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); // postpone termination std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1)); // postpone termination
else else
Terminate (); {
auto s = shared_from_this ();
m_Owner.GetService ().post ([s] { s->Terminate (); });
}
} }
else else
Terminate (); {
auto s = shared_from_this ();
m_Owner.GetService ().post ([s] { s->Terminate (); });
}
} }
else else
{ {
@ -653,10 +665,6 @@ namespace client
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID); LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
m_Stream = stream; m_Stream = stream;
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ()); context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
auto session = m_Owner.FindSession (m_ID);
if (session)
session->localDestination->StopAcceptingStreams ();
m_SocketType = eSAMSocketTypeStream;
if (!m_IsSilent) if (!m_IsSilent)
{ {
// get remote peer address // get remote peer address
@ -698,26 +706,76 @@ namespace client
} }
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest): SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
localDestination (dest) localDestination (dest),
m_BacklogPumper(dest->GetService())
{ {
PumpBacklog();
} }
SAMSession::~SAMSession () void SAMSession::AcceptI2P(std::shared_ptr<i2p::stream::Stream> stream)
{ {
CloseStreams(); if(!stream) return; // fail
i2p::client::context.DeleteLocalDestination (localDestination); std::unique_lock<std::mutex> lock(m_SocketsMutex);
if(m_Backlog.size() > SAM_MAX_ACCEPT_BACKLOG) {
stream->Close();
return;
}
m_Backlog.push_back(stream);
} }
void SAMSession::CloseStreams () void SAMSession::PumpBacklog()
{
// pump backlog every 100ms
boost::posix_time::milliseconds dlt(100);
m_BacklogPumper.expires_from_now(dlt);
m_BacklogPumper.async_wait(std::bind(&SAMSession::HandlePumpBacklog, this, std::placeholders::_1));
}
std::shared_ptr<SAMSocket> SAMSession::FindAcceptor()
{
for (auto & sock : m_Sockets) {
auto t = sock->GetSocketType();
if(t == eSAMSocketTypeAcceptor) {
return sock;
}
}
return nullptr;
}
void SAMSession::HandlePumpBacklog(const boost::system::error_code & ec)
{
if(ec) return;
{ {
std::unique_lock<std::mutex> lock(m_SocketsMutex);
auto itr = m_Backlog.begin();
while(itr != m_Backlog.end()) {
auto sock = FindAcceptor();
if (sock) {
sock->Accept(*itr);
itr = m_Backlog.erase(itr);
} else {
++itr;
}
}
}
PumpBacklog();
}
void SAMSession::CloseStreams ()
{ {
m_BacklogPumper.cancel();
localDestination->GetService().post([&] () {
std::lock_guard<std::mutex> lock(m_SocketsMutex); std::lock_guard<std::mutex> lock(m_SocketsMutex);
for (auto& sock : m_Sockets) { for (auto& sock : m_Sockets) {
sock->CloseStream(); sock->CloseStream();
} }
for(auto & stream : m_Backlog) {
stream->Close();
} }
// XXX: should this be done inside locked parts?
m_Sockets.clear(); m_Sockets.clear();
m_Backlog.clear();
i2p::client::context.DeleteLocalDestination (localDestination);
});
} }
SAMBridge::SAMBridge (const std::string& address, int port): SAMBridge::SAMBridge (const std::string& address, int port):
@ -828,8 +886,9 @@ namespace client
auto session = std::make_shared<SAMSession>(localDestination); auto session = std::make_shared<SAMSession>(localDestination);
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
auto ret = m_Sessions.insert (std::make_pair(id, session)); auto ret = m_Sessions.insert (std::make_pair(id, session));
if (!ret.second) if (!ret.second) {
LogPrint (eLogWarning, "SAM: Session ", id, " already exists"); LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
}
return ret.first->second; return ret.first->second;
} }
return nullptr; return nullptr;

13
SAM.h

@ -21,6 +21,7 @@ namespace client
const size_t SAM_SOCKET_BUFFER_SIZE = 8192; const size_t SAM_SOCKET_BUFFER_SIZE = 8192;
const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds const int SAM_SOCKET_CONNECTION_MAX_IDLE = 3600; // in seconds
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
const int SAM_MAX_ACCEPT_BACKLOG = 50;
const char SAM_HANDSHAKE[] = "HELLO VERSION"; const char SAM_HANDSHAKE[] = "HELLO VERSION";
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n"; const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n"; const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
@ -84,6 +85,8 @@ namespace client
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; }; void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
SAMSocketType GetSocketType () const { return m_SocketType; }; SAMSocketType GetSocketType () const { return m_SocketType; };
void Accept(std::shared_ptr<i2p::stream::Stream> stream);
private: private:
void Terminate (); void Terminate ();
@ -134,6 +137,8 @@ namespace client
struct SAMSession struct SAMSession
{ {
std::shared_ptr<ClientDestination> localDestination; std::shared_ptr<ClientDestination> localDestination;
boost::asio::deadline_timer m_BacklogPumper;
std::list<std::shared_ptr<i2p::stream::Stream> > m_Backlog;
std::list<std::shared_ptr<SAMSocket> > m_Sockets; std::list<std::shared_ptr<SAMSocket> > m_Sockets;
std::mutex m_SocketsMutex; std::mutex m_SocketsMutex;
@ -160,7 +165,13 @@ namespace client
} }
SAMSession (std::shared_ptr<ClientDestination> dest); SAMSession (std::shared_ptr<ClientDestination> dest);
~SAMSession ();
void AcceptI2P(std::shared_ptr<i2p::stream::Stream> stream);
std::shared_ptr<SAMSocket> FindAcceptor();
void PumpBacklog();
void HandlePumpBacklog(const boost::system::error_code & ec);
void CloseStreams (); void CloseStreams ();
}; };

2
SSUSession.cpp

@ -1101,7 +1101,7 @@ namespace transport
{ {
// we are Alice // we are Alice
LogPrint (eLogDebug, "SSU: sending peer test"); LogPrint (eLogDebug, "SSU: sending peer test");
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (i2p::context.SupportsV4 ());
if (!address) if (!address)
{ {
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test"); LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");

9
TunnelEndpoint.cpp

@ -116,6 +116,7 @@ namespace tunnel
if (!isFollowOnFragment) // create new incomlete message if (!isFollowOnFragment) // create new incomlete message
{ {
m.nextFragmentNum = 1; m.nextFragmentNum = 1;
m.receiveTime = i2p::util::GetMillisecondsSinceEpoch ();
auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m)); auto ret = m_IncompleteMessages.insert (std::pair<uint32_t, TunnelMessageBlockEx>(msgID, m));
if (ret.second) if (ret.second)
HandleOutOfSequenceFragments (msgID, ret.first->second); HandleOutOfSequenceFragments (msgID, ret.first->second);
@ -284,6 +285,14 @@ namespace tunnel
else else
++it; ++it;
} }
// incomplete messages
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
{
if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
it = m_IncompleteMessages.erase (it);
else
++it;
}
} }
} }
} }

1
TunnelEndpoint.h

@ -15,6 +15,7 @@ namespace tunnel
{ {
struct TunnelMessageBlockEx: public TunnelMessageBlock struct TunnelMessageBlockEx: public TunnelMessageBlock
{ {
uint64_t receiveTime; // milliseconds since epoch
uint8_t nextFragmentNum; uint8_t nextFragmentNum;
}; };

2
Win32/installer.iss

@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.10.1" #define I2Pd_ver "2.11.0"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
[Setup] [Setup]

2
android/AndroidManifest.xml

@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.purplei2p.i2pd" package="org.purplei2p.i2pd"
android:versionCode="1" android:versionCode="1"
android:versionName="2.10.1"> android:versionName="2.11.0">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="24"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>

1
android/jni/Android.mk

@ -59,6 +59,7 @@ LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \
../../TunnelPool.cpp \ ../../TunnelPool.cpp \
../../Timestamp.cpp \ ../../Timestamp.cpp \
../../Event.cpp \ ../../Event.cpp \
../../BloomFilter.cpp \
../../util.cpp \ ../../util.cpp \
../../i2pd.cpp ../../UPnP.cpp ../../i2pd.cpp ../../UPnP.cpp

1
build/CMakeLists.txt

@ -26,6 +26,7 @@ set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
set ( CMAKE_SOURCE_DIR ".." ) set ( CMAKE_SOURCE_DIR ".." )
set (LIBI2PD_SRC set (LIBI2PD_SRC
"${CMAKE_SOURCE_DIR}/BloomFilter.cpp"
"${CMAKE_SOURCE_DIR}/Config.cpp" "${CMAKE_SOURCE_DIR}/Config.cpp"
"${CMAKE_SOURCE_DIR}/Crypto.cpp" "${CMAKE_SOURCE_DIR}/Crypto.cpp"
"${CMAKE_SOURCE_DIR}/Garlic.cpp" "${CMAKE_SOURCE_DIR}/Garlic.cpp"

12
debian/changelog vendored

@ -1,3 +1,15 @@
i2pd (2.11.0-1) unstable; urgency=low
* updated to version 2.11.0/0.9.28
-- orignal <orignal@i2pmail.org> Sun, 18 Dec 2016 21:01:30 +0000
i2pd (2.10.2-1) unstable; urgency=low
* updated to version 2.10.2
-- orignal <orignal@i2pmail.org> Sun, 4 Dec 2016 19:38:30 +0000
i2pd (2.10.1-1) unstable; urgency=low i2pd (2.10.1-1) unstable; urgency=low
* updated to version 2.10.1 * updated to version 2.10.1

6
debian/patches/01-tune-build-opts.patch vendored

@ -1,5 +1,6 @@
diff --git a/Makefile b/Makefile diff --git a/Makefile b/Makefile
index b6fc795..abc3ace 100644 index bdadfe0..2f71eec 100644
--- a/Makefile --- a/Makefile
+++ b/Makefile +++ b/Makefile
@@ -9,10 +9,10 @@ DEPS := obj/make.dep @@ -9,10 +9,10 @@ DEPS := obj/make.dep
@ -8,9 +9,10 @@ index b6fc795..abc3ace 100644
-USE_AESNI := yes -USE_AESNI := yes
+USE_AESNI := no +USE_AESNI := no
-USE_AVX := yes
+USE_AVX := no
USE_STATIC := no USE_STATIC := no
USE_MESHNET := no USE_MESHNET := no
USE_UPNP := no USE_UPNP := no
ifeq ($(WEBSOCKETS),1) ifeq ($(WEBSOCKETS),1)
NEEDED_CXXFLAGS += -DWITH_EVENTS

2
filelist.mk

@ -1,5 +1,5 @@
LIB_SRC = \ LIB_SRC = \
Gzip.cpp Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ BloomFilter.cpp Gzip.cpp Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \
Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \ Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \
Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \ Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="2" android:installLocation="auto"> <manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.11.0" android:versionCode="2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/> <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" --> <!-- <application android:hardwareAccelerated="true" -->

5
qt/i2pd_qt/i2pd_qt.pro

@ -36,7 +36,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \ ../../SSUData.cpp ../../SSUSession.cpp ../../Streaming.cpp ../../TransitTunnel.cpp \
../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \ ../../Transports.cpp ../../Tunnel.cpp ../../TunnelEndpoint.cpp ../../TunnelGateway.cpp \
../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \ ../../TunnelPool.cpp ../../UPnP.cpp ../../Gzip.cpp ../../Timestamp.cpp ../../util.cpp \
../../Event.cpp ../../i2pd.cpp ../../Event.cpp ../../BloomFiler.cpp ../../i2pd.cpp
HEADERS += DaemonQT.h mainwindow.h \ HEADERS += DaemonQT.h mainwindow.h \
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
@ -50,7 +50,8 @@ HEADERS += DaemonQT.h mainwindow.h \
../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \ ../../Streaming.h ../../Timestamp.h ../../TransitTunnel.h ../../Transports.h \
../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \ ../../TransportSession.h ../../Tunnel.h ../../TunnelBase.h ../../TunnelConfig.h \
../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \ ../../TunnelEndpoint.h ../../TunnelGateway.h ../../TunnelPool.h ../../UPnP.h \
../../util.h ../../version.h ../../Gzip.h ../../Tag.h ../../Event.h ../../util.h ../../version.h ../../Gzip.h ../../Tag.h \
../../BloomFiler.h ../../Event.h
FORMS += mainwindow.ui FORMS += mainwindow.ui

6
version.h

@ -7,8 +7,8 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 10 #define I2PD_VERSION_MINOR 11
#define I2PD_VERSION_MICRO 1 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
#define VERSION I2PD_VERSION #define VERSION I2PD_VERSION
@ -21,7 +21,7 @@
#define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9 #define I2P_VERSION_MINOR 9
#define I2P_VERSION_MICRO 27 #define I2P_VERSION_MICRO 28
#define I2P_VERSION_PATCH 0 #define I2P_VERSION_PATCH 0
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)

Loading…
Cancel
Save