Compare commits

..

115 Commits

Author SHA1 Message Date
Mikal
6cc3021baa MSVC13 Fix
Fixed build issue on MSVC13. Bumping to v0.3.0 as we release binaries
and SU3 is added.
2014-11-20 23:46:36 -08:00
orignal
0f4e4a7944 return shared_ptr to RI 2014-11-20 16:20:02 -05:00
orignal
683c97d5c8 shared pointer for local RI 2014-11-20 15:48:28 -05:00
orignal
af2a5b93f2 SU3 file parser 2014-11-20 14:29:22 -05:00
orignal
f9ec60265a support of RI with EcDSA 2014-11-20 12:21:27 -05:00
orignal
a449dc1377 read RI from buffer 2014-11-19 16:21:40 -05:00
orignal
f6849442a9 encrypted delivery status 2014-11-19 14:56:47 -05:00
orignal
c3e329e406 fixed misalignment 2014-11-19 11:01:04 -05:00
orignal
69cbd71fe0 receive buffers aligned to 16 2014-11-18 12:37:04 -05:00
orignal
dd1a798128 AES buffer aligned to 16 bytes 2014-11-18 12:11:45 -05:00
orignal
96387aecbd store RIs as shared pointers 2014-11-18 11:08:10 -05:00
orignal
77b7fff5ed streaming api functions added 2014-11-18 09:33:58 -05:00
orignal
72c0d8443a create local destination through API 2014-11-17 17:00:30 -05:00
orignal
2988395b81 specify application name 2014-11-17 15:28:52 -05:00
orignal
439b8798c9 start/stop/init through api 2014-11-17 14:42:45 -05:00
orignal
7cf19f5784 api added 2014-11-17 12:37:40 -05:00
orignal
b9e2b7bf64 delete single message routing session immediately 2014-11-16 15:41:54 -05:00
Mikal
cc14b526cd Adding Icon for windows
Adding icon for windows executable.
2014-11-11 02:46:35 +01:00
Mikal
5e67bc62c1 Adding windows installer 2014-11-11 02:21:05 +01:00
692cde5151 Remove "DLL-Output" from README's example
This is not required to build i2pd.
2014-11-09 22:32:17 +00:00
4fbb823391 Merge branch 'master' into proposed_build_fixes
Conflicts:
	Win32/i2pd.vcxproj
2014-11-08 13:45:10 +00:00
d636d55cc8 Adding Windows build instructions 2014-11-08 13:29:15 +00:00
apekatten
901eb10125 Removed required admin-level for running 2014-11-08 13:44:18 +01:00
4b0001b442 innosetup: Add i2pd to PATH 2014-11-07 15:04:33 +00:00
3cd1281167 updates to innosetup script
* support installation of both x64 and x86 binaries
* add readme
* add function to convert line endings. The README.md file currently has
  Windows line endings, but if that ever changes this function will
  automatically make the file "Windows friendly".
2014-11-07 15:04:33 +00:00
33f9918854 minor updates to readme
* grammar fixes
* note working VS2013 version
* change tabs to spaces to ensure proper viewing on systems with
* different tab settings
2014-11-07 15:04:33 +00:00
a518d6063c update vcxproj.filters 2014-11-07 15:04:33 +00:00
1232278c46 Various changes to Windows build
- No hard coded dependency paths. These are better set with environment
  variables or property pages.
- Don't require admin rights to run
- Add support for running on Windows XP (note that Boost and Crypto++
  *also* need to be built targetting XP).
- Explicitly set type to console application
- Initial stubs for building x64 version
- Turn off sending error reports to Microsoft
- spaces, not tabs (matches the default when saved by VS2013 itself)
- disable multibyte
- re-enable SDL checks
2014-11-07 15:04:33 +00:00
dd4283b7c1 Revert "fixed typo" and "fixed crash for Windows"
This reverts commits c8a80a497d and f7791e5289

This didn't actually fix Windows crash problem. In fact, it still
crashed without --log=0 being set. Changes to the i2pd.vcxproj file
fixed the crashes with VS 2013 > update 1.  i2pd now works with VS 2013
Update 3 and Update 4 RC.

Since these changes didn't have the intended effect, let's remove them.
2014-11-07 14:58:27 +00:00
3e826cd6dc easier static builds (STATIC=yes)
This will also disable AESNI
2014-11-07 14:49:16 +00:00
2f8c37b132 Allow setting the LIBDIR at build time 2014-11-07 14:48:49 +00:00
e914d1640c allow AESNI to be disabled 2014-11-07 14:17:24 +00:00
25b5068f5e allow LDFLAGS to be set by user
Move old LDFLAGS variable to LDLIBS. By doing ths, a user can set their
own LDFLAGS without breaking the build. A case in which this can be
useful is hardening with debian, e.g.

    $ dpkg-buildflags --get LDFLAGS
    -Wl,-z,relro
2014-11-04 02:37:12 +00:00
orignal
38b901484a check for SSU packet size 2014-11-03 10:15:01 -05:00
orignal
c8a80a497d fixed typo 2014-11-02 08:28:28 -05:00
orignal
faf1fe7a7c aligned AES keys 2014-11-01 21:53:45 -04:00
orignal
f7791e5289 fixed crash for Windows 2014-11-01 21:48:26 -04:00
orignal
a8acb8ebb4 fixed double deletion 2014-11-01 17:15:59 -04:00
orignal
4334007688 aligned AES and MAC keys 2014-11-01 14:56:13 -04:00
orignal
7a976dd5f2 specify actual mtu in our RI for i2pv6 2014-10-31 18:27:51 -04:00
orignal
f28376bf71 DATAGRAM RECEIVED message 2014-10-31 16:44:44 -04:00
orignal
3b435f1e1d get local MTU for Linux 2014-10-31 14:34:08 -04:00
orignal
a314feff33 get local MTU for Linux 2014-10-31 14:17:52 -04:00
orignal
0b77c9651b 0.2.0 2014-10-30 18:04:17 -04:00
orignal
6b860c8c88 split SSU to SSU and SSUSession 2014-10-30 15:13:29 -04:00
orignal
0cd04c23c5 split SSU to SSU and SSUSession 2014-10-30 15:13:12 -04:00
orignal
51c908ab55 Merge pull request #106 from kytvi2p/fix_makefiles
Makefile updates
2014-10-30 10:36:33 -04:00
orignal
c0482319e5 always specify mtu for ipv6 address 2014-10-30 10:07:39 -04:00
38eaea121f recognize clang in linux 2014-10-30 13:53:55 +00:00
6681e25513 allow CXXFLAGS to be set without overwriting needed flags 2014-10-30 13:53:47 +00:00
5acbc6a23e use standard make variables 2014-10-30 13:50:29 +00:00
524b2e9f8a check for 64-bit compiler 2014-10-30 13:50:18 +00:00
orignal
6320572917 find SSU V6 sessions 2014-10-29 21:56:45 -04:00
orignal
54ec71d30d select proper SSU address for incoming sessions 2014-10-29 21:16:27 -04:00
orignal
67001e1696 incoming ipv6 SSU sessions 2014-10-29 18:46:35 -04:00
orignal
21aff9f9f7 check router identity certificate 2014-10-29 16:27:42 -04:00
orignal
a53457e8c1 delete SSU V6 address 2014-10-29 16:08:01 -04:00
orignal
f0e6b414e8 don't verify signature for RI loaded from file 2014-10-29 16:03:07 -04:00
orignal
8403c17c59 incoming SSU V6 sessions 2014-10-29 15:02:48 -04:00
orignal
a3fd338fab pass our address as boost's address 2014-10-29 13:49:21 -04:00
orignal
d513f20225 handle ipv6 adrresses 2014-10-29 12:28:44 -04:00
orignal
d84a7ebc7e MTU for ipv6 2014-10-29 11:17:30 -04:00
orignal
7e82686818 signature size for SessionCreated 2014-10-28 22:02:21 -04:00
orignal
faf093c474 process ipv6 addresses in SessionCreated 2014-10-28 21:32:32 -04:00
orignal
b6bc49c33a process ipv6 addresses in SessionCreated 2014-10-28 21:26:55 -04:00
orignal
39644d3bb2 send actual identity in SessionConfirmed message 2014-10-28 18:56:11 -04:00
orignal
1f69d1b890 different log levels 2014-10-28 17:55:58 -04:00
orignal
11a0bbc368 different log levels 2014-10-28 16:36:17 -04:00
orignal
fe4de7c8ac use SignedData class for signing/verification 2014-10-28 14:17:29 -04:00
orignal
7f93c680fd added missing line 2014-10-28 11:47:28 -04:00
orignal
659edf2590 common code for signing and verifing exchanged data 2014-10-28 11:34:50 -04:00
orignal
b89daaa58b Merge branch 'master' of https://github.com/orignal/i2pd 2014-10-27 20:38:17 -04:00
orignal
7900e9b126 accept v6 only for v6 acceptor 2014-10-27 20:36:03 -04:00
Meeh
af0bdc2a5e Merge branch 'master' of github-meeh420:PrivacySolutions/i2pd
Note; we use _MSC_VER instead of _WIN32 for MSVC spesific code.

* 'master' of github-meeh420:PrivacySolutions/i2pd: (35 commits)
  handle incoming datagramms
  send datagram through destination's thread
  incoming ipv6 connections
  support ipv6 for outgoing NTCP connections
  some cleanup
  Update Daemon.cpp
  Add Upstart job to debian packaging
  Implement reload in init script
  Rename init.d to i2pd.init
  Decouple logging and daemonization
  verify signature through remore identity
  moved remote RI and identity to TransportSession
  set unreachable trough NetDb
  moved AddressBook to ClientContext
  initialize router identity
  don't specify RI for inbound NTCP connections
  use remote router indentity
  take identity of local RI from private keys
  send datagram from SAM
  fixed windows build
  ...

Conflicts:
	SAM.cpp
2014-10-27 22:56:31 +01:00
Meeh
88fb8a217d Fix for build error in msvc12 2014-10-27 22:53:01 +01:00
orignal
2dfd351e7a handle incoming datagramms 2014-10-27 16:30:56 -04:00
orignal
35d4692f5f send datagram through destination's thread 2014-10-27 16:01:22 -04:00
orignal
f2434d66fc incoming ipv6 connections 2014-10-27 15:08:50 -04:00
orignal
7fb7341502 support ipv6 for outgoing NTCP connections 2014-10-26 21:32:06 -04:00
orignal
1408422da9 some cleanup 2014-10-25 22:23:28 -04:00
orignal
a20cc97fa3 Update Daemon.cpp
rollback
2014-10-25 22:11:31 -04:00
orignal
51b2b5676c Merge pull request #105 from CameronNemo/daemon
Various init script and daemonization fixups
2014-10-25 22:10:06 -04:00
Cameron Norman
e768e33ddd Add Upstart job to debian packaging 2014-10-25 18:42:35 -07:00
Cameron Norman
ced4149679 Implement reload in init script 2014-10-25 18:41:04 -07:00
Cameron Norman
61932ff49f Rename init.d to i2pd.init 2014-10-25 18:40:11 -07:00
Cameron Norman
65c13f1758 Decouple logging and daemonization 2014-10-25 18:25:03 -07:00
orignal
2308f854b1 verify signature through remore identity 2014-10-24 21:51:55 -04:00
orignal
6281fa625a moved remote RI and identity to TransportSession 2014-10-24 15:50:48 -04:00
orignal
c9abb62988 set unreachable trough NetDb 2014-10-24 15:39:53 -04:00
orignal
af997473b2 moved AddressBook to ClientContext 2014-10-24 15:22:36 -04:00
orignal
a96d70a94c initialize router identity 2014-10-24 14:24:48 -04:00
orignal
8d75d51803 don't specify RI for inbound NTCP connections 2014-10-24 13:36:55 -04:00
orignal
f81a122223 use remote router indentity 2014-10-24 13:04:14 -04:00
orignal
39bdfa8791 take identity of local RI from private keys 2014-10-24 11:25:07 -04:00
orignal
47fb6f6e04 send datagram from SAM 2014-10-23 21:14:17 -04:00
orignal
336fa8eed7 fixed windows build 2014-10-23 19:04:46 -04:00
orignal
61d36ea8c3 send datagram 2014-10-23 16:56:50 -04:00
orignal
65719ae645 send destination port for streaming 2014-10-22 21:36:11 -04:00
orignal
4ae8c3c62c create datagram destination through SAM 2014-10-22 16:42:26 -04:00
orignal
78d8d34e3b Datagram added 2014-10-22 15:30:25 -04:00
orignal
3da35c592f moved Data payload processing to StreamingDestination 2014-10-22 15:01:30 -04:00
orignal
b11877d002 create streams through ClientDestination 2014-10-22 14:01:23 -04:00
orignal
4d97b0e206 moved StreamingDestination inside ClientDestination 2014-10-22 11:46:54 -04:00
orignal
ab843b6552 cleaned up from duplicated methods 2014-10-21 15:44:28 -04:00
orignal
e96ffd4189 don't block HTTP server/proxy for 10 seconds anymore 2014-10-21 14:28:56 -04:00
orignal
7b768ccb26 moved transports to 'transport' namespace 2014-10-21 12:25:53 -04:00
orignal
165af090b6 Update README.md 2014-10-21 07:44:48 -04:00
orignal
898c81b5d6 better packaging 2014-10-20 21:39:32 -04:00
orignal
43a989872d fixed typo 2014-10-20 16:57:18 -04:00
orignal
c4dda06cde TransportSession added 2014-10-20 16:09:59 -04:00
orignal
a8871d9f98 moved DHKeysPair to Transport 2014-10-20 15:19:56 -04:00
orignal
8e8eb3b588 Merge pull request #102 from herrniemand/patch-1
Update BUILD_NOTES.md
2014-10-20 07:45:40 -04:00
Ackermann Yuriy
e7031e02e7 Update BUILD_NOTES.md 2014-10-20 20:52:45 +13:00
orignal
9b3ac19b58 show queue size 2014-10-18 15:50:34 -04:00
orignal
fcd3680547 delete expired incoming tags 2014-10-17 22:15:42 -04:00
86 changed files with 4171 additions and 1825 deletions

View File

@@ -11,14 +11,14 @@
namespace i2p
{
namespace data
namespace client
{
AddressBook::AddressBook (): m_IsLoaded (false), m_IsDowloading (false)
{
}
bool AddressBook::GetIdentHash (const std::string& address, IdentHash& ident)
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
{
auto pos = address.find(".b32.i2p");
if (pos != std::string::npos)
@@ -42,7 +42,7 @@ namespace data
return false;
}
const IdentHash * AddressBook::FindAddress (const std::string& address)
const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
{
if (!m_IsLoaded)
LoadHosts ();
@@ -57,7 +57,7 @@ namespace data
void AddressBook::InsertAddress (const std::string& address, const std::string& base64)
{
IdentityEx ident;
i2p::data::IdentityEx ident;
ident.FromBase64 (base64);
m_Addresses[address] = ident.GetIdentHash ();
LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added");
@@ -118,7 +118,7 @@ namespace data
std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos);
IdentityEx ident;
i2p::data::IdentityEx ident;
ident.FromBase64(addr);
m_Addresses[name] = ident.GetIdentHash ();
numAddresses++;

View File

@@ -11,15 +11,15 @@
namespace i2p
{
namespace data
namespace client
{
class AddressBook
{
public:
AddressBook ();
bool GetIdentHash (const std::string& address, IdentHash& ident);
const IdentHash * FindAddress (const std::string& address);
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
const i2p::data::IdentHash * FindAddress (const std::string& address);
void InsertAddress (const std::string& address, const std::string& base64); // for jump service
private:
@@ -27,7 +27,7 @@ namespace data
void LoadHosts ();
void LoadHostsFromI2P ();
std::map<std::string, IdentHash> m_Addresses;
std::map<std::string, i2p::data::IdentHash> m_Addresses;
bool m_IsLoaded, m_IsDowloading;
};
}

View File

@@ -27,7 +27,7 @@ namespace client
{
if (!m_SharedLocalDestination)
{
m_SharedLocalDestination = new i2p::stream::StreamingDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA
m_SharedLocalDestination = new ClientDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA
m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination;
m_SharedLocalDestination->Start ();
}
@@ -41,7 +41,7 @@ namespace client
std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
if (ircDestination.length () > 0) // ircdest is presented
{
i2p::stream::StreamingDestination * localDestination = nullptr;
ClientDestination * localDestination = nullptr;
std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
if (ircKeys.length () > 0)
localDestination = i2p::client::context.LoadLocalDestination (ircKeys, false);
@@ -125,7 +125,7 @@ namespace client
#else
it->path();
#endif
auto localDestination = new i2p::stream::StreamingDestination (fullPath, true);
auto localDestination = new ClientDestination (fullPath, true);
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
numDestinations++;
}
@@ -134,25 +134,25 @@ namespace client
LogPrint (numDestinations, " local destinations loaded");
}
i2p::stream::StreamingDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
ClientDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
{
auto localDestination = new i2p::stream::StreamingDestination (i2p::util::filesystem::GetFullPath (filename), isPublic);
auto localDestination = new ClientDestination (i2p::util::filesystem::GetFullPath (filename), isPublic);
std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start ();
return localDestination;
}
i2p::stream::StreamingDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType)
ClientDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType)
{
auto localDestination = new i2p::stream::StreamingDestination (isPublic, sigType);
auto localDestination = new ClientDestination (isPublic, sigType);
std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start ();
return localDestination;
}
void ClientContext::DeleteLocalDestination (i2p::stream::StreamingDestination * destination)
void ClientContext::DeleteLocalDestination (ClientDestination * destination)
{
if (!destination) return;
auto it = m_Destinations.find (destination->GetIdentHash ());
@@ -168,7 +168,7 @@ namespace client
}
}
i2p::stream::StreamingDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic)
ClientDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic)
{
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
if (it != m_Destinations.end ())
@@ -181,14 +181,14 @@ namespace client
}
return nullptr;
}
auto localDestination = new i2p::stream::StreamingDestination (keys, isPublic);
auto localDestination = new ClientDestination (keys, isPublic);
std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination;
localDestination->Start ();
return localDestination;
}
i2p::stream::StreamingDestination * ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
ClientDestination * ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
{
auto it = m_Destinations.find (destination);
if (it != m_Destinations.end ())

View File

@@ -7,6 +7,7 @@
#include "SOCKS.h"
#include "I2PTunnel.h"
#include "SAM.h"
#include "AddressBook.h"
namespace i2p
{
@@ -22,12 +23,14 @@ namespace client
void Start ();
void Stop ();
i2p::stream::StreamingDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; };
i2p::stream::StreamingDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient
i2p::stream::StreamingDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
void DeleteLocalDestination (i2p::stream::StreamingDestination * destination);
i2p::stream::StreamingDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const;
i2p::stream::StreamingDestination * LoadLocalDestination (const std::string& filename, bool isPublic);
ClientDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; };
ClientDestination * CreateNewLocalDestination (bool isPublic = true, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient
ClientDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
void DeleteLocalDestination (ClientDestination * destination);
ClientDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const;
ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic);
AddressBook& GetAddressBook () { return m_AddressBook; };
private:
@@ -36,8 +39,10 @@ namespace client
private:
std::mutex m_DestinationsMutex;
std::map<i2p::data::IdentHash, i2p::stream::StreamingDestination *> m_Destinations;
i2p::stream::StreamingDestination * m_SharedLocalDestination;
std::map<i2p::data::IdentHash, ClientDestination *> m_Destinations;
ClientDestination * m_SharedLocalDestination;
AddressBook m_AddressBook;
i2p::proxy::HTTPProxy * m_HttpProxy;
i2p::proxy::SOCKSProxy * m_SocksProxy;

View File

@@ -67,11 +67,13 @@ namespace i2p
i2p::context.UpdatePort (port);
const char * host = i2p::util::config::GetCharArg("-host", "");
if (host && host[0])
i2p::context.UpdateAddress (host);
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
if (i2p::util::config::GetArg("-unreachable", 0))
i2p::context.SetUnreachable ();
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
LogPrint("CMD parameters:");
for (int i = 0; i < argc; ++i)
LogPrint(i, " ", argv[i]);
@@ -103,7 +105,7 @@ namespace i2p
LogPrint("HTTP Server started");
i2p::data::netdb.Start();
LogPrint("NetDB started");
i2p::transports.Start();
i2p::transport::transports.Start();
LogPrint("Transports started");
i2p::tunnel::tunnels.Start();
LogPrint("Tunnels started");
@@ -120,7 +122,7 @@ namespace i2p
LogPrint("Client stoped");
i2p::tunnel::tunnels.Stop();
LogPrint("Tunnels stoped");
i2p::transports.Stop();
i2p::transport::transports.Stop();
LogPrint("Transports stoped");
i2p::data::netdb.Stop();
LogPrint("NetDB stoped");

135
Datagram.cpp Normal file
View File

@@ -0,0 +1,135 @@
#include <string.h>
#include <vector>
#include <cryptopp/sha.h>
#include <cryptopp/gzip.h>
#include "Log.h"
#include "TunnelBase.h"
#include "RouterContext.h"
#include "Destination.h"
#include "Datagram.h"
namespace i2p
{
namespace datagram
{
DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner):
m_Owner (owner), m_Receiver (nullptr)
{
}
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote)
{
uint8_t buf[MAX_DATAGRAM_SIZE];
auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE);
uint8_t * signature = buf + identityLen;
auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen ();
uint8_t * buf1 = signature + signatureLen;
size_t headerLen = identityLen + signatureLen;
memcpy (buf1, payload, len);
if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{
uint8_t hash[32];
CryptoPP::SHA256().CalculateDigest (hash, buf1, len);
m_Owner.Sign (hash, 32, signature);
}
else
m_Owner.Sign (buf1, len, signature);
auto service = m_Owner.GetService ();
if (service)
service->post (boost::bind (&DatagramDestination::SendMsg, this,
CreateDataMessage (buf, len + headerLen), remote));
else
LogPrint (eLogWarning, "Failed to send datagram. Destination is not running");
}
void DatagramDestination::SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote)
{
auto leases = remote.GetNonExpiredLeases ();
if (!leases.empty ())
{
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
auto garlic = m_Owner.WrapMessage (remote, msg, true);
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
leases[i].tunnelGateway, leases[i].tunnelID,
garlic
});
m_Owner.SendTunnelDataMsgs (msgs);
}
else
{
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
DeleteI2NPMessage (msg);
}
}
void DatagramDestination::HandleDatagram (const uint8_t * buf, size_t len)
{
i2p::data::IdentityEx identity;
size_t identityLen = identity.FromBuffer (buf, len);
const uint8_t * signature = buf + identityLen;
size_t headerLen = identityLen + identity.GetSignatureLen ();
bool verified = false;
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{
uint8_t hash[32];
CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen);
verified = identity.Verify (hash, 32, signature);
}
else
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
if (verified)
{
if (m_Receiver != nullptr)
m_Receiver (identity, buf + headerLen, len -headerLen);
else
LogPrint (eLogWarning, "Receiver for datagram is not set");
}
else
LogPrint (eLogWarning, "Datagram signature verification failed");
}
void DatagramDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
{
// unzip it
CryptoPP::Gunzip decompressor;
decompressor.Put (buf, len);
decompressor.MessageEnd();
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
auto uncompressedLen = decompressor.MaxRetrievable ();
if (uncompressedLen <= MAX_DATAGRAM_SIZE)
{
decompressor.Get (uncompressed, uncompressedLen);
HandleDatagram (uncompressed, uncompressedLen);
}
else
LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size");
}
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len)
{
I2NPMessage * msg = NewI2NPMessage ();
CryptoPP::Gzip compressor; // default level
compressor.Put (payload, len);
compressor.MessageEnd();
int size = compressor.MaxRetrievable ();
uint8_t * buf = msg->GetPayload ();
*(uint32_t *)buf = htobe32 (size); // length
buf += 4;
compressor.Get (buf, size);
memset (buf + 4, 0, 4); // source and destination are zeroes
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData);
return msg;
}
}
}

49
Datagram.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef DATAGRAM_H__
#define DATAGRAM_H__
#include <inttypes.h>
#include <functional>
#include "Identity.h"
#include "LeaseSet.h"
#include "I2NPProtocol.h"
namespace i2p
{
namespace client
{
class ClientDestination;
}
namespace datagram
{
const size_t MAX_DATAGRAM_SIZE = 32768;
class DatagramDestination
{
typedef std::function<void (const i2p::data::IdentityEx& ident, const uint8_t *, size_t)> Receiver;
public:
DatagramDestination (i2p::client::ClientDestination& owner);
~DatagramDestination () {};
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::LeaseSet& remote);
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
void ResetReceiver () { m_Receiver = nullptr; };
private:
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
void SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote);
void HandleDatagram (const uint8_t * buf, size_t len);
private:
i2p::client::ClientDestination& m_Owner;
Receiver m_Receiver;
};
}
}
#endif

View File

@@ -1,7 +1,6 @@
#include <fstream>
#include <algorithm>
#include <cryptopp/dh.h>
#include <cryptopp/gzip.h>
#include "Log.h"
#include "util.h"
#include "NetDb.h"
@@ -13,7 +12,8 @@ namespace client
{
ClientDestination::ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType):
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr),
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic)
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic),
m_DatagramDestination (nullptr)
{
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
@@ -21,11 +21,13 @@ namespace client
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
if (m_IsPublic)
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
}
ClientDestination::ClientDestination (const std::string& fullPath, bool isPublic):
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr),
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic)
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic),
m_DatagramDestination (nullptr)
{
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
if (s.is_open ())
@@ -56,17 +58,20 @@ namespace client
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
}
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic):
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr),
m_Keys (keys), m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic)
m_Keys (keys), m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic),
m_DatagramDestination (nullptr)
{
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
if (m_IsPublic)
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
}
ClientDestination::~ClientDestination ()
@@ -79,6 +84,8 @@ namespace client
delete m_LeaseSet;
delete m_Work;
delete m_Service;
delete m_StreamingDestination;
delete m_DatagramDestination;
}
void ClientDestination::Run ()
@@ -94,10 +101,18 @@ namespace client
m_Pool->SetActive (true);
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
m_StreamingDestination->Start ();
}
void ClientDestination::Stop ()
{
m_StreamingDestination->Stop ();
if (m_DatagramDestination)
{
auto d = m_DatagramDestination;
m_DatagramDestination = nullptr;
delete d;
}
if (m_Pool)
i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
m_IsRunning = false;
@@ -238,135 +253,58 @@ namespace client
uint32_t length = be32toh (*(uint32_t *)buf);
buf += 4;
// we assume I2CP payload
if (buf[9] == 6) // streaming protocol
switch (buf[9])
{
// unzip it
CryptoPP::Gunzip decompressor;
decompressor.Put (buf, length);
decompressor.MessageEnd();
i2p::stream::Packet * uncompressed = new i2p::stream::Packet;
uncompressed->offset = 0;
uncompressed->len = decompressor.MaxRetrievable ();
if (uncompressed->len <= i2p::stream::MAX_PACKET_SIZE)
{
decompressor.Get (uncompressed->buf, uncompressed->len);
HandleNextPacket (uncompressed);
}
case PROTOCOL_TYPE_STREAMING:
// streaming protocol
if (m_StreamingDestination)
m_StreamingDestination->HandleDataMessagePayload (buf, length);
else
{
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped");
decompressor.Skip ();
delete uncompressed;
}
}
LogPrint ("Missing streaming destination");
break;
case PROTOCOL_TYPE_DATAGRAM:
// datagram protocol
if (m_DatagramDestination)
m_DatagramDestination->HandleDataMessagePayload (buf, length);
else
LogPrint ("Missing streaming destination");
break;
default:
LogPrint ("Data: unexpected protocol ", buf[9]);
}
I2NPMessage * ClientDestination::CreateDataMessage (const uint8_t * payload, size_t len)
{
I2NPMessage * msg = NewI2NPShortMessage ();
CryptoPP::Gzip compressor;
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL);
else
compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL);
compressor.Put (payload, len);
compressor.MessageEnd();
int size = compressor.MaxRetrievable ();
uint8_t * buf = msg->GetPayload ();
*(uint32_t *)buf = htobe32 (size); // length
buf += 4;
compressor.Get (buf, size);
memset (buf + 4, 0, 4); // source and destination ports. TODO: fill with proper values later
buf[9] = 6; // streaming protocol
msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData);
return msg;
}
}
namespace stream
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
{
void StreamingDestination::Start ()
{
ClientDestination::Start ();
if (m_StreamingDestination)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
return nullptr;
}
void StreamingDestination::Stop ()
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
{
ResetAcceptor ();
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear ();
}
ClientDestination::Stop ();
if (m_StreamingDestination)
m_StreamingDestination->SetAcceptor (acceptor);
}
void StreamingDestination::HandleNextPacket (Packet * packet)
void ClientDestination::StopAcceptingStreams ()
{
uint32_t sendStreamID = packet->GetSendStreamID ();
if (sendStreamID)
{
auto it = m_Streams.find (sendStreamID);
if (it != m_Streams.end ())
it->second->HandleNextPacket (packet);
else
{
LogPrint ("Unknown stream ", sendStreamID);
delete packet;
}
}
else // new incoming stream
{
auto incomingStream = CreateNewIncomingStream ();
incomingStream->HandleNextPacket (packet);
if (m_Acceptor != nullptr)
m_Acceptor (incomingStream);
else
{
LogPrint ("Acceptor for incoming stream is not set");
DeleteStream (incomingStream);
}
}
if (m_StreamingDestination)
m_StreamingDestination->ResetAcceptor ();
}
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote)
bool ClientDestination::IsAcceptingStreams () const
{
Stream * s = new Stream (*GetService (), *this, remote);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
if (m_StreamingDestination)
return m_StreamingDestination->IsAcceptorSet ();
return false;
}
Stream * StreamingDestination::CreateNewIncomingStream ()
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination ()
{
Stream * s = new Stream (*GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
void StreamingDestination::DeleteStream (Stream * stream)
{
if (stream)
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
auto it = m_Streams.find (stream->GetRecvStreamID ());
if (it != m_Streams.end ())
{
m_Streams.erase (it);
if (GetService ())
GetService ()->post ([stream](void) { delete stream; });
else
delete stream;
}
}
if (!m_DatagramDestination)
m_DatagramDestination = new i2p::datagram::DatagramDestination (*this);
return m_DatagramDestination;
}
}
}

View File

@@ -9,11 +9,16 @@
#include "LeaseSet.h"
#include "Garlic.h"
#include "Streaming.h"
#include "Datagram.h"
namespace i2p
{
namespace client
{
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
const uint8_t PROTOCOL_TYPE_RAW = 18;
class ClientDestination: public i2p::garlic::GarlicDestination
{
public:
@@ -34,6 +39,17 @@ namespace client
const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident);
void SendTunnelDataMsgs (const std::vector<i2p::tunnel::TunnelMessageBlock>& msgs);
// streaming
i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; };
i2p::stream::Stream * CreateStream (const i2p::data::LeaseSet& remote, int port = 0);
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
void StopAcceptingStreams ();
bool IsAcceptingStreams () const;
// datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
// implements LocalDestination
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; };
@@ -50,11 +66,6 @@ namespace client
// I2CP
void HandleDataMessage (const uint8_t * buf, size_t len);
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
protected:
virtual void HandleNextPacket (i2p::stream::Packet * packet) = 0; // TODO
private:
@@ -77,55 +88,15 @@ namespace client
i2p::data::LeaseSet * m_LeaseSet;
bool m_IsPublic;
i2p::stream::StreamingDestination * m_StreamingDestination;
i2p::datagram::DatagramDestination * m_DatagramDestination;
public:
// for HTTP only
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
};
}
namespace stream
{
class StreamingDestination: public i2p::client::ClientDestination
{
public:
StreamingDestination (bool isPublic, i2p::data::SigningKeyType sigType):
ClientDestination (isPublic, sigType) {};
StreamingDestination (const std::string& fullPath, bool isPublic):
ClientDestination (fullPath, isPublic) {};
StreamingDestination (const i2p::data::PrivateKeys& keys, bool isPublic):
ClientDestination (keys, isPublic) {};
~StreamingDestination () {};
void Start ();
void Stop ();
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote);
void DeleteStream (Stream * stream);
void SetAcceptor (const std::function<void (Stream *)>& acceptor) { m_Acceptor = acceptor; };
void ResetAcceptor () { m_Acceptor = nullptr; };
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
// ClientDestination
void HandleNextPacket (Packet * packet);
private:
Stream * CreateNewIncomingStream ();
private:
std::mutex m_StreamsMutex;
std::map<uint32_t, Stream *> m_Streams;
std::function<void (Stream *)> m_Acceptor;
public:
// for HTTP only
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
};
}
}
#endif

View File

@@ -148,7 +148,7 @@ namespace garlic
size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, const I2NPMessage * msg)
{
size_t blockSize = 0;
bool createNewTags = m_Owner && ((int)m_SessionTags.size () <= m_NumTags/4);
bool createNewTags = m_Owner && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags/2);
UnconfirmedTags * newTags = createNewTags ? GenerateSessionTags () : nullptr;
*(uint16_t *)buf = newTags ? htobe16 (newTags->numTags) : 0; // tag count
blockSize += 2;
@@ -272,6 +272,16 @@ namespace garlic
size += 4;
// create msg
I2NPMessage * msg = CreateDeliveryStatusMsg (msgID);
if (m_Owner)
{
//encrypt
uint8_t key[32], tag[32];
m_Rnd.GenerateBlock (key, 32); // random session key
m_Rnd.GenerateBlock (tag, 32); // random session tag
m_Owner->AddSessionKey (key, tag);
GarlicRoutingSession garlic (key, tag);
msg = garlic.WrapSingleMessage (msg);
}
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength ();
DeleteI2NPMessage (msg);
@@ -304,9 +314,10 @@ namespace garlic
{
if (key)
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
auto decryption = std::make_shared<i2p::crypto::CBCDecryption>();
decryption->SetKey (key);
m_Tags[SessionTag(tag)] = decryption;
m_Tags[SessionTag(tag, ts)] = decryption;
}
}
@@ -314,7 +325,7 @@ namespace garlic
{
uint8_t * buf = msg->GetPayload ();
uint32_t length = be32toh (*(uint32_t *)buf);
buf += 4; // lentgh
buf += 4; // length
auto it = m_Tags.find (SessionTag(buf));
if (it != m_Tags.end ())
{
@@ -344,6 +355,28 @@ namespace garlic
LogPrint ("Failed to decrypt garlic");
}
DeleteI2NPMessage (msg);
// cleanup expired tags
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts > m_LastTagsCleanupTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
if (m_LastTagsCleanupTime)
{
int numExpiredTags = 0;
for (auto it = m_Tags.begin (); it != m_Tags.end ();)
{
if (ts > it->first.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
numExpiredTags++;
it = m_Tags.erase (it);
}
else
it++;
}
LogPrint (numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
}
m_LastTagsCleanupTime = ts;
}
}
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<i2p::crypto::CBCDecryption> decryption,
@@ -447,9 +480,17 @@ namespace garlic
I2NPMessage * GarlicDestination::WrapMessage (const i2p::data::RoutingDestination& destination,
I2NPMessage * msg, bool attachLeaseSet)
{
auto session = GetRoutingSession (destination, attachLeaseSet ? 32 : 0); // don't use tag if no LeaseSet
if (attachLeaseSet) // we should maintain this session
{
auto session = GetRoutingSession (destination, 32); // 32 tags by default
return session->WrapSingleMessage (msg);
}
else // one time session
{
GarlicRoutingSession session (this, &destination, 0); // don't use tag if no LeaseSet
return session.WrapSingleMessage (msg);
}
}
GarlicRoutingSession * GarlicDestination::GetRoutingSession (
const i2p::data::RoutingDestination& destination, int numTags)

View File

@@ -37,7 +37,7 @@ namespace garlic
};
#pragma pack()
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 900; // 15 minutes
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
struct SessionTag: public i2p::data::Tag<32>
@@ -88,7 +88,7 @@ namespace garlic
GarlicDestination * m_Owner;
const i2p::data::RoutingDestination * m_Destination;
uint8_t m_SessionKey[32];
i2p::crypto::AESKey m_SessionKey;
std::list<SessionTag> m_SessionTags;
int m_NumTags;
std::map<uint32_t, UnconfirmedTags *> m_UnconfirmedTagsMsgs;
@@ -102,7 +102,7 @@ namespace garlic
{
public:
GarlicDestination () {};
GarlicDestination (): m_LastTagsCleanupTime (0) {};
~GarlicDestination ();
GarlicRoutingSession * GetRoutingSession (const i2p::data::RoutingDestination& destination, int numTags);
@@ -137,6 +137,7 @@ namespace garlic
std::map<i2p::data::IdentHash, GarlicRoutingSession *> m_Sessions;
// incoming
std::map<SessionTag, std::shared_ptr<i2p::crypto::CBCDecryption>> m_Tags;
uint32_t m_LastTagsCleanupTime;
// DeliveryStatus
std::map<uint32_t, GarlicRoutingSession *> m_CreatedSessions; // msgID -> session
};

View File

@@ -1,7 +1,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
#include "NetDb.h"
#include "ClientContext.h"
#include "HTTPProxy.h"
namespace i2p
@@ -52,10 +52,11 @@ namespace proxy
}
path=m[4].str();
}
LogPrint("server is: ",server, "\n path is: ",path);
LogPrint("server is: ",server, " port is: ", port, "\n path is: ",path);
r.uri = path;
r.method = method;
r.host = server;
r.port = boost::lexical_cast<int>(port);
}
@@ -73,12 +74,12 @@ namespace proxy
{
LogPrint ("Jump service for ", r.host, " found. Inserting to address book");
auto base64 = r.uri.substr (addressPos + 1);
i2p::data::netdb.GetAddressBook ().InsertAddress (r.host, base64);
i2p::client::context.GetAddressBook ().InsertAddress (r.host, base64);
}
}
LogPrint("Requesting ", r.host, " with path ", r.uri, " and method ", r.method);
SendToAddress (r.host, m_Buffer, m_BufferLen);
LogPrint("Requesting ", r.host, ":", r.port, " with path ", r.uri, " and method ", r.method);
SendToAddress (r.host, r.port, m_Buffer, m_BufferLen);
}
}

View File

@@ -517,7 +517,7 @@ namespace util
if (m_Stream)
{
m_Stream->Close ();
i2p::client::context.GetSharedLocalDestination ()->DeleteStream (m_Stream);
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
m_Socket->close ();
@@ -644,9 +644,15 @@ namespace util
switch (address.transportStyle)
{
case i2p::data::RouterInfo::eTransportNTCP:
if (address.host.is_v6 ())
s << "NTCP6&nbsp;&nbsp;";
else
s << "NTCP&nbsp;&nbsp;";
break;
case i2p::data::RouterInfo::eTransportSSU:
if (address.host.is_v6 ())
s << "SSU6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
else
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
break;
default:
@@ -699,14 +705,14 @@ namespace util
void HTTPConnection::ShowTransports (std::stringstream& s)
{
s << "NTCP<br>";
for (auto it: i2p::transports.GetNTCPSessions ())
for (auto it: i2p::transport::transports.GetNTCPSessions ())
{
// RouterInfo of incoming connection doesn't have address
bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress ();
if (it.second->IsEstablished ())
if (it.second && it.second->IsEstablished ())
{
// incoming connection doesn't have remote RI
bool outgoing = it.second->GetRemoteRouter ();
if (outgoing) s << "-->";
s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": "
s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": "
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
if (!outgoing) s << "-->";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
@@ -714,7 +720,7 @@ namespace util
}
s << std::endl;
}
auto ssuServer = i2p::transports.GetSSUServer ();
auto ssuServer = i2p::transport::transports.GetSSUServer ();
if (ssuServer)
{
s << "<br>SSU<br>";
@@ -813,10 +819,11 @@ namespace util
}
}
s << "<br><b>Streams:</b><br>";
for (auto it: dest->GetStreams ())
for (auto it: dest->GetStreamingDestination ()->GetStreams ())
{
s << it.first << "->" << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase32 () << ".b32.i2p ";
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]";
s << "<br>"<< std::endl;
}
}
@@ -838,38 +845,49 @@ namespace util
{
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n";
LogPrint("HTTP Client Request: ", request);
SendToAddress (address, request.c_str (), request.size ());
SendToAddress (address, 80, request.c_str (), request.size ());
}
void HTTPConnection::SendToAddress (const std::string& address, const char * buf, size_t len)
void HTTPConnection::SendToAddress (const std::string& address, int port, const char * buf, size_t len)
{
i2p::data::IdentHash destination;
if (!i2p::data::netdb.GetAddressBook ().GetIdentHash (address, destination))
if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
{
LogPrint ("Unknown address ", address);
SendReply ("<html>" + itoopieImage + "<br>Unknown address " + address + "</html>", 404);
return;
}
SendToDestination (destination, buf, len);
}
void HTTPConnection::SendToDestination (const i2p::data::IdentHash& destination, const char * buf, size_t len)
{
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
if (!leaseSet || !leaseSet->HasNonExpiredLeases ())
if (leaseSet && leaseSet->HasNonExpiredLeases ())
SendToDestination (leaseSet, port, buf, len);
else
{
i2p::data::netdb.RequestDestination (destination, true, i2p::client::context.GetSharedLocalDestination ()->GetTunnelPool ());
std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds
leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet
m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT));
m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout,
this, boost::asio::placeholders::error, destination, port, buf, len));
}
}
void HTTPConnection::HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
i2p::data::IdentHash destination, int port, const char * buf, size_t len)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (destination);
if (leaseSet && leaseSet->HasNonExpiredLeases ())
SendToDestination (leaseSet, port, buf, len);
else
// still no LeaseSet
SendReply (leaseSet ? "<html>" + itoopieImage + "<br>Leases expired</html>" : "<html>" + itoopieImage + "LeaseSet not found</html>", 504);
return;
}
}
void HTTPConnection::SendToDestination (const i2p::data::LeaseSet * remote, int port, const char * buf, size_t len)
{
if (!m_Stream)
m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream (*leaseSet);
m_Stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (*remote, port);
if (m_Stream)
{
m_Stream->Send ((uint8_t *)buf, len);

View File

@@ -5,6 +5,7 @@
#include <thread>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include "LeaseSet.h"
#include "Streaming.h"
namespace i2p
@@ -12,6 +13,7 @@ namespace i2p
namespace util
{
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
class HTTPConnection
{
protected:
@@ -27,6 +29,7 @@ namespace util
std::string method;
std::string uri;
std::string host;
int port;
int http_version_major;
int http_version_minor;
std::vector<header> headers;
@@ -43,7 +46,8 @@ namespace util
public:
HTTPConnection (boost::asio::ip::tcp::socket * socket):
m_Socket (socket), m_Stream (nullptr), m_BufferLen (0) { Receive (); };
m_Socket (socket), m_Timer (socket->get_io_service ()),
m_Stream (nullptr), m_BufferLen (0) { Receive (); };
virtual ~HTTPConnection() { delete m_Socket; }
private:
@@ -74,6 +78,7 @@ namespace util
protected:
boost::asio::ip::tcp::socket * m_Socket;
boost::asio::deadline_timer m_Timer;
i2p::stream::Stream * m_Stream;
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
size_t m_BufferLen;
@@ -84,8 +89,10 @@ namespace util
virtual void RunRequest ();
void HandleDestinationRequest(const std::string& address, const std::string& uri);
void SendToAddress (const std::string& address, const char * buf, size_t len);
void SendToDestination (const i2p::data::IdentHash& destination, const char * buf, size_t len);
void SendToAddress (const std::string& address, int port, const char * buf, size_t len);
void HandleDestinationRequestTimeout (const boost::system::error_code& ecode,
i2p::data::IdentHash destination, int port, const char * buf, size_t len);
void SendToDestination (const i2p::data::LeaseSet * remote, int port, const char * buf, size_t len);
public:

View File

@@ -13,9 +13,10 @@
#include "Garlic.h"
#include "I2NPProtocol.h"
using namespace i2p::transport;
namespace i2p
{
I2NPMessage * NewI2NPMessage ()
{
return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>();
@@ -289,7 +290,7 @@ namespace i2p
{
LogPrint ("Record ",i," is ours");
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKey (), records[i].encrypted, (uint8_t *)&clearText);
i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), records[i].encrypted, (uint8_t *)&clearText);
// replace record to reply
I2NPBuildResponseRecord * reply = (I2NPBuildResponseRecord *)(records + i);
if (i2p::context.AcceptsTunnels ())
@@ -353,13 +354,13 @@ namespace i2p
if (clearText.flag & 0x40) // we are endpoint of outboud tunnel
{
// so we send it to reply tunnel
i2p::transports.SendMessage (clearText.nextIdent,
transports.SendMessage (clearText.nextIdent,
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
eI2NPVariableTunnelBuildReply, buf, len,
be32toh (clearText.nextMessageID)));
}
else
i2p::transports.SendMessage (clearText.nextIdent,
transports.SendMessage (clearText.nextIdent,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
}
}
@@ -373,13 +374,13 @@ namespace i2p
if (clearText.flag & 0x40) // we are endpoint of outbound tunnel
{
// so we send it to reply tunnel
i2p::transports.SendMessage (clearText.nextIdent,
transports.SendMessage (clearText.nextIdent,
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
eI2NPTunnelBuildReply, buf, len,
be32toh (clearText.nextMessageID)));
}
else
i2p::transports.SendMessage (clearText.nextIdent,
transports.SendMessage (clearText.nextIdent,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
}
}

View File

@@ -34,6 +34,14 @@ uint16_t be16toh(uint16_t big16);
uint32_t be32toh(uint32_t big32);
uint64_t be64toh(uint64_t big64);
// assume LittleEndine
#define htole16
#define htole32
#define htole64
#define le16toh
#define le32toh
#define le64toh
#endif
#endif // I2PENDIAN_H__

View File

@@ -14,7 +14,7 @@ namespace client
boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet):
m_Socket (socket), m_Owner (owner)
{
m_Stream = m_Owner->GetLocalDestination ()->CreateNewOutgoingStream (*leaseSet);
m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet);
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
@@ -39,7 +39,7 @@ namespace client
if (m_Stream)
{
m_Stream->Close ();
m_Owner->GetLocalDestination ()->DeleteStream (m_Stream);
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
m_Socket->close ();
@@ -115,7 +115,7 @@ namespace client
if (ecode != boost::asio::error::operation_aborted)
{
if (m_Stream) m_Stream->Close ();
m_Owner->GetLocalDestination ()->DeleteStream (m_Stream);
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
}
@@ -145,7 +145,7 @@ namespace client
}
I2PClientTunnel::I2PClientTunnel (boost::asio::io_service& service, const std::string& destination,
int port, i2p::stream::StreamingDestination * localDestination):
int port, ClientDestination * localDestination):
I2PTunnel (service, localDestination ? localDestination :
i2p::client::context.CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256)),
m_Acceptor (service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)),
@@ -162,7 +162,7 @@ namespace client
void I2PClientTunnel::Start ()
{
i2p::data::IdentHash identHash;
if (i2p::data::netdb.GetAddressBook ().GetIdentHash (m_Destination, identHash))
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
if (!m_DestinationIdentHash)
LogPrint ("I2PTunnel unknown destination ", m_Destination);
@@ -192,7 +192,7 @@ namespace client
if (!m_DestinationIdentHash)
{
i2p::data::IdentHash identHash;
if (i2p::data::netdb.GetAddressBook ().GetIdentHash (m_Destination, identHash))
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
}
if (m_DestinationIdentHash)
@@ -251,7 +251,7 @@ namespace client
}
I2PServerTunnel::I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port,
i2p::stream::StreamingDestination * localDestination): I2PTunnel (service, localDestination),
ClientDestination * localDestination): I2PTunnel (service, localDestination),
m_Endpoint (boost::asio::ip::address::from_string (address), port)
{
}
@@ -270,7 +270,7 @@ namespace client
{
auto localDestination = GetLocalDestination ();
if (localDestination)
localDestination->SetAcceptor (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
else
LogPrint ("Local destination not set for server tunnel");
}

View File

@@ -6,6 +6,7 @@
#include <set>
#include <boost/asio.hpp>
#include "Identity.h"
#include "Destination.h"
#include "Streaming.h"
namespace i2p
@@ -51,22 +52,22 @@ namespace client
{
public:
I2PTunnel (boost::asio::io_service& service, i2p::stream::StreamingDestination * localDestination):
I2PTunnel (boost::asio::io_service& service, ClientDestination * localDestination):
m_Service (service), m_LocalDestination (localDestination) {};
virtual ~I2PTunnel () { ClearConnections (); };
void AddConnection (I2PTunnelConnection * conn);
void RemoveConnection (I2PTunnelConnection * conn);
void ClearConnections ();
i2p::stream::StreamingDestination * GetLocalDestination () { return m_LocalDestination; };
void SetLocalDestination (i2p::stream::StreamingDestination * dest) { m_LocalDestination = dest; };
ClientDestination * GetLocalDestination () { return m_LocalDestination; };
void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; };
boost::asio::io_service& GetService () { return m_Service; };
private:
boost::asio::io_service& m_Service;
i2p::stream::StreamingDestination * m_LocalDestination;
ClientDestination * m_LocalDestination;
std::set<I2PTunnelConnection *> m_Connections;
};
@@ -75,7 +76,7 @@ namespace client
public:
I2PClientTunnel (boost::asio::io_service& service, const std::string& destination, int port,
i2p::stream::StreamingDestination * localDestination = nullptr);
ClientDestination * localDestination = nullptr);
~I2PClientTunnel ();
void Start ();
@@ -102,7 +103,7 @@ namespace client
public:
I2PServerTunnel (boost::asio::io_service& service, const std::string& address, int port,
i2p::stream::StreamingDestination * localDestination);
ClientDestination * localDestination);
void Start ();
void Stop ();

View File

@@ -2,7 +2,6 @@
#include <stdio.h>
#include <cryptopp/sha.h>
#include <cryptopp/osrng.h>
#include <cryptopp/dh.h>
#include <cryptopp/dsa.h>
#include "base64.h"
#include "CryptoConst.h"
@@ -101,7 +100,7 @@ namespace data
m_ExtendedBuffer = nullptr;
delete m_Verifier;
CreateVerifier ();
m_Verifier = nullptr;
return *this;
}
@@ -116,7 +115,7 @@ namespace data
m_ExtendedLen = 0;
delete m_Verifier;
CreateVerifier ();
m_Verifier = nullptr;
return *this;
}
@@ -140,7 +139,7 @@ namespace data
CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ());
delete m_Verifier;
CreateVerifier ();
m_Verifier = nullptr;
return GetFullLen ();
}
@@ -162,6 +161,7 @@ namespace data
size_t IdentityEx::GetSigningPublicKeyLen () const
{
if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetPublicKeyLen ();
return 128;
@@ -169,12 +169,14 @@ namespace data
size_t IdentityEx::GetSignatureLen () const
{
if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetSignatureLen ();
return 40;
}
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->Verify (buf, len, signature);
return false;
@@ -187,7 +189,7 @@ namespace data
return SIGNING_KEY_TYPE_DSA_SHA1;
}
void IdentityEx::CreateVerifier ()
void IdentityEx::CreateVerifier () const
{
auto keyType = GetSigningKeyType ();
switch (keyType)
@@ -293,14 +295,6 @@ namespace data
return keys;
}
void CreateRandomDHKeysPair (DHKeysPair * keys)
{
if (!keys) return;
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(rnd, keys->privateKey, keys->publicKey);
}
IdentHash CreateRoutingKey (const IdentHash& ident)
{
uint8_t buf[41]; // ident + yyyymmdd

View File

@@ -67,13 +67,6 @@ namespace data
typedef Tag<32> IdentHash;
#pragma pack(1)
struct DHKeysPair // transient keys for transport sessions
{
uint8_t publicKey[256];
uint8_t privateKey[256];
};
struct Keys
{
uint8_t privateKey[256];
@@ -82,7 +75,6 @@ namespace data
uint8_t signingKey[128];
};
const uint8_t CERTIFICATE_TYPE_NULL = 0;
const uint8_t CERTIFICATE_TYPE_HASHCASH = 1;
const uint8_t CERTIFICATE_TYPE_HIDDEN = 2;
@@ -106,6 +98,9 @@ namespace data
size_t FromBuffer (const uint8_t * buf, size_t len);
IdentHash Hash () const;
};
#pragma pack()
Keys CreateRandomKeys ();
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
@@ -139,13 +134,13 @@ namespace data
private:
void CreateVerifier ();
void CreateVerifier () const;
private:
Identity m_StandardIdentity;
IdentHash m_IdentHash;
i2p::crypto::Verifier * m_Verifier;
mutable i2p::crypto::Verifier * m_Verifier;
size_t m_ExtendedLen;
uint8_t * m_ExtendedBuffer;
};
@@ -184,11 +179,6 @@ namespace data
i2p::crypto::Signer * m_Signer;
};
#pragma pack()
Keys CreateRandomKeys ();
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
// kademlia
struct XORMetric
{

11
Log.cpp
View File

@@ -3,9 +3,18 @@
Log * g_Log = nullptr;
static const char * g_LogLevelStr[eNumLogLevels] =
{
"error", // eLogError
"warn", // eLogWarning
"info", // eLogInfo
"debug" // eLogDebug
};
void LogMsg::Process()
{
output << boost::posix_time::second_clock::local_time().time_of_day () << " - ";
output << boost::posix_time::second_clock::local_time().time_of_day () <<
"/" << g_LogLevelStr[level] << " - ";
output << s.str();
}

23
Log.h
View File

@@ -8,12 +8,22 @@
#include <functional>
#include "Queue.h"
enum LogLevel
{
eLogError = 0,
eLogWarning,
eLogInfo,
eLogDebug,
eNumLogLevels
};
struct LogMsg
{
std::stringstream s;
std::ostream& output;
LogLevel level;
LogMsg (std::ostream& o = std::cout): output (o) {};
LogMsg (std::ostream& o = std::cout, LogLevel l = eLogInfo): output (o), level (l) {};
void Process();
};
@@ -72,9 +82,10 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
}
template<typename... TArgs>
void LogPrint (TArgs... args)
void LogPrint (LogLevel level, TArgs... args)
{
LogMsg * msg = (g_Log && g_Log->GetLogFile ()) ? new LogMsg (*g_Log->GetLogFile ()) : new LogMsg ();
LogMsg * msg = (g_Log && g_Log->GetLogFile ()) ? new LogMsg (*g_Log->GetLogFile (), level) :
new LogMsg (std::cout, level);
LogPrint (msg->s, args...);
msg->s << std::endl;
if (g_Log)
@@ -86,4 +97,10 @@ void LogPrint (TArgs... args)
}
}
template<typename... TArgs>
void LogPrint (TArgs... args)
{
LogPrint (eLogInfo, args...);
}
#endif

View File

@@ -11,13 +11,13 @@ endif
all: obj i2p
i2p: $(OBJECTS:obj/%=obj/%)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : %.cpp
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
$(CXX) -o $@ $< -c $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS)
obj:
mkdir -p obj

View File

@@ -1,6 +1,8 @@
CC = g++
CFLAGS = -std=c++11 -O2
CXX = g++
CXXFLAGS = -O2
NEEDED_CXXFLAGS = -std=c++11
include filelist.mk
INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =

View File

@@ -1,25 +1,43 @@
CC = g++
CFLAGS = -g -Wall
CXXVER := $(shell ${CC} -dumpversion)
CXXFLAGS = -g -Wall
CXXVER := $(shell $(CXX) -dumpversion)
FGREP = fgrep
IS_64 := $(shell $(CXX) -dumpmachine 2>&1 | $(FGREP) -c "64")
USE_AESNI := yes
ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # >= 4.10
CFLAGS += -std=c++11
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
CFLAGS += -std=c++11
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
CFLAGS += -std=c++0x
NEEDED_CXXFLAGS += -std=c++0x
else ifeq ($(shell expr match $(CXX) 'clang'),5)
NEEDED_CXXFLAGS += -std=c++11
else # not supported
$(error Compiler too old)
endif
LIBDIR := /usr/lib
include filelist.mk
INCFLAGS =
LDFLAGS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
ifeq ($(STATIC),yes)
LDLIBS += $(LIBDIR)/libcryptopp.a $(LIBDIR)/libboost_system.a
LDLIBS += $(LIBDIR)/libboost_date_time.a $(LIBDIR)/libboost_filesystem.a
LDLIBS += $(LIBDIR)/libboost_regex.a $(LIBDIR)/libboost_program_options.a
LDLIBS += -lpthread -static-libstdc++ -static-libgcc
USE_AESNI := no
else
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
endif
LIBS =
ifeq ($(USE_AESNI),yes)
ifeq ($(IS_64),1)
#check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
CPU_FLAGS = -maes -DAESNI
endif
endif
endif

View File

@@ -1,15 +1,16 @@
CC = clang++
CFLAGS = -g -Wall -std=c++11 -lstdc++ -I/usr/local/include
CXX = clang++
CXXFLAGS = -g -Wall -std=c++11 -lstdc++ -I/usr/local/include
include filelist.mk
INCFLAGS = -DCRYPTOPP_DISABLE_ASM
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =
# 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
CFLAGS += -DAESNI
CXXFLAGS += -maes -DAESNI
# Apple Mac OSX
UNAME_S := $(shell uname -s)

View File

@@ -3,7 +3,6 @@
#include "I2PEndian.h"
#include <boost/bind.hpp>
#include <cryptopp/dh.h>
#include <cryptopp/dsa.h>
#include "base64.h"
#include "Log.h"
#include "Timestamp.h"
@@ -11,28 +10,27 @@
#include "I2NPProtocol.h"
#include "RouterContext.h"
#include "Transports.h"
#include "NetDb.h"
#include "NTCPSession.h"
using namespace i2p::crypto;
namespace i2p
{
namespace ntcp
namespace transport
{
NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo):
m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false),
m_DHKeysPair (nullptr), m_RemoteRouterInfo (in_RemoteRouterInfo),
m_ReceiveBufferOffset (0), m_NextMessage (nullptr),
m_NumSentBytes (0), m_NumReceivedBytes (0)
NTCPSession::NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter):
TransportSession (in_RemoteRouter), m_Socket (service),
m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0),
m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0)
{
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
m_DHKeysPair = transports.GetNextDHKeysPair ();
m_Establisher = new Establisher;
}
NTCPSession::~NTCPSession ()
{
delete m_Establisher;
delete m_DHKeysPair;
if (m_NextMessage)
i2p::DeleteI2NPMessage (m_NextMessage);
for (auto it :m_DelayedMessages)
@@ -40,7 +38,7 @@ namespace ntcp
m_DelayedMessages.clear ();
}
void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey)
void NTCPSession::CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key)
{
CryptoPP::DH dh (elgp, elgg);
uint8_t sharedKey[256];
@@ -51,6 +49,7 @@ namespace ntcp
return;
};
uint8_t * aesKey = key;
if (sharedKey[0] & 0x80)
{
aesKey[0] = 0;
@@ -79,12 +78,13 @@ namespace ntcp
{
m_IsEstablished = false;
m_Socket.close ();
i2p::transports.RemoveNTCPSession (this);
transports.RemoveNTCPSession (this);
int numDelayed = 0;
for (auto it :m_DelayedMessages)
{
// try to send them again
i2p::transports.SendMessage (m_RemoteRouterInfo.GetIdentHash (), it);
if (m_RemoteRouter)
transports.SendMessage (m_RemoteRouter->GetIdentHash (), it);
numDelayed++;
}
m_DelayedMessages.clear ();
@@ -121,12 +121,12 @@ namespace ntcp
void NTCPSession::ClientLogin ()
{
if (!m_DHKeysPair)
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
m_DHKeysPair = transports.GetNextDHKeysPair ();
// send Phase1
const uint8_t * x = m_DHKeysPair->publicKey;
memcpy (m_Establisher->phase1.pubKey, x, 256);
CryptoPP::SHA256().CalculateDigest(m_Establisher->phase1.HXxorHI, x, 256);
const uint8_t * ident = m_RemoteRouterInfo.GetIdentHash ();
const uint8_t * ident = m_RemoteIdentity.GetIdentHash ();
for (int i = 0; i < 32; i++)
m_Establisher->phase1.HXxorHI[i] ^= ident[i];
@@ -191,7 +191,7 @@ namespace ntcp
void NTCPSession::SendPhase2 ()
{
if (!m_DHKeysPair)
m_DHKeysPair = i2p::transports.GetNextDHKeysPair ();
m_DHKeysPair = transports.GetNextDHKeysPair ();
const uint8_t * y = m_DHKeysPair->publicKey;
memcpy (m_Establisher->phase2.pubKey, y, 256);
uint8_t xy[512];
@@ -202,7 +202,7 @@ namespace ntcp
m_Establisher->phase2.encrypted.timestamp = tsB;
// TODO: fill filler
uint8_t aesKey[32];
i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase1.pubKey, aesKey);
m_Encryption.SetKey (aesKey);
m_Encryption.SetIV (y + 240);
@@ -239,8 +239,9 @@ namespace ntcp
LogPrint ("Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
if (ecode != boost::asio::error::operation_aborted)
{
GetRemoteRouterInfo ().SetUnreachable (true); // this RouterInfo is not valid
i2p::transports.ReuseDHKeysPair (m_DHKeysPair);
// this RI is not valid
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr;
Terminate ();
}
@@ -249,7 +250,7 @@ namespace ntcp
{
LogPrint ("Phase 2 received: ", bytes_transferred);
uint8_t aesKey[32];
i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase2.pubKey, aesKey);
m_Decryption.SetKey (aesKey);
m_Decryption.SetIV (m_Establisher->phase2.pubKey + 240);
@@ -265,7 +266,7 @@ namespace ntcp
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
{
LogPrint ("Incorrect hash");
i2p::transports.ReuseDHKeysPair (m_DHKeysPair);
transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr;
Terminate ();
return ;
@@ -277,17 +278,17 @@ namespace ntcp
void NTCPSession::SendPhase3 ()
{
m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE);
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetRouterIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE);
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetIdentity ().GetStandardIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); // TODO:
uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->phase3.timestamp = tsA;
SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
memcpy (s.y, m_Establisher->phase2.pubKey, 256);
memcpy (s.ident, m_RemoteRouterInfo.GetIdentHash (), 32);
s.tsA = tsA;
s.tsB = m_Establisher->phase2.encrypted.timestamp;
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase3.signature);
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase3.signature);
m_Encryption.Encrypt((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3);
@@ -324,19 +325,15 @@ namespace ntcp
{
LogPrint ("Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3);
m_RemoteRouterInfo.SetRouterIdentity (m_Establisher->phase3.ident);
m_RemoteIdentity = m_Establisher->phase3.ident;
SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
memcpy (s.y, m_Establisher->phase2.pubKey, 256);
memcpy (s.ident, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
s.tsA = m_Establisher->phase3.timestamp;
s.tsB = tsB;
CryptoPP::DSA::PublicKey pubKey;
pubKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (m_RemoteRouterInfo.GetRouterIdentity ().signingKey, 128));
CryptoPP::DSA::Verifier verifier (pubKey);
if (!verifier.VerifyMessage ((uint8_t *)&s, sizeof(s), m_Establisher->phase3.signature, 40))
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA
s.Insert (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase3.signature))
{
LogPrint ("signature verification failed");
Terminate ();
@@ -350,12 +347,12 @@ namespace ntcp
void NTCPSession::SendPhase4 (uint32_t tsB)
{
SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
memcpy (s.y, m_Establisher->phase2.pubKey, 256);
memcpy (s.ident, m_RemoteRouterInfo.GetIdentHash (), 32);
s.tsA = m_Establisher->phase3.timestamp;
s.tsB = tsB;
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Establisher->phase4.signature);
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA
s.Insert (tsB); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase4.signature);
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (),
@@ -387,7 +384,8 @@ namespace ntcp
LogPrint ("Phase 4 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
GetRemoteRouterInfo ().SetUnreachable (true); // this router doesn't like us
// this router doesn't like us
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
Terminate ();
}
}
@@ -398,16 +396,13 @@ namespace ntcp
// verify signature
SignedData s;
memcpy (s.x, m_Establisher->phase1.pubKey, 256);
memcpy (s.y, m_Establisher->phase2.pubKey, 256);
memcpy (s.ident, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
s.tsA = tsA;
s.tsB = m_Establisher->phase2.encrypted.timestamp;
s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
CryptoPP::DSA::PublicKey pubKey;
pubKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (m_RemoteRouterInfo.GetRouterIdentity ().signingKey, 128));
CryptoPP::DSA::Verifier verifier (pubKey);
if (!verifier.VerifyMessage ((uint8_t *)&s, sizeof(s), m_Establisher->phase4.signature, 40))
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase4.signature))
{
LogPrint ("signature verification failed");
Terminate ();
@@ -433,7 +428,7 @@ namespace ntcp
if (ecode)
{
LogPrint ("Read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
//if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
@@ -595,15 +590,15 @@ namespace ntcp
if (ecode != boost::asio::error::operation_aborted)
{
LogPrint ("No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
Terminate ();
//Terminate ();
m_Socket.close ();// invoke Terminate () from HandleReceive
}
}
NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address,
int port, i2p::data::RouterInfo& in_RouterInfo):
NTCPSession (service, in_RouterInfo),
m_Endpoint (address, port)
int port, const i2p::data::RouterInfo& in_RouterInfo):
NTCPSession (service, &in_RouterInfo), m_Endpoint (address, port)
{
Connect ();
}
@@ -622,13 +617,15 @@ namespace ntcp
LogPrint ("Connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
GetRemoteRouterInfo ().SetUnreachable (true);
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true);
Terminate ();
}
}
else
{
LogPrint ("Connected");
if (GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
context.UpdateNTCPV6Address (GetSocket ().local_endpoint ().address ());
ClientLogin ();
}
}
@@ -636,11 +633,8 @@ namespace ntcp
void NTCPServerConnection::Connected ()
{
LogPrint ("NTCP server session connected");
SetIsEstablished (true);
i2p::transports.AddNTCPSession (this);
SendTimeSyncMessage ();
SendI2NPMessage (CreateDatabaseStoreMsg ()); // we tell immediately who we are
transports.AddNTCPSession (this);
NTCPSession::Connected ();
}
}
}

View File

@@ -11,10 +11,11 @@
#include "Identity.h"
#include "RouterInfo.h"
#include "I2NPProtocol.h"
#include "TransportSession.h"
namespace i2p
{
namespace ntcp
namespace transport
{
#pragma pack(1)
@@ -51,30 +52,21 @@ namespace ntcp
uint8_t padding[8];
};
struct SignedData // used for signature in Phase3 and Phase4
{
uint8_t x[256];
uint8_t y[256];
uint8_t ident[32];
uint32_t tsA;
uint32_t tsB;
};
#pragma pack()
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
class NTCPSession
class NTCPSession: public TransportSession
{
public:
NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo);
virtual ~NTCPSession ();
NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter = nullptr);
~NTCPSession ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
bool IsEstablished () const { return m_IsEstablished; };
i2p::data::RouterInfo& GetRemoteRouterInfo () { return m_RemoteRouterInfo; };
void ClientLogin ();
void ServerLogin ();
@@ -92,7 +84,7 @@ namespace ntcp
private:
void CreateAESKey (uint8_t * pubKey, uint8_t * aesKey);
void CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key);
// client
void SendPhase3 ();
@@ -127,14 +119,11 @@ namespace ntcp
boost::asio::ip::tcp::socket m_Socket;
boost::asio::deadline_timer m_TerminationTimer;
bool m_IsEstablished;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
i2p::crypto::CBCDecryption m_Decryption;
i2p::crypto::CBCEncryption m_Encryption;
CryptoPP::Adler32 m_Adler;
i2p::data::RouterInfo& m_RemoteRouterInfo;
struct Establisher
{
NTCPPhase1 phase1;
@@ -157,7 +146,7 @@ namespace ntcp
{
public:
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, i2p::data::RouterInfo& in_RouterInfo);
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, const i2p::data::RouterInfo& in_RouterInfo);
private:
@@ -174,15 +163,11 @@ namespace ntcp
public:
NTCPServerConnection (boost::asio::io_service& service):
NTCPSession (service, m_DummyRemoteRouterInfo) {};
NTCPSession (service) {};
protected:
virtual void Connected ();
private:
i2p::data::RouterInfo m_DummyRemoteRouterInfo;
};
}
}

View File

@@ -15,6 +15,8 @@
#include "Reseed.h"
#include "util.h"
using namespace i2p::transport;
namespace i2p
{
namespace data
@@ -69,8 +71,6 @@ namespace data
Stop ();
for (auto l:m_LeaseSets)
delete l.second;
for (auto r:m_RouterInfos)
delete r.second;
for (auto r:m_RequestedDestinations)
delete r.second;
}
@@ -179,7 +179,7 @@ namespace data
else
{
LogPrint ("New RouterInfo added");
RouterInfo * r = new RouterInfo (buf, len);
auto r = std::make_shared<RouterInfo> (buf, len);
m_RouterInfos[r->GetIdentHash ()] = r;
if (r->IsFloodfill ())
{
@@ -213,7 +213,7 @@ namespace data
{
auto it = m_RouterInfos.find (ident);
if (it != m_RouterInfos.end ())
return it->second;
return it->second.get ();
else
return nullptr;
}
@@ -227,6 +227,13 @@ namespace data
return nullptr;
}
void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable)
{
auto it = m_RouterInfos.find (ident);
if (it != m_RouterInfos.end ())
return it->second->SetUnreachable (unreachable);
}
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
bool NetDb::CreateNetDb(boost::filesystem::path directory)
{
@@ -262,8 +269,6 @@ namespace data
if (!CreateNetDb(p)) return;
}
// make sure we cleanup netDb from previous attempts
for (auto r: m_RouterInfos)
delete r.second;
m_RouterInfos.clear ();
m_Floodfills.clear ();
@@ -282,7 +287,7 @@ namespace data
#else
const std::string& fullPath = it1->path();
#endif
RouterInfo * r = new RouterInfo(fullPath);
auto r = std::make_shared<RouterInfo>(fullPath);
if (!r->IsUnreachable () && (!r->UsesIntroducer () || ts < r->GetTimestamp () + 3600*1000LL)) // 1 hour
{
r->DeleteBuffer ();
@@ -295,7 +300,6 @@ namespace data
{
if (boost::filesystem::exists (fullPath))
boost::filesystem::remove (fullPath);
delete r;
}
}
}
@@ -332,7 +336,7 @@ namespace data
{
if (it.second->IsUpdated ())
{
it.second->SaveToFile (GetFilePath(fullDirectory, it.second));
it.second->SaveToFile (GetFilePath(fullDirectory, it.second.get ()));
it.second->SetUpdated (false);
it.second->DeleteBuffer ();
count++;
@@ -350,9 +354,9 @@ namespace data
if (it.second->IsUnreachable ())
{
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second)))
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ())))
{
boost::filesystem::remove (GetFilePath (fullDirectory, it.second));
boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ()));
deletedCount++;
}
}
@@ -403,7 +407,7 @@ namespace data
RequestedDestination * dest = CreateRequestedDestination (destination, false, false, pool);
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
if (floodfill)
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
}
}
@@ -655,10 +659,10 @@ namespace data
if (outbound)
outbound->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg);
else
i2p::transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
transports.SendMessage (buf+32, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
}
else
i2p::transports.SendMessage (buf+32, replyMsg);
transports.SendMessage (buf+32, replyMsg);
}
i2p::DeleteI2NPMessage (msg);
}
@@ -712,7 +716,7 @@ namespace data
});
}
else
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
}
else
DeleteRequestedDestination (dest);
@@ -774,37 +778,37 @@ namespace data
}
}
const RouterInfo * NetDb::GetRandomRouter () const
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter () const
{
return GetRandomRouter (
[](const RouterInfo * router)->bool
[](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden ();
});
}
const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith) const
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (const RouterInfo * compatibleWith) const
{
return GetRandomRouter (
[compatibleWith](const RouterInfo * router)->bool
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden () && router != compatibleWith &&
return !router->IsHidden () && router.get () != compatibleWith &&
router->IsCompatible (*compatibleWith);
});
}
const RouterInfo * NetDb::GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const
{
return GetRandomRouter (
[compatibleWith](const RouterInfo * router)->bool
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden () && router != compatibleWith &&
return !router->IsHidden () && router.get () != compatibleWith &&
router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth);
});
}
template<typename Filter>
const RouterInfo * NetDb::GetRandomRouter (Filter filter) const
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (Filter filter) const
{
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1);
@@ -848,7 +852,7 @@ namespace data
if (m < minMetric)
{
minMetric = m;
r = it;
r = it.get ();
}
}
}

16
NetDb.h
View File

@@ -15,7 +15,6 @@
#include "LeaseSet.h"
#include "Tunnel.h"
#include "TunnelPool.h"
#include "AddressBook.h"
namespace i2p
{
@@ -67,7 +66,6 @@ namespace data
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from);
RouterInfo * FindRouter (const IdentHash& ident) const;
LeaseSet * FindLeaseSet (const IdentHash& destination) const;
AddressBook& GetAddressBook () { return m_AddressBook; };// TODO: move AddressBook away from NetDb
void PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool);
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false,
@@ -77,9 +75,10 @@ namespace data
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
void HandleDatabaseLookupMsg (I2NPMessage * msg);
const RouterInfo * GetRandomRouter () const;
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith) const;
const RouterInfo * GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const;
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (const RouterInfo * compatibleWith) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const;
void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (I2NPMessage * msg);
@@ -105,14 +104,14 @@ namespace data
void DeleteRequestedDestination (RequestedDestination * dest);
template<typename Filter>
const RouterInfo * GetRandomRouter (Filter filter) const;
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
private:
std::map<IdentHash, LeaseSet *> m_LeaseSets;
std::map<IdentHash, RouterInfo *> m_RouterInfos;
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex;
std::vector<RouterInfo *> m_Floodfills;
std::vector<std::shared_ptr<RouterInfo> > m_Floodfills;
std::mutex m_RequestedDestinationsMutex;
std::map<IdentHash, RequestedDestination *> m_RequestedDestinations;
@@ -120,7 +119,6 @@ namespace data
int m_ReseedRetries;
std::thread * m_Thread;
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg
AddressBook m_AddressBook;
static const char m_NetDbPath[];
};

View File

@@ -1,21 +1,28 @@
i2pd
====
i2p router for Linux written on C++
I2P router written in C++
Requires gcc 4.6 and higher, boost 1.46 and higher, crypto++
Requirements for Linux/FreeBSD/OSX
----------------------------------
on Windows
GCC 4.6 or newer, Boost 1.46 or newer, crypto++. Clang can be used instead of
GCC.
Requires msvs2013 (require Visual C++ Compiler November 2013 CTP update), boost 1.46 and higher, crypto++
Requirements for Windows
------------------------
VS2013 (known to work with 12.0.21005.1 or newer), Boost 1.46 or newer,
crypto++ 5.62. See Win32/README-Build.txt for instructions on how to build i2pd
and its dependencies.
Build Statuses
---------------
- Linux x64 - [![Build Status](https://jenkins.nordcloud.no/buildStatus/icon?job=i2pd-linux)](https://jenkins.nordcloud.no/job/i2pd-linux/)
- Linux ARM - Too be added
- Mac OS X - Too be added
- Microsoft VC13 - Too be added
- Linux ARM - To be added
- Mac OS X - To be added
- Microsoft VC13 - To be added
Testing
@@ -35,10 +42,10 @@ $ ./i2p --host=YOUR_PUBLIC_IP
The client should now reseed by itself.
To visit an I2P page, you need to find the b32 address of your destination.
After that, go to the webconsole and add it behind the url. (Remove http:// and b32.i2p from the address)
After that, go to the webconsole and add it behind the url. (Remove http:// from the address)
This should resulting in for example:
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p
Options
@@ -51,6 +58,7 @@ Options
* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no.
* --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd).
* --unreachable= - 1 if router is declared as unreachable and works through introducers.
* --v6= - 1 if supports communication through ipv6, off by default
* --httpproxyport= - The port to listen on (HTTP Proxy)
* --socksproxyport= - The port to listen on (SOCKS Proxy)
* --ircport= - The local port of IRC tunnel to listen on. 6668 by default

View File

@@ -2,6 +2,8 @@
#include <fstream>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
#include <cryptopp/gzip.h>
#include "I2PEndian.h"
#include "Reseed.h"
#include "Log.h"
#include "util.h"
@@ -119,6 +121,59 @@ namespace data
return false;
}
void ProcessSU3File (const char * filename)
{
static uint32_t headerSignature = htole32 (0x04044B50);
std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ())
{
while (!s.eof ())
{
uint32_t signature;
s.read ((char *)&signature, 4);
if (signature == headerSignature)
{
// next local file
s.seekg (14, std::ios::cur); // skip field we don't care about
uint32_t compressedSize, uncompressedSize;
s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize);
s.read ((char *)&uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize);
uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2);
fileNameLength = le32toh (fileNameLength);
s.read ((char *)&extraFieldLength, 2);
extraFieldLength = le32toh (extraFieldLength);
char localFileName[255];
s.read (localFileName, fileNameLength);
localFileName[fileNameLength] = 0;
s.seekg (extraFieldLength, std::ios::cur);
uint8_t * compressed = new uint8_t[compressedSize];
s.read ((char *)compressed, compressedSize);
CryptoPP::Gunzip decompressor;
decompressor.Put (compressed, compressedSize);
delete[] compressed;
if (decompressor.MaxRetrievable () <= uncompressedSize)
{
uint8_t * uncompressed = new uint8_t[uncompressedSize];
decompressor.Get (uncompressed, decompressor.MaxRetrievable ());
// TODO: save file
delete[] uncompressed;
}
else
LogPrint (eLogError, "Actual uncompressed size ", decompressor.MaxRetrievable (), " exceed ", uncompressedSize, " from header");
}
else
break; // no more files
}
}
else
LogPrint (eLogError, "Can't open file ", filename);
}
}
}

View File

@@ -17,6 +17,7 @@ namespace data
bool reseedNow();
};
void ProcessSU3File (const char * filename);
}
}

View File

@@ -34,7 +34,7 @@ namespace i2p
void RouterContext::NewRouterInfo ()
{
i2p::data::RouterInfo routerInfo;
routerInfo.SetRouterIdentity (GetIdentity ().GetStandardIdentity ());
routerInfo.SetRouterIdentity (GetIdentity ());
int port = i2p::util::config::GetArg("-port", 0);
if (!port)
port = m_Rnd.GenerateWord32 (9111, 30777); // I2P network ports range
@@ -72,15 +72,14 @@ namespace i2p
UpdateRouterInfo ();
}
void RouterContext::UpdateAddress (const char * host)
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
{
bool updated = false;
auto newAddress = boost::asio::ip::address::from_string (host);
for (auto& address : m_RouterInfo.GetAddresses ())
{
if (address.host != newAddress)
if (address.host != host && address.IsCompatible (host))
{
address.host = newAddress;
address.host = host;
updated = true;
}
}
@@ -131,6 +130,51 @@ namespace i2p
UpdateRouterInfo ();
}
void RouterContext::SetSupportsV6 (bool supportsV6)
{
if (supportsV6)
m_RouterInfo.EnableV6 ();
else
m_RouterInfo.DisableV6 ();
UpdateRouterInfo ();
}
void RouterContext::UpdateNTCPV6Address (const boost::asio::ip::address& host)
{
bool updated = false, found = false;
int port = 0;
auto& addresses = m_RouterInfo.GetAddresses ();
for (auto& addr : addresses)
{
if (addr.host.is_v6 () && addr.transportStyle == i2p::data::RouterInfo::eTransportNTCP)
{
if (addr.host != host)
{
addr.host = host;
updated = true;
}
found = true;
}
else
port = addr.port;
}
if (!found)
{
// create new address
m_RouterInfo.AddNTCPAddress (host.to_string ().c_str (), port);
auto mtu = i2p::util::net::GetMTU (host);
if (mtu)
{
LogPrint ("Our v6 MTU=", mtu);
if (mtu > 1472) mtu = 1472;
}
m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
updated = true;
}
if (updated)
UpdateRouterInfo ();
}
bool RouterContext::Load ()
{
std::ifstream fk (i2p::util::filesystem::GetFullPath (ROUTER_KEYS).c_str (), std::ifstream::binary | std::ofstream::in);

View File

@@ -2,6 +2,9 @@
#define ROUTER_CONTEXT_H__
#include <inttypes.h>
#include <string>
#include <memory>
#include <boost/asio.hpp>
#include <cryptopp/dsa.h>
#include <cryptopp/osrng.h>
#include "Identity.h"
@@ -22,19 +25,24 @@ namespace i2p
void Init ();
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
const uint8_t * GetPrivateKey () const { return m_Keys.GetPrivateKey (); };
const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); };
const i2p::data::IdentHash& GetRouterIdentHash () const { return m_RouterInfo.GetIdentHash (); };
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
{
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
[](const i2p::data::RouterInfo *) {});
}
CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; };
void UpdatePort (int port); // called from Daemon
void UpdateAddress (const char * host); // called from SSU or Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
bool AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag);
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
bool IsUnreachable () const { return m_IsUnreachable; };
void SetUnreachable ();
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
void SetSupportsV6 (bool supportsV6);
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
// implements LocalDestination
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };

View File

@@ -31,7 +31,7 @@ namespace data
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
memcpy (m_Buffer, buf, len);
m_BufferLen = len;
ReadFromBuffer ();
ReadFromBuffer (true);
}
RouterInfo::~RouterInfo ()
@@ -51,15 +51,13 @@ namespace data
m_Properties.clear ();
memcpy (m_Buffer, buf, len);
m_BufferLen = len;
ReadFromBuffer ();
ReadFromBuffer (true);
// don't delete buffer until save to file
}
void RouterInfo::SetRouterIdentity (const Identity& identity)
void RouterInfo::SetRouterIdentity (const IdentityEx& identity)
{
m_RouterIdentity = identity;
m_IdentHash = m_RouterIdentity.Hash ();
UpdateIdentHashBase64 ();
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
}
@@ -72,7 +70,7 @@ namespace data
m_BufferLen = s.tellg ();
if (m_BufferLen < 40)
{
LogPrint("File", m_FullPath, " is malformed");
LogPrint(eLogError, "File", m_FullPath, " is malformed");
return false;
}
s.seekg(0, std::ios::beg);
@@ -82,7 +80,7 @@ namespace data
}
else
{
LogPrint ("Can't open file ", m_FullPath);
LogPrint (eLogError, "Can't open file ", m_FullPath);
return false;
}
return true;
@@ -91,27 +89,25 @@ namespace data
void RouterInfo::ReadFromFile ()
{
if (LoadFile ())
ReadFromBuffer ();
ReadFromBuffer (false);
}
void RouterInfo::ReadFromBuffer ()
void RouterInfo::ReadFromBuffer (bool verifySignature)
{
std::stringstream str (std::string ((char *)m_Buffer, m_BufferLen));
size_t identityLen = m_RouterIdentity.FromBuffer (m_Buffer, m_BufferLen);
std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
ReadFromStream (str);
// verify signature
CryptoPP::DSA::PublicKey pubKey;
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_RouterIdentity.signingKey, 128));
CryptoPP::DSA::Verifier verifier (pubKey);
int l = m_BufferLen - 40;
if (!verifier.VerifyMessage ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l, 40))
if (verifySignature)
{
LogPrint ("signature verification failed");
// verify signature
int l = m_BufferLen - m_RouterIdentity.GetSignatureLen ();
if (!m_RouterIdentity.Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
LogPrint (eLogError, "signature verification failed");
}
}
void RouterInfo::ReadFromStream (std::istream& s)
{
s.read ((char *)&m_RouterIdentity, sizeof (m_RouterIdentity));
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
m_Timestamp = be64toh (m_Timestamp);
// read addresses
@@ -151,7 +147,7 @@ namespace data
if (ecode)
{
// TODO: we should try to resolve address here
LogPrint ("Unexpected address ", value);
LogPrint (eLogWarning, "Unexpected address ", value);
isValidAddress = false;
}
else
@@ -225,9 +221,6 @@ namespace data
ExtractCaps (value);
}
CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity));
UpdateIdentHashBase64 ();
if (!m_SupportedTransports || !m_Addresses.size() || (UsesIntroducer () && !introducers))
SetUnreachable (true);
}
@@ -280,17 +273,8 @@ namespace data
SetProperty ("caps", caps.c_str ());
}
void RouterInfo::UpdateIdentHashBase64 ()
{
size_t l = i2p::data::ByteStreamToBase64 (m_IdentHash, 32, m_IdentHashBase64, 48);
m_IdentHashBase64[l] = 0;
memcpy (m_IdentHashAbbreviation, m_IdentHashBase64, 4);
m_IdentHashAbbreviation[4] = 0;
}
void RouterInfo::WriteToStream (std::ostream& s)
{
s.write ((char *)&m_RouterIdentity, sizeof (m_RouterIdentity));
uint64_t ts = htobe64 (m_Timestamp);
s.write ((char *)&ts, sizeof (ts));
@@ -376,6 +360,14 @@ namespace data
value[l] = 0;
WriteString (value, properties);
properties << ';';
// write mtu
if (address.mtu)
{
WriteString ("mtu", properties);
properties << '=';
WriteString (boost::lexical_cast<std::string>(address.mtu), properties);
properties << ';';
}
}
WriteString ("port", properties);
properties << '=';
@@ -410,7 +402,7 @@ namespace data
if (!m_Buffer)
{
if (LoadFile ())
LogPrint ("Buffer for ", m_IdentHashAbbreviation, " loaded from file");
LogPrint ("Buffer for ", GetIdentHashAbbreviation (), " loaded from file");
}
return m_Buffer;
}
@@ -419,6 +411,9 @@ namespace data
{
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp
std::stringstream s;
uint8_t ident[1024];
auto identLen = privateKeys.GetPublic ().ToBuffer (ident, 1024);
s.write ((char *)ident, identLen);
WriteToStream (s);
m_BufferLen = s.str ().size ();
if (!m_Buffer)
@@ -438,7 +433,7 @@ namespace data
f.write ((char *)m_Buffer, m_BufferLen);
}
else
LogPrint ("Can't save to file");
LogPrint (eLogError, "Can't save to file");
}
size_t RouterInfo::ReadString (char * str, std::istream& s)
@@ -465,11 +460,12 @@ namespace data
addr.transportStyle = eTransportNTCP;
addr.cost = 2;
addr.date = 0;
addr.mtu = 0;
m_Addresses.push_back(addr);
m_SupportedTransports |= eNTCPV4;
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4;
}
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key)
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
{
Address addr;
addr.host = boost::asio::ip::address::from_string (host);
@@ -477,9 +473,10 @@ namespace data
addr.transportStyle = eTransportSSU;
addr.cost = 10; // NTCP should have priority over SSU
addr.date = 0;
addr.mtu = mtu;
memcpy (addr.key, key, 32);
m_Addresses.push_back(addr);
m_SupportedTransports |= eSSUV4;
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4;
m_Caps |= eSSUTesting;
m_Caps |= eSSUIntroducer;
}
@@ -568,6 +565,47 @@ namespace data
return m_SupportedTransports & (eSSUV4 | eSSUV6);
}
bool RouterInfo::IsV6 () const
{
return m_SupportedTransports & (eNTCPV6 | eSSUV6);
}
void RouterInfo::EnableV6 ()
{
if (!IsV6 ())
m_SupportedTransports |= eNTCPV6 | eSSUV6;
}
void RouterInfo::DisableV6 ()
{
if (IsV6 ())
{
// NTCP
m_SupportedTransports &= ~eNTCPV6;
for (size_t i = 0; i < m_Addresses.size (); i++)
{
if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportNTCP &&
m_Addresses[i].host.is_v6 ())
{
m_Addresses.erase (m_Addresses.begin () + i);
break;
}
}
// SSU
m_SupportedTransports &= ~eSSUV6;
for (size_t i = 0; i < m_Addresses.size (); i++)
{
if (m_Addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU &&
m_Addresses[i].host.is_v6 ())
{
m_Addresses.erase (m_Addresses.begin () + i);
break;
}
}
}
}
bool RouterInfo::UsesIntroducer () const
{
return m_Caps & Caps::eUnreachable; // non-reachable
@@ -583,13 +621,18 @@ namespace data
return GetAddress (eTransportSSU, v4only);
}
const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) const
const RouterInfo::Address * RouterInfo::GetSSUV6Address () const
{
return GetAddress (eTransportSSU, false, true);
}
const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
{
for (auto& address : m_Addresses)
{
if (address.transportStyle == s)
{
if (!v4only || address.host.is_v4 ())
if ((!v4only || address.host.is_v4 ()) && (!v6only || address.host.is_v6 ()))
return &address;
}
}

View File

@@ -75,26 +75,33 @@ namespace data
// SSU only
Tag<32> key; // intro key for SSU
std::vector<Introducer> introducers;
bool IsCompatible (const boost::asio::ip::address& other) const
{
return (host.is_v4 () && other.is_v4 ()) ||
(host.is_v6 () && other.is_v6 ());
}
};
RouterInfo (const std::string& fullPath);
RouterInfo (): m_Buffer (nullptr) { m_IdentHashBase64[0] = 0; m_IdentHashAbbreviation[0] = 0; };
RouterInfo (): m_Buffer (nullptr) { };
RouterInfo (const RouterInfo& ) = default;
RouterInfo& operator=(const RouterInfo& ) = default;
RouterInfo (const uint8_t * buf, int len);
~RouterInfo ();
const Identity& GetRouterIdentity () const { return m_RouterIdentity; };
void SetRouterIdentity (const Identity& identity);
const char * GetIdentHashBase64 () const { return m_IdentHashBase64; };
const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; };
const IdentityEx& GetRouterIdentity () const { return m_RouterIdentity; };
void SetRouterIdentity (const IdentityEx& identity);
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
std::string GetIdentHashAbbreviation () const { return GetIdentHash ().ToBase64 ().substr (0, 4); };
uint64_t GetTimestamp () const { return m_Timestamp; };
std::vector<Address>& GetAddresses () { return m_Addresses; };
const Address * GetNTCPAddress (bool v4only = true) const;
const Address * GetSSUAddress (bool v4only = true) const;
const Address * GetSSUV6Address () const;
void AddNTCPAddress (const char * host, int port);
void AddSSUAddress (const char * host, int port, const uint8_t * key);
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
bool AddIntroducer (const Address * address, uint32_t tag);
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
void SetProperty (const char * key, const char * value);
@@ -102,6 +109,9 @@ namespace data
bool IsFloodfill () const;
bool IsNTCP (bool v4only = true) const;
bool IsSSU (bool v4only = true) const;
bool IsV6 () const;
void EnableV6 ();
void DisableV6 ();
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool UsesIntroducer () const;
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
@@ -128,8 +138,8 @@ namespace data
void DeleteBuffer () { delete m_Buffer; m_Buffer = nullptr; };
// implements RoutingDestination
const IdentHash& GetIdentHash () const { return m_IdentHash; };
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.publicKey; };
const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); };
const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.GetStandardIdentity ().publicKey; };
bool IsDestination () const { return false; };
@@ -138,21 +148,18 @@ namespace data
bool LoadFile ();
void ReadFromFile ();
void ReadFromStream (std::istream& s);
void ReadFromBuffer ();
void ReadFromBuffer (bool verifySignature);
void WriteToStream (std::ostream& s);
size_t ReadString (char * str, std::istream& s);
void WriteString (const std::string& str, std::ostream& s);
void ExtractCaps (const char * value);
void UpdateIdentHashBase64 ();
const Address * GetAddress (TransportStyle s, bool v4only) const;
const Address * GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
void UpdateCapsProperty ();
private:
std::string m_FullPath;
Identity m_RouterIdentity;
IdentHash m_IdentHash;
char m_IdentHashBase64[48], m_IdentHashAbbreviation[5];
IdentityEx m_RouterIdentity;
uint8_t * m_Buffer;
int m_BufferLen;
uint64_t m_Timestamp;

133
SAM.cpp
View File

@@ -1,5 +1,8 @@
#include <string.h>
#include <stdio.h>
#ifdef _MSC_VER
#include <stdlib.h>
#endif
#include <boost/bind.hpp>
#include "base64.h"
#include "Identity.h"
@@ -25,8 +28,8 @@ namespace client
if (m_Stream)
{
m_Stream->Close ();
if (m_Session && m_Session->localDestination)
m_Session->localDestination->DeleteStream (m_Stream);
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
}
@@ -35,8 +38,7 @@ namespace client
if (m_Stream)
{
m_Stream->Close ();
if (m_Session && m_Session->localDestination)
m_Session->localDestination->DeleteStream (m_Stream);
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
switch (m_SocketType)
@@ -55,7 +57,7 @@ namespace client
if (m_Session)
{
m_Session->sockets.remove (this);
m_Session->localDestination->ResetAcceptor ();
m_Session->localDestination->StopAcceptingStreams ();
}
break;
}
@@ -207,6 +209,7 @@ namespace client
LogPrint ("SAM session create: ", buf);
std::map<std::string, std::string> params;
ExtractParams (buf, len, params);
std::string& style = params[SAM_PARAM_STYLE];
std::string& id = params[SAM_PARAM_ID];
std::string& destination = params[SAM_PARAM_DESTINATION];
m_ID = id;
@@ -221,7 +224,15 @@ namespace client
{
m_SocketType = eSAMSocketTypeSession;
if (m_Session->localDestination->IsReady ())
{
if (style == SAM_VALUE_DATAGRAM)
{
auto dest = m_Session->localDestination->CreateDatagramDestination ();
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
SendSessionCreateReplyOk ();
}
else
{
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
@@ -255,7 +266,11 @@ namespace client
size_t l = m_Session->localDestination->GetPrivateKeys ().ToBuffer (buf, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, priv, 1024);
priv[l1] = 0;
#ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
#else
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_SESSION_CREATE_REPLY_OK, priv);
#endif
SendMessageReply (m_Buffer, l2, false);
}
@@ -295,7 +310,7 @@ namespace client
{
m_SocketType = eSAMSocketTypeStream;
m_Session->sockets.push_back (this);
m_Stream = m_Session->localDestination->CreateNewOutgoingStream (remote);
m_Stream = m_Session->localDestination->CreateStream (remote);
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
I2PReceive ();
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
@@ -326,7 +341,11 @@ namespace client
else
{
LogPrint ("SAM name destination not found");
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_KEY_NOT_FOUND, (ident.ToBase32 () + ".b32.i2p").c_str ());
#else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_KEY_NOT_FOUND, (ident.ToBase32 () + ".b32.i2p").c_str ());
#endif
SendMessageReply (m_Buffer, len, false);
}
}
@@ -344,11 +363,11 @@ namespace client
m_Session = m_Owner.FindSession (id);
if (m_Session)
{
if (!m_Session->localDestination->IsAcceptorSet ())
if (!m_Session->localDestination->IsAcceptingStreams ())
{
m_SocketType = eSAMSocketTypeAcceptor;
m_Session->sockets.push_back (this);
m_Session->localDestination->SetAcceptor (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1));
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1));
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
}
else
@@ -373,7 +392,11 @@ namespace client
l = localDestination->GetIdentity ().ToBuffer (buf, 1024);
l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0;
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv);
#endif
SendMessageReply (m_Buffer, len, true);
}
else
@@ -389,7 +412,7 @@ namespace client
i2p::data::IdentHash ident;
if (name == "ME")
SendNamingLookupReply (nullptr);
else if (m_Session && i2p::data::netdb.GetAddressBook ().GetIdentHash (name, ident))
else if (m_Session && context.GetAddressBook ().GetIdentHash (name, ident))
{
auto leaseSet = m_Session->localDestination->FindLeaseSet (ident);
if (leaseSet)
@@ -404,7 +427,11 @@ namespace client
}
else
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
#else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
#endif
SendMessageReply (m_Buffer, len, false);
}
}
@@ -417,7 +444,11 @@ namespace client
size_t l = identity.ToBuffer (buf, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0;
#ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#else
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub);
#endif
SendMessageReply (m_Buffer, l2, false);
}
@@ -507,7 +538,7 @@ namespace client
m_Stream = stream;
auto session = m_Owner.FindSession (m_ID);
if (session)
session->localDestination->ResetAcceptor ();
session->localDestination->StopAcceptingStreams ();
if (!m_IsSilent)
{
// send remote peer address
@@ -521,9 +552,31 @@ namespace client
}
}
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len)
{
uint8_t identBuf[1024];
size_t l = ident.ToBuffer (identBuf, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (identBuf, l, m_Buffer, SAM_SOCKET_BUFFER_SIZE);
m_Buffer[l1] = 0;
#ifdef _MSC_VER
size_t l2 = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, m_Buffer, len);
#else
size_t l2 = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, m_Buffer, len);
#endif
if (len < SAM_SOCKET_BUFFER_SIZE - l2)
{
memcpy (m_StreamBuffer + l2, buf, len);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l2),
boost::bind (&SAMSocket::HandleWriteI2PData, this, boost::asio::placeholders::error));
}
else
LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer");
}
SAMBridge::SAMBridge (int port):
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint),
m_NewSocket (nullptr)
{
}
@@ -537,6 +590,7 @@ namespace client
void SAMBridge::Start ()
{
Accept ();
ReceiveDatagram ();
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&SAMBridge::Run, this));
}
@@ -595,7 +649,7 @@ namespace client
SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination)
{
i2p::stream::StreamingDestination * localDestination = nullptr;
ClientDestination * localDestination = nullptr;
if (destination != "")
{
uint8_t * buf = new uint8_t[destination.length ()];
@@ -642,5 +696,62 @@ namespace client
return &it->second;
return nullptr;
}
void SAMBridge::ReceiveDatagram ()
{
m_DatagramSocket.async_receive_from (
boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE),
m_SenderEndpoint,
boost::bind (&SAMBridge::HandleReceivedDatagram, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (!ecode)
{
m_DatagramReceiveBuffer[bytes_transferred] = 0;
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
*eol = 0; eol++;
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
LogPrint ("SAM datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
if (sessionID)
{
sessionID++;
char * destination = strchr (sessionID, ' ');
if (destination)
{
*destination = 0; destination++;
auto session = FindSession (sessionID);
if (session)
{
uint8_t ident[1024];
size_t l = i2p::data::Base64ToByteStream (destination, strlen(destination), ident, 1024);
i2p::data::IdentityEx dest;
dest.FromBuffer (ident, l);
auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ());
if (leaseSet)
session->localDestination->GetDatagramDestination ()->
SendDatagramTo ((uint8_t *)eol, payloadLen, *leaseSet);
else
{
LogPrint ("SAM datagram destination not found");
i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true,
session->localDestination->GetTunnelPool ());
}
}
else
LogPrint ("Session ", sessionID, " not found");
}
else
LogPrint ("Missing destination key");
}
else
LogPrint ("Missing sessionID");
ReceiveDatagram ();
}
else
LogPrint ("SAM datagram receive error: ", ecode.message ());
}
}
}

14
SAM.h
View File

@@ -11,6 +11,7 @@
#include "Identity.h"
#include "LeaseSet.h"
#include "Streaming.h"
#include "Destination.h"
namespace i2p
{
@@ -38,6 +39,7 @@ namespace client
const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n";
const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP";
const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n";
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM_RECEIVED DESTINATION=%s SIZE=%i\n";
const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n";
const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n";
const char SAM_PARAM_STYLE[] = "STYLE";
@@ -46,6 +48,9 @@ namespace client
const char SAM_PARAM_DESTINATION[] = "DESTINATION";
const char SAM_PARAM_NAME[] = "NAME";
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
const char SAM_VALUE_STREAM[] = "STREAM";
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
const char SAM_VALUE_RAW[] = "RAW";
const char SAM_VALUE_TRUE[] = "true";
const char SAM_VALUE_FALSE[] = "false";
@@ -84,6 +89,7 @@ namespace client
void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleI2PAccept (i2p::stream::Stream * stream);
void HandleWriteI2PData (const boost::system::error_code& ecode);
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len);
void ProcessSessionCreate (char * buf, size_t len);
void ProcessStreamConnect (char * buf, size_t len);
@@ -115,7 +121,7 @@ namespace client
struct SAMSession
{
i2p::stream::StreamingDestination * localDestination;
ClientDestination * localDestination;
std::list<SAMSocket *> sockets;
};
@@ -141,15 +147,21 @@ namespace client
void Accept ();
void HandleAccept(const boost::system::error_code& ecode);
void ReceiveDatagram ();
void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred);
private:
bool m_IsRunning;
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint;
boost::asio::ip::udp::socket m_DatagramSocket;
SAMSocket * m_NewSocket;
std::mutex m_SessionsMutex;
std::map<std::string, SAMSession> m_Sessions;
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
};
}
}

View File

@@ -224,7 +224,7 @@ namespace proxy
void SOCKS4AHandler::SentConnectionSuccess(const boost::system::error_code & ecode)
{
LogPrint("--- socks4a making connection");
m_stream = i2p::client::context.GetSharedLocalDestination ()->CreateNewOutgoingStream(*m_ls);
m_stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream(*m_ls);
m_state = OKAY;
LogPrint("--- socks4a state is ", m_state);
AsyncSockRead();

994
SSU.cpp

File diff suppressed because it is too large Load Diff

139
SSU.h
View File

@@ -13,139 +13,16 @@
#include "Identity.h"
#include "RouterInfo.h"
#include "I2NPProtocol.h"
#include "SSUData.h"
#include "SSUSession.h"
namespace i2p
{
namespace ssu
namespace transport
{
#pragma pack(1)
struct SSUHeader
{
uint8_t mac[16];
uint8_t iv[16];
uint8_t flag;
uint32_t time;
uint8_t GetPayloadType () const { return flag >> 4; };
};
#pragma pack()
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
const size_t SSU_MAX_NUM_INTRODUCERS = 3;
// payload types (4 bits)
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
const uint8_t PAYLOAD_TYPE_DATA = 6;
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
enum SessionState
{
eSessionStateUnknown,
eSessionStateIntroduced,
eSessionStateEstablished,
eSessionStateFailed
};
class SSUServer;
class SSUSession
{
public:
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router = nullptr, bool peerTest = false);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession ();
void Connect ();
void Introduce (uint32_t iTag, const uint8_t * iKey);
void WaitForIntroduction ();
void Close ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; };
void SendI2NPMessage (I2NPMessage * msg);
void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; };
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void SendKeepAlive ();
uint32_t GetRelayTag () const { return m_RelayTag; };
uint32_t GetCreationTime () const { return m_CreationTime; };
private:
void CreateAESandMacKey (const uint8_t * pubKey);
void PostI2NPMessage (I2NPMessage * msg);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest ();
void SendRelayRequest (uint32_t iTag, const uint8_t * iKey);
void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x);
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress);
void ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
void ProcessRelayResponse (uint8_t * buf, size_t len);
void ProcessRelayIntro (uint8_t * buf, size_t len);
void Established ();
void Failed ();
void ScheduleConnectTimer ();
void HandleConnectTimer (const boost::system::error_code& ecode);
void ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true);
void ProcessData (uint8_t * buf, size_t len);
void SendSesionDestroyed ();
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
void Send (const uint8_t * buf, size_t size);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
void DecryptSessionKey (uint8_t * buf, size_t len);
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
const uint8_t * GetIntroKey () const;
void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode);
private:
friend class SSUData; // TODO: change in later
SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
const i2p::data::RouterInfo * m_RemoteRouter;
i2p::data::IdentHash m_RemoteIdent; // if m_RemoteRouter is null
boost::asio::deadline_timer m_Timer;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
bool m_PeerTest;
SessionState m_State;
bool m_IsSessionKey;
uint32_t m_RelayTag;
std::set<uint32_t> m_PeerTestNonces;
i2p::crypto::CBCEncryption m_SessionKeyEncryption;
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
uint8_t m_SessionKey[32], m_MacKey[32];
std::list<i2p::I2NPMessage *> m_DelayedMessages;
SSUData m_Data;
size_t m_NumSentBytes, m_NumReceivedBytes;
uint32_t m_CreationTime; // seconds since epoch
};
class SSUServer
{
public:
@@ -171,7 +48,10 @@ namespace ssu
void Run ();
void Receive ();
void ReceiveV6 ();
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred);
template<typename Filter>
SSUSession * GetRandomSession (Filter filter);
@@ -186,12 +66,13 @@ namespace ssu
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work;
boost::asio::ip::udp::endpoint m_Endpoint;
boost::asio::ip::udp::socket m_Socket;
boost::asio::ip::udp::endpoint m_SenderEndpoint;
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
boost::asio::ip::udp::endpoint m_SenderEndpoint, m_SenderEndpointV6;
boost::asio::deadline_timer m_IntroducersUpdateTimer;
std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to
uint8_t m_ReceiveBuffer[2*SSU_MTU];
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6;
std::map<boost::asio::ip::udp::endpoint, SSUSession *> m_Sessions;
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer

View File

@@ -8,12 +8,13 @@
namespace i2p
{
namespace ssu
namespace transport
{
SSUData::SSUData (SSUSession& session):
m_Session (session), m_ResendTimer (session.m_Server.GetService ())
{
m_PacketSize = SSU_MAX_PACKET_SIZE;
m_MaxPacketSize = session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE;
m_PacketSize = m_MaxPacketSize;
auto remoteRouter = session.GetRemoteRouter ();
if (remoteRouter)
AdjustPacketSize (*remoteRouter);
@@ -36,19 +37,22 @@ namespace ssu
auto ssuAddress = remoteRouter.GetSSUAddress ();
if (ssuAddress && ssuAddress->mtu)
{
if (m_Session.IsV6 ())
m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
else
m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
if (m_PacketSize > 0)
{
// make sure packet size multiple of 16
m_PacketSize >>= 4;
m_PacketSize <<= 4;
if (m_PacketSize > (int)SSU_MAX_PACKET_SIZE) m_PacketSize = SSU_MAX_PACKET_SIZE;
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
LogPrint ("MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
}
else
{
LogPrint ("Unexpected MTU ", ssuAddress->mtu);
m_PacketSize = SSU_MAX_PACKET_SIZE;
LogPrint (eLogWarning, "Unexpected MTU ", ssuAddress->mtu);
m_PacketSize = m_MaxPacketSize;
}
}
}
@@ -143,7 +147,12 @@ namespace ssu
uint16_t fragmentSize = fragmentInfo & 0x1FFF; // bits 0 - 13
bool isLast = fragmentInfo & 0x010000; // bit 16
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
LogPrint ("SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last");
LogPrint (eLogDebug, "SSU data fragment ", (int)fragmentNum, " of message ", msgID, " size=", (int)fragmentSize, isLast ? " last" : " non-last");
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
{
LogPrint (eLogError, "Fragment size ", fragmentSize, "exceeds max SSU packet size");
return;
}
// find message with msgID
I2NPMessage * msg = nullptr;
@@ -190,22 +199,22 @@ namespace ssu
break;
}
if (isLast)
LogPrint ("Message ", msgID, " complete");
LogPrint (eLogDebug, "Message ", msgID, " complete");
}
}
else
{
if (fragmentNum < incompleteMessage->nextFragmentNum)
// duplicate fragment
LogPrint ("Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
LogPrint (eLogWarning, "Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
else
{
// missing fragment
LogPrint ("Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
LogPrint (eLogWarning, "Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
if (!incompleteMessage->savedFragments.insert (savedFragment).second)
{
LogPrint ("Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
LogPrint (eLogWarning, "Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
delete savedFragment;
}
}
@@ -230,7 +239,7 @@ namespace ssu
}
else
{
LogPrint ("SSU message ", msgID, " already received");
LogPrint (eLogWarning, "SSU message ", msgID, " already received");
i2p::DeleteI2NPMessage (msg);
}
}
@@ -243,7 +252,7 @@ namespace ssu
m_Session.Established ();
}
else
LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID);
LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetHeader ()->typeID);
DeleteI2NPMessage (msg);
}
}
@@ -258,7 +267,7 @@ namespace ssu
//uint8_t * start = buf;
uint8_t flag = *buf;
buf++;
LogPrint ("Process SSU data flags=", (int)flag);
LogPrint (eLogDebug, "Process SSU data flags=", (int)flag);
// process acks if presented
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
ProcessAcks (buf, flag);
@@ -267,7 +276,7 @@ namespace ssu
{
uint8_t extendedDataSize = *buf;
buf++; // size
LogPrint ("SSU extended data of ", extendedDataSize, " bytes presented");
LogPrint (eLogDebug, "SSU extended data of ", extendedDataSize, " bytes presented");
buf += extendedDataSize;
}
// process data
@@ -279,7 +288,7 @@ namespace ssu
uint32_t msgID = msg->ToSSU ();
if (m_SentMessages.count (msgID) > 0)
{
LogPrint ("SSU message ", msgID, " already sent");
LogPrint (eLogWarning, "SSU message ", msgID, " already sent");
DeleteI2NPMessage (msg);
return;
}
@@ -363,7 +372,7 @@ namespace ssu
{
if (fragmentNum > 64)
{
LogPrint ("Fragment number ", fragmentNum, " exceeds 64");
LogPrint (eLogWarning, "Fragment number ", fragmentNum, " exceeds 64");
return;
}
uint8_t buf[64 + 18];

View File

@@ -13,13 +13,16 @@
namespace i2p
{
namespace ssu
namespace transport
{
const size_t SSU_MTU = 1484;
const size_t SSU_MTU_V4 = 1484;
const size_t SSU_MTU_V6 = 1472;
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;
const size_t SSU_MAX_PACKET_SIZE = SSU_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1424
const int RESEND_INTERVAL = 3; // in seconds
const int MAX_NUM_RESENDS = 5;
// data flags
@@ -35,7 +38,7 @@ namespace ssu
int fragmentNum;
size_t len;
bool isLast;
uint8_t buf[SSU_MAX_PACKET_SIZE + 18];
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
Fragment () = default;
Fragment (int n, const uint8_t * b, int l, bool last):
@@ -102,7 +105,7 @@ namespace ssu
std::map<uint32_t, SentMessage *> m_SentMessages;
std::set<uint32_t> m_ReceivedMessages;
boost::asio::deadline_timer m_ResendTimer;
int m_PacketSize;
int m_MaxPacketSize, m_PacketSize;
};
}
}

1012
SSUSession.cpp Normal file

File diff suppressed because it is too large Load Diff

145
SSUSession.h Normal file
View File

@@ -0,0 +1,145 @@
#ifndef SSU_SESSION_H__
#define SSU_SESSION_H__
#include <inttypes.h>
#include <set>
#include <list>
#include <boost/asio.hpp>
#include "aes.h"
#include "hmac.h"
#include "I2NPProtocol.h"
#include "TransportSession.h"
#include "SSUData.h"
namespace i2p
{
namespace transport
{
#pragma pack(1)
struct SSUHeader
{
uint8_t mac[16];
uint8_t iv[16];
uint8_t flag;
uint32_t time;
uint8_t GetPayloadType () const { return flag >> 4; };
};
#pragma pack()
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
// payload types (4 bits)
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
const uint8_t PAYLOAD_TYPE_DATA = 6;
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
enum SessionState
{
eSessionStateUnknown,
eSessionStateIntroduced,
eSessionStateEstablished,
eSessionStateFailed
};
class SSUServer;
class SSUSession: public TransportSession
{
public:
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router = nullptr, bool peerTest = false);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession ();
void Connect ();
void Introduce (uint32_t iTag, const uint8_t * iKey);
void WaitForIntroduction ();
void Close ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
void SendI2NPMessage (I2NPMessage * msg);
void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; };
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void SendKeepAlive ();
uint32_t GetRelayTag () const { return m_RelayTag; };
uint32_t GetCreationTime () const { return m_CreationTime; };
private:
void CreateAESandMacKey (const uint8_t * pubKey);
void PostI2NPMessage (I2NPMessage * msg);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest ();
void SendRelayRequest (uint32_t iTag, const uint8_t * iKey);
void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x);
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
void ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
void ProcessRelayResponse (uint8_t * buf, size_t len);
void ProcessRelayIntro (uint8_t * buf, size_t len);
void Established ();
void Failed ();
void ScheduleConnectTimer ();
void HandleConnectTimer (const boost::system::error_code& ecode);
void ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, const uint8_t * introKey, bool toAddress = true);
void ProcessData (uint8_t * buf, size_t len);
void SendSesionDestroyed ();
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
void Send (const uint8_t * buf, size_t size);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
void DecryptSessionKey (uint8_t * buf, size_t len);
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
const uint8_t * GetIntroKey () const;
void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode);
private:
friend class SSUData; // TODO: change in later
SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
boost::asio::deadline_timer m_Timer;
bool m_PeerTest;
SessionState m_State;
bool m_IsSessionKey;
uint32_t m_RelayTag;
std::set<uint32_t> m_PeerTestNonces;
i2p::crypto::CBCEncryption m_SessionKeyEncryption;
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
i2p::crypto::AESKey m_SessionKey;
i2p::crypto::MACKey m_MacKey;
std::list<i2p::I2NPMessage *> m_DelayedMessages;
SSUData m_Data;
size_t m_NumSentBytes, m_NumReceivedBytes;
uint32_t m_CreationTime; // seconds since epoch
};
}
}
#endif

View File

@@ -1,3 +1,4 @@
#include <cryptopp/gzip.h>
#include "Log.h"
#include "RouterInfo.h"
#include "RouterContext.h"
@@ -11,12 +12,12 @@ namespace i2p
namespace stream
{
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
const i2p::data::LeaseSet& remote): m_Service (service), m_SendStreamID (0),
const i2p::data::LeaseSet& remote, int port): m_Service (service), m_SendStreamID (0),
m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false),
m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service),
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0),
m_NumReceivedBytes (0)
m_NumReceivedBytes (0), m_Port (port)
{
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
UpdateCurrentRemoteLease ();
@@ -27,7 +28,7 @@ namespace stream
m_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service),
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0),
m_NumReceivedBytes (0)
m_NumReceivedBytes (0), m_Port (0)
{
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
}
@@ -115,7 +116,7 @@ namespace stream
{
// we have received duplicate. Most likely our outbound tunnel is dead
LogPrint ("Duplicate message ", receivedSeqn, " received");
m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel
m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel
UpdateCurrentRemoteLease (); // pick another lease
SendQuickAck (); // resend ack for previous message again
delete packet; // packet dropped
@@ -274,11 +275,11 @@ namespace stream
if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
*(uint16_t *)(packet + size) = htobe16 (flags);
size += 2; // flags
size_t identityLen = m_LocalDestination.GetIdentity ().GetFullLen ();
size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen ();
size_t identityLen = m_LocalDestination.GetOwner ().GetIdentity ().GetFullLen ();
size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen ();
*(uint16_t *)(packet + size) = htobe16 (identityLen + signatureLen + 2); // identity + signature + packet size
size += 2; // options size
m_LocalDestination.GetIdentity ().ToBuffer (packet + size, identityLen);
m_LocalDestination.GetOwner ().GetIdentity ().ToBuffer (packet + size, identityLen);
size += identityLen; // from
*(uint16_t *)(packet + size) = htobe16 (STREAMING_MTU);
size += 2; // max packet size
@@ -291,7 +292,7 @@ namespace stream
buf += sentLen;
len -= sentLen;
size += sentLen; // payload
m_LocalDestination.Sign (packet, size, signature);
m_LocalDestination.GetOwner ().Sign (packet, size, signature);
}
else
{
@@ -362,13 +363,13 @@ namespace stream
size++; // resend delay
*(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED);
size += 2; // flags
size_t signatureLen = m_LocalDestination.GetIdentity ().GetSignatureLen ();
size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen ();
*(uint16_t *)(packet + size) = htobe16 (signatureLen); // signature only
size += 2; // options size
uint8_t * signature = packet + size;
memset (packet + size, 0, signatureLen);
size += signatureLen; // signature
m_LocalDestination.Sign (packet, size, signature);
m_LocalDestination.GetOwner ().Sign (packet, size, signature);
p->len = size;
SendPacket (p);
@@ -412,6 +413,8 @@ namespace stream
if (isEmpty)
ScheduleResend ();
}
else
delete packet;
return true;
}
else
@@ -438,8 +441,7 @@ namespace stream
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
for (auto it: packets)
{
auto msg = m_RoutingSession->WrapSingleMessage (
m_LocalDestination.CreateDataMessage (it->GetBuffer (), it->GetLength ()));
auto msg = m_RoutingSession->WrapSingleMessage (CreateDataMessage (it->GetBuffer (), it->GetLength ()));
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeTunnel,
@@ -448,7 +450,7 @@ namespace stream
});
m_NumSentBytes += it->GetLength ();
}
m_LocalDestination.SendTunnelDataMsgs (msgs);
m_LocalDestination.GetOwner ().SendTunnelDataMsgs (msgs);
}
else
LogPrint ("All leases are expired");
@@ -482,7 +484,7 @@ namespace stream
}
if (packets.size () > 0)
{
m_LocalDestination.ResetCurrentOutboundTunnel (); // pick another outbound tunnel
m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel
UpdateCurrentRemoteLease (); // pick another lease
SendPackets (packets);
}
@@ -504,14 +506,14 @@ namespace stream
{
if (!m_RemoteLeaseSet)
{
m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ());
m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ());
if (!m_RemoteLeaseSet)
LogPrint ("LeaseSet ", m_RemoteIdentity.GetIdentHash ().ToBase64 (), " not found");
}
if (m_RemoteLeaseSet)
{
if (!m_RoutingSession)
m_RoutingSession = m_LocalDestination.GetRoutingSession (*m_RemoteLeaseSet, 32);
m_RoutingSession = m_LocalDestination.GetOwner ().GetRoutingSession (*m_RemoteLeaseSet, 32);
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases ();
if (!leases.empty ())
{
@@ -520,12 +522,139 @@ namespace stream
}
else
{
m_RemoteLeaseSet = m_LocalDestination.FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); // re-request expired
m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); // re-request expired
m_CurrentRemoteLease.endDate = 0;
}
}
else
m_CurrentRemoteLease.endDate = 0;
}
I2NPMessage * Stream::CreateDataMessage (const uint8_t * payload, size_t len)
{
I2NPMessage * msg = NewI2NPShortMessage ();
CryptoPP::Gzip compressor;
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL);
else
compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL);
compressor.Put (payload, len);
compressor.MessageEnd();
int size = compressor.MaxRetrievable ();
uint8_t * buf = msg->GetPayload ();
*(uint32_t *)buf = htobe32 (size); // length
buf += 4;
compressor.Get (buf, size);
*(uint16_t *)(buf + 4) = 0; // source port
*(uint16_t *)(buf + 6) = htobe16 (m_Port); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData);
return msg;
}
void StreamingDestination::Start ()
{
}
void StreamingDestination::Stop ()
{
ResetAcceptor ();
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear ();
}
}
void StreamingDestination::HandleNextPacket (Packet * packet)
{
uint32_t sendStreamID = packet->GetSendStreamID ();
if (sendStreamID)
{
auto it = m_Streams.find (sendStreamID);
if (it != m_Streams.end ())
it->second->HandleNextPacket (packet);
else
{
LogPrint ("Unknown stream ", sendStreamID);
delete packet;
}
}
else // new incoming stream
{
auto incomingStream = CreateNewIncomingStream ();
incomingStream->HandleNextPacket (packet);
if (m_Acceptor != nullptr)
m_Acceptor (incomingStream);
else
{
LogPrint ("Acceptor for incoming stream is not set");
DeleteStream (incomingStream);
}
}
}
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
{
Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
Stream * StreamingDestination::CreateNewIncomingStream ()
{
Stream * s = new Stream (*m_Owner.GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s;
return s;
}
void StreamingDestination::DeleteStream (Stream * stream)
{
if (stream)
{
std::unique_lock<std::mutex> l(m_StreamsMutex);
auto it = m_Streams.find (stream->GetRecvStreamID ());
if (it != m_Streams.end ())
{
m_Streams.erase (it);
if (m_Owner.GetService ())
m_Owner.GetService ()->post ([stream](void) { delete stream; });
else
delete stream;
}
}
}
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
{
// unzip it
CryptoPP::Gunzip decompressor;
decompressor.Put (buf, len);
decompressor.MessageEnd();
Packet * uncompressed = new Packet;
uncompressed->offset = 0;
uncompressed->len = decompressor.MaxRetrievable ();
if (uncompressed->len <= MAX_PACKET_SIZE)
{
decompressor.Get (uncompressed->buf, uncompressed->len);
HandleNextPacket (uncompressed);
}
else
{
LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped");
delete uncompressed;
}
}
void DeleteStream (Stream * stream)
{
if (stream)
stream->GetLocalDestination ().DeleteStream (stream);
}
}
}

View File

@@ -18,6 +18,10 @@
namespace i2p
{
namespace client
{
class ClientDestination;
}
namespace stream
{
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
@@ -78,7 +82,8 @@ namespace stream
{
public:
Stream (boost::asio::io_service& service, StreamingDestination& local, const i2p::data::LeaseSet& remote); // outgoing
Stream (boost::asio::io_service& service, StreamingDestination& local,
const i2p::data::LeaseSet& remote, int port = 0); // outgoing
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
~Stream ();
@@ -100,6 +105,8 @@ namespace stream
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
size_t GetSendQueueSize () const { return m_SentPackets.size (); };
size_t GetReceiveQueueSize () const { return m_ReceiveQueue.size (); };
private:
@@ -121,6 +128,8 @@ namespace stream
void HandleResendTimer (const boost::system::error_code& ecode);
void HandleAckSendTimer (const boost::system::error_code& ecode);
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len);
private:
boost::asio::io_service& m_Service;
@@ -137,8 +146,50 @@ namespace stream
std::set<Packet *, PacketCmp> m_SentPackets;
boost::asio::deadline_timer m_ReceiveTimer, m_ResendTimer, m_AckSendTimer;
size_t m_NumSentBytes, m_NumReceivedBytes;
uint16_t m_Port;
};
class StreamingDestination
{
public:
typedef std::function<void (Stream *)> Acceptor;
StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {};
~StreamingDestination () {};
void Start ();
void Stop ();
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0);
void DeleteStream (Stream * stream);
void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; };
void ResetAcceptor () { m_Acceptor = nullptr; };
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
i2p::client::ClientDestination& GetOwner () { return m_Owner; };
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
private:
void HandleNextPacket (Packet * packet);
Stream * CreateNewIncomingStream ();
private:
i2p::client::ClientDestination& m_Owner;
std::mutex m_StreamsMutex;
std::map<uint32_t, Stream *> m_Streams;
Acceptor m_Acceptor;
public:
// for HTTP only
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
};
void DeleteStream (Stream * stream);
//-------------------------------------------------
template<typename Buffer, typename ReceiveHandler>

View File

@@ -34,7 +34,7 @@ namespace tunnel
*(uint32_t *)(tunnelMsg->GetPayload ()) = htobe32 (m_NextTunnelID);
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData);
i2p::transports.SendMessage (m_NextIdent, tunnelMsg);
i2p::transport::transports.SendMessage (m_NextIdent, tunnelMsg);
}
void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg)

75
TransportSession.h Normal file
View File

@@ -0,0 +1,75 @@
#ifndef TRANSPORT_SESSION_H__
#define TRANSPORT_SESSION_H__
#include <inttypes.h>
#include <iostream>
#include "Identity.h"
#include "RouterInfo.h"
namespace i2p
{
namespace transport
{
struct DHKeysPair // transient keys for transport sessions
{
uint8_t publicKey[256];
uint8_t privateKey[256];
};
class SignedData
{
public:
SignedData () {};
void Insert (const uint8_t * buf, size_t len)
{
m_Stream.write ((char *)buf, len);
}
template<typename T>
void Insert (T t)
{
m_Stream.write ((char *)&t, sizeof (T));
}
bool Verify (const i2p::data::IdentityEx& ident, const uint8_t * signature) const
{
return ident.Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
}
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const
{
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
}
private:
std::stringstream m_Stream;
};
class TransportSession
{
public:
TransportSession (const i2p::data::RouterInfo * in_RemoteRouter):
m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr)
{
if (m_RemoteRouter)
m_RemoteIdentity = m_RemoteRouter->GetRouterIdentity ();
}
virtual ~TransportSession () { delete m_DHKeysPair; };
const i2p::data::RouterInfo * GetRemoteRouter () { return m_RemoteRouter; };
const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; };
protected:
const i2p::data::RouterInfo * m_RemoteRouter;
i2p::data::IdentityEx m_RemoteIdentity;
DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
};
}
}
#endif

View File

@@ -1,5 +1,7 @@
#include <cryptopp/dh.h>
#include <boost/bind.hpp>
#include "Log.h"
#include "CryptoConst.h"
#include "RouterContext.h"
#include "I2NPProtocol.h"
#include "NetDb.h"
@@ -9,6 +11,13 @@ using namespace i2p::data;
namespace i2p
{
namespace transport
{
DHKeysPairSupplier::DHKeysPairSupplier (int size):
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
{
}
DHKeysPairSupplier::~DHKeysPairSupplier ()
{
Stop ();
@@ -48,17 +57,18 @@ namespace i2p
{
if (num > 0)
{
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
for (int i = 0; i < num; i++)
{
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
i2p::data::CreateRandomDHKeysPair (pair);
i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair ();
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair);
}
}
}
i2p::data::DHKeysPair * DHKeysPairSupplier::Acquire ()
DHKeysPair * DHKeysPairSupplier::Acquire ()
{
if (!m_Queue.empty ())
{
@@ -70,13 +80,14 @@ namespace i2p
}
else // queue is empty, create new
{
i2p::data::DHKeysPair * pair = new i2p::data::DHKeysPair ();
i2p::data::CreateRandomDHKeysPair (pair);
DHKeysPair * pair = new DHKeysPair ();
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey);
return pair;
}
}
void DHKeysPairSupplier::Return (i2p::data::DHKeysPair * pair)
void DHKeysPairSupplier::Return (DHKeysPair * pair)
{
std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair);
@@ -85,7 +96,7 @@ namespace i2p
Transports transports;
Transports::Transports ():
m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr),
m_Thread (nullptr), m_Work (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr),
m_SSUServer (nullptr), m_DHKeysPairSupplier (5) // 5 pre-generated keys
{
}
@@ -104,21 +115,35 @@ namespace i2p
auto addresses = context.GetRouterInfo ().GetAddresses ();
for (auto& address : addresses)
{
if (address.transportStyle == RouterInfo::eTransportNTCP)
if (address.transportStyle == RouterInfo::eTransportNTCP && address.host.is_v4 ())
{
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
LogPrint ("Start listening TCP port ", address.port);
auto conn = new i2p::ntcp::NTCPServerConnection (m_Service);
auto conn = new NTCPServerConnection (m_Service);
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error));
if (context.SupportsV6 ())
{
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service);
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port));
m_NTCPV6Acceptor->listen ();
LogPrint ("Start listening V6 TCP port ", address.port);
auto conn = new NTCPServerConnection (m_Service);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6,
this, conn, boost::asio::placeholders::error));
}
else if (address.transportStyle == RouterInfo::eTransportSSU)
}
else if (address.transportStyle == RouterInfo::eTransportSSU && address.host.is_v4 ())
{
if (!m_SSUServer)
{
m_SSUServer = new i2p::ssu::SSUServer (address.port);
m_SSUServer = new SSUServer (address.port);
LogPrint ("Start listening UDP port ", address.port);
m_SSUServer->Start ();
DetectExternalIP ();
@@ -143,6 +168,8 @@ namespace i2p
m_NTCPSessions.clear ();
delete m_NTCPAcceptor;
m_NTCPAcceptor = nullptr;
delete m_NTCPV6Acceptor;
m_NTCPV6Acceptor = nullptr;
m_DHKeysPairSupplier.Stop ();
m_IsRunning = false;
@@ -170,19 +197,19 @@ namespace i2p
}
}
void Transports::AddNTCPSession (i2p::ntcp::NTCPSession * session)
void Transports::AddNTCPSession (NTCPSession * session)
{
if (session)
m_NTCPSessions[session->GetRemoteRouterInfo ().GetIdentHash ()] = session;
m_NTCPSessions[session->GetRemoteIdentity ().GetIdentHash ()] = session;
}
void Transports::RemoveNTCPSession (i2p::ntcp::NTCPSession * session)
void Transports::RemoveNTCPSession (NTCPSession * session)
{
if (session)
m_NTCPSessions.erase (session->GetRemoteRouterInfo ().GetIdentHash ());
m_NTCPSessions.erase (session->GetRemoteIdentity ().GetIdentHash ());
}
void Transports::HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error)
void Transports::HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error)
{
if (!error)
{
@@ -194,13 +221,31 @@ namespace i2p
if (error != boost::asio::error::operation_aborted)
{
conn = new i2p::ntcp::NTCPServerConnection (m_Service);
conn = new NTCPServerConnection (m_Service);
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error));
}
}
i2p::ntcp::NTCPSession * Transports::GetNextNTCPSession ()
void Transports::HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error)
{
if (!error)
{
LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ());
conn->ServerLogin ();
}
else
delete conn;
if (error != boost::asio::error::operation_aborted)
{
conn = new NTCPServerConnection (m_Service);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, this,
conn, boost::asio::placeholders::error));
}
}
NTCPSession * Transports::GetNextNTCPSession ()
{
for (auto session: m_NTCPSessions)
if (session.second->IsEstablished ())
@@ -208,7 +253,7 @@ namespace i2p
return 0;
}
i2p::ntcp::NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident)
NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident)
{
auto it = m_NTCPSessions.find (ident);
if (it != m_NTCPSessions.end ())
@@ -242,10 +287,10 @@ namespace i2p
{
// existing session not found. create new
// try NTCP first if message size < 16K
auto address = r->GetNTCPAddress ();
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < i2p::ntcp::NTCP_MAX_MESSAGE_SIZE)
auto address = r->GetNTCPAddress (!context.SupportsV6 ());
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE)
{
auto s = new i2p::ntcp::NTCPClient (m_Service, address->host, address->port, *r);
auto s = new NTCPClient (m_Service, address->host, address->port, *r);
AddNTCPSession (s);
s->SendI2NPMessage (msg);
}
@@ -315,18 +360,19 @@ namespace i2p
{
auto router = i2p::data::netdb.GetRandomRouter ();
if (router && router->IsSSU () && m_SSUServer)
m_SSUServer->GetSession (router, true); // peer test
m_SSUServer->GetSession (router.get (), true); // peer test
}
}
i2p::data::DHKeysPair * Transports::GetNextDHKeysPair ()
DHKeysPair * Transports::GetNextDHKeysPair ()
{
return m_DHKeysPairSupplier.Acquire ();
}
void Transports::ReuseDHKeysPair (i2p::data::DHKeysPair * pair)
void Transports::ReuseDHKeysPair (DHKeysPair * pair)
{
m_DHKeysPairSupplier.Return (pair);
}
}
}

View File

@@ -8,7 +8,9 @@
#include <map>
#include <queue>
#include <string>
#include <cryptopp/osrng.h>
#include <boost/asio.hpp>
#include "TransportSession.h"
#include "NTCPSession.h"
#include "SSU.h"
#include "RouterInfo.h"
@@ -16,17 +18,19 @@
#include "Identity.h"
namespace i2p
{
namespace transport
{
class DHKeysPairSupplier
{
public:
DHKeysPairSupplier (int size): m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr) {};
DHKeysPairSupplier (int size);
~DHKeysPairSupplier ();
void Start ();
void Stop ();
i2p::data::DHKeysPair * Acquire ();
void Return (i2p::data::DHKeysPair * pair);
DHKeysPair * Acquire ();
void Return (DHKeysPair * pair);
private:
@@ -36,12 +40,13 @@ namespace i2p
private:
const int m_QueueSize;
std::queue<i2p::data::DHKeysPair *> m_Queue;
std::queue<DHKeysPair *> m_Queue;
bool m_IsRunning;
std::thread * m_Thread;
std::condition_variable m_Acquired;
std::mutex m_AcquiredMutex;
CryptoPP::AutoSeededRandomPool m_Rnd;
};
class Transports
@@ -55,14 +60,14 @@ namespace i2p
void Stop ();
boost::asio::io_service& GetService () { return m_Service; };
i2p::data::DHKeysPair * GetNextDHKeysPair ();
void ReuseDHKeysPair (i2p::data::DHKeysPair * pair);
i2p::transport::DHKeysPair * GetNextDHKeysPair ();
void ReuseDHKeysPair (DHKeysPair * pair);
void AddNTCPSession (i2p::ntcp::NTCPSession * session);
void RemoveNTCPSession (i2p::ntcp::NTCPSession * session);
void AddNTCPSession (NTCPSession * session);
void RemoveNTCPSession (NTCPSession * session);
i2p::ntcp::NTCPSession * GetNextNTCPSession ();
i2p::ntcp::NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
NTCPSession * GetNextNTCPSession ();
NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void CloseSession (const i2p::data::RouterInfo * router);
@@ -70,7 +75,8 @@ namespace i2p
private:
void Run ();
void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error);
void HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error);
void HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error);
void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer,
const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
@@ -84,10 +90,10 @@ namespace i2p
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work;
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor;
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
std::map<i2p::data::IdentHash, i2p::ntcp::NTCPSession *> m_NTCPSessions;
i2p::ssu::SSUServer * m_SSUServer;
std::map<i2p::data::IdentHash, NTCPSession *> m_NTCPSessions;
SSUServer * m_SSUServer;
DHKeysPairSupplier m_DHKeysPairSupplier;
@@ -95,10 +101,11 @@ namespace i2p
// for HTTP only
const decltype(m_NTCPSessions)& GetNTCPSessions () const { return m_NTCPSessions; };
const i2p::ssu::SSUServer * GetSSUServer () const { return m_SSUServer; };
const SSUServer * GetSSUServer () const { return m_SSUServer; };
};
extern Transports transports;
}
}
#endif

View File

@@ -92,7 +92,7 @@ namespace tunnel
if (outboundTunnel)
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
else
i2p::transports.SendMessage (GetNextIdentHash (), msg);
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
}
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
@@ -468,7 +468,7 @@ namespace tunnel
CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
{
i2p::data::netdb.GetRandomRouter ()
i2p::data::netdb.GetRandomRouter ().get ()
},
inboundTunnel->GetTunnelConfig ()));
}
@@ -521,7 +521,7 @@ namespace tunnel
CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
{
i2p::data::netdb.GetRandomRouter ()
i2p::data::netdb.GetRandomRouter ().get ()
}));
}
}

View File

@@ -235,7 +235,7 @@ namespace tunnel
i2p::HandleI2NPMessage (msg.data);
break;
case eDeliveryTypeTunnel:
i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
break;
case eDeliveryTypeRouter:
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
@@ -253,7 +253,7 @@ namespace tunnel
*ds = *(msg.data);
i2p::data::netdb.PostI2NPMsg (ds);
}
i2p::transports.SendMessage (msg.hash, msg.data);
i2p::transport::transports.SendMessage (msg.hash, msg.data);
}
else // we shouldn't send this message. possible leakage
{

View File

@@ -12,8 +12,12 @@ namespace tunnel
{
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
{
bool messageCreated = false;
if (!m_CurrentTunnelDataMsg)
{
CreateCurrentTunnelDataMessage ();
messageCreated = true;
}
// create delivery instructions
uint8_t di[43]; // max delivery instruction length is 43 for tunnel
@@ -33,7 +37,8 @@ namespace tunnel
// create fragments
I2NPMessage * msg = block.data;
if (diLen + msg->GetLength () + 2<= m_RemainingSize)
auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
if (fullMsgLen <= m_RemainingSize)
{
// message fits. First and last fragment
*(uint16_t *)(di + diLen) = htobe16 (msg->GetLength ());
@@ -48,6 +53,18 @@ namespace tunnel
}
else
{
if (!messageCreated) // check if we should complete previous message
{
auto numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
// length of bytes don't fit full tunnel message
// every follow-on fragment adds 7 bytes
auto nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
if (!nonFit || nonFit > m_RemainingSize)
{
CompleteCurrentTunnelDataMessage ();
CreateCurrentTunnelDataMessage ();
}
}
if (diLen + 6 <= m_RemainingSize)
{
// delivery instructions fit
@@ -169,7 +186,7 @@ namespace tunnel
{
m_Tunnel->EncryptTunnelMsg (tunnelMsg);
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData);
i2p::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg);
i2p::transport::transports.SendMessage (m_Tunnel->GetNextIdentHash (), tunnelMsg);
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
}
m_Buffer.ClearTunnelDataMsgs ();

View File

@@ -237,10 +237,10 @@ namespace tunnel
const i2p::data::RouterInfo * TunnelPool::SelectNextHop (const i2p::data::RouterInfo * prevHop) const
{
auto hop = m_NumHops >= 3 ? i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop) :
i2p::data::netdb.GetRandomRouter (prevHop);
auto hop = m_NumHops >= 3 ? i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop).get () :
i2p::data::netdb.GetRandomRouter (prevHop).get ();
if (!hop)
hop = i2p::data::netdb.GetRandomRouter ();
hop = i2p::data::netdb.GetRandomRouter ().get ();
return hop;
}
@@ -257,7 +257,7 @@ namespace tunnel
{
// last hop
auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router;
if (hop->GetIdentHash () != i2p::context.GetRouterIdentHash ()) // outbound shouldn't be zero-hop tunnel
if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel
{
prevHop = hop;
hops.push_back (prevHop);

View File

@@ -33,7 +33,7 @@ namespace tunnel
const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); };
const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; };
i2p::garlic::GarlicDestination& GetGarlicDestination () const { return m_LocalDestination; };
bool IsExploratory () const { return GetIdentHash () == i2p::context.GetRouterIdentHash (); };
bool IsExploratory () const { return GetIdentHash () == i2p::context.GetIdentHash (); };
void CreateTunnels ();
void TunnelCreated (InboundTunnel * createdTunnel);

282
Win32/PurpleI2P.nsi Normal file
View File

@@ -0,0 +1,282 @@
# NSIS Installer script. (Tested with NSIS 2.64 on Windows 7)
# Author: Mikal Villa (Meeh)
# Version: 1.0
Name PurpleI2P
RequestExecutionLevel highest
SetCompressor /SOLID lzma
ShowInstDetails show
# General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.2.0.0
!define COMPANY "The Privacy Solutions Project"
!define URL "https://i2p.io"
# MUI Symbol Definitions
!define MUI_ICON "ictoopie.ico"
#!define MUI_WELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
!define MUI_HEADERIMAGE
!define MUI_HEADERIMAGE_RIGHT
#!define MUI_HEADERIMAGE_BITMAP "../share/pixmaps/nsis-header.bmp"
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_STARTMENUPAGE_REGISTRY_ROOT HKLM
!define MUI_STARTMENUPAGE_REGISTRY_KEY ${REGKEY}
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME StartMenuGroup
!define MUI_STARTMENUPAGE_DEFAULTFOLDER PurpleI2P
!define MUI_FINISHPAGE_RUN $INSTDIR\i2pd.exe
!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\Readme.txt
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "../share/pixmaps/nsis-wizard.bmp"
!define MUI_UNFINISHPAGE_NOAUTOCLOSE
# Included files
!include Sections.nsh
!include MUI2.nsh
!include nsDialogs.nsh
!include winmessages.nsh
!include logiclib.nsh
# Local included files
!include nsi\helper_readme.nsh
;!include nsi\servicelib.nsh
# Variables
Var StartMenuGroup
# Installer pages
# Execution flow of installer windows
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_README "../Readme.md"
!insertmacro MUI_PAGE_DIRECTORY
# Disabled for now. Use the bat
;Page custom mode_selection # Meeh's hack for installing and starting service.
!insertmacro MUI_PAGE_STARTMENU Application $StartMenuGroup
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
# Uninstall pages
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
# Installer languages
!insertmacro MUI_LANGUAGE English
# Installer attributes
OutFile PurpleI2P-0.2.0.0-win32-setup.exe
InstallDir $PROGRAMFILES\PurpleI2P
CRCCheck on
XPStyle on
BrandingText " "
ShowInstDetails show
VIProductVersion 0.2.0.0
VIAddVersionKey ProductName PurpleI2P
VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}"
VIAddVersionKey CompanyWebsite "${URL}"
VIAddVersionKey FileVersion "${VERSION}"
VIAddVersionKey FileDescription ""
VIAddVersionKey LegalCopyright ""
InstallDirRegKey HKCU "${REGKEY}" Path
ShowUninstDetails show
# Readme definitions
;--------------------------------
;Languages
;Set up install lang strings for 1st lang
${ReadmeLanguage} "${LANG_ENGLISH}" \
"Read Me" \
"Please review the following important information." \
"About $(^name):" \
"$\n Click on scrollbar arrows or press Page Down to review the entire text."
;Add 2nd language
!insertmacro MUI_LANGUAGE "Norwegian"
;set up install lang strings for second lang
${ReadmeLanguage} "${LANG_NORWEGIAN}" \
"Les meg!" \
"Vennligst les informasjonen om hvordan du skal bruke PurpleI2P." \
"Om $(^name):" \
"$\n Klikk på scrollbaren til høyre for å se hele innholdet."
;--------------------------------
# Installer sections
Section -Main SEC0000
SetOutPath $INSTDIR
SetOverwrite on
File /oname=i2pd.exe Release\i2pd.exe
File /oname=install_service.bat install_service.bat
File /oname=uninstall_service.bat uninstall_service.bat
File /oname=LICENSE.txt ..\LICENSE
File /oname=Readme.txt ..\README.md
SetOutPath $INSTDIR\src
File /r /x *.nsi /x *.rc /x *.exe /x *.obj /x *.nsh /x *.sln /x *.vcxproj /x *.tlog /x *.log /x *.res /x *.pdb /x *.suo /x *.opensdf /x *.filters /x *.sdf /x *.iss /x *.aps /x .gitignore /x *.o ../\*.*
SetOutPath $INSTDIR
RMDir /r /REBOOTOK $INSTDIR\src\.git # Remove git directory
RMDir /r /REBOOTOK $INSTDIR\src\Win32\Release # Removing release directory
RMDir /r /REBOOTOK $INSTDIR\src\Win32\nsi
WriteRegStr HKCU "${REGKEY}\Components" Main 1
SectionEnd
Section -post SEC0001
WriteRegStr HKCU "${REGKEY}" Path $INSTDIR
SetOutPath $INSTDIR
WriteUninstaller $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
CreateDirectory $SMPROGRAMS\$StartMenuGroup
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\PurpleI2P.lnk" $INSTDIR\i2pd.exe
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Install PurpleI2P Service.lnk" $INSTDIR\install_service.bat
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall PurpleI2P Service.lnk" $INSTDIR\uninstall_service.bat
CreateShortcut "$SMPROGRAMS\$StartMenuGroup\Uninstall PurpleI2P.lnk" $INSTDIR\uninstall.exe
!insertmacro MUI_STARTMENU_WRITE_END
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayName "$(^Name)"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayVersion "${VERSION}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" Publisher "${COMPANY}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" URLInfoAbout "${URL}"
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" DisplayIcon $INSTDIR\uninstall.exe
WriteRegStr HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" UninstallString $INSTDIR\uninstall.exe
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoModify 1
WriteRegDWORD HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)" NoRepair 1
WriteRegStr HKCR "i2pd" "URL Protocol" ""
WriteRegStr HKCR "i2pd" "" "URL:i2pd" # TODO: if a instance of own is found, relaunch with a proxyfied browser to open webage. (e.g i2pd://meeh.i2p)
WriteRegStr HKCR "i2pd\DefaultIcon" "" $INSTDIR\i2pd.exe
WriteRegStr HKCR "i2pd\shell\open\command" "" '"$INSTDIR\i2pd.exe" "%1"'
SectionEnd
# Macro for selecting uninstaller sections
!macro SELECT_UNSECTION SECTION_NAME UNSECTION_ID
Push $R0
ReadRegStr $R0 HKCU "${REGKEY}\Components" "${SECTION_NAME}"
StrCmp $R0 1 0 next${UNSECTION_ID}
!insertmacro SelectSection "${UNSECTION_ID}"
GoTo done${UNSECTION_ID}
next${UNSECTION_ID}:
!insertmacro UnselectSection "${UNSECTION_ID}"
done${UNSECTION_ID}:
Pop $R0
!macroend
# Uninstaller sections
Section /o -un.Main UNSEC0000
Delete /REBOOTOK $INSTDIR\i2pd.exe
Delete /REBOOTOK $INSTDIR\LICENSE.txt
Delete /REBOOTOK $INSTDIR\Readme.txt
Delete /REBOOTOK $INSTDIR\install_service.bat
Delete /REBOOTOK $INSTDIR\uninstall_service.bat
RMDir /r /REBOOTOK $INSTDIR\src
DeleteRegValue HKCU "${REGKEY}\Components" Main
SectionEnd
Section -un.post UNSEC0001
DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name)"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall PurpleI2P.lnk"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\PurpleI2P.lnk"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Install PurpleI2P Service.lnk"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\UnInstall PurpleI2P Service.lnk"
Delete /REBOOTOK "$SMSTARTUP\PurpleI2P.lnk"
Delete /REBOOTOK $INSTDIR\uninstall.exe
Delete /REBOOTOK $INSTDIR\debug.log
DeleteRegValue HKCU "${REGKEY}" StartMenuGroup
DeleteRegValue HKCU "${REGKEY}" Path
DeleteRegKey /IfEmpty HKCU "${REGKEY}\Components"
DeleteRegKey /IfEmpty HKCU "${REGKEY}"
DeleteRegKey HKCR "i2pd"
RmDir /REBOOTOK $SMPROGRAMS\$StartMenuGroup
RmDir /REBOOTOK $INSTDIR
Push $R0
StrCpy $R0 $StartMenuGroup 1
StrCmp $R0 ">" no_smgroup
no_smgroup:
Pop $R0
SectionEnd
; var hwndExecModeRadio
; var hwndRunServiceNowRadio
; Function mode_selection
; nsDialogs::Create 1018
; Pop $0
; ${NSD_CreateLabel} 0 10 75% 20u "How would you like PurpleI2P (i2pd) to run?"
; Pop $0
; ${NSD_CreateRadioButton} 20 60 80% 25u "Service Mode"
; Pop $hwndExecModeRadio
; ${NSD_AddStyle} $hwndExecModeRadio ${WS_GROUP}
; ${NSD_CreateRadioButton} 20 90 80% 25u "Command line Mode"
; Pop $0
; ${NSD_CreateButton} 20 150 -40 14u "Do it!"
; Pop $0
; ${NSD_OnClick} $0 perform_mode
; nsDialogs::Show
; FunctionEnd
; Function start_now_selection
; nsDialogs::Create 1018
; Pop $0
; ${NSD_CreateLabel} 0 10 75% 20u "Enable the service now?"
; Pop $0
; ${NSD_CreateRadioButton} 20 60 80% 25u "Yes"
; Pop $hwndRunServiceNowRadio
; ${NSD_AddStyle} $hwndRunServiceNowRadio ${WS_GROUP}
; ${NSD_CreateRadioButton} 20 90 80% 25u "No"
; Pop $0
; ${NSD_CreateButton} 20 150 -40 14u "Do it!"
; Pop $0
; ${NSD_OnClick} $0 perform_mode
; nsDialogs::Show
; FunctionEnd
; Function perform_mode
; ${NSD_GetState} $hwndExecModeRadio $0
; ${If} $0 = ${BST_CHECKED}
; Call service_mode
; ${EndIF}
; FunctionEnd
; Function start_now
; ${NSD_GetState} $hwndRunServiceNowRadio $0
; ${If} $0 = ${BST_CHECKED}
; Call start_now_selection
; ${EndIF}
; FunctionEnd
; Function service_mode
; Push "create"
; Push "PurpleI2P Service"
; Push "$INSTDIR\i2pd.exe;autostart=1;display=PurpleI2P"
; Call Service
; Pop $0 ; Actually more to write than !insertmacro, but much more fun :D
; Push "start"
; Push "PurpleI2P Service"
; Call Service
; Pop $0
; Call start_now
; !define MUI_FINISHPAGE_RUN_NOTCHECKED
; !define MUI_FINISHPAGE_RUN_TEXT "No need to run now since we already installed and launched it as a Windows service!"
; FunctionEnd
# Installer functions
Function .onInit
InitPluginsDir
!insertmacro MUI_LANGDLL_DISPLAY
FunctionEnd
# Uninstaller functions
Function un.onInit
ReadRegStr $INSTDIR HKCU "${REGKEY}" Path
!insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuGroup
!insertmacro SELECT_UNSECTION Main ${UNSEC0000}
!insertmacro MUI_UNGETLANGUAGE
FunctionEnd

84
Win32/README-Build.txt Normal file
View File

@@ -0,0 +1,84 @@
Building i2pd for Windows
=========================
Requirements for building:
* Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4 RC)
* Boost (tested with 1.56 and 1.57)
* Crypto++ (tested with 5.6.2)
Building Boost (32-bit)
-----------------------
Open a Visual Studio x86 command prompt and run the following:
cd C:\path\to\boost\sources
bootstrap
b2 toolset=msvc-12.0 --build-type=complete --libdir=C:\Boost\lib\Win32 install --with-filesystem --with-program_options --with-regex --with-date_time
Building Boost (64-bit)
-----------------------
Open a Visual Studio x64 command prompt and run the following:
cd C:\path\to\boost\sources
bootstrap
b2 toolset=msvc-12.0 --build-type=complete --libdir=C:\Boost\lib\x64 architecture=x86 address-model=64 install --with-filesystem --with-program_options --with-regex --with-date_time
After Boost is compiled, set the environment variable `BOOST` to the directory
Boost was installed to. If you followed the instructions outlined here, you
should set it to `C:\Boost`. Additionally, set the BOOSTVER variable to the
version of Boost that you're using, but instead of a '.' use a '_'. For
example, I have `BOOSTVER` set to `1_57`.
Building Crypto++
-----------------
* Open the crypttest Solution in VS2013
* Visual Studio will ask to update the Solution/Project. Allow it.
* Build the `cryptopp` project, both the Debug and Release targets and for both
Win32 and x64.
* Create a folder called `cryptopp` in the crypto++ source directory, then copy
the header files to this new directory.
* Set the `CRYPTOPP` environment variable pointing to the Crypto++ source directory.
Building i2pd
-------------
## Prep work ##
I strongly advise setting up your own `INCLUDES` and `LIBS` instead of relying
on the settings in the i2pd project file. By using your own settings, if the
i2pd devs change the paths in the project file, your builds will still work.
To do this, create or edit the file
`%localappdata%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user`.
For comparison, my file is reproduced below:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets">
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<LibraryPath>$(CRYPTOPP)\$(Platform)\Output\$(Configuration);$(BOOST)\lib\$(Platform);$(LibraryPath)</LibraryPath>
<IncludePath>$(CRYPTOPP);$(BOOST)\include\boost-$(BOOSTVER);$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />
</Project>
If you want to build x64 binaries as well, you'll want to edit or create the
file `%localappdata%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.x64.user`. If you
followed the steps outlined earlier you can copy (or link) the win32 file to
the x64 one.
## Anti-Climatic End ##
After following the above instructions, you'll be able to build Debug Win32,
Debug x64, Release Win32, and Release x64 i2pd binaries.

BIN
Win32/Resource.rc Normal file

Binary file not shown.

View File

@@ -1,27 +1,30 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.30501.0
VisualStudioVersion = 12.0.30723.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "i2pd", "i2pd.vcxproj", "{930568EC-31C9-406A-AD1C-9636DF5D8FAA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.ActiveCfg = Debug|Win32
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.Build.0 = Debug|Win32
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|Win32.Deploy.0 = Debug|Win32
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|x64.ActiveCfg = Debug|x64
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Debug|x64.Build.0 = Debug|x64
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.ActiveCfg = Release|Win32
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.Build.0 = Release|Win32
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|Win32.Deploy.0 = Release|Win32
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|x64.ActiveCfg = Release|x64
{930568EC-31C9-406A-AD1C-9636DF5D8FAA}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal

View File

@@ -5,10 +5,18 @@
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\AddressBook.cpp" />
@@ -34,7 +42,9 @@
<ClCompile Include="..\SAM.cpp" />
<ClCompile Include="..\SSU.cpp" />
<ClCompile Include="..\SSUData.cpp" />
<ClCompile Include="..\SSUSession.cpp" />
<ClCompile Include="..\Streaming.cpp" />
<ClCompile Include="..\Datagram.cpp" />
<ClCompile Include="..\Destination.cpp" />
<ClCompile Include="..\TransitTunnel.cpp" />
<ClCompile Include="..\Transports.cpp" />
@@ -73,7 +83,9 @@
<ClInclude Include="..\SAM.h" />
<ClInclude Include="..\SSU.h" />
<ClInclude Include="..\SSUData.h" />
<ClInclude Include="..\SSUSession.h" />
<ClInclude Include="..\Streaming.h" />
<ClInclude Include="..\Datagram.h" />
<ClInclude Include="..\Destination.h" />
<ClInclude Include="..\Timestamp.h" />
<ClInclude Include="..\TransitTunnel.h" />
@@ -91,8 +103,13 @@
<ClInclude Include="..\version.h" />
<ClInclude Include="..\Signature.h" />
<ClInclude Include="..\ClientContext.h" />
<ClInclude Include="..\TransportSession.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="Win32Service.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resource.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{930568EC-31C9-406A-AD1C-9636DF5D8FAA}</ProjectGuid>
<RootNamespace>i2pd</RootNamespace>
@@ -101,15 +118,28 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120_xp</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -117,19 +147,36 @@
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>E:\build\cryptopp562;E:\build\boost_1_56_0;./..;$(IncludePath)</IncludePath>
<LibraryPath>E:\build\cryptopp562\Win32\Output\Debug;E:\build\boost_1_56_0\stage\lib;$(LibraryPath)</LibraryPath>
<IncludePath>./..;$(IncludePath);$(BOOST);$(CRYPTOPP);C:\build-lib\cryptopp;C:\build-lib\boost_1_57_0\</IncludePath>
<LibraryPath>$(BOOST)\stage\lib;C:\build-lib\cryptopp;C:\build-lib\boost_1_57_0\stage\lib;$(CRYPTOPP)\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
<TargetName>$(ProjectName)_d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>./..;$(IncludePath);$(BOOST);$(CRYPTOPP)</IncludePath>
<LibraryPath>$(BOOST)\stage\lib;$(CRYPTOPP)\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
<TargetName>$(ProjectName)_d</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>E:\build\cryptopp562;E:\build\boost_1_56_0;./..;$(IncludePath)</IncludePath>
<LibraryPath>E:\build\cryptopp562\Win32\Output\Release;E:\build\cryptopp562\Win32\cryptopp\Release;E:\build\boost_1_56_0\stage\lib;E:\build\cryptopp562\Win32\cryptlib\DLL-Import Release;$(LibraryPath)</LibraryPath>
<IncludePath>./..;$(IncludePath);$(BOOST);C:\build-lib\boost_1_57_0\;C:\build-lib</IncludePath>
<LibraryPath>C:\build-lib\boost_1_57_0\stage\lib;C:\build-lib\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>./..;$(IncludePath);$(BOOST);$(CRYPTOPP)</IncludePath>
<LibraryPath>$(BOOST)\stage\lib;$(CRYPTOPP)\cryptopp\$(Platform)\Output\$(Configuration);$(LibraryPath)</LibraryPath>
<SourcePath>./..;$(VC_SourcePath);</SourcePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -144,26 +191,82 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<Version>0.2</Version>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PreprocessorDefinitions>_MBCS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<Version>0.2</Version>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level2</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>_WIN32_WINNT=0x0501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>false</OptimizeReferences>
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<Version>
</Version>
<SubSystem>Console</SubSystem>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
<LinkErrorReporting>NoErrorReport</LinkErrorReporting>
</Link>
<Manifest>
<AssemblyIdentity>
</AssemblyIdentity>
<ComponentFileName>
</ComponentFileName>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PreprocessorDefinitions>_WIN32_WINNT=0x0502;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<GenerateDebugInformation>false</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>false</OptimizeReferences>
<AdditionalDependencies>cryptlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
<UACExecutionLevel>AsInvoker</UACExecutionLevel>
<Version>
</Version>
<SubSystem>Console</SubSystem>
<MinimumRequiredVersion>5.02</MinimumRequiredVersion>
<LinkErrorReporting>NoErrorReport</LinkErrorReporting>
</Link>
<Manifest>
<AssemblyIdentity>

View File

@@ -123,6 +123,18 @@
<ClCompile Include="..\SAM.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\SSUSession.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Datagram.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Destination.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\ClientContext.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Identity.h">
@@ -245,5 +257,28 @@
<ClInclude Include="..\SAM.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\SSUSession.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Datagram.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\Destination.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\ClientContext.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\TransportSession.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Resource.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

BIN
Win32/ictoopie.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -1,6 +1,6 @@
#define I2Pd_AppName "i2pd"
#define I2Pd_ver "0.1"
#define I2Pd_ver "0.2"
[Setup]
AppName={#I2Pd_AppName}
@@ -13,12 +13,21 @@ SolidCompression=yes
OutputDir=.
LicenseFile=.\..\LICENSE
OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver}
ArchitecturesInstallIn64BitMode=x64
[Files]
Source: "i2pd.exe"; DestDir: "{app}"
Source: "x64\Release\i2pd.exe"; DestDir: "{app}"; DestName: "i2pd.exe"; Check: Is64BitInstallMode
Source: "Release\i2pd.exe"; DestDir: "{app}"; Check: not Is64BitInstallMode
Source: "..\README.md"; DestDir: "{app}"; DestName: "Readme.txt"; AfterInstall: ConvertLineEndings
[Icons]
Name: "{group}\I2Pd"; Filename: "{app}\i2pd.exe"
Name: "{group}\Readme"; Filename: "{app}\Readme.txt"
[Registry]
Root: HKCU; Subkey: "Environment"; ValueName: "Path"; ValueType: "string"; ValueData: "{app};{olddata}"; Check: NotOnPathAlready(); Flags: preservestringtype;
[Code]
@@ -34,6 +43,20 @@ var
const
LicenseHeight = 400;
LF = #10;
CR = #13;
CRLF = CR + LF;
procedure ConvertLineEndings();
var
FilePath : String;
FileContents : String;
begin
FilePath := ExpandConstant(CurrentFileName)
LoadStringFromFile(FilePath, FileContents);
StringChangeEx(FileContents, LF, CRLF, False);
SaveStringToFile(FilePath, FileContents, False);
end;
procedure InitializeWizard();
begin
@@ -79,3 +102,48 @@ begin
WizardForm.Bevel.Top := DefaultBevelTop;
end;
end;
function NotOnPathAlready(): Boolean;
var
BinDir, Path: String;
begin
Log('Checking if i2pd dir is already in the %PATH%');
if RegQueryStringValue(HKEY_CURRENT_USER, 'Environment', 'Path', Path) then
begin // Successfully read the value
Log('HKCUEnvironmentPATH = ' + Path);
BinDir := ExpandConstant('{app}');
Log('Looking for i2pd dir in %PATH%: ' + BinDir + ' in ' + Path);
if Pos(LowerCase(BinDir), Lowercase(Path)) = 0 then
begin
Log('Did not find i2pd dir in %PATH% so I will add it');
Result := True;
end
else
begin
Log('Found i2pd dir in %PATH% so will not add it again');
Result := False;
end
end
else // The key probably doesn't exist
begin
Log('Could not access HKCUEnvironmentPATH so I assume that it is OK to add it');
Result := True;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
BinDir, Path: String;
begin
if (CurUninstallStep = usPostUninstall)
and (RegQueryStringValue(HKEY_CURRENT_USER, 'Environment', 'PATH', Path)) then
begin
BinDir := ExpandConstant('{app}');
if Pos(LowerCase(BinDir) + ';', Lowercase(Path)) <> 0 then
begin
StringChange(Path, BinDir + ';', '');
RegWriteStringValue(HKEY_CURRENT_USER, 'Environment', 'PATH', Path);
end;
end;
end;

View File

@@ -0,0 +1,57 @@
!verbose push
!verbose 3
!ifndef _MUI_EXTRAPAGES_NSH
!define _MUI_EXTRAPAGES_NSH
!ifmacrondef MUI_EXTRAPAGE_README & MUI_PAGE_README & MUI_UNPAGE_README & ReadmeLangStrings
!macro MUI_EXTRAPAGE_README UN ReadmeFile
!verbose push
!verbose 3
!define MUI_PAGE_HEADER_TEXT "$(${UN}ReadmeHeader)"
!define MUI_PAGE_HEADER_SUBTEXT "$(${UN}ReadmeSubHeader)"
!define MUI_LICENSEPAGE_TEXT_TOP "$(${UN}ReadmeTextTop)"
!define MUI_LICENSEPAGE_TEXT_BOTTOM "$(${UN}ReadmeTextBottom)"
!define MUI_LICENSEPAGE_BUTTON "$(^NextBtn)"
!insertmacro MUI_${UN}PAGE_LICENSE "${ReadmeFile}"
!verbose pop
!macroend
!define ReadmeRun "!insertmacro MUI_EXTRAPAGE_README"
!macro MUI_PAGE_README ReadmeFile
!verbose push
!verbose 3
${ReadmeRun} "" "${ReadmeFile}"
!verbose pop
!macroend
!macro MUI_UNPAGE_README ReadmeFile
!verbose push
!verbose 3
${ReadmeRun} "UN" "${ReadmeFile}"
!verbose pop
!macroend
!macro ReadmeLangStrings UN MUI_LANG ReadmeHeader ReadmeSubHeader ReadmeTextTop ReadmeTextBottom
!verbose push
!verbose 3
LangString ${UN}ReadmeHeader ${MUI_LANG} "${ReadmeHeader}"
LangString ${UN}ReadmeSubHeader ${MUI_LANG} "${ReadmeSubHeader}"
LangString ${UN}ReadmeTextTop ${MUI_LANG} "${ReadmeTextTop}"
LangString ${UN}ReadmeTextBottom ${MUI_LANG} "${ReadmeTextBottom}"
!verbose pop
!macroend
!define ReadmeLanguage `!insertmacro ReadmeLangStrings ""`
!define Un.ReadmeLanguage `!insertmacro ReadmeLangStrings "UN"`
!endif
!endif
!verbose pop

419
Win32/nsi/servicelib.nsh Normal file
View File

@@ -0,0 +1,419 @@
; NSIS SERVICE LIBRARY - servicelib.nsh
; Version 1.8.1 - Jun 21th, 2013
; Questions/Comments - dselkirk@hotmail.com
;
; Description:
; Provides an interface to window services
;
; Inputs:
; action - systemlib action ie. create, delete, start, stop, pause,
; continue, installed, running, status
; name - name of service to manipulate
; param - action parameters; usage: var1=value1;var2=value2;...etc.
; (don't forget to add a ';' after the last value!)
;
; Actions:
; create - creates a new windows service
; Parameters:
; path - path to service executable
; autostart - automatically start with system ie. 1|0
; interact - interact with the desktop ie. 1|0
; depend - service dependencies
; user - user that runs the service
; password - password of the above user
; display - display name in service's console
; description - Description of service
; starttype - start type (supersedes autostart)
; servicetype - service type (supersedes interact)
;
; delete - deletes a windows service
; start - start a stopped windows service
; stop - stops a running windows service
; pause - pauses a running windows service
; continue - continues a paused windows service
; installed - is the provided service installed
; Parameters:
; action - if true then invokes the specified action
; running - is the provided service running
; Parameters:
; action - if true then invokes the specified action
; status - check the status of the provided service
;
; Usage:
; Method 1:
; Push "action"
; Push "name"
; Push "param"
; Call Service
; Pop $0 ;response
;
; Method 2:
; !insertmacro SERVICE "action" "name" "param"
;
; History:
; 1.0 - 09/15/2003 - Initial release
; 1.1 - 09/16/2003 - Changed &l to i, thx brainsucker
; 1.2 - 02/29/2004 - Fixed documentation.
; 1.3 - 01/05/2006 - Fixed interactive flag and pop order (Kichik)
; 1.4 - 12/07/2006 - Added display and depend, fixed datatypes (Vitoco)
; 1.5 - 06/25/2008 - Added description of service.(DeSafe.com/liuqixing#gmail.com)
; 1.5.1 - 06/12/2009 - Added use of __UNINSTALL__
; 1.6 - 08/02/2010 - Fixed description implementation (Anders)
; 1.7 - 04/11/2010 - Added get running service process id (Nico)
; 1.8 - 24/03/2011 - Added starttype and servicetype (Sergius)
; 1.8.1 - 21/06/2013 - Added dynamic ASCII & Unicode support (Zinthose)
!ifndef SERVICELIB
!define SERVICELIB
!define SC_MANAGER_ALL_ACCESS 0x3F
!define SC_STATUS_PROCESS_INFO 0x0
!define SERVICE_ALL_ACCESS 0xF01FF
!define SERVICE_CONTROL_STOP 1
!define SERVICE_CONTROL_PAUSE 2
!define SERVICE_CONTROL_CONTINUE 3
!define SERVICE_STOPPED 0x1
!define SERVICE_START_PENDING 0x2
!define SERVICE_STOP_PENDING 0x3
!define SERVICE_RUNNING 0x4
!define SERVICE_CONTINUE_PENDING 0x5
!define SERVICE_PAUSE_PENDING 0x6
!define SERVICE_PAUSED 0x7
!define SERVICE_KERNEL_DRIVER 0x00000001
!define SERVICE_FILE_SYSTEM_DRIVER 0x00000002
!define SERVICE_WIN32_OWN_PROCESS 0x00000010
!define SERVICE_WIN32_SHARE_PROCESS 0x00000020
!define SERVICE_INTERACTIVE_PROCESS 0x00000100
!define SERVICE_BOOT_START 0x00000000
!define SERVICE_SYSTEM_START 0x00000001
!define SERVICE_AUTO_START 0x00000002
!define SERVICE_DEMAND_START 0x00000003
!define SERVICE_DISABLED 0x00000004
## Added by Zinthose for Native Unicode Support
!ifdef NSIS_UNICODE
!define APITAG "W"
!else
!define APITAG "A"
!endif
!macro SERVICE ACTION NAME PARAM
Push '${ACTION}'
Push '${NAME}'
Push '${PARAM}'
!ifdef __UNINSTALL__
Call un.Service
!else
Call Service
!endif
!macroend
!macro FUNC_GETPARAM
Push $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
Exch 8
Pop $1 ;name
Exch 8
Pop $2 ;source
StrCpy $0 ""
StrLen $7 $2
StrCpy $3 0
lbl_loop:
IntCmp $3 $7 0 0 lbl_done
StrLen $4 "$1="
StrCpy $5 $2 $4 $3
StrCmp $5 "$1=" 0 lbl_next
IntOp $5 $3 + $4
StrCpy $3 $5
lbl_loop2:
IntCmp $3 $7 0 0 lbl_done
StrCpy $6 $2 1 $3
StrCmp $6 ";" 0 lbl_next2
IntOp $6 $3 - $5
StrCpy $0 $2 $6 $5
Goto lbl_done
lbl_next2:
IntOp $3 $3 + 1
Goto lbl_loop2
lbl_next:
IntOp $3 $3 + 1
Goto lbl_loop
lbl_done:
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch 2
Pop $6
Pop $7
Exch $0
!macroend
!macro CALL_GETPARAM VAR NAME DEFAULT LABEL
Push $1
Push ${NAME}
Call ${UN}GETPARAM
Pop $6
StrCpy ${VAR} "${DEFAULT}"
StrCmp $6 "" "${LABEL}" 0
StrCpy ${VAR} $6
!macroend
!macro FUNC_SERVICE UN
Push $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
Push $7
Exch 8
Pop $1 ;param
Exch 8
Pop $2 ;name
Exch 8
Pop $3 ;action
;$0 return
;$4 OpenSCManager
;$5 OpenService
StrCpy $0 "false"
System::Call 'advapi32::OpenSCManager${APITAG}(n, n, i ${SC_MANAGER_ALL_ACCESS}) i.r4'
IntCmp $4 0 lbl_done
StrCmp $3 "create" lbl_create
System::Call 'advapi32::OpenService${APITAG}(i r4, t r2, i ${SERVICE_ALL_ACCESS}) i.r5'
IntCmp $5 0 lbl_done
lbl_select:
StrCmp $3 "delete" lbl_delete
StrCmp $3 "start" lbl_start
StrCmp $3 "stop" lbl_stop
StrCmp $3 "pause" lbl_pause
StrCmp $3 "continue" lbl_continue
StrCmp $3 "installed" lbl_installed
StrCmp $3 "running" lbl_running
StrCmp $3 "status" lbl_status
StrCmp $3 "processid" lbl_processid
Goto lbl_done
; create service
lbl_create:
Push $R1 ;depend
Push $R2 ;user
Push $R3 ;password
Push $R4 ;servicetype/interact
Push $R5 ;starttype/autostart
Push $R6 ;path
Push $R7 ;display
Push $R8 ;description
!insertmacro CALL_GETPARAM $R1 "depend" "n" "lbl_depend"
StrCpy $R1 't "$R1"'
lbl_depend:
StrCmp $R1 "n" 0 lbl_machine ;old name of depend param
!insertmacro CALL_GETPARAM $R1 "machine" "n" "lbl_machine"
StrCpy $R1 't "$R1"'
lbl_machine:
!insertmacro CALL_GETPARAM $R2 "user" "n" "lbl_user"
StrCpy $R2 't "$R2"'
lbl_user:
!insertmacro CALL_GETPARAM $R3 "password" "n" "lbl_password"
StrCpy $R3 't "$R3"'
lbl_password:
!insertmacro CALL_GETPARAM $R4 "interact" "${SERVICE_WIN32_OWN_PROCESS}" "lbl_interact"
StrCpy $6 ${SERVICE_WIN32_OWN_PROCESS}
IntCmp $R4 0 +2
IntOp $6 $6 | ${SERVICE_INTERACTIVE_PROCESS}
StrCpy $R4 $6
lbl_interact:
!insertmacro CALL_GETPARAM $R4 "servicetype" "$R4" "lbl_servicetype"
lbl_servicetype:
!insertmacro CALL_GETPARAM $R5 "autostart" "${SERVICE_DEMAND_START}" "lbl_autostart"
StrCpy $6 ${SERVICE_DEMAND_START}
IntCmp $R5 0 +2
StrCpy $6 ${SERVICE_AUTO_START}
StrCpy $R5 $6
lbl_autostart:
!insertmacro CALL_GETPARAM $R5 "starttype" "$R5" "lbl_starttype"
lbl_starttype:
!insertmacro CALL_GETPARAM $R6 "path" "n" "lbl_path"
lbl_path:
!insertmacro CALL_GETPARAM $R7 "display" "$2" "lbl_display"
lbl_display:
!insertmacro CALL_GETPARAM $R8 "description" "$2" "lbl_description"
lbl_description:
System::Call 'advapi32::CreateService${APITAG}(i r4, t r2, t R7, i ${SERVICE_ALL_ACCESS}, \
i R4, i R5, i 0, t R6, n, n, $R1, $R2, $R3) i.r6'
; write description of service (SERVICE_CONFIG_DESCRIPTION)
System::Call 'advapi32::ChangeServiceConfig2${APITAG}(ir6,i1,*t "$R8")i.R7'
strcmp $R7 "error" 0 lbl_descriptioncomplete
WriteRegStr HKLM "SYSTEM\CurrentControlSet\Services\$2" "Description" $R8
lbl_descriptioncomplete:
Pop $R8
Pop $R7
Pop $R6
Pop $R5
Pop $R4
Pop $R3
Pop $R2
Pop $R1
StrCmp $6 0 lbl_done lbl_good
; delete service
lbl_delete:
System::Call 'advapi32::DeleteService(i r5) i.r6'
StrCmp $6 0 lbl_done lbl_good
; start service
lbl_start:
System::Call 'advapi32::StartService${APITAG}(i r5, i 0, i 0) i.r6'
StrCmp $6 0 lbl_done lbl_good
; stop service
lbl_stop:
Push $R1
System::Call '*(i,i,i,i,i,i,i) i.R1'
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_STOP}, i $R1) i'
System::Free $R1
Pop $R1
StrCmp $6 0 lbl_done lbl_good
; pause service
lbl_pause:
Push $R1
System::Call '*(i,i,i,i,i,i,i) i.R1'
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_PAUSE}, i $R1) i'
System::Free $R1
Pop $R1
StrCmp $6 0 lbl_done lbl_good
; continue service
lbl_continue:
Push $R1
System::Call '*(i,i,i,i,i,i,i) i.R1'
System::Call 'advapi32::ControlService(i r5, i ${SERVICE_CONTROL_CONTINUE}, i $R1) i'
System::Free $R1
Pop $R1
StrCmp $6 0 lbl_done lbl_good
; is installed
lbl_installed:
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good"
StrCpy $3 $7
Goto lbl_select
; is service running
lbl_running:
Push $R1
System::Call '*(i,i,i,i,i,i,i) i.R1'
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
System::Call '*$R1(i, i.r6)'
System::Free $R1
Pop $R1
IntFmt $6 "0x%X" $6
StrCmp $6 ${SERVICE_RUNNING} 0 lbl_done
!insertmacro CALL_GETPARAM $7 "action" "" "lbl_good"
StrCpy $3 $7
Goto lbl_select
lbl_status:
Push $R1
System::Call '*(i,i,i,i,i,i,i) i.R1'
System::Call 'advapi32::QueryServiceStatus(i r5, i $R1) i'
System::Call '*$R1(i, i .r6)'
System::Free $R1
Pop $R1
IntFmt $6 "0x%X" $6
StrCpy $0 "running"
IntCmp $6 ${SERVICE_RUNNING} lbl_done
StrCpy $0 "stopped"
IntCmp $6 ${SERVICE_STOPPED} lbl_done
StrCpy $0 "start_pending"
IntCmp $6 ${SERVICE_START_PENDING} lbl_done
StrCpy $0 "stop_pending"
IntCmp $6 ${SERVICE_STOP_PENDING} lbl_done
StrCpy $0 "running"
IntCmp $6 ${SERVICE_RUNNING} lbl_done
StrCpy $0 "continue_pending"
IntCmp $6 ${SERVICE_CONTINUE_PENDING} lbl_done
StrCpy $0 "pause_pending"
IntCmp $6 ${SERVICE_PAUSE_PENDING} lbl_done
StrCpy $0 "paused"
IntCmp $6 ${SERVICE_PAUSED} lbl_done
StrCpy $0 "unknown"
Goto lbl_done
lbl_processid:
Push $R1
Push $R2
System::Call '*(i,i,i,i,i,i,i,i,i) i.R1'
System::Call '*(i 0) i.R2'
System::Call "advapi32::QueryServiceStatusEx(i r5, i ${SC_STATUS_PROCESS_INFO}, i $R1, i 36, i $R2) i"
System::Call "*$R1(i,i,i,i,i,i,i, i .r0)"
System::Free $R2
System::Free $R1
Pop $R2
Pop $R1
Goto lbl_done
lbl_good:
StrCpy $0 "true"
lbl_done:
IntCmp $5 0 +2
System::Call 'advapi32::CloseServiceHandle(i r5) n'
IntCmp $4 0 +2
System::Call 'advapi32::CloseServiceHandle(i r4) n'
Pop $4
Pop $3
Pop $2
Pop $1
Exch 3
Pop $5
Pop $7
Pop $6
Exch $0
!macroend
Function Service
!insertmacro FUNC_SERVICE ""
FunctionEnd
Function un.Service
!insertmacro FUNC_SERVICE "un."
FunctionEnd
Function GetParam
!insertmacro FUNC_GETPARAM
FunctionEnd
Function un.GetParam
!insertmacro FUNC_GETPARAM
FunctionEnd
!undef APITAG
!endif

BIN
Win32/resource.h Normal file

Binary file not shown.

20
aes.cpp
View File

@@ -9,14 +9,6 @@ namespace crypto
#ifdef AESNI
ECBCryptoAESNI::ECBCryptoAESNI ()
{
m_KeySchedule = m_UnalignedBuffer;
uint8_t rem = ((uint64_t)m_KeySchedule) & 0x0f;
if (rem)
m_KeySchedule += (16 - rem);
}
#define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
"movaps %%xmm1, %%xmm4 \n" \
@@ -40,7 +32,7 @@ namespace crypto
"pxor %%xmm2, %%xmm3 \n" \
"movaps %%xmm3, "#round1"(%[sched]) \n"
void ECBCryptoAESNI::ExpandKey (const uint8_t * key)
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
{
__asm__
(
@@ -73,7 +65,7 @@ namespace crypto
"pxor %%xmm2, %%xmm1 \n"
"movups %%xmm1, 224(%[sched]) \n"
: // output
: [key]"r"(key), [sched]"r"(m_KeySchedule) // input
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
: "%xmm1", "%xmm2", "%xmm3", "%xmm4" // clogged
);
}
@@ -102,7 +94,7 @@ namespace crypto
"movups (%[in]), %%xmm0 \n"
EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
: : [sched]"r"(m_KeySchedule), [in]"r"(in), [out]"r"(out) : "%xmm0"
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0"
);
}
@@ -130,7 +122,7 @@ namespace crypto
"movups (%[in]), %%xmm0 \n"
DecryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
: : [sched]"r"(m_KeySchedule), [in]"r"(in), [out]"r"(out) : "%xmm0"
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0"
);
}
@@ -139,7 +131,7 @@ namespace crypto
"aesimc %%xmm0, %%xmm0 \n" \
"movaps %%xmm0, "#offset"(%[shed]) \n"
void ECBDecryptionAESNI::SetKey (const uint8_t * key)
void ECBDecryptionAESNI::SetKey (const AESKey& key)
{
ExpandKey (key); // expand encryption key first
// then invert it using aesimc
@@ -158,7 +150,7 @@ namespace crypto
CallAESIMC(176)
CallAESIMC(192)
CallAESIMC(208)
: : [shed]"r"(m_KeySchedule) : "%xmm0"
: : [shed]"r"(GetKeySchedule ()) : "%xmm0"
);
}

71
aes.h
View File

@@ -4,46 +4,83 @@
#include <inttypes.h>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include "Identity.h"
namespace i2p
{
namespace crypto
{
union ChipherBlock
struct ChipherBlock
{
uint8_t buf[16];
uint64_t ll[2];
void operator^=(const ChipherBlock& other) // XOR
{
ll[0] ^= other.ll[0];
ll[1] ^= other.ll[1];
#if defined(__x86_64__) // for Intel x64
__asm__
(
"movups (%[buf]), %%xmm0 \n"
"movups (%[other]), %%xmm1 \n"
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory"
);
#else
// TODO: implement it better
for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i];
#endif
}
};
typedef i2p::data::Tag<32> AESKey;
template<size_t sz>
class AESAlignedBuffer // 16 bytes alignment
{
public:
AESAlignedBuffer ()
{
m_Buf = m_UnalignedBuffer;
uint8_t rem = ((uint64_t)m_Buf) & 0x0f;
if (rem)
m_Buf += (16 - rem);
}
operator uint8_t * () { return m_Buf; };
operator const uint8_t * () const { return m_Buf; };
private:
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
uint8_t * m_Buf;
};
#ifdef AESNI
class ECBCryptoAESNI
{
public:
ECBCryptoAESNI ();
uint8_t * GetKeySchedule () { return m_KeySchedule; };
protected:
void ExpandKey (const uint8_t * key);
void ExpandKey (const AESKey& key);
protected:
private:
uint8_t * m_KeySchedule; // start of 16 bytes boundary of m_UnalignedBuffer
uint8_t m_UnalignedBuffer[256]; // 14 rounds for AES-256, 240 + 16 bytes
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
};
class ECBEncryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const uint8_t * key) { ExpandKey (key); };
void SetKey (const AESKey& key) { ExpandKey (key); };
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
};
@@ -51,7 +88,7 @@ namespace crypto
{
public:
void SetKey (const uint8_t * key);
void SetKey (const AESKey& key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
};
@@ -64,7 +101,7 @@ namespace crypto
{
public:
void SetKey (const uint8_t * key)
void SetKey (const AESKey& key)
{
m_Encryption.SetKey (key, 32);
}
@@ -82,7 +119,7 @@ namespace crypto
{
public:
void SetKey (const uint8_t * key)
void SetKey (const AESKey& key)
{
m_Decryption.SetKey (key, 32);
}
@@ -105,7 +142,7 @@ namespace crypto
CBCEncryption () { memset (m_LastBlock.buf, 0, 16); };
void SetKey (const uint8_t * key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
@@ -125,7 +162,7 @@ namespace crypto
CBCDecryption () { memset (m_IV.buf, 0, 16); };
void SetKey (const uint8_t * key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
@@ -142,7 +179,7 @@ namespace crypto
{
public:
void SetKeys (const uint8_t * layerKey, const uint8_t * ivKey)
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
{
m_LayerEncryption.SetKey (layerKey);
m_IVEncryption.SetKey (ivKey);
@@ -164,7 +201,7 @@ namespace crypto
{
public:
void SetKeys (const uint8_t * layerKey, const uint8_t * ivKey)
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
{
m_LayerDecryption.SetKey (layerKey);
m_IVDecryption.SetKey (ivKey);

33
api/Makefile Normal file
View File

@@ -0,0 +1,33 @@
UNAME := $(shell uname -s)
ifeq ($(UNAME),Darwin)
include ../Makefile.osx
else ifeq ($(UNAME), FreeBSD)
include ../Makefile.bsd
else
include ../Makefile.linux
endif
SHARED_LIB = libi2pd.so
all: obj $(SHARED_LIB)
$(SHARED_LIB): $(OBJECTS:obj/%=obj/%)
$(CXX) -shared -o $(SHARED_LIB) $^
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : ../%.cpp
$(CXX) -o $@ $< -c $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -I.. -fPIC $(CPU_FLAGS)
obj/api.o: api.cpp
$(CXX) -o obj/api.o api.cpp -c $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -I.. -fPIC $(CPU_FLAGS)
obj:
mkdir -p obj
clean:
rm -fr obj $(SHARED_LIB)
.PHONY: all
.PHONY: clean

108
api/api.cpp Normal file
View File

@@ -0,0 +1,108 @@
#include <string>
#include <map>
#include "Log.h"
#include "NetDb.h"
#include "Transports.h"
#include "Tunnel.h"
#include "RouterContext.h"
#include "Identity.h"
#include "Destination.h"
#include "util.h"
#include "api.h"
namespace i2p
{
namespace api
{
void InitI2P (int argc, char* argv[], const char * appName)
{
i2p::util::filesystem::SetAppName (appName);
i2p::util::config::OptionParser(argc, argv);
i2p::context.Init ();
}
void StartI2P ()
{
StartLog (i2p::util::filesystem::GetAppName () + ".log");
i2p::data::netdb.Start();
LogPrint("NetDB started");
i2p::transport::transports.Start();
LogPrint("Transports started");
i2p::tunnel::tunnels.Start();
LogPrint("Tunnels started");
}
void StopI2P ()
{
LogPrint("Shutdown started.");
i2p::tunnel::tunnels.Stop();
LogPrint("Tunnels stoped");
i2p::transport::transports.Stop();
LogPrint("Transports stoped");
i2p::data::netdb.Stop();
LogPrint("NetDB stoped");
StopLog ();
}
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic)
{
auto localDestination = new i2p::client::ClientDestination (keys, isPublic);
localDestination->Start ();
return localDestination;
}
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType)
{
auto localDestination = new i2p::client::ClientDestination (isPublic, sigType);
localDestination->Start ();
return localDestination;
}
void DestroyLocalDestination (i2p::client::ClientDestination * dest)
{
if (dest)
{
dest->Stop ();
delete dest;
}
}
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
{
if (dest)
i2p::data::netdb.RequestDestination (remote, true, dest->GetTunnelPool ());
}
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
{
auto leaseSet = i2p::data::netdb.FindLeaseSet (remote);
if (leaseSet)
{
auto stream = dest->CreateStream (*leaseSet);
stream->Send (nullptr, 0); // connect
return stream;
}
else
{
RequestLeaseSet (dest, remote);
return nullptr;
}
}
void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)
{
if (dest)
dest->AcceptStreams (acceptor);
}
void DestroyStream (i2p::stream::Stream * stream)
{
if (stream)
{
stream->Close ();
i2p::stream::DeleteStream (stream);
}
}
}
}

31
api/api.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef API_H__
#define API_H__
#include "Identity.h"
#include "Destination.h"
#include "Streaming.h"
namespace i2p
{
namespace api
{
// initialization start and stop
void InitI2P (int argc, char* argv[], const char * appName);
void StartI2P ();
void StopI2P ();
// destinations
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true);
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // transient destinations usually not published
void DestoroyLocalDestination (i2p::client::ClientDestination * dest);
// streams
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor);
void DestroyStream (i2p::stream::Stream * stream);
}
}
#endif

19
api/filelist.mk Normal file
View File

@@ -0,0 +1,19 @@
CPP_FILES := ../CryptoConst.cpp ../base64.cpp ../NTCPSession.cpp ../RouterInfo.cpp \
../Transports.cpp ../RouterContext.cpp ../NetDb.cpp ../LeaseSet.cpp Tunnel.cpp \
../TunnelEndpoint.cpp ../TunnelGateway.cpp ../TransitTunnel.cpp ../I2NPProtocol.cpp \
../Log.cpp ../Garlic.cpp ../Streaming.cpp ../Destination.cpp ../Identity.cpp \
../SSU.cpp ../SSUSession.cpp ../SSUData.cpp ../util.cpp ../Reseed.cpp ../SSUData.cpp \
../aes.cpp ../TunnelPool.cpp ../AddressBook.cpp ../Datagram.cpp api.cpp
H_FILES := ../CryptoConst.h ../base64.h ../NTCPSession.h ../RouterInfo.h ../Transports.h \
../RouterContext.h ../NetDb.h ../LeaseSet.h ../Tunnel.h ../TunnelEndpoint.h \
../TunnelGateway.h ../TransitTunnel.h ../I2NPProtocol.h ../Log.h ../Garlic.h \
../Streaming.h ../Destination.h ../Identity.h ../SSU.h ../SSUSession.h ../SSUData.h \
../util.h ../Reseed.h ../SSUData.h ../aes.h ../TunnelPool.h ../AddressBook.h ../version.h \
../Signature.h ../TransportSession.h ../Datagram.h api.h
OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))

View File

@@ -3,11 +3,11 @@ Build notes
Common build/install process:
git clone https://github.com/PrivacySolutions/i2pd.git
cd i2pd/build
cmake -DCMAKE_BUILD_TYPE=Release <more options> .
make
make install
* git clone https://github.com/PrivacySolutions/i2pd.git
* cd i2pd/build
* cmake -DCMAKE_BUILD_TYPE=Release <more options> .
* make
* make install
Available cmake options:
@@ -19,7 +19,6 @@ Debian
------
Required "-dev" packages:
* cmake
* libboost-filesystem-dev
* libboost-program-options-dev

View File

@@ -44,6 +44,7 @@ set (SOURCES
"${CMAKE_SOURCE_DIR}/util.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.cpp"
"${CMAKE_SOURCE_DIR}/Datagram.cpp"
)
file (GLOB HEADERS "${CMAKE_SOURCE_DIR}/*.h")

View File

@@ -114,7 +114,8 @@ am_i2p_OBJECTS = AddressBook.$(OBJEXT) CryptoConst.$(OBJEXT) \
Transports.$(OBJEXT) Tunnel.$(OBJEXT) TunnelEndpoint.$(OBJEXT) \
TunnelGateway.$(OBJEXT) TunnelPool.$(OBJEXT) UPnP.$(OBJEXT) \
aes.$(OBJEXT) base64.$(OBJEXT) i2p.$(OBJEXT) util.$(OBJEXT) \
SAM.$(OBJEXT) Destination.$(OBJEXT)
SAM.$(OBJEXT) Destination.$(OBJEXT) ClientContext.$(OBJEXT) \
Datagram.$(OBJEXT) SSUSession.$(OBJEXT)
i2p_OBJECTS = $(am_i2p_OBJECTS)
i2p_LDADD = $(LDADD)
AM_V_P = $(am__v_P_@AM_V@)
@@ -325,7 +326,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \
TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \
base64.cpp i2p.cpp util.cpp SAM.cpp Destination.cpp \
ClientContext.cpp \
ClientContext.cpp DataFram.cpp SSUSession.cpp \
\
AddressBook.h CryptoConst.h Daemon.h ElGamal.h \
Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.h \
@@ -336,7 +337,8 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
TransitTunnel.h Transports.h Tunnel.h TunnelBase.h \
TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \
TunnelPool.h UPnP.h aes.h base64.h config.h hmac.h \
util.h version.h Destination.h ClientContext.h
util.h version.h Destination.h ClientContext.h \
TransportSession.h Datagram.h SSUSession.h
AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \
@BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_LIB@ \
@@ -485,6 +487,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SAM.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClientContext.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Datagram.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSUSession.Po@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@@ -57,10 +57,10 @@ do_stop()
}
# Function that sends a SIGHUP to the daemon/service
#do_reload() {
# start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
# return 0
#}
do_reload() {
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
@@ -82,14 +82,12 @@ case "$1" in
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
# If the "reload" option is implemented then remove the
# 'force-reload' alias
reload|force-reload)
log_daemon_msg "Reloading $DESC" "$NAME"
do_reload
log_end_msg $?
;;
restart)
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in

10
debian/i2pd.upstart vendored Normal file
View File

@@ -0,0 +1,10 @@
description "i2p client daemon"
start on runlevel [2345]
stop on runlevel [016] or unmounting-filesystem
# these can be overridden in /etc/init/i2pd.override
env I2P_HOST="1.2.3.4"
env I2P_PORT="4567"
exec /usr/sbin/i2pd --daemon=0 --log=1 --host=$I2P_HOST --port=$I2P_PORT

View File

@@ -1,8 +1,6 @@
diff --git a/Makefile b/Makefile
index 9b9425b..84de72f 100644
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,9 @@ else
@@ -10,9 +10,9 @@
include Makefile.linux
endif
@@ -11,10 +9,10 @@ index 9b9425b..84de72f 100644
-i2p: $(OBJECTS:obj/%=obj/%)
+i2pd: $(OBJECTS:obj/%=obj/%)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(CXX) -o $@ $^ $(LDFLAGS) $(LIBS)
.SUFFIXES:
@@ -23,7 +23,7 @@ obj:
@@ -25,7 +25,7 @@
mkdir -p obj
clean:

1
debian/rules vendored
View File

@@ -6,7 +6,6 @@
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/buildflags.mk
CFLAGS+=$(CPPFLAGS)
CXXFLAGS+=$(CPPFLAGS)
PREFIX=/usr

View File

@@ -3,17 +3,17 @@
CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transports.cpp \
RouterContext.cpp NetDb.cpp LeaseSet.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelGateway.cpp \
TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.cpp \
Destination.cpp Identity.cpp SSU.cpp util.cpp Reseed.cpp DaemonLinux.cpp SSUData.cpp \
aes.cpp SOCKS.cpp UPnP.cpp TunnelPool.cpp HTTPProxy.cpp AddressBook.cpp Daemon.cpp \
I2PTunnel.cpp SAM.cpp ClientContext.cpp i2p.cpp
Destination.cpp Identity.cpp SSU.cpp SSUSession.cpp SSUData.cpp util.cpp Reseed.cpp \
DaemonLinux.cpp SSUData.cpp aes.cpp SOCKS.cpp UPnP.cpp TunnelPool.cpp HTTPProxy.cpp \
AddressBook.cpp Daemon.cpp I2PTunnel.cpp SAM.cpp ClientContext.cpp Datagram.cpp i2p.cpp
H_FILES := CryptoConst.h base64.h NTCPSession.h RouterInfo.h Transports.h \
RouterContext.h NetDb.h LeaseSet.h Tunnel.h TunnelEndpoint.h TunnelGateway.h \
TransitTunnel.h I2NPProtocol.h Log.h Garlic.h HTTPServer.h Streaming.h Destination.h \
Identity.h SSU.h util.h Reseed.h DaemonLinux.h SSUData.h i2p.h aes.h SOCKS.h \
UPnP.h TunnelPool.h HTTPProxy.h AddressBook.h Daemon.h I2PTunnel.h version.h \
Signature.h SAM.h ClientContext.h
Identity.h SSU.h SSUSession.h SSUData.h util.h Reseed.h DaemonLinux.h SSUData.h \
aes.h SOCKS.h UPnP.h TunnelPool.h HTTPProxy.h AddressBook.h Daemon.h I2PTunnel.h \
version.h Signature.h SAM.h ClientContext.h TransportSession.h Datagram.h
OBJECTS = $(addprefix obj/, $(notdir $(CPP_FILES:.cpp=.o)))

21
hmac.h
View File

@@ -5,6 +5,7 @@
#include <string.h>
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <cryptopp/md5.h>
#include "Identity.h"
namespace i2p
{
@@ -13,17 +14,19 @@ namespace crypto
const uint64_t IPAD = 0x3636363636363636;
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
inline void HMACMD5Digest (uint8_t * msg, size_t len, const uint8_t * key, uint8_t * digest)
typedef i2p::data::Tag<32> MACKey;
inline void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
// key is 32 bytes
// digest is 16 bytes
// block size is 64 bytes
{
uint64_t buf[256];
// ikeypad
buf[0] = ((uint64_t *)key)[0] ^ IPAD;
buf[1] = ((uint64_t *)key)[1] ^ IPAD;
buf[2] = ((uint64_t *)key)[2] ^ IPAD;
buf[3] = ((uint64_t *)key)[3] ^ IPAD;
buf[0] = key.GetLL ()[0] ^ IPAD;
buf[1] = key.GetLL ()[1] ^ IPAD;
buf[2] = key.GetLL ()[2] ^ IPAD;
buf[3] = key.GetLL ()[3] ^ IPAD;
buf[4] = IPAD;
buf[5] = IPAD;
buf[6] = IPAD;
@@ -35,10 +38,10 @@ namespace crypto
CryptoPP::Weak1::MD5().CalculateDigest (hash, (uint8_t *)buf, len + 64);
// okeypad
buf[0] = ((uint64_t *)key)[0] ^ OPAD;
buf[1] = ((uint64_t *)key)[1] ^ OPAD;
buf[2] = ((uint64_t *)key)[2] ^ OPAD;
buf[3] = ((uint64_t *)key)[3] ^ OPAD;
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;

View File

@@ -15,6 +15,11 @@
#include "util.h"
#include "Log.h"
#if defined(__linux__) || defined(__FreeBSD_kernel__)
#include <sys/types.h>
#include <ifaddrs.h>
#endif
#ifdef WIN32
#include <Windows.h>
#include <shlobj.h>
@@ -96,6 +101,18 @@ namespace config
namespace filesystem
{
std::string appName ("i2pd");
void SetAppName (const std::string& name)
{
appName = name;
}
std::string GetAppName ()
{
return appName;
}
const boost::filesystem::path &GetDataDir()
{
static boost::filesystem::path path;
@@ -173,10 +190,10 @@ namespace filesystem
// Windows
char localAppData[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData);
return boost::filesystem::path(std::string(localAppData) + "\\i2pd");
return boost::filesystem::path(std::string(localAppData) + "\\" + appName);
#else
if (i2p::util::config::GetArg("-service", 0)) // use system folder
return boost::filesystem::path("/var/lib/i2pd");
return boost::filesystem::path(std::string ("/var/lib/") + appName);
boost::filesystem::path pathRet;
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
@@ -187,10 +204,10 @@ namespace filesystem
// Mac
pathRet /= "Library/Application Support";
boost::filesystem::create_directory(pathRet);
return pathRet / "i2pd";
return pathRet / appName;
#else
// Unix
return pathRet / ".i2pd";
return pathRet / (std::string (".") + appName);
#endif
#endif
}
@@ -391,8 +408,63 @@ namespace http
}
} // Namespace end
namespace net
{
int GetMTU (const boost::asio::ip::address& localAddress)
{
#if defined(__linux__) || defined(__FreeBSD_kernel__)
ifaddrs * ifaddr, * ifa = nullptr;
if (getifaddrs(&ifaddr) == -1)
{
LogPrint (eLogError, "Can't excute getifaddrs");
return 0;
}
int family = 0;
// loook for interface matching local address
for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{
if (!ifa->ifa_addr) continue;
family = ifa->ifa_addr->sa_family;
if (family == AF_INET && localAddress.is_v4 ())
{
sockaddr_in * sa = (sockaddr_in *)ifa->ifa_addr;
if (!memcmp (&sa->sin_addr, localAddress.to_v4 ().to_bytes ().data (), 4))
break; // address matches
}
else if (family == AF_INET6 && localAddress.is_v6 ())
{
sockaddr_in6 * sa = (sockaddr_in6 *)ifa->ifa_addr;
if (!memcmp (&sa->sin6_addr, localAddress.to_v6 ().to_bytes ().data (), 16))
break; // address matches
}
}
int mtu = 0;
if (ifa && family) // interface found?
{
int fd = socket (family, SOCK_DGRAM, 0);
if (fd > 0)
{
ifreq ifr;
strncpy (ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query
if (ioctl (fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU
else
LogPrint (eLogError, "Failed to run ioctl");
close (fd);
}
else
LogPrint (eLogError, "Failed to create datagram socket");
}
else
LogPrint (eLogWarning, "Interface for local address", localAddress.to_string (), " not found");
freeifaddrs (ifaddr);
return mtu;
#else
return 0;
#endif
}
}
} // util
} // i2p

9
util.h
View File

@@ -3,6 +3,7 @@
#include <map>
#include <string>
#include <boost/asio.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
@@ -24,6 +25,9 @@ namespace util
namespace filesystem
{
void SetAppName (const std::string& name);
std::string GetAppName ();
const boost::filesystem::path &GetDataDir();
std::string GetFullPath (const std::string& filename);
boost::filesystem::path GetDefaultDataDir();
@@ -49,6 +53,11 @@ namespace util
std::string pass_;
};
}
namespace net
{
int GetMTU (const boost::asio::ip::address& localAddress);
}
}
}

View File

@@ -2,7 +2,7 @@
#define _VERSION_H_
#define CODENAME "Purple"
#define VERSION "0.1.0"
#define I2P_VERSION "0.9.15"
#define VERSION "0.3.0"
#define I2P_VERSION "0.9.16"
#endif