Compare commits

...

170 Commits

Author SHA1 Message Date
orignal
25ccfef4b0 version updated 2014-12-17 09:20:58 -05:00
orignal
ec8e3574f9 delete local destination on session close 2014-12-16 21:26:29 -05:00
orignal
7da694825d fixed handshake 2014-12-16 19:04:13 -05:00
orignal
9606883b78 handle signature type for SAM 3.1 2014-12-16 16:23:42 -05:00
orignal
54cffb583f check max version 2014-12-16 15:54:02 -05:00
orignal
fe4d640504 drop incoming garlic messages if local destination doesn't exist anymore 2014-12-16 14:50:29 -05:00
orignal
1a69770e15 fixed compilation warning 2014-12-16 14:35:39 -05:00
orignal
75b67b7ea7 CRC32 verification 2014-12-16 12:48:42 -05:00
orignal
e3f077ee9a create io_service together with destination 2014-12-15 22:50:11 -05:00
orignal
f357a5864c pass local destination by pointer 2014-12-15 21:24:01 -05:00
orignal
6e32c389b1 some cleanup 2014-12-15 19:08:46 -05:00
orignal
219abaa7e1 don't use AESNI if not supported 2014-12-15 16:15:06 -05:00
orignal
82d5bf2f8a load certificates before reseed 2014-12-15 12:38:35 -05:00
orignal
1ffe7955a3 RSA raw verifier 2014-12-15 12:32:06 -05:00
orignal
ef73353a0a use RSA-raw for SU3 verification 2014-12-14 22:45:09 -05:00
orignal
52a0b9ca03 extend LeaseSet buffer to fir RSA-4096 key and signature 2014-12-13 20:54:18 -05:00
orignal
0a9eca9f94 load certificates and verify signatures 2014-12-13 18:35:53 -05:00
orignal
b399d45d66 extract public key from ceritificate 2014-12-13 15:01:08 -05:00
orignal
d6fe4556fb don't make executable as shared 2014-12-13 14:45:44 -05:00
orignal
6ad0313dbe Merge pull request #117 from hagen-i2p/library-build-2
Library build 2
2014-12-13 13:56:48 -05:00
hagen
ca2566e778 * reorder makefile rules : fix depends on header 2014-12-13 13:39:57 +00:00
orignal
2b093a0e3f extract issuer name 2014-12-13 08:32:41 -05:00
hagen
0e212f29d0 * update build/CMakeLists.txt 2014-12-13 13:21:24 +00:00
hagen
cd3a7040b0 * Makefile : add dist target 2014-12-13 13:21:24 +00:00
hagen
cf8e229098 * almost fixed static linking 2014-12-13 13:21:24 +00:00
hagen
05a62af99b * move USE_* to main Makefile 2014-12-13 13:21:24 +00:00
hagen
56c404e6c1 * Makefile.linux : use idents with spaces 2014-12-13 13:21:24 +00:00
hagen
5ee4969322 * Makefile.linux : reorder checks 2014-12-13 13:21:24 +00:00
hagen
8a43e070d8 * Makefile.osx : exchange options 2014-12-13 13:21:24 +00:00
hagen
aa0cb6b2c4 * (3/3) cleanup : unused variable 2014-12-13 13:21:24 +00:00
hagen
d6ec412422 * (2/3) cleanup : use $CXXFLAGS instead $NEEDED_FLAGS 2014-12-13 13:21:24 +00:00
hagen
4e94bc9efc * (1/3) cleanup : use $CXXFLAGS instead $CPU_FLAGS 2014-12-13 13:21:24 +00:00
hagen
bc0f0e96a3 * (3/3) 2nd try : drop api/ subdir 2014-12-13 13:21:24 +00:00
hagen
9552edf82d * (2/3) update main Makefile 2014-12-13 13:21:24 +00:00
hagen
8c218bd5df * (1/3) update filelist.mk : 3 lists of sources: common, daemon-specific and library-specific 2014-12-13 13:21:24 +00:00
hagen
01bb492faf * cleanup : remove 100% garbage in Makefile.osx 2014-12-13 13:21:24 +00:00
orignal
afd0a43725 read certificate file 2014-12-12 16:17:53 -05:00
orignal
366b160727 initial parsin of X.509 certificate 2014-12-12 15:45:39 -05:00
Kill Your TV
8b61aedc3f sync certificates with the java router 2014-12-12 19:43:09 +00:00
orignal
23e49e730f process SU3 files with data descriptor 2014-12-12 13:36:02 -05:00
orignal
0e935a3511 check for data descriptor flag 2014-12-12 10:34:50 -05:00
orignal
56a95fa9b5 check for RI size 2014-12-11 22:31:39 -05:00
orignal
6ac846f95d SU3 resseed first 2014-12-11 21:14:04 -05:00
orignal
9ce56eb95f handle compression method field 2014-12-11 20:44:08 -05:00
orignal
3643d2f1da reseed from SU3 2014-12-11 15:41:04 -05:00
orignal
96851ab2fd Merge branch 'master' of https://github.com/PrivacySolutions/i2pd 2014-12-11 13:29:03 -05:00
orignal
7e52f8af5e pass params to destination 2014-12-11 13:28:37 -05:00
Kill Your TV
ca3817abe3 minor tweaks to the README 2014-12-11 18:05:21 +00:00
orignal
aaf9a70153 pass RSA public key in constructor 2014-12-11 12:33:32 -05:00
orignal
0ee7f02f51 extend temporary buffer size to 1024 2014-12-11 12:22:22 -05:00
orignal
18d9325800 fixed tabs 2014-12-11 08:07:45 -05:00
orignal
bec638914a reaturned api folder back 2014-12-11 08:02:35 -05:00
orignal
67c4c237a9 Merge pull request #116 from hagen-i2p/library-build
update buildsystem (cleanup and library build for cmake)
2014-12-11 07:32:25 -05:00
orignal
6c98c80268 Merge pull request #115 from hagen-i2p/conf-option
* README.md : add -conf option
2014-12-11 07:29:39 -05:00
hagen
342c87e15b * fix cmake build 2014-12-11 07:57:46 +00:00
hagen
5966113268 * build library in the same tree as main binary 2014-12-11 07:48:08 +00:00
hagen
a6ff3df591 * README.md : add -conf option 2014-12-11 04:59:22 +00:00
orignal
9438f388ad copy private signing key of proper size 2014-12-10 22:38:01 -05:00
orignal
0b3ee77717 RSA signatures 2014-12-10 21:31:06 -05:00
orignal
7ccb7f05bf added RSA verifier 2014-12-10 15:48:07 -05:00
orignal
5b53665f4f rolled back 2014-12-10 12:10:07 -05:00
orignal
b66aa7408e use Inflator instead Gunzip 2014-12-10 12:07:25 -05:00
orignal
5dbee6b300 fixed fields length 2014-12-10 10:06:37 -05:00
orignal
a0893eabfa fixed build error 2014-12-10 07:28:49 -05:00
orignal
c8e34052a7 some cleanup 2014-12-09 21:07:54 -05:00
orignal
a2d69a8b66 fixed build error 2014-12-09 17:21:19 -05:00
orignal
fd7fca1d54 process SU3 header 2014-12-09 16:44:58 -05:00
orignal
47589125e0 look for LeaseSet in local database 2014-12-09 14:59:19 -05:00
orignal
02256be720 fxied build error for VS 2014-12-09 14:15:02 -05:00
orignal
b9b224fdc3 fixed crash 2014-12-08 21:28:11 -05:00
orignal
cb06f8e0bb enale tunnl test encryption back 2014-12-08 19:33:50 -05:00
orignal
bb05bcf39f pass instance of std::ostream for logging from API 2014-12-08 16:27:10 -05:00
orignal
b7d1b74ffa add single tag from destination's tread 2014-12-08 15:36:00 -05:00
orignal
d1cca92459 fixed typo 2014-12-08 11:45:13 -05:00
orignal
1d497cf8d6 BOB 'clear' command 2014-12-07 21:06:04 -05:00
orignal
efa771310d Merge branch 'master' of https://github.com/PrivacySolutions/i2pd 2014-12-07 21:04:27 -05:00
orignal
8f12881162 BOB 'clear' command 2014-12-07 21:04:02 -05:00
orignal
85624e4f4b verify tag count field 2014-12-07 21:00:19 -05:00
orignal
5bbe661392 Update README.md
-bobport added
2014-12-07 17:29:09 -05:00
orignal
5e31d6b2bd proper response to 'setkeys' 2014-12-07 17:19:56 -05:00
orignal
06621a2198 don't publish to non-responding floodfill twice 2014-12-07 16:10:25 -05:00
orignal
4d77dad9cc Merge pull request #113 from arabesc/master
Fix build under FreeBSD 10.1 + Clang
2014-12-07 13:09:05 -05:00
orignal
e89938e9df fixed crash at startup 2014-12-07 12:54:35 -05:00
Igor Pavlov
1568128356 change asm labels to temporarily labels to fix clang compilation 2014-12-07 19:37:52 +03:00
Igor Pavlov
d13329471e add SSUSession.cpp to CMakeList.txt 2014-12-07 19:34:42 +03:00
orignal
9dbd5a583a AddressReceiver for inbound BOB tunnel 2014-12-07 09:48:03 -05:00
orignal
07ad7fea9e inbound and outbound BOB tunnels per destination 2014-12-06 21:23:43 -05:00
orignal
fbff749838 pass BOB options to destination 2014-12-06 16:06:46 -05:00
orignal
797c8750d8 pass BOB options to destination 2014-12-06 15:31:39 -05:00
orignal
9164ac8a3e BOB 'list' command 2014-12-05 22:25:31 -05:00
orignal
8788e1b2fd BOB 'clear' command 2014-12-05 19:16:54 -05:00
orignal
9a9d6e8e00 BOB lookup command 2014-12-05 16:03:43 -05:00
orignal
047a371050 send base64 adress from outbound non-quiet BOB connections 2014-12-05 14:46:59 -05:00
orignal
392075bf60 BOB quiet command 2014-12-05 14:13:16 -05:00
orignal
07d5e8c756 don't close session if unknown command 2014-12-05 10:59:37 -05:00
orignal
e84d4e5f42 populate session keys 2014-12-04 19:29:20 -05:00
orignal
4c8d85870b check identity buffer size 2014-12-04 19:28:20 -05:00
orignal
519330015f handle .i2p address for BOB inbound connections 2014-12-04 14:16:33 -05:00
orignal
08762870b4 fixed crash on termination 2014-12-04 11:24:00 -05:00
orignal
517a7ba3ab BOB setkeys/getkeys 2014-12-03 21:01:40 -05:00
orignal
3d0349191d fixed memory corruption 2014-12-03 21:00:25 -05:00
orignal
76478ceaa2 send recived data after address from BOB inbound connection 2014-12-03 20:37:20 -05:00
orignal
9328bd1caf temporary disabled tunnel test encryption due instability 2014-12-03 20:06:56 -05:00
orignal
b2a6b6657f handle stop command 2014-12-03 15:24:30 -05:00
orignal
0214ad69a6 inbound tunnels 2014-12-03 15:02:19 -05:00
orignal
1c0c530769 BOB inbound tunnel 2014-12-03 14:48:41 -05:00
orignal
75666e3e39 return public key only for newkeys 2014-12-02 21:55:30 -05:00
orignal
60e4e52373 BOB outgoing tunnels 2014-12-02 21:45:01 -05:00
orignal
30a1f9d447 send BOB message reply 2014-12-02 16:45:51 -05:00
orignal
cb293b93d2 BOB command parser 2014-12-02 15:47:44 -05:00
orignal
3ab65bbe0d command channel acceptor 2014-12-02 11:42:35 -05:00
orignal
e7f05cc462 BOB added 2014-12-02 10:34:02 -05:00
orignal
cfcec8229c delete non-responding streams 2014-12-02 08:07:31 -05:00
orignal
4e54fbec08 delete stream from inside 2014-12-01 21:26:51 -05:00
orignal
38ee813e41 wait for all messages acked before termination of a stream 2014-12-01 18:29:46 -05:00
orignal
9acf80e563 from/to base64 2014-12-01 14:50:10 -05:00
orignal
9539fb8cb0 fixed memory leak 2014-11-30 20:18:31 -05:00
orignal
bd13406f42 don't delete HTTP connection twice 2014-11-30 18:19:32 -05:00
orignal
fbec753dcd show local destination's tuunels state 2014-11-30 17:29:26 -05:00
orignal
e6c92a535d handle ipv6 sessions in separate thread 2014-11-30 17:19:21 -05:00
orignal
32a767dc91 pass I2CP options to local destination. Process tunnel length 2014-11-30 10:51:22 -05:00
orignal
3ca560b895 different tunnel length for IB and OB 2014-11-29 22:00:52 -05:00
orignal
5e83d950f5 count NACKs in plain ack message size 2014-11-29 19:15:41 -05:00
orignal
95027930f2 send NACKs 2014-11-29 16:21:19 -05:00
orignal
3ff1158384 fixed crash 2014-11-29 08:31:12 -05:00
orignal
404f21ea76 fixed API build error 2014-11-28 16:46:26 -05:00
orignal
49173da84d encypt tunnel test messages 2014-11-28 16:19:56 -05:00
orignal
d794dfb7e5 moved private keys creation to client context 2014-11-28 16:04:57 -05:00
orignal
8350f16b20 store SAM destinations if address book 2014-11-28 15:08:23 -05:00
orignal
e1c25fedb0 wait for confirmantion of publishing 2014-11-28 13:01:35 -05:00
orignal
3e3cfa3d68 load from addressbook first 2014-11-28 09:40:27 -05:00
orignal
092b445e36 store addresses in csv format 2014-11-27 16:26:55 -05:00
orignal
b9806ac86b fixed crash 2014-11-26 21:59:07 -05:00
orignal
a8c08563f1 alignment 2014-11-26 21:42:14 -05:00
orignal
eb6b04d6c2 send packets of a longer message at the that time 2014-11-26 19:25:12 -05:00
orignal
68c321609d naming lookup through addressbook 2014-11-26 16:51:36 -05:00
orignal
fae01f61d2 filesytem-based addressbook 2014-11-26 16:19:36 -05:00
orignal
aca87b5fd1 remember last outgoing tunnel per stream rather than per client destination 2014-11-26 13:20:35 -05:00
orignal
77687a70a2 adjust message length after alignment 2014-11-26 11:54:35 -05:00
orignal
357a9a6a56 16 bytes alignmen of AES block 2014-11-26 11:04:49 -05:00
orignal
f7d90648e3 drop verifier not used anymore 2014-11-26 10:28:06 -05:00
orignal
6153d799bc use shared pointer for NTCPSession 2014-11-25 16:30:15 -05:00
orignal
f15508aff5 Merge branch 'master' of https://github.com/orignal/i2pd 2014-11-25 15:16:35 -05:00
orignal
0ccb66476e moved NTCP client code to Transports 2014-11-25 15:16:03 -05:00
orignal
6c13ad78a5 eliminated NTCPServerConnection 2014-11-25 14:29:06 -05:00
orignal
8fde36a4b0 Update version.h
version 0.4.0
2014-11-25 12:46:30 -05:00
orignal
de14f8dcd7 handle Phase3 in two steps 2014-11-25 12:33:51 -05:00
orignal
1e81652a62 send Phase3 with proper identity 2014-11-25 10:59:29 -05:00
orignal
f7ce86e0c4 pass tsA to SendPhase4 2014-11-25 10:35:35 -05:00
orignal
9eb5982ea3 use generic receive buffer for phase 4 2014-11-25 10:14:18 -05:00
orignal
4778c8bdfb fixed excess data for P521 2014-11-24 21:48:01 -05:00
orignal
9574163aeb fixed incorrect certificate length 2014-11-24 21:23:12 -05:00
orignal
199ff0c210 ECDSA P384 and ECDSA P521 support 2014-11-24 20:19:13 -05:00
orignal
e0635548e9 handle EcDSA signatures 2014-11-24 15:26:57 -05:00
orignal
95524c8db3 shared pointer for SSU 2014-11-24 12:26:11 -05:00
orignal
1a0957b571 move WaitForConnect away from constructor 2014-11-24 11:18:12 -05:00
orignal
97656e7349 shared pointer for I2PTunnelConnection 2014-11-23 22:23:17 -05:00
orignal
0262a8b057 replaced boost::bind to std::bind 2014-11-23 17:00:45 -05:00
orignal
4bd8b44ab2 shared pointers for streams 2014-11-23 11:33:58 -05:00
orignal
4dc33a6f45 fixed crash 2014-11-22 21:56:59 -05:00
Mikal Villa
335de27095 Merge branch 'master' of github.com:PrivacySolutions/i2pd
* 'master' of github.com:PrivacySolutions/i2pd:
  shared pointers for SAM sockets
2014-11-22 23:12:34 +01:00
Mikal Villa
fa461b1254 Added prefix support, which enables the homebrew package to work. 2014-11-22 23:12:05 +01:00
orignal
81c63b0c30 shared pointers for SAM sockets 2014-11-22 16:35:58 -05:00
orignal
dcefe7d221 fixed typo 2014-11-21 13:49:49 -05:00
orignal
ed3aaefe96 delete delete routers from memory 2014-11-21 13:29:19 -05:00
orignal
6042aefd17 delete dead floodfill 2014-11-21 13:02:46 -05:00
orignal
1c3f70056a use shared pointer of RI for transports 2014-11-21 12:34:17 -05:00
orignal
d8b9968aed use shared pointer for RI in requested destination 2014-11-21 11:37:17 -05:00
orignal
8a357ac46c store shared pointer to RI in tunnel config 2014-11-21 10:46:11 -05:00
Mikal
5187701af1 Updated NSI file
Forgot to update version in NSI installer script
2014-11-21 00:28:21 -08:00
79 changed files with 3568 additions and 1238 deletions

View File

@@ -1,23 +1,168 @@
#include <string.h> #include <string.h>
#include <inttypes.h>
#include <string> #include <string>
#include <map> #include <map>
#include <fstream>
#include <boost/filesystem.hpp>
#include "base64.h" #include "base64.h"
#include "util.h" #include "util.h"
#include "Identity.h" #include "Identity.h"
#include "Log.h" #include "Log.h"
#include "AddressBook.h" #include "AddressBook.h"
#include <boost/algorithm/string.hpp>
namespace i2p namespace i2p
{ {
namespace client namespace client
{ {
class AddressBookFilesystemStorage: public AddressBookStorage
{
public:
AddressBookFilesystemStorage ();
bool GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const;
void AddAddress (const i2p::data::IdentityEx& address);
void RemoveAddress (const i2p::data::IdentHash& ident);
int Load (std::map<std::string, i2p::data::IdentHash>& addresses);
int Save (const std::map<std::string, i2p::data::IdentHash>& addresses);
private:
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / "addressbook"; };
};
AddressBookFilesystemStorage::AddressBookFilesystemStorage ()
{
auto path = GetPath ();
if (!boost::filesystem::exists (path))
{
// Create directory is necessary
if (!boost::filesystem::create_directory (path))
LogPrint (eLogError, "Failed to create addressbook directory");
}
}
bool AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const
{
auto filename = GetPath () / (ident.ToBase32() + ".b32");
std::ifstream f(filename.c_str (), std::ifstream::binary);
if (f.is_open ())
{
f.seekg (0,std::ios::end);
size_t len = f.tellg ();
if (len < i2p::data::DEFAULT_IDENTITY_SIZE)
{
LogPrint (eLogError, "File ", filename, " is too short. ", len);
return false;
}
f.seekg(0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
f.read((char *)buf, len);
address.FromBuffer (buf, len);
delete[] buf;
return true;
}
else
return false;
}
void AddressBookFilesystemStorage::AddAddress (const i2p::data::IdentityEx& address)
{
auto filename = GetPath () / (address.GetIdentHash ().ToBase32() + ".b32");
std::ofstream f (filename.c_str (), std::ofstream::binary | std::ofstream::out);
if (f.is_open ())
{
size_t len = address.GetFullLen ();
uint8_t * buf = new uint8_t[len];
address.ToBuffer (buf, len);
f.write ((char *)buf, len);
delete[] buf;
}
else
LogPrint (eLogError, "Can't open file ", filename);
}
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
{
auto filename = GetPath () / (ident.ToBase32() + ".b32");
if (boost::filesystem::exists (filename))
boost::filesystem::remove (filename);
}
int AddressBookFilesystemStorage::Load (std::map<std::string, i2p::data::IdentHash>& addresses)
{
int num = 0;
auto filename = GetPath () / "addresses.csv";
std::ifstream f (filename.c_str (), std::ofstream::in); // in text mode
if (f.is_open ())
{
addresses.clear ();
while (!f.eof ())
{
std::string s;
getline(f, s);
if (!s.length())
continue; // skip empty line
size_t pos = s.find(',');
if (pos != std::string::npos)
{
std::string name = s.substr(0, pos++);
std::string addr = s.substr(pos);
i2p::data::IdentHash ident;
ident.FromBase32 (addr);
addresses[name] = ident;
num++;
}
}
LogPrint (eLogInfo, num, " addresses loaded");
}
else
LogPrint (eLogWarning, filename, " not found");
return num;
}
int AddressBookFilesystemStorage::Save (const std::map<std::string, i2p::data::IdentHash>& addresses)
{
int num = 0;
auto filename = GetPath () / "addresses.csv";
std::ofstream f (filename.c_str (), std::ofstream::out); // in text mode
if (f.is_open ())
{
for (auto it: addresses)
{
f << it.first << "," << it.second.ToBase32 () << std::endl;
num++;
}
LogPrint (eLogInfo, num, " addresses save");
}
else
LogPrint (eLogError, "Can't open file ", filename);
return num;
}
//---------------------------------------------------------------------
AddressBook::AddressBook (): m_IsLoaded (false), m_IsDowloading (false) AddressBook::AddressBook (): m_IsLoaded (false), m_IsDowloading (false)
{ {
} }
AddressBook::~AddressBook ()
{
if (m_Storage)
{
m_Storage->Save (m_Addresses);
delete m_Storage;
}
}
AddressBookStorage * AddressBook::CreateStorage ()
{
return new AddressBookFilesystemStorage ();
}
bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident) bool AddressBook::GetIdentHash (const std::string& address, i2p::data::IdentHash& ident)
{ {
auto pos = address.find(".b32.i2p"); auto pos = address.find(".b32.i2p");
@@ -37,9 +182,16 @@ namespace client
ident = *identHash; ident = *identHash;
return true; return true;
} }
else
return false;
} }
} }
return false; // if not .b32 we assume full base64 address
i2p::data::IdentityEx dest;
if (!dest.FromBase64 (address))
return false;
ident = dest.GetIdentHash ();
return true;
} }
const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address) const i2p::data::IdentHash * AddressBook::FindAddress (const std::string& address)
@@ -59,10 +211,29 @@ namespace client
{ {
i2p::data::IdentityEx ident; i2p::data::IdentityEx ident;
ident.FromBase64 (base64); ident.FromBase64 (base64);
if (!m_Storage)
m_Storage = CreateStorage ();
m_Storage->AddAddress (ident);
m_Addresses[address] = ident.GetIdentHash (); m_Addresses[address] = ident.GetIdentHash ();
LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added"); LogPrint (address,"->",ident.GetIdentHash ().ToBase32 (), ".b32.i2p added");
} }
void AddressBook::InsertAddress (const i2p::data::IdentityEx& address)
{
if (!m_Storage)
m_Storage = CreateStorage ();
m_Storage->AddAddress (address);
}
bool AddressBook::GetAddress (const std::string& address, i2p::data::IdentityEx& identity)
{
if (!m_Storage)
m_Storage = CreateStorage ();
i2p::data::IdentHash ident;
if (!GetIdentHash (address, ident)) return false;
return m_Storage->GetAddress (ident, identity);
}
void AddressBook::LoadHostsFromI2P () void AddressBook::LoadHostsFromI2P ()
{ {
std::string content; std::string content;
@@ -88,6 +259,16 @@ namespace client
void AddressBook::LoadHosts () void AddressBook::LoadHosts ()
{ {
if (!m_Storage)
m_Storage = CreateStorage ();
int numAddresses = m_Storage->Load (m_Addresses);
if (numAddresses > 0)
{
m_IsLoaded = true;
return;
}
// otherwise try hosts.txt
std::ifstream f (i2p::util::filesystem::GetFullPath ("hosts.txt").c_str (), std::ofstream::in); // in text mode std::ifstream f (i2p::util::filesystem::GetFullPath ("hosts.txt").c_str (), std::ofstream::in); // in text mode
if (!f.is_open ()) if (!f.is_open ())
{ {
@@ -100,10 +281,8 @@ namespace client
} }
return; return;
} }
int numAddresses = 0;
std::string s; std::string s;
while (!f.eof ()) while (!f.eof ())
{ {
getline(f, s); getline(f, s);
@@ -121,10 +300,12 @@ namespace client
i2p::data::IdentityEx ident; i2p::data::IdentityEx ident;
ident.FromBase64(addr); ident.FromBase64(addr);
m_Addresses[name] = ident.GetIdentHash (); m_Addresses[name] = ident.GetIdentHash ();
m_Storage->AddAddress (ident);
numAddresses++; numAddresses++;
} }
} }
LogPrint (numAddresses, " addresses loaded"); LogPrint (numAddresses, " addresses loaded");
m_Storage->Save (m_Addresses);
m_IsLoaded = true; m_IsLoaded = true;
} }

View File

@@ -13,21 +13,42 @@ namespace i2p
{ {
namespace client namespace client
{ {
class AddressBookStorage // interface for storage
{
public:
virtual ~AddressBookStorage () {};
virtual bool GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const = 0;
virtual void AddAddress (const i2p::data::IdentityEx& address) = 0;
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
virtual int Save (const std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
};
class AddressBook class AddressBook
{ {
public: public:
AddressBook (); AddressBook ();
~AddressBook ();
bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident); bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident);
bool GetAddress (const std::string& address, i2p::data::IdentityEx& identity);
const i2p::data::IdentHash * FindAddress (const std::string& address); const i2p::data::IdentHash * FindAddress (const std::string& address);
void InsertAddress (const std::string& address, const std::string& base64); // for jump service void InsertAddress (const std::string& address, const std::string& base64); // for jump service
void InsertAddress (const i2p::data::IdentityEx& address);
private: private:
AddressBookStorage * CreateStorage ();
private:
void LoadHosts (); void LoadHosts ();
void LoadHostsFromI2P (); void LoadHostsFromI2P ();
std::map<std::string, i2p::data::IdentHash> m_Addresses; std::map<std::string, i2p::data::IdentHash> m_Addresses;
AddressBookStorage * m_Storage;
bool m_IsLoaded, m_IsDowloading; bool m_IsLoaded, m_IsDowloading;
}; };
} }

656
BOB.cpp Normal file
View File

@@ -0,0 +1,656 @@
#include <string.h>
#include <boost/lexical_cast.hpp>
#include "Log.h"
#include "NetDb.h"
#include "ClientContext.h"
#include "BOB.h"
namespace i2p
{
namespace client
{
BOBI2PInboundTunnel::BOBI2PInboundTunnel (boost::asio::io_service& service, int port, ClientDestination * localDestination):
BOBI2PTunnel (service, localDestination),
m_Acceptor (service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)),
m_Timer (service)
{
}
BOBI2PInboundTunnel::~BOBI2PInboundTunnel ()
{
Stop ();
}
void BOBI2PInboundTunnel::Start ()
{
m_Acceptor.listen ();
Accept ();
}
void BOBI2PInboundTunnel::Stop ()
{
m_Acceptor.close();
ClearConnections ();
}
void BOBI2PInboundTunnel::Accept ()
{
auto receiver = new AddressReceiver ();
receiver->socket = new boost::asio::ip::tcp::socket (GetService ());
m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this,
std::placeholders::_1, receiver));
}
void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, AddressReceiver * receiver)
{
if (!ecode)
{
Accept ();
ReceiveAddress (receiver);
}
else
{
delete receiver->socket;
delete receiver;
}
}
void BOBI2PInboundTunnel::ReceiveAddress (AddressReceiver * receiver)
{
receiver->socket->async_read_some (boost::asio::buffer(
receiver->buffer + receiver->bufferOffset,
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
std::placeholders::_1, std::placeholders::_2, receiver));
}
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
AddressReceiver * receiver)
{
if (ecode)
{
LogPrint ("BOB inbound tunnel read error: ", ecode.message ());
delete receiver->socket;
delete receiver;
}
else
{
receiver->bufferOffset += bytes_transferred;
receiver->buffer[receiver->bufferOffset] = 0;
char * eol = strchr (receiver->buffer, '\n');
if (eol)
{
*eol = 0;
receiver->data = (uint8_t *)eol + 1;
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
i2p::data::IdentHash ident;
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
{
LogPrint (eLogError, "BOB address ", receiver->buffer, " not found");
delete receiver->socket;
delete receiver;
return;
}
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
if (leaseSet)
CreateConnection (receiver, leaseSet);
else
{
i2p::data::netdb.RequestDestination (ident, true, GetLocalDestination ()->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT));
m_Timer.async_wait (std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestTimer,
this, std::placeholders::_1, receiver, ident));
}
}
else
{
if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE)
ReceiveAddress (receiver);
else
{
LogPrint ("BOB missing inbound address ");
delete receiver->socket;
delete receiver;
}
}
}
}
void BOBI2PInboundTunnel::HandleDestinationRequestTimer (const boost::system::error_code& ecode, AddressReceiver * receiver, i2p::data::IdentHash ident)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
if (leaseSet)
{
CreateConnection (receiver, leaseSet);
return;
}
else
LogPrint ("LeaseSet for BOB inbound destination not found");
}
delete receiver->socket;
delete receiver;
}
void BOBI2PInboundTunnel::CreateConnection (AddressReceiver * receiver, const i2p::data::LeaseSet * leaseSet)
{
LogPrint ("New BOB inbound connection");
auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet);
AddConnection (connection);
connection->I2PConnect (receiver->data, receiver->dataLen);
delete receiver;
}
BOBI2POutboundTunnel::BOBI2POutboundTunnel (boost::asio::io_service& service, const std::string& address, int port,
ClientDestination * localDestination, bool quiet): BOBI2PTunnel (service, localDestination),
m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsQuiet (quiet)
{
}
void BOBI2POutboundTunnel::Start ()
{
Accept ();
}
void BOBI2POutboundTunnel::Stop ()
{
ClearConnections ();
}
void BOBI2POutboundTunnel::Accept ()
{
auto localDestination = GetLocalDestination ();
if (localDestination)
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
else
LogPrint ("Local destination not set for server tunnel");
}
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
{
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint, m_IsQuiet);
AddConnection (conn);
conn->Connect ();
}
}
BOBDestination::BOBDestination (boost::asio::io_service& service, ClientDestination& localDestination):
m_Service (service), m_LocalDestination (localDestination),
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr)
{
}
BOBDestination::~BOBDestination ()
{
delete m_OutboundTunnel;
delete m_InboundTunnel;
}
void BOBDestination::Start ()
{
if (m_OutboundTunnel) m_OutboundTunnel->Start ();
if (m_InboundTunnel) m_InboundTunnel->Start ();
}
void BOBDestination::Stop ()
{
StopTunnels ();
m_LocalDestination.Stop ();
}
void BOBDestination::StopTunnels ()
{
if (m_OutboundTunnel)
{
m_OutboundTunnel->Stop ();
delete m_OutboundTunnel;
m_OutboundTunnel = nullptr;
}
if (m_InboundTunnel)
{
m_InboundTunnel->Stop ();
delete m_InboundTunnel;
m_InboundTunnel = nullptr;
}
}
void BOBDestination::CreateInboundTunnel (int port)
{
if (!m_InboundTunnel)
m_InboundTunnel = new BOBI2PInboundTunnel (m_Service, port, &m_LocalDestination);
}
void BOBDestination::CreateOutboundTunnel (const std::string& address, int port, bool quiet)
{
if (!m_OutboundTunnel)
m_OutboundTunnel = new BOBI2POutboundTunnel (m_Service, address, port, &m_LocalDestination, quiet);
}
BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner):
m_Owner (owner), m_Socket (m_Owner.GetService ()), m_ReceiveBufferOffset (0),
m_IsOpen (true), m_IsQuiet (false), m_InPort (0), m_OutPort (0),
m_CurrentDestination (nullptr)
{
}
BOBCommandSession::~BOBCommandSession ()
{
}
void BOBCommandSession::Terminate ()
{
m_Socket.close ();
m_IsOpen = false;
}
void BOBCommandSession::Receive ()
{
m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, BOB_COMMAND_BUFFER_SIZE - m_ReceiveBufferOffset),
std::bind(&BOBCommandSession::HandleReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
void BOBCommandSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
LogPrint ("BOB command channel read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
size_t size = m_ReceiveBufferOffset + bytes_transferred;
m_ReceiveBuffer[size] = 0;
char * eol = strchr (m_ReceiveBuffer, '\n');
if (eol)
{
*eol = 0;
char * operand = strchr (m_ReceiveBuffer, ' ');
if (operand)
{
*operand = 0;
operand++;
}
else
operand = eol;
// process command
auto& handlers = m_Owner.GetCommandHandlers ();
auto it = handlers.find (m_ReceiveBuffer);
if (it != handlers.end ())
(this->*(it->second))(operand, eol - operand);
else
{
LogPrint (eLogError, "BOB unknown command ", m_ReceiveBuffer);
SendReplyError ("unknown command");
}
m_ReceiveBufferOffset = size - (eol - m_ReceiveBuffer) - 1;
memmove (m_ReceiveBuffer, eol + 1, m_ReceiveBufferOffset);
}
else
{
if (size < BOB_COMMAND_BUFFER_SIZE)
m_ReceiveBufferOffset = size;
else
{
LogPrint (eLogError, "Malformed input of the BOB command channel");
Terminate ();
}
}
}
}
void BOBCommandSession::Send (size_t len)
{
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SendBuffer, len),
boost::asio::transfer_all (),
std::bind(&BOBCommandSession::HandleSent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
void BOBCommandSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
{
LogPrint ("BOB command channel send error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
if (m_IsOpen)
Receive ();
else
Terminate ();
}
}
void BOBCommandSession::SendReplyOK (const char * msg)
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg);
#else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg);
#endif
Send (len);
}
void BOBCommandSession::SendReplyError (const char * msg)
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg);
#else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg);
#endif
Send (len);
}
void BOBCommandSession::SendVersion ()
{
size_t len = strlen (BOB_VERSION);
memcpy (m_SendBuffer, BOB_VERSION, len);
Send (len);
}
void BOBCommandSession::SendData (const char * nickname)
{
#ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname);
#else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname);
#endif
Send (len);
}
void BOBCommandSession::ZapCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: zap");
Terminate ();
}
void BOBCommandSession::QuitCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: quit");
m_IsOpen = false;
SendReplyOK ("Bye!");
}
void BOBCommandSession::StartCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: start ", m_Nickname);
if (!m_CurrentDestination)
{
m_CurrentDestination = new BOBDestination (m_Owner.GetService (),
*context.CreateNewLocalDestination (m_Keys, true, &m_Options));
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
}
if (m_InPort)
m_CurrentDestination->CreateInboundTunnel (m_InPort);
if (m_OutPort && !m_Address.empty ())
m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet);
m_CurrentDestination->Start ();
SendReplyOK ("tunnel starting");
}
void BOBCommandSession::StopCommandHandler (const char * operand, size_t len)
{
auto dest = m_Owner.FindDestination (m_Nickname);
if (dest)
{
dest->StopTunnels ();
SendReplyOK ("tunnel stopping");
}
else
SendReplyError ("tunnel not found");
}
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: setnick ", operand);
m_Nickname = operand;
std::string msg ("Nickname set to ");
msg += operand;
SendReplyOK (msg.c_str ());
}
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getnick ", operand);
m_CurrentDestination = m_Owner.FindDestination (operand);
if (m_CurrentDestination)
{
m_Keys = m_CurrentDestination->GetKeys ();
m_Nickname = operand;
std::string msg ("Nickname set to ");
msg += operand;
SendReplyOK (msg.c_str ());
}
else
SendReplyError ("tunnel not found");
}
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: newkeys");
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys ();
SendReplyOK (m_Keys.GetPublic ().ToBase64 ().c_str ());
}
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: setkeys ", operand);
m_Keys.FromBase64 (operand);
SendReplyOK (m_Keys.GetPublic ().ToBase64 ().c_str ());
}
void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getkeys");
SendReplyOK (m_Keys.ToBase64 ().c_str ());
}
void BOBCommandSession::GetdestCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getdest");
SendReplyOK (m_Keys.GetPublic ().ToBase64 ().c_str ());
}
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outhost ", operand);
m_Address = operand;
SendReplyOK ("outhost set");
}
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outport ", operand);
m_OutPort = boost::lexical_cast<int>(operand);
SendReplyOK ("outbound port set");
}
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inhost ", operand);
m_Address = operand;
SendReplyOK ("inhost set");
}
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inport ", operand);
m_InPort = boost::lexical_cast<int>(operand);
SendReplyOK ("inbound port set");
}
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: quiet");
m_IsQuiet = true;
SendReplyOK ("quiet");
}
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: lookup ", operand);
i2p::data::IdentityEx addr;
if (!context.GetAddressBook ().GetAddress (operand, addr))
{
SendReplyError ("Address Not found");
return;
}
SendReplyOK (addr.ToBase64 ().c_str ());
}
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: clear");
m_Owner.DeleteDestination (m_Nickname);
SendReplyOK ("cleared");
}
void BOBCommandSession::ListCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: list");
auto& destinations = m_Owner.GetDestinations ();
for (auto it: destinations)
SendData (it.first.c_str ());
SendReplyOK ("Listing done");
}
void BOBCommandSession::OptionCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: option ", operand);
const char * value = strchr (operand, '=');
if (value)
{
*(const_cast<char *>(value)) = 0;
m_Options[operand] = value + 1;
*(const_cast<char *>(value)) = '=';
SendReplyOK ("option");
}
else
SendReplyError ("malformed");
}
BOBCommandChannel::BOBCommandChannel (int port):
m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
{
// command -> handler
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
m_CommandHandlers[BOB_COMMAND_QUIT] = &BOBCommandSession::QuitCommandHandler;
m_CommandHandlers[BOB_COMMAND_START] = &BOBCommandSession::StartCommandHandler;
m_CommandHandlers[BOB_COMMAND_STOP] = &BOBCommandSession::StopCommandHandler;
m_CommandHandlers[BOB_COMMAND_SETNICK] = &BOBCommandSession::SetNickCommandHandler;
m_CommandHandlers[BOB_COMMAND_GETNICK] = &BOBCommandSession::GetNickCommandHandler;
m_CommandHandlers[BOB_COMMAND_NEWKEYS] = &BOBCommandSession::NewkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_GETKEYS] = &BOBCommandSession::GetkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_SETKEYS] = &BOBCommandSession::SetkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_GETDEST] = &BOBCommandSession::GetdestCommandHandler;
m_CommandHandlers[BOB_COMMAND_OUTHOST] = &BOBCommandSession::OuthostCommandHandler;
m_CommandHandlers[BOB_COMMAND_OUTPORT] = &BOBCommandSession::OutportCommandHandler;
m_CommandHandlers[BOB_COMMAND_INHOST] = &BOBCommandSession::InhostCommandHandler;
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler;
m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler;
m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler;
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;
}
BOBCommandChannel::~BOBCommandChannel ()
{
Stop ();
for (auto it: m_Destinations)
delete it.second;
}
void BOBCommandChannel::Start ()
{
Accept ();
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&BOBCommandChannel::Run, this));
}
void BOBCommandChannel::Stop ()
{
for (auto it: m_Destinations)
it.second->Stop ();
m_IsRunning = false;
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
}
void BOBCommandChannel::Run ()
{
while (m_IsRunning)
{
try
{
m_Service.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "BOB: ", ex.what ());
}
}
}
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
{
m_Destinations[name] = dest;
}
void BOBCommandChannel::DeleteDestination (const std::string& name)
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
{
it->second->Stop ();
delete it->second;
m_Destinations.erase (it);
}
}
BOBDestination * BOBCommandChannel::FindDestination (const std::string& name)
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
return it->second;
return nullptr;
}
void BOBCommandChannel::Accept ()
{
auto newSession = std::make_shared<BOBCommandSession> (*this);
m_Acceptor.async_accept (newSession->GetSocket (), std::bind (&BOBCommandChannel::HandleAccept, this,
std::placeholders::_1, newSession));
}
void BOBCommandChannel::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session)
{
if (ecode != boost::asio::error::operation_aborted)
Accept ();
if (!ecode)
{
LogPrint (eLogInfo, "New BOB command connection from ", session->GetSocket ().remote_endpoint ());
session->SendVersion ();
}
else
LogPrint (eLogError, "BOB accept error: ", ecode.message ());
}
}
}

238
BOB.h Normal file
View File

@@ -0,0 +1,238 @@
#ifndef BOB_H__
#define BOB_H__
#include <inttypes.h>
#include <thread>
#include <memory>
#include <map>
#include <string>
#include <boost/asio.hpp>
#include "I2PTunnel.h"
#include "Identity.h"
#include "LeaseSet.h"
namespace i2p
{
namespace client
{
const size_t BOB_COMMAND_BUFFER_SIZE = 1024;
const char BOB_COMMAND_ZAP[] = "zap";
const char BOB_COMMAND_QUIT[] = "quit";
const char BOB_COMMAND_START[] = "start";
const char BOB_COMMAND_STOP[] = "stop";
const char BOB_COMMAND_SETNICK[] = "setnick";
const char BOB_COMMAND_GETNICK[] = "getnick";
const char BOB_COMMAND_NEWKEYS[] = "newkeys";
const char BOB_COMMAND_GETKEYS[] = "getkeys";
const char BOB_COMMAND_SETKEYS[] = "setkeys";
const char BOB_COMMAND_GETDEST[] = "getdest";
const char BOB_COMMAND_OUTHOST[] = "outhost";
const char BOB_COMMAND_OUTPORT[] = "outport";
const char BOB_COMMAND_INHOST[] = "inhost";
const char BOB_COMMAND_INPORT[] = "inport";
const char BOB_COMMAND_QUIET[] = "quiet";
const char BOB_COMMAND_LOOKUP[] = "lookup";
const char BOB_COMMAND_CLEAR[] = "clear";
const char BOB_COMMAND_LIST[] = "list";
const char BOB_COMMAND_OPTION[] = "option";
const char BOB_VERSION[] = "BOB 00.00.10\nOK\n";
const char BOB_REPLY_OK[] = "OK %s\n";
const char BOB_REPLY_ERROR[] = "ERROR %s\n";
const char BOB_DATA[] = "NICKNAME %s\n";
class BOBI2PTunnel: public I2PTunnel
{
public:
BOBI2PTunnel (boost::asio::io_service& service, ClientDestination * localDestination):
I2PTunnel (service, localDestination) {};
virtual void Start () {};
virtual void Stop () {};
};
class BOBI2PInboundTunnel: public BOBI2PTunnel
{
struct AddressReceiver
{
boost::asio::ip::tcp::socket * socket;
char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address
uint8_t * data;
size_t dataLen, bufferOffset;
AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {};
};
public:
BOBI2PInboundTunnel (boost::asio::io_service& service, int port, ClientDestination * localDestination);
~BOBI2PInboundTunnel ();
void Start ();
void Stop ();
private:
void Accept ();
void HandleAccept (const boost::system::error_code& ecode, AddressReceiver * receiver);
void ReceiveAddress (AddressReceiver * receiver);
void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
AddressReceiver * receiver);
void HandleDestinationRequestTimer (const boost::system::error_code& ecode, AddressReceiver * receiver, i2p::data::IdentHash ident);
void CreateConnection (AddressReceiver * receiver, const i2p::data::LeaseSet * leaseSet);
private:
boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::deadline_timer m_Timer;
};
class BOBI2POutboundTunnel: public BOBI2PTunnel
{
public:
BOBI2POutboundTunnel (boost::asio::io_service& service, const std::string& address, int port,
ClientDestination * localDestination, bool quiet);
void Start ();
void Stop ();
void SetQuiet () { m_IsQuiet = true; };
private:
void Accept ();
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
private:
boost::asio::ip::tcp::endpoint m_Endpoint;
bool m_IsQuiet;
};
class BOBDestination
{
public:
BOBDestination (boost::asio::io_service& service, ClientDestination& localDestination);
~BOBDestination ();
void Start ();
void Stop ();
void StopTunnels ();
void CreateInboundTunnel (int port);
void CreateOutboundTunnel (const std::string& address, int port, bool quiet);
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination.GetPrivateKeys (); };
private:
boost::asio::io_service& m_Service;
ClientDestination& m_LocalDestination;
BOBI2POutboundTunnel * m_OutboundTunnel;
BOBI2PInboundTunnel * m_InboundTunnel;
};
class BOBCommandChannel;
class BOBCommandSession: public std::enable_shared_from_this<BOBCommandSession>
{
public:
BOBCommandSession (BOBCommandChannel& owner);
~BOBCommandSession ();
void Terminate ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
void SendVersion ();
// command handlers
void ZapCommandHandler (const char * operand, size_t len);
void QuitCommandHandler (const char * operand, size_t len);
void StartCommandHandler (const char * operand, size_t len);
void StopCommandHandler (const char * operand, size_t len);
void SetNickCommandHandler (const char * operand, size_t len);
void GetNickCommandHandler (const char * operand, size_t len);
void NewkeysCommandHandler (const char * operand, size_t len);
void SetkeysCommandHandler (const char * operand, size_t len);
void GetkeysCommandHandler (const char * operand, size_t len);
void GetdestCommandHandler (const char * operand, size_t len);
void OuthostCommandHandler (const char * operand, size_t len);
void OutportCommandHandler (const char * operand, size_t len);
void InhostCommandHandler (const char * operand, size_t len);
void InportCommandHandler (const char * operand, size_t len);
void QuietCommandHandler (const char * operand, size_t len);
void LookupCommandHandler (const char * operand, size_t len);
void ClearCommandHandler (const char * operand, size_t len);
void ListCommandHandler (const char * operand, size_t len);
void OptionCommandHandler (const char * operand, size_t len);
private:
void Receive ();
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void Send (size_t len);
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void SendReplyOK (const char * msg);
void SendReplyError (const char * msg);
void SendData (const char * nickname);
private:
BOBCommandChannel& m_Owner;
boost::asio::ip::tcp::socket m_Socket;
char m_ReceiveBuffer[BOB_COMMAND_BUFFER_SIZE + 1], m_SendBuffer[BOB_COMMAND_BUFFER_SIZE + 1];
size_t m_ReceiveBufferOffset;
bool m_IsOpen, m_IsQuiet;
std::string m_Nickname, m_Address;
int m_InPort, m_OutPort;
i2p::data::PrivateKeys m_Keys;
std::map<std::string, std::string> m_Options;
BOBDestination * m_CurrentDestination;
};
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
class BOBCommandChannel
{
public:
BOBCommandChannel (int port);
~BOBCommandChannel ();
void Start ();
void Stop ();
boost::asio::io_service& GetService () { return m_Service; };
void AddDestination (const std::string& name, BOBDestination * dest);
void DeleteDestination (const std::string& name);
BOBDestination * FindDestination (const std::string& name);
private:
void Run ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session);
private:
bool m_IsRunning;
std::thread * m_Thread;
boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor;
std::map<std::string, BOBDestination *> m_Destinations;
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
public:
const decltype(m_CommandHandlers)& GetCommandHandlers () const { return m_CommandHandlers; };
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
};
}
}
#endif

View File

@@ -1,5 +1,7 @@
#include <fstream>
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
#include "Identity.h"
#include "ClientContext.h" #include "ClientContext.h"
namespace i2p namespace i2p
@@ -10,7 +12,7 @@ namespace client
ClientContext::ClientContext (): m_SharedLocalDestination (nullptr), ClientContext::ClientContext (): m_SharedLocalDestination (nullptr),
m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_IrcTunnel (nullptr), m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_IrcTunnel (nullptr),
m_ServerTunnel (nullptr), m_SamBridge (nullptr) m_ServerTunnel (nullptr), m_SamBridge (nullptr), m_BOBCommandChannel (nullptr)
{ {
} }
@@ -21,13 +23,14 @@ namespace client
delete m_IrcTunnel; delete m_IrcTunnel;
delete m_ServerTunnel; delete m_ServerTunnel;
delete m_SamBridge; delete m_SamBridge;
delete m_BOBCommandChannel;
} }
void ClientContext::Start () void ClientContext::Start ()
{ {
if (!m_SharedLocalDestination) if (!m_SharedLocalDestination)
{ {
m_SharedLocalDestination = new ClientDestination (false, i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); // non-public, DSA m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination; m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination;
m_SharedLocalDestination->Start (); m_SharedLocalDestination->Start ();
} }
@@ -44,7 +47,7 @@ namespace client
ClientDestination * localDestination = nullptr; ClientDestination * localDestination = nullptr;
std::string ircKeys = i2p::util::config::GetArg("-irckeys", ""); std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
if (ircKeys.length () > 0) if (ircKeys.length () > 0)
localDestination = i2p::client::context.LoadLocalDestination (ircKeys, false); localDestination = LoadLocalDestination (ircKeys, false);
m_IrcTunnel = new I2PClientTunnel (m_SocksProxy->GetService (), ircDestination, m_IrcTunnel = new I2PClientTunnel (m_SocksProxy->GetService (), ircDestination,
i2p::util::config::GetArg("-ircport", 6668), localDestination); i2p::util::config::GetArg("-ircport", 6668), localDestination);
m_IrcTunnel->Start (); m_IrcTunnel->Start ();
@@ -53,7 +56,7 @@ namespace client
std::string eepKeys = i2p::util::config::GetArg("-eepkeys", ""); std::string eepKeys = i2p::util::config::GetArg("-eepkeys", "");
if (eepKeys.length () > 0) // eepkeys file is presented if (eepKeys.length () > 0) // eepkeys file is presented
{ {
auto localDestination = i2p::client::context.LoadLocalDestination (eepKeys, true); auto localDestination = LoadLocalDestination (eepKeys, true);
m_ServerTunnel = new I2PServerTunnel (m_SocksProxy->GetService (), m_ServerTunnel = new I2PServerTunnel (m_SocksProxy->GetService (),
i2p::util::config::GetArg("-eephost", "127.0.0.1"), i2p::util::config::GetArg("-eepport", 80), i2p::util::config::GetArg("-eephost", "127.0.0.1"), i2p::util::config::GetArg("-eepport", 80),
localDestination); localDestination);
@@ -67,6 +70,13 @@ namespace client
m_SamBridge->Start (); m_SamBridge->Start ();
LogPrint("SAM bridge started"); LogPrint("SAM bridge started");
} }
int bobPort = i2p::util::config::GetArg("-bobport", 0);
if (bobPort)
{
m_BOBCommandChannel = new BOBCommandChannel (bobPort);
m_BOBCommandChannel->Start ();
LogPrint("BOB command channel started");
}
} }
void ClientContext::Stop () void ClientContext::Stop ()
@@ -100,7 +110,14 @@ namespace client
m_SamBridge = nullptr; m_SamBridge = nullptr;
LogPrint("SAM brdige stoped"); LogPrint("SAM brdige stoped");
} }
if (m_BOBCommandChannel)
{
m_BOBCommandChannel->Stop ();
delete m_BOBCommandChannel;
m_BOBCommandChannel = nullptr;
LogPrint("BOB command channel stoped");
}
for (auto it: m_Destinations) for (auto it: m_Destinations)
{ {
it.second->Stop (); it.second->Stop ();
@@ -109,43 +126,49 @@ namespace client
m_Destinations.clear (); m_Destinations.clear ();
m_SharedLocalDestination = 0; // deleted through m_Destination m_SharedLocalDestination = 0; // deleted through m_Destination
} }
void ClientContext::LoadLocalDestinations ()
{
int numDestinations = 0;
boost::filesystem::path p (i2p::util::filesystem::GetDataDir());
boost::filesystem::directory_iterator end;
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
{
if (boost::filesystem::is_regular_file (*it) && it->path ().extension () == ".dat")
{
auto fullPath =
#if BOOST_VERSION > 10500
it->path().string();
#else
it->path();
#endif
auto localDestination = new ClientDestination (fullPath, true);
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
numDestinations++;
}
}
if (numDestinations > 0)
LogPrint (numDestinations, " local destinations loaded");
}
ClientDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic) ClientDestination * ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
{ {
auto localDestination = new ClientDestination (i2p::util::filesystem::GetFullPath (filename), isPublic); i2p::data::PrivateKeys keys;
std::string fullPath = i2p::util::filesystem::GetFullPath (filename);
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
if (s.is_open ())
{
s.seekg (0, std::ios::end);
size_t len = s.tellg();
s.seekg (0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
s.read ((char *)buf, len);
keys.FromBuffer (buf, len);
delete[] buf;
LogPrint ("Local address ", keys.GetPublic ().GetIdentHash ().ToBase32 (), ".b32.i2p loaded");
}
else
{
LogPrint ("Can't open file ", fullPath, " Creating new one");
keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1);
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
size_t len = keys.GetFullLen ();
uint8_t * buf = new uint8_t[len];
len = keys.ToBuffer (buf, len);
f.write ((char *)buf, len);
delete[] buf;
LogPrint ("New private keys file ", fullPath, " for ", keys.GetPublic ().GetIdentHash ().ToBase32 (), ".b32.i2p created");
}
auto localDestination = new ClientDestination (keys, isPublic);
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination; m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();
return localDestination; return localDestination;
} }
ClientDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType) ClientDestination * ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
const std::map<std::string, std::string> * params)
{ {
auto localDestination = new ClientDestination (isPublic, sigType); i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
auto localDestination = new ClientDestination (keys, isPublic, params);
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination; m_Destinations[localDestination->GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();
@@ -168,7 +191,8 @@ namespace client
} }
} }
ClientDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic) ClientDestination * ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
const std::map<std::string, std::string> * params)
{ {
auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ()); auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ());
if (it != m_Destinations.end ()) if (it != m_Destinations.end ())
@@ -181,7 +205,7 @@ namespace client
} }
return nullptr; return nullptr;
} }
auto localDestination = new ClientDestination (keys, isPublic); auto localDestination = new ClientDestination (keys, isPublic, params);
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination; m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination;
localDestination->Start (); localDestination->Start ();

View File

@@ -7,6 +7,7 @@
#include "SOCKS.h" #include "SOCKS.h"
#include "I2PTunnel.h" #include "I2PTunnel.h"
#include "SAM.h" #include "SAM.h"
#include "BOB.h"
#include "AddressBook.h" #include "AddressBook.h"
namespace i2p namespace i2p
@@ -24,17 +25,15 @@ namespace client
void Stop (); void Stop ();
ClientDestination * GetSharedLocalDestination () const { return m_SharedLocalDestination; }; 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 (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
ClientDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true); const std::map<std::string, std::string> * params = nullptr); // transient
ClientDestination * CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
const std::map<std::string, std::string> * params = nullptr);
void DeleteLocalDestination (ClientDestination * destination); void DeleteLocalDestination (ClientDestination * destination);
ClientDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const; ClientDestination * FindLocalDestination (const i2p::data::IdentHash& destination) const;
ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic); ClientDestination * LoadLocalDestination (const std::string& filename, bool isPublic);
AddressBook& GetAddressBook () { return m_AddressBook; }; AddressBook& GetAddressBook () { return m_AddressBook; };
private:
void LoadLocalDestinations ();
private: private:
@@ -49,6 +48,7 @@ namespace client
I2PClientTunnel * m_IrcTunnel; I2PClientTunnel * m_IrcTunnel;
I2PServerTunnel * m_ServerTunnel; I2PServerTunnel * m_ServerTunnel;
SAMBridge * m_SamBridge; SAMBridge * m_SamBridge;
BOBCommandChannel * m_BOBCommandChannel;
public: public:
// for HTTP // for HTTP

View File

@@ -28,7 +28,10 @@ namespace crypto
// DSA // DSA
#define dsap GetCryptoConstants ().dsap #define dsap GetCryptoConstants ().dsap
#define dsaq GetCryptoConstants ().dsaq #define dsaq GetCryptoConstants ().dsaq
#define dsag GetCryptoConstants ().dsag #define dsag GetCryptoConstants ().dsag
// RSA
const int rsae = 65537;
} }
} }

View File

@@ -36,18 +36,15 @@ namespace datagram
else else
m_Owner.Sign (buf1, len, signature); m_Owner.Sign (buf1, len, signature);
auto service = m_Owner.GetService (); m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this,
if (service) CreateDataMessage (buf, len + headerLen), remote));
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) void DatagramDestination::SendMsg (I2NPMessage * msg, const i2p::data::LeaseSet& remote)
{ {
auto outboundTunnel = m_Owner.GetTunnelPool ()->GetNextOutboundTunnel ();
auto leases = remote.GetNonExpiredLeases (); auto leases = remote.GetNonExpiredLeases ();
if (!leases.empty ()) if (!leases.empty () && outboundTunnel)
{ {
std::vector<i2p::tunnel::TunnelMessageBlock> msgs; std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
@@ -58,11 +55,14 @@ namespace datagram
leases[i].tunnelGateway, leases[i].tunnelID, leases[i].tunnelGateway, leases[i].tunnelID,
garlic garlic
}); });
m_Owner.SendTunnelDataMsgs (msgs); outboundTunnel->SendTunnelDataMsg (msgs);
} }
else else
{ {
LogPrint (eLogWarning, "Failed to send datagram. All leases expired"); if (outboundTunnel)
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
else
LogPrint (eLogWarning, "Failed to send datagram. No outbound tunnels");
DeleteI2NPMessage (msg); DeleteI2NPMessage (msg);
} }
} }

View File

@@ -1,5 +1,5 @@
#include <fstream>
#include <algorithm> #include <algorithm>
#include <boost/lexical_cast.hpp>
#include <cryptopp/dh.h> #include <cryptopp/dh.h>
#include "Log.h" #include "Log.h"
#include "util.h" #include "util.h"
@@ -10,67 +10,42 @@ namespace i2p
{ {
namespace client namespace client
{ {
ClientDestination::ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType): ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
m_IsRunning (false), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), const std::map<std::string, std::string> * params):
m_CurrentOutboundTunnel (nullptr), m_LeaseSet (nullptr), m_IsPublic (isPublic), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_DatagramDestination (nullptr) m_Keys (keys), m_LeaseSet (nullptr), m_IsPublic (isPublic), m_PublishReplyToken (0),
{ m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service)
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); {
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
if (m_IsPublic) int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created"); if (params)
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_DatagramDestination (nullptr)
{
std::ifstream s(fullPath.c_str (), std::ifstream::binary);
if (s.is_open ())
{
s.seekg (0, std::ios::end);
size_t len = s.tellg();
s.seekg (0, std::ios::beg);
uint8_t * buf = new uint8_t[len];
s.read ((char *)buf, len);
m_Keys.FromBuffer (buf, len);
delete[] buf;
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p loaded");
}
else
{ {
LogPrint ("Can't open file ", fullPath, " Creating new one"); auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1); if (it != params->end ())
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); {
size_t len = m_Keys.GetFullLen (); int len = boost::lexical_cast<int>(it->second);
uint8_t * buf = new uint8_t[len]; if (len > 0)
len = m_Keys.ToBuffer (buf, len); {
f.write ((char *)buf, len); inboundTunnelLen = len;
delete[] buf; LogPrint (eLogInfo, "Inbound tunnel length set to ", len);
}
LogPrint ("New private keys file ", fullPath, " for ", m_Keys.GetPublic ().GetIdentHash ().ToBase32 (), ".b32.i2p created"); }
it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH);
if (it != params->end ())
{
int len = boost::lexical_cast<int>(it->second);
if (len > 0)
{
outboundTunnelLen = len;
LogPrint (eLogInfo, "Outbound tunnel length set to ", len);
}
}
} }
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen);
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_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) if (m_IsPublic)
LogPrint ("Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created"); LogPrint (eLogInfo, "Local address ", GetIdentHash ().ToBase32 (), ".b32.i2p created");
m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO: m_StreamingDestination = new i2p::stream::StreamingDestination (*this); // TODO:
} }
@@ -81,23 +56,26 @@ namespace client
delete it.second; delete it.second;
if (m_Pool) if (m_Pool)
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
delete m_LeaseSet;
delete m_Work;
delete m_Service;
delete m_StreamingDestination;
delete m_DatagramDestination;
} }
void ClientDestination::Run () void ClientDestination::Run ()
{ {
if (m_Service) while (m_IsRunning)
m_Service->run (); {
try
{
m_Service.run ();
}
catch (std::exception& ex)
{
LogPrint ("Destination: ", ex.what ());
}
}
} }
void ClientDestination::Start () void ClientDestination::Start ()
{ {
m_Service = new boost::asio::io_service; m_Pool->SetLocalDestination (this);
m_Work = new boost::asio::io_service::work (*m_Service);
m_Pool->SetActive (true); m_Pool->SetActive (true);
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this)); m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
@@ -114,18 +92,18 @@ namespace client
delete d; delete d;
} }
if (m_Pool) if (m_Pool)
{
m_Pool->SetLocalDestination (nullptr);
i2p::tunnel::tunnels.StopTunnelPool (m_Pool); i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
}
m_IsRunning = false; m_IsRunning = false;
if (m_Service) m_Service.stop ();
m_Service->stop ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = 0;
} }
delete m_Work; m_Work = nullptr;
delete m_Service; m_Service = nullptr;
} }
const i2p::data::LeaseSet * ClientDestination::FindLeaseSet (const i2p::data::IdentHash& ident) const i2p::data::LeaseSet * ClientDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
@@ -175,27 +153,29 @@ namespace client
} }
} }
void ClientDestination::SendTunnelDataMsgs (const std::vector<i2p::tunnel::TunnelMessageBlock>& msgs) bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{ {
m_CurrentOutboundTunnel = m_Pool->GetNextOutboundTunnel (m_CurrentOutboundTunnel); struct
if (m_CurrentOutboundTunnel)
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
else
{ {
LogPrint ("No outbound tunnels in the pool"); uint8_t k[32], t[32];
for (auto it: msgs) } data;
DeleteI2NPMessage (it.data); memcpy (data.k, key, 32);
} memcpy (data.t, tag, 32);
m_Service.post ([this,data](void)
{
this->AddSessionKey (data.k, data.t);
});
return true;
} }
void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg) void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg)
{ {
m_Service->post (boost::bind (&ClientDestination::HandleGarlicMessage, this, msg)); m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg));
} }
void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg) void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg)
{ {
m_Service->post (boost::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg)); m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg));
} }
void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from) void ClientDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from)
@@ -223,21 +203,36 @@ namespace client
offset += 36; offset += 36;
if (msg->type == 1) // LeaseSet if (msg->type == 1) // LeaseSet
{ {
LogPrint ("Remote LeaseSet"); LogPrint (eLogDebug, "Remote LeaseSet");
auto it = m_RemoteLeaseSets.find (msg->key); auto it = m_RemoteLeaseSets.find (msg->key);
if (it != m_RemoteLeaseSets.end ()) if (it != m_RemoteLeaseSets.end ())
{ {
it->second->Update (buf + offset, len - offset); it->second->Update (buf + offset, len - offset);
LogPrint ("Remote LeaseSet updated"); LogPrint (eLogDebug, "Remote LeaseSet updated");
} }
else else
{ {
LogPrint ("New remote LeaseSet added"); LogPrint (eLogDebug, "New remote LeaseSet added");
m_RemoteLeaseSets[msg->key] = new i2p::data::LeaseSet (buf + offset, len - offset); m_RemoteLeaseSets[msg->key] = new i2p::data::LeaseSet (buf + offset, len - offset);
} }
} }
else else
LogPrint ("Unexpected client's DatabaseStore type ", msg->type, ". Dropped"); LogPrint (eLogError, "Unexpected client's DatabaseStore type ", msg->type, ". Dropped");
}
void ClientDestination::HandleDeliveryStatusMessage (I2NPMessage * msg)
{
I2NPDeliveryStatusMsg * deliveryStatus = (I2NPDeliveryStatusMsg *)msg->GetPayload ();
uint32_t msgID = be32toh (deliveryStatus->msgID);
if (msgID == m_PublishReplyToken)
{
LogPrint (eLogDebug, "Publishing confirmed");
m_ExcludedFloodfills.clear ();
m_PublishReplyToken = 0;
i2p::DeleteI2NPMessage (msg);
}
else
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
} }
void ClientDestination::SetLeaseSetUpdated () void ClientDestination::SetLeaseSetUpdated ()
@@ -245,7 +240,56 @@ namespace client
i2p::garlic::GarlicDestination::SetLeaseSetUpdated (); i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
UpdateLeaseSet (); UpdateLeaseSet ();
if (m_IsPublic) if (m_IsPublic)
i2p::data::netdb.PublishLeaseSet (m_LeaseSet, m_Pool); Publish ();
}
void ClientDestination::Publish ()
{
if (!m_LeaseSet || !m_Pool)
{
LogPrint (eLogError, "Can't publish non-existing LeaseSet");
return;
}
if (m_PublishReplyToken)
{
LogPrint (eLogInfo, "Publishing is pending");
return;
}
auto outbound = m_Pool->GetNextOutboundTunnel ();
if (!outbound)
{
LogPrint ("Can't publish LeaseSet. No outbound tunnels");
return;
}
std::set<i2p::data::IdentHash> excluded;
auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills);
if (!floodfill)
{
LogPrint ("Can't publish LeaseSet. No more floodfills found");
m_ExcludedFloodfills.clear ();
return;
}
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
m_PublishReplyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
auto msg = WrapMessage (*floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken));
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer,
this, std::placeholders::_1));
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
}
void ClientDestination::HandlePublishConfirmationTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
if (m_PublishReplyToken)
{
LogPrint (eLogWarning, "Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, "seconds. Try again");
m_PublishReplyToken = 0;
Publish ();
}
}
} }
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
@@ -274,7 +318,7 @@ namespace client
} }
} }
i2p::stream::Stream * ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port) std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::LeaseSet& remote, int port)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port); return m_StreamingDestination->CreateNewOutgoingStream (remote, port);

View File

@@ -3,6 +3,9 @@
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory>
#include <map>
#include <string>
#include "Identity.h" #include "Identity.h"
#include "TunnelPool.h" #include "TunnelPool.h"
#include "CryptoConst.h" #include "CryptoConst.h"
@@ -18,30 +21,32 @@ namespace client
const uint8_t PROTOCOL_TYPE_STREAMING = 6; const uint8_t PROTOCOL_TYPE_STREAMING = 6;
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
const uint8_t PROTOCOL_TYPE_RAW = 18; const uint8_t PROTOCOL_TYPE_RAW = 18;
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
// I2CP
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3;
const char I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH[] = "outbound.length";
const int DEFAULT_OUTBOUND_TUNNEL_LENGTH = 3;
class ClientDestination: public i2p::garlic::GarlicDestination class ClientDestination: public i2p::garlic::GarlicDestination
{ {
public: public:
ClientDestination (bool isPublic, i2p::data::SigningKeyType sigType); ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
ClientDestination (const std::string& fullPath, bool isPublic);
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic);
~ClientDestination (); ~ClientDestination ();
virtual void Start (); virtual void Start ();
virtual void Stop (); virtual void Stop ();
bool IsRunning () const { return m_IsRunning; }; bool IsRunning () const { return m_IsRunning; };
boost::asio::io_service * GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; }; i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; };
bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases (); }; bool IsReady () const { return m_LeaseSet && m_LeaseSet->HasNonExpiredLeases (); };
void ResetCurrentOutboundTunnel () { m_CurrentOutboundTunnel = nullptr; };
const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident); const i2p::data::LeaseSet * FindLeaseSet (const i2p::data::IdentHash& ident);
void SendTunnelDataMsgs (const std::vector<i2p::tunnel::TunnelMessageBlock>& msgs);
// streaming // streaming
i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; }; i2p::stream::StreamingDestination * GetStreamingDestination () const { return m_StreamingDestination; };
i2p::stream::Stream * CreateStream (const i2p::data::LeaseSet& remote, int port = 0); std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::LeaseSet& remote, int port = 0);
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
void StopAcceptingStreams (); void StopAcceptingStreams ();
bool IsAcceptingStreams () const; bool IsAcceptingStreams () const;
@@ -60,6 +65,7 @@ namespace client
void HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from); void HandleI2NPMessage (const uint8_t * buf, size_t len, i2p::tunnel::InboundTunnel * from);
// override GarlicDestination // override GarlicDestination
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
void ProcessGarlicMessage (I2NPMessage * msg); void ProcessGarlicMessage (I2NPMessage * msg);
void ProcessDeliveryStatusMessage (I2NPMessage * msg); void ProcessDeliveryStatusMessage (I2NPMessage * msg);
void SetLeaseSetUpdated (); void SetLeaseSetUpdated ();
@@ -71,26 +77,32 @@ namespace client
void Run (); void Run ();
void UpdateLeaseSet (); void UpdateLeaseSet ();
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); void Publish ();
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
void HandleDeliveryStatusMessage (I2NPMessage * msg);
private: private:
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service * m_Service; boost::asio::io_service m_Service;
boost::asio::io_service::work * m_Work; boost::asio::io_service::work m_Work;
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
std::map<i2p::data::IdentHash, i2p::data::LeaseSet *> m_RemoteLeaseSets; std::map<i2p::data::IdentHash, i2p::data::LeaseSet *> m_RemoteLeaseSets;
i2p::tunnel::TunnelPool * m_Pool; i2p::tunnel::TunnelPool * m_Pool;
i2p::tunnel::OutboundTunnel * m_CurrentOutboundTunnel;
i2p::data::LeaseSet * m_LeaseSet; i2p::data::LeaseSet * m_LeaseSet;
bool m_IsPublic; bool m_IsPublic;
uint32_t m_PublishReplyToken;
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
i2p::stream::StreamingDestination * m_StreamingDestination; i2p::stream::StreamingDestination * m_StreamingDestination;
i2p::datagram::DatagramDestination * m_DatagramDestination; i2p::datagram::DatagramDestination * m_DatagramDestination;
boost::asio::deadline_timer m_PublishConfirmationTimer;
public: public:
// for HTTP only // for HTTP only

View File

@@ -83,6 +83,7 @@ namespace garlic
I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg) I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg)
{ {
I2NPMessage * m = NewI2NPMessage (); I2NPMessage * m = NewI2NPMessage ();
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
size_t len = 0; size_t len = 0;
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
@@ -278,7 +279,7 @@ namespace garlic
uint8_t key[32], tag[32]; uint8_t key[32], tag[32];
m_Rnd.GenerateBlock (key, 32); // random session key m_Rnd.GenerateBlock (key, 32); // random session key
m_Rnd.GenerateBlock (tag, 32); // random session tag m_Rnd.GenerateBlock (tag, 32); // random session tag
m_Owner->AddSessionKey (key, tag); m_Owner->SubmitSessionKey (key, tag);
GarlicRoutingSession garlic (key, tag); GarlicRoutingSession garlic (key, tag);
msg = garlic.WrapSingleMessage (msg); msg = garlic.WrapSingleMessage (msg);
} }
@@ -321,6 +322,12 @@ namespace garlic
} }
} }
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{
AddSessionKey (key, tag);
return true;
}
void GarlicDestination::HandleGarlicMessage (I2NPMessage * msg) void GarlicDestination::HandleGarlicMessage (I2NPMessage * msg)
{ {
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
@@ -383,18 +390,24 @@ namespace garlic
i2p::tunnel::InboundTunnel * from) i2p::tunnel::InboundTunnel * from)
{ {
uint16_t tagCount = be16toh (*(uint16_t *)buf); uint16_t tagCount = be16toh (*(uint16_t *)buf);
buf += 2; buf += 2; len -= 2;
if (tagCount > 0) if (tagCount > 0)
{ {
if (tagCount*32 > len)
{
LogPrint (eLogError, "Tag count ", tagCount, " exceeds length ", len);
return ;
}
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (int i = 0; i < tagCount; i++) for (int i = 0; i < tagCount; i++)
m_Tags[SessionTag(buf + i*32, ts)] = decryption; m_Tags[SessionTag(buf + i*32, ts)] = decryption;
} }
buf += tagCount*32; buf += tagCount*32;
len -= tagCount*32;
uint32_t payloadSize = be32toh (*(uint32_t *)buf); uint32_t payloadSize = be32toh (*(uint32_t *)buf);
if (payloadSize > len) if (payloadSize > len)
{ {
LogPrint ("Unexpected payload size ", payloadSize); LogPrint (eLogError, "Unexpected payload size ", payloadSize);
return; return;
} }
buf += 4; buf += 4;

View File

@@ -110,6 +110,7 @@ namespace garlic
I2NPMessage * msg, bool attachLeaseSet = false); I2NPMessage * msg, bool attachLeaseSet = false);
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSession * session, uint32_t msgID); void DeliveryStatusSent (GarlicRoutingSession * session, uint32_t msgID);
virtual void ProcessGarlicMessage (I2NPMessage * msg); virtual void ProcessGarlicMessage (I2NPMessage * msg);

View File

@@ -514,14 +514,16 @@ namespace util
void HTTPConnection::Terminate () void HTTPConnection::Terminate ()
{ {
if (m_Stream) if (!m_Stream) return;
{
m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
m_Socket->close (); m_Socket->close ();
//delete this; m_Stream->Close ();
m_Socket->get_io_service ().post ([=](void)
{
m_Stream.reset ();
m_Stream = nullptr;
// delete this
});
} }
void HTTPConnection::Receive () void HTTPConnection::Receive ()
@@ -602,7 +604,10 @@ namespace util
void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode) void HTTPConnection::HandleWriteReply (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{
m_Socket->close ();
Terminate (); Terminate ();
}
} }
void HTTPConnection::HandleWrite (const boost::system::error_code& ecode) void HTTPConnection::HandleWrite (const boost::system::error_code& ecode)
@@ -710,7 +715,7 @@ namespace util
if (it.second && it.second->IsEstablished ()) if (it.second && it.second->IsEstablished ())
{ {
// incoming connection doesn't have remote RI // incoming connection doesn't have remote RI
bool outgoing = it.second->GetRemoteRouter (); auto outgoing = it.second->GetRemoteRouter ();
if (outgoing) s << "-->"; if (outgoing) s << "-->";
s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": " s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": "
<< it.second->GetSocket ().remote_endpoint().address ().to_string (); << it.second->GetSocket ().remote_endpoint().address ().to_string ();
@@ -727,7 +732,7 @@ namespace util
for (auto it: ssuServer->GetSessions ()) for (auto it: ssuServer->GetSessions ())
{ {
// incoming connections don't have remote router // incoming connections don't have remote router
bool outgoing = it.second->GetRemoteRouter (); auto outgoing = it.second->GetRemoteRouter ();
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
if (outgoing) s << "-->"; if (outgoing) s << "-->";
s << endpoint.address ().to_string () << ":" << endpoint.port (); s << endpoint.address ().to_string () << ":" << endpoint.port ();
@@ -744,8 +749,6 @@ namespace util
for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ())
{ {
it->GetTunnelConfig ()->Print (s); it->GetTunnelConfig ()->Print (s);
if (it->GetTunnelPool () && !it->GetTunnelPool ()->IsExploratory ())
s << " " << "Pool";
auto state = it->GetState (); auto state = it->GetState ();
if (state == i2p::tunnel::eTunnelStateFailed) if (state == i2p::tunnel::eTunnelStateFailed)
s << " " << "Failed"; s << " " << "Failed";
@@ -758,8 +761,6 @@ namespace util
for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ())
{ {
it.second->GetTunnelConfig ()->Print (s); it.second->GetTunnelConfig ()->Print (s);
if (it.second->GetTunnelPool () && !it.second->GetTunnelPool ()->IsExploratory ())
s << " " << "Pool";
auto state = it.second->GetState (); auto state = it.second->GetState ();
if (state == i2p::tunnel::eTunnelStateFailed) if (state == i2p::tunnel::eTunnelStateFailed)
s << " " << "Failed"; s << " " << "Failed";
@@ -810,11 +811,21 @@ namespace util
for (auto it: pool->GetOutboundTunnels ()) for (auto it: pool->GetOutboundTunnels ())
{ {
it->GetTunnelConfig ()->Print (s); it->GetTunnelConfig ()->Print (s);
auto state = it->GetState ();
if (state == i2p::tunnel::eTunnelStateFailed)
s << " " << "Failed";
else if (state == i2p::tunnel::eTunnelStateExpiring)
s << " " << "Exp";
s << "<br>" << std::endl; s << "<br>" << std::endl;
} }
for (auto it: pool->GetInboundTunnels ()) for (auto it: pool->GetInboundTunnels ())
{ {
it->GetTunnelConfig ()->Print (s); it->GetTunnelConfig ()->Print (s);
auto state = it->GetState ();
if (state == i2p::tunnel::eTunnelStateFailed)
s << " " << "Failed";
else if (state == i2p::tunnel::eTunnelStateExpiring)
s << " " << "Exp";
s << "<br>" << std::endl; s << "<br>" << std::endl;
} }
} }

View File

@@ -3,6 +3,7 @@
#include <sstream> #include <sstream>
#include <thread> #include <thread>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/array.hpp> #include <boost/array.hpp>
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -79,7 +80,7 @@ namespace util
boost::asio::ip::tcp::socket * m_Socket; boost::asio::ip::tcp::socket * m_Socket;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
i2p::stream::Stream * m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
size_t m_BufferLen; size_t m_BufferLen;
request m_Request; request m_Request;

View File

@@ -160,8 +160,8 @@ namespace i2p
rnd.GenerateBlock (buf, 32); // key rnd.GenerateBlock (buf, 32); // key
buf[32] = 1; // 1 tag buf[32] = 1; // 1 tag
rnd.GenerateBlock (buf + 33, 32); // tag rnd.GenerateBlock (buf + 33, 32); // tag
if (pool) if (pool && pool->GetLocalDestination ())
pool->GetGarlicDestination ().AddSessionKey (buf, buf + 33); // introduce new key-tag to garlic engine pool->GetLocalDestination ()->SubmitSessionKey (buf, buf + 33); // introduce new key-tag to garlic engine
else else
LogPrint ("Destination for encrypteed reply not specified"); LogPrint ("Destination for encrypteed reply not specified");
buf += 65; buf += 65;
@@ -562,8 +562,16 @@ namespace i2p
break; break;
case eI2NPGarlic: case eI2NPGarlic:
LogPrint ("Garlic"); LogPrint ("Garlic");
if (msg->from && msg->from->GetTunnelPool ()) if (msg->from)
msg->from->GetTunnelPool ()->GetGarlicDestination ().ProcessGarlicMessage (msg); {
if (msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
else
{
LogPrint (eLogInfo, "Local destination for garlic doesn't exist anymore");
DeleteI2NPMessage (msg);
}
}
else else
i2p::context.ProcessGarlicMessage (msg); i2p::context.ProcessGarlicMessage (msg);
break; break;

View File

@@ -118,6 +118,15 @@ namespace tunnel
uint8_t * GetBuffer () { return buf + offset; }; uint8_t * GetBuffer () { return buf + offset; };
const uint8_t * GetBuffer () const { return buf + offset; }; const uint8_t * GetBuffer () const { return buf + offset; };
size_t GetLength () const { return len - offset; }; size_t GetLength () const { return len - offset; };
void Align (size_t alignment)
{
size_t rem = ((size_t)GetBuffer ()) % alignment;
if (rem)
{
offset += (alignment - rem);
len += (alignment - rem);
}
}
I2NPMessage& operator=(const I2NPMessage& other) I2NPMessage& operator=(const I2NPMessage& other)
{ {

View File

@@ -1,4 +1,3 @@
#include <boost/bind.hpp>
#include "base64.h" #include "base64.h"
#include "Log.h" #include "Log.h"
#include "NetDb.h" #include "NetDb.h"
@@ -12,21 +11,16 @@ namespace client
{ {
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner,
boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet): boost::asio::ip::tcp::socket * socket, const i2p::data::LeaseSet * leaseSet):
m_Socket (socket), m_Owner (owner) m_Socket (socket), m_Owner (owner), m_RemoteEndpoint (socket->remote_endpoint ()),
m_IsQuiet (true)
{ {
m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet); m_Stream = m_Owner->GetLocalDestination ()->CreateStream (*leaseSet);
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
} }
I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, i2p::stream::Stream * stream, I2PTunnelConnection::I2PTunnelConnection (I2PTunnel * owner, std::shared_ptr<i2p::stream::Stream> stream,
boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target): boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
m_Socket (socket), m_Stream (stream), m_Owner (owner) m_Socket (socket), m_Stream (stream), m_Owner (owner), m_RemoteEndpoint (target), m_IsQuiet (quiet)
{ {
if (m_Socket)
m_Socket->async_connect (target, boost::bind (&I2PTunnelConnection::HandleConnect,
this, boost::asio::placeholders::error));
} }
I2PTunnelConnection::~I2PTunnelConnection () I2PTunnelConnection::~I2PTunnelConnection ()
@@ -34,25 +28,40 @@ namespace client
delete m_Socket; delete m_Socket;
} }
void I2PTunnelConnection::I2PConnect (const uint8_t * msg, size_t len)
{
if (msg)
m_Stream->Send (msg, len); // connect and send
else
m_Stream->Send (m_Buffer, 0); // connect
StreamReceive ();
Receive ();
}
void I2PTunnelConnection::Connect ()
{
if (m_Socket)
m_Socket->async_connect (m_RemoteEndpoint, std::bind (&I2PTunnelConnection::HandleConnect,
shared_from_this (), std::placeholders::_1));
}
void I2PTunnelConnection::Terminate () void I2PTunnelConnection::Terminate ()
{ {
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream); m_Stream.reset ();
m_Stream = nullptr;
} }
m_Socket->close (); m_Socket->close ();
if (m_Owner) if (m_Owner)
m_Owner->RemoveConnection (this); m_Owner->RemoveConnection (shared_from_this ());
//delete this;
} }
void I2PTunnelConnection::Receive () void I2PTunnelConnection::Receive ()
{ {
m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), m_Socket->async_read_some (boost::asio::buffer(m_Buffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
boost::bind(&I2PTunnelConnection::HandleReceived, this, std::bind(&I2PTunnelConnection::HandleReceived, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void I2PTunnelConnection::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -87,8 +96,8 @@ namespace client
{ {
if (m_Stream) if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE), m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, I2P_TUNNEL_CONNECTION_BUFFER_SIZE),
boost::bind (&I2PTunnelConnection::HandleStreamReceive, this, std::bind (&I2PTunnelConnection::HandleStreamReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), std::placeholders::_1, std::placeholders::_2),
I2P_TUNNEL_CONNECTION_MAX_IDLE); I2P_TUNNEL_CONNECTION_MAX_IDLE);
} }
@@ -103,7 +112,7 @@ namespace client
else else
{ {
boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
boost::bind (&I2PTunnelConnection::HandleWrite, this, boost::asio::placeholders::error)); std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
} }
} }
@@ -112,35 +121,37 @@ namespace client
if (ecode) if (ecode)
{ {
LogPrint ("I2PTunnel connect error: ", ecode.message ()); LogPrint ("I2PTunnel connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) Terminate ();
{
if (m_Stream) m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
} }
else else
{ {
LogPrint ("I2PTunnel connected"); LogPrint ("I2PTunnel connected");
StreamReceive (); if (m_IsQuiet)
StreamReceive ();
else
{
// send destination first like received from I2P
std::string dest = m_Stream->GetRemoteIdentity ().ToBase64 ();
dest += "\n";
memcpy (m_StreamBuffer, dest.c_str (), dest.size ());
HandleStreamReceive (boost::system::error_code (), dest.size ());
}
Receive (); Receive ();
} }
} }
void I2PTunnel::AddConnection (I2PTunnelConnection * conn) void I2PTunnel::AddConnection (std::shared_ptr<I2PTunnelConnection> conn)
{ {
m_Connections.insert (conn); m_Connections.insert (conn);
} }
void I2PTunnel::RemoveConnection (I2PTunnelConnection * conn) void I2PTunnel::RemoveConnection (std::shared_ptr<I2PTunnelConnection> conn)
{ {
m_Connections.erase (conn); m_Connections.erase (conn);
} }
void I2PTunnel::ClearConnections () void I2PTunnel::ClearConnections ()
{ {
for (auto it: m_Connections)
delete it;
m_Connections.clear (); m_Connections.clear ();
} }
@@ -181,8 +192,8 @@ namespace client
void I2PClientTunnel::Accept () void I2PClientTunnel::Accept ()
{ {
auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); auto newSocket = new boost::asio::ip::tcp::socket (GetService ());
m_Acceptor.async_accept (*newSocket, boost::bind (&I2PClientTunnel::HandleAccept, this, m_Acceptor.async_accept (*newSocket, std::bind (&I2PClientTunnel::HandleAccept, this,
boost::asio::placeholders::error, newSocket)); std::placeholders::_1, newSocket));
} }
void I2PClientTunnel::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) void I2PClientTunnel::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket)
@@ -205,8 +216,8 @@ namespace client
{ {
i2p::data::netdb.RequestDestination (*m_DestinationIdentHash, true, GetLocalDestination ()->GetTunnelPool ()); i2p::data::netdb.RequestDestination (*m_DestinationIdentHash, true, GetLocalDestination ()->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds (I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT));
m_Timer.async_wait (boost::bind (&I2PClientTunnel::HandleDestinationRequestTimer, m_Timer.async_wait (std::bind (&I2PClientTunnel::HandleDestinationRequestTimer,
this, boost::asio::placeholders::error, socket)); this, std::placeholders::_1, socket));
} }
} }
else else
@@ -240,8 +251,9 @@ namespace client
if (m_RemoteLeaseSet) // leaseSet found if (m_RemoteLeaseSet) // leaseSet found
{ {
LogPrint ("New I2PTunnel connection"); LogPrint ("New I2PTunnel connection");
auto connection = new I2PTunnelConnection (this, socket, m_RemoteLeaseSet); auto connection = std::make_shared<I2PTunnelConnection>(this, socket, m_RemoteLeaseSet);
AddConnection (connection); AddConnection (connection);
connection->I2PConnect ();
} }
else else
{ {
@@ -275,10 +287,14 @@ namespace client
LogPrint ("Local destination not set for server tunnel"); LogPrint ("Local destination not set for server tunnel");
} }
void I2PServerTunnel::HandleAccept (i2p::stream::Stream * stream) void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
new I2PTunnelConnection (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint); {
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint);
AddConnection (conn);
conn->Connect ();
}
} }
} }
} }

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <set> #include <set>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "Destination.h" #include "Destination.h"
@@ -18,16 +19,19 @@ namespace client
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
class I2PTunnel; class I2PTunnel;
class I2PTunnelConnection class I2PTunnelConnection: public std::enable_shared_from_this<I2PTunnelConnection>
{ {
public: public:
I2PTunnelConnection (I2PTunnel * owner, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PTunnel * owner, boost::asio::ip::tcp::socket * socket,
const i2p::data::LeaseSet * leaseSet); const i2p::data::LeaseSet * leaseSet); // to I2P
I2PTunnelConnection (I2PTunnel * owner, i2p::stream::Stream * stream, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PTunnel * owner, std::shared_ptr<i2p::stream::Stream> stream, boost::asio::ip::tcp::socket * socket,
const boost::asio::ip::tcp::endpoint& target); const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P
~I2PTunnelConnection (); ~I2PTunnelConnection ();
void I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
void Connect ();
private: private:
void Terminate (); void Terminate ();
@@ -44,8 +48,10 @@ namespace client
uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE]; uint8_t m_Buffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE], m_StreamBuffer[I2P_TUNNEL_CONNECTION_BUFFER_SIZE];
boost::asio::ip::tcp::socket * m_Socket; boost::asio::ip::tcp::socket * m_Socket;
i2p::stream::Stream * m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
I2PTunnel * m_Owner; I2PTunnel * m_Owner;
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
bool m_IsQuiet; // don't send destination
}; };
class I2PTunnel class I2PTunnel
@@ -56,8 +62,8 @@ namespace client
m_Service (service), m_LocalDestination (localDestination) {}; m_Service (service), m_LocalDestination (localDestination) {};
virtual ~I2PTunnel () { ClearConnections (); }; virtual ~I2PTunnel () { ClearConnections (); };
void AddConnection (I2PTunnelConnection * conn); void AddConnection (std::shared_ptr<I2PTunnelConnection> conn);
void RemoveConnection (I2PTunnelConnection * conn); void RemoveConnection (std::shared_ptr<I2PTunnelConnection> conn);
void ClearConnections (); void ClearConnections ();
ClientDestination * GetLocalDestination () { return m_LocalDestination; }; ClientDestination * GetLocalDestination () { return m_LocalDestination; };
void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; }; void SetLocalDestination (ClientDestination * dest) { m_LocalDestination = dest; };
@@ -68,7 +74,7 @@ namespace client
boost::asio::io_service& m_Service; boost::asio::io_service& m_Service;
ClientDestination * m_LocalDestination; ClientDestination * m_LocalDestination;
std::set<I2PTunnelConnection *> m_Connections; std::set<std::shared_ptr<I2PTunnelConnection> > m_Connections;
}; };
class I2PClientTunnel: public I2PTunnel class I2PClientTunnel: public I2PTunnel
@@ -111,7 +117,7 @@ namespace client
private: private:
void Accept (); void Accept ();
void HandleAccept (i2p::stream::Stream * stream); void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
private: private:

View File

@@ -42,18 +42,77 @@ namespace data
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type) IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type)
{ {
memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey)); memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey));
if (type == SIGNING_KEY_TYPE_ECDSA_SHA256_P256) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
memcpy (m_StandardIdentity.signingKey + 64, signingKey, 64); size_t excessLen = 0;
uint8_t * excessBuf = nullptr;
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
{
memcpy (m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132 - 128
excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen);
break;
}
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
{
memcpy (m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::RSASHA2562048_KEY_LENGTH - 128; // 128 = 256 - 128
excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen);
break;
}
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
{
memcpy (m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::RSASHA3843072_KEY_LENGTH - 128; // 256 = 384 - 128
excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen);
break;
}
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
{
memcpy (m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::RSASHA5124096_KEY_LENGTH - 128; // 384 = 512 - 128
excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen);
break;
}
default:
LogPrint ("Signing key type ", (int)type, " is not supported");
}
m_ExtendedLen = 4 + excessLen; // 4 bytes extra + excess length
// fill certificate
m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY; m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY;
m_ExtendedLen = 4; // 4 bytes extra m_StandardIdentity.certificate.length = htobe16 (m_ExtendedLen);
m_StandardIdentity.certificate.length = htobe16 (4); // fill extended buffer
m_ExtendedBuffer = new uint8_t[m_ExtendedLen]; m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
*(uint16_t *)m_ExtendedBuffer = htobe16 (SIGNING_KEY_TYPE_ECDSA_SHA256_P256); *(uint16_t *)m_ExtendedBuffer = htobe16 (type);
*(uint16_t *)(m_ExtendedBuffer + 2) = htobe16 (CRYPTO_KEY_TYPE_ELGAMAL); *(uint16_t *)(m_ExtendedBuffer + 2) = htobe16 (CRYPTO_KEY_TYPE_ELGAMAL);
uint8_t buf[DEFAULT_IDENTITY_SIZE + 4]; if (excessLen && excessBuf)
ToBuffer (buf, DEFAULT_IDENTITY_SIZE + 4); {
memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen);
delete[] excessBuf;
}
// calculate ident hash
uint8_t * buf = new uint8_t[GetFullLen ()];
ToBuffer (buf, GetFullLen ());
CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ()); CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ());
delete[] buf;
} }
else // DSA-SHA1 else // DSA-SHA1
{ {
@@ -122,14 +181,27 @@ namespace data
size_t IdentityEx::FromBuffer (const uint8_t * buf, size_t len) size_t IdentityEx::FromBuffer (const uint8_t * buf, size_t len)
{ {
if (len < DEFAULT_IDENTITY_SIZE)
{
LogPrint (eLogError, "Identity buffer length ", len, " is too small");
return 0;
}
memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE); memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
delete[] m_ExtendedBuffer; delete[] m_ExtendedBuffer;
if (m_StandardIdentity.certificate.length) if (m_StandardIdentity.certificate.length)
{ {
m_ExtendedLen = be16toh (m_StandardIdentity.certificate.length); m_ExtendedLen = be16toh (m_StandardIdentity.certificate.length);
m_ExtendedBuffer = new uint8_t[m_ExtendedLen]; if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len)
memcpy (m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen); {
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
memcpy (m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen);
}
else
{
LogPrint (eLogError, "Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
return 0;
}
} }
else else
{ {
@@ -154,11 +226,21 @@ namespace data
size_t IdentityEx::FromBase64(const std::string& s) size_t IdentityEx::FromBase64(const std::string& s)
{ {
uint8_t buf[512]; uint8_t buf[1024];
auto len = Base64ToByteStream (s.c_str(), s.length(), buf, 512); auto len = Base64ToByteStream (s.c_str(), s.length(), buf, 1024);
return FromBuffer (buf, len); return FromBuffer (buf, len);
} }
std::string IdentityEx::ToBase64 () const
{
uint8_t buf[1024];
char str[1536];
size_t l = ToBuffer (buf, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, 1536);
str[l1] = 0;
return std::string (str);
}
size_t IdentityEx::GetSigningPublicKeyLen () const size_t IdentityEx::GetSigningPublicKeyLen () const
{ {
if (!m_Verifier) CreateVerifier (); if (!m_Verifier) CreateVerifier ();
@@ -167,6 +249,14 @@ namespace data
return 128; return 128;
} }
size_t IdentityEx::GetSigningPrivateKeyLen () const
{
if (!m_Verifier) CreateVerifier ();
if (m_Verifier)
return m_Verifier->GetPrivateKeyLen ();
return GetSignatureLen ()/2;
}
size_t IdentityEx::GetSignatureLen () const size_t IdentityEx::GetSignatureLen () const
{ {
if (!m_Verifier) CreateVerifier (); if (!m_Verifier) CreateVerifier ();
@@ -188,6 +278,13 @@ namespace data
return be16toh (*(const uint16_t *)m_ExtendedBuffer); // signing key return be16toh (*(const uint16_t *)m_ExtendedBuffer); // signing key
return SIGNING_KEY_TYPE_DSA_SHA1; return SIGNING_KEY_TYPE_DSA_SHA1;
} }
CryptoKeyType IdentityEx::GetCryptoKeyType () const
{
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
return be16toh (*(const uint16_t *)(m_ExtendedBuffer + 2)); // crypto key
return CRYPTO_KEY_TYPE_ELGAMAL;
}
void IdentityEx::CreateVerifier () const void IdentityEx::CreateVerifier () const
{ {
@@ -198,19 +295,72 @@ namespace data
m_Verifier = new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey); m_Verifier = new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey);
break; break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + 64); {
break; size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
m_Verifier = new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding);
break;
}
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
{
uint8_t signingKey[i2p::crypto::ECDSAP521_KEY_LENGTH];
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto::ECDSAP521Verifier (signingKey);
break;
}
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
{
uint8_t signingKey[i2p::crypto::RSASHA2562048_KEY_LENGTH];
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::RSASHA2562048_KEY_LENGTH - 128; // 128 = 256- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto:: RSASHA2562048Verifier (signingKey);
break;
}
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
{
uint8_t signingKey[i2p::crypto::RSASHA3843072_KEY_LENGTH];
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::RSASHA3843072_KEY_LENGTH - 128; // 256 = 384- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto:: RSASHA3843072Verifier (signingKey);
break;
}
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
{
uint8_t signingKey[i2p::crypto::RSASHA5124096_KEY_LENGTH];
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = i2p::crypto::RSASHA5124096_KEY_LENGTH - 128; // 384 = 512- 128
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto:: RSASHA5124096Verifier (signingKey);
break;
}
default: default:
LogPrint ("Signing key type ", (int)keyType, " is not supported"); LogPrint ("Signing key type ", (int)keyType, " is not supported");
} }
} }
void IdentityEx::DropVerifier ()
{
auto verifier = m_Verifier;
m_Verifier = nullptr; // TODO: make this atomic
delete verifier;
}
PrivateKeys& PrivateKeys::operator=(const Keys& keys) PrivateKeys& PrivateKeys::operator=(const Keys& keys)
{ {
m_Public = Identity (keys); m_Public = Identity (keys);
memcpy (m_PrivateKey, keys.privateKey, 256); // 256 memcpy (m_PrivateKey, keys.privateKey, 256); // 256
memcpy (m_SigningPrivateKey, keys.signingPrivateKey, 20); // 20 - DSA memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public.GetSigningPrivateKeyLen ());
delete m_Signer; delete m_Signer;
m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return *this; return *this;
} }
@@ -219,8 +369,9 @@ namespace data
{ {
m_Public = other.m_Public; m_Public = other.m_Public;
memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256 memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, 128); // 128 memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_Public.GetSigningPrivateKeyLen ());
delete m_Signer; delete m_Signer;
m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return *this; return *this;
} }
@@ -230,10 +381,11 @@ namespace data
size_t ret = m_Public.FromBuffer (buf, len); size_t ret = m_Public.FromBuffer (buf, len);
memcpy (m_PrivateKey, buf + ret, 256); // private key always 256 memcpy (m_PrivateKey, buf + ret, 256); // private key always 256
ret += 256; ret += 256;
size_t signingPrivateKeySize = m_Public.GetSignatureLen ()/2; // 20 for DSA size_t signingPrivateKeySize = m_Public.GetSigningPrivateKeyLen ();
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
ret += signingPrivateKeySize; ret += signingPrivateKeySize;
delete m_Signer; delete m_Signer;
m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return ret; return ret;
} }
@@ -243,12 +395,34 @@ namespace data
size_t ret = m_Public.ToBuffer (buf, len); size_t ret = m_Public.ToBuffer (buf, len);
memcpy (buf + ret, m_PrivateKey, 256); // private key always 256 memcpy (buf + ret, m_PrivateKey, 256); // private key always 256
ret += 256; ret += 256;
size_t signingPrivateKeySize = m_Public.GetSignatureLen ()/2; // 20 for DSA size_t signingPrivateKeySize = m_Public.GetSigningPrivateKeyLen ();
memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize); memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize);
ret += signingPrivateKeySize; ret += signingPrivateKeySize;
return ret; return ret;
} }
size_t PrivateKeys::FromBase64(const std::string& s)
{
uint8_t * buf = new uint8_t[s.length ()];
size_t l = i2p::data::Base64ToByteStream (s.c_str (), s.length (), buf, s.length ());
size_t ret = FromBuffer (buf, l);
delete[] buf;
return ret;
}
std::string PrivateKeys::ToBase64 () const
{
uint8_t * buf = new uint8_t[GetFullLen ()];
char * str = new char[GetFullLen ()*2];
size_t l = ToBuffer (buf, GetFullLen ());
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, GetFullLen ()*2);
str[l1] = 0;
delete[] buf;
std::string ret(str);
delete[] str;
return ret;
}
void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
if (m_Signer) if (m_Signer)
@@ -257,26 +431,73 @@ namespace data
void PrivateKeys::CreateSigner () void PrivateKeys::CreateSigner ()
{ {
if (m_Public.GetSigningKeyType () == SIGNING_KEY_TYPE_ECDSA_SHA256_P256) switch (m_Public.GetSigningKeyType ())
m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey); {
else case SIGNING_KEY_TYPE_DSA_SHA1:
m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey); m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
m_Signer = new i2p::crypto::ECDSAP384Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
m_Signer = new i2p::crypto::ECDSAP521Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
m_Signer = new i2p::crypto::RSASHA2562048Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
m_Signer = new i2p::crypto::RSASHA3843072Signer (m_SigningPrivateKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
m_Signer = new i2p::crypto::RSASHA5124096Signer (m_SigningPrivateKey);
break;
default:
LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported");
}
} }
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type) PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type)
{ {
if (type == SIGNING_KEY_TYPE_ECDSA_SHA256_P256) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
PrivateKeys keys; PrivateKeys keys;
auto& rnd = i2p::context.GetRandomNumberGenerator (); auto& rnd = i2p::context.GetRandomNumberGenerator ();
// signature
uint8_t signingPublicKey[512]; // signing public key is 512 bytes max
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
i2p::crypto::CreateECDSAP384RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
i2p::crypto::CreateECDSAP521RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
i2p::crypto::CreateRSARandomKeys (rnd, i2p::crypto::RSASHA2562048_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
i2p::crypto::CreateRSARandomKeys (rnd, i2p::crypto::RSASHA3843072_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
i2p::crypto::CreateRSARandomKeys (rnd, i2p::crypto::RSASHA5124096_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey);
break;
default:
LogPrint ("Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
}
// encryption // encryption
uint8_t publicKey[256]; uint8_t publicKey[256];
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey); dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey);
// signature // identity
uint8_t signingPublicKey[64]; keys.m_Public = IdentityEx (publicKey, signingPublicKey, type);
i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey);
keys.m_Public = IdentityEx (publicKey, signingPublicKey, SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
keys.CreateSigner (); keys.CreateSigner ();
return keys; return keys;
} }

View File

@@ -56,6 +56,11 @@ namespace data
return std::string (str); return std::string (str);
} }
void FromBase32 (const std::string& s)
{
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
}
private: private:
union // 8 bytes alignment union // 8 bytes alignment
@@ -102,11 +107,17 @@ namespace data
Keys CreateRandomKeys (); Keys CreateRandomKeys ();
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA384_P384 = 2;
const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA512_P521 = 3;
const uint16_t SIGNING_KEY_TYPE_RSA_SHA256_2048 = 4;
const uint16_t SIGNING_KEY_TYPE_RSA_SHA384_3072 = 5;
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
typedef uint16_t SigningKeyType; typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType;
class IdentityEx class IdentityEx
{ {
@@ -121,17 +132,21 @@ namespace data
IdentityEx& operator=(const IdentityEx& other); IdentityEx& operator=(const IdentityEx& other);
IdentityEx& operator=(const Identity& standard); IdentityEx& operator=(const Identity& standard);
size_t FromBase64(const std::string& s);
size_t FromBuffer (const uint8_t * buf, size_t len); size_t FromBuffer (const uint8_t * buf, size_t len);
size_t ToBuffer (uint8_t * buf, size_t len) const; size_t ToBuffer (uint8_t * buf, size_t len) const;
size_t FromBase64(const std::string& s);
std::string ToBase64 () const;
const Identity& GetStandardIdentity () const { return m_StandardIdentity; }; const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
const IdentHash& GetIdentHash () const { return m_IdentHash; }; const IdentHash& GetIdentHash () const { return m_IdentHash; };
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; }; size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
size_t GetSigningPublicKeyLen () const; size_t GetSigningPublicKeyLen () const;
size_t GetSigningPrivateKeyLen () const;
size_t GetSignatureLen () const; size_t GetSignatureLen () const;
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
SigningKeyType GetSigningKeyType () const; SigningKeyType GetSigningKeyType () const;
CryptoKeyType GetCryptoKeyType () const;
void DropVerifier (); // to save memory
private: private:
void CreateVerifier () const; void CreateVerifier () const;
@@ -161,10 +176,13 @@ namespace data
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
size_t GetFullLen () const { return m_Public.GetFullLen () + 256 + m_Public.GetSignatureLen ()/2; }; size_t GetFullLen () const { return m_Public.GetFullLen () + 256 + m_Public.GetSigningPrivateKeyLen (); };
size_t FromBuffer (const uint8_t * buf, size_t len); size_t FromBuffer (const uint8_t * buf, size_t len);
size_t ToBuffer (uint8_t * buf, size_t len) const; size_t ToBuffer (uint8_t * buf, size_t len) const;
size_t FromBase64(const std::string& s);
std::string ToBase64 () const;
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1); static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1);
private: private:
@@ -175,7 +193,7 @@ namespace data
IdentityEx m_Public; IdentityEx m_Public;
uint8_t m_PrivateKey[256]; uint8_t m_PrivateKey[256];
uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes uint8_t m_SigningPrivateKey[1024]; // assume private key doesn't exceed 1024 bytes
i2p::crypto::Signer * m_Signer; i2p::crypto::Signer * m_Signer;
}; };

View File

@@ -22,11 +22,17 @@ namespace data
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool) LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool)
{ {
// header // header
const i2p::data::LocalDestination& localDestination = pool.GetLocalDestination (); const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination ();
m_BufferLen = localDestination.GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); if (!localDestination)
memcpy (m_Buffer + m_BufferLen, localDestination.GetEncryptionPublicKey (), 256); {
m_BufferLen = 0;
LogPrint (eLogError, "Destination for local LeaseSet doesn't exist");
return;
}
m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE);
memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256);
m_BufferLen += 256; m_BufferLen += 256;
auto signingKeyLen = localDestination.GetIdentity ().GetSigningPublicKeyLen (); auto signingKeyLen = localDestination->GetIdentity ().GetSigningPublicKeyLen ();
memset (m_Buffer + m_BufferLen, 0, signingKeyLen); memset (m_Buffer + m_BufferLen, 0, signingKeyLen);
m_BufferLen += signingKeyLen; m_BufferLen += signingKeyLen;
auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum
@@ -44,8 +50,8 @@ namespace data
m_BufferLen += sizeof (Lease); m_BufferLen += sizeof (Lease);
} }
// signature // signature
localDestination.Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen); localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
m_BufferLen += localDestination.GetIdentity ().GetSignatureLen (); m_BufferLen += localDestination->GetIdentity ().GetSignatureLen ();
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created"); LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
ReadFromBuffer (); ReadFromBuffer ();

View File

@@ -36,7 +36,7 @@ namespace data
#pragma pack() #pragma pack()
const int MAX_LS_BUFFER_SIZE = 2048; const int MAX_LS_BUFFER_SIZE = 3072;
class LeaseSet: public RoutingDestination class LeaseSet: public RoutingDestination
{ {
public: public:

25
Log.cpp
View File

@@ -20,19 +20,24 @@ void LogMsg::Process()
void Log::Flush () void Log::Flush ()
{ {
if (m_LogFile) if (m_LogStream)
m_LogFile->flush(); m_LogStream->flush();
} }
void Log::SetLogFile (const std::string& fullFilePath) void Log::SetLogFile (const std::string& fullFilePath)
{ {
if (m_LogFile) delete m_LogFile; auto logFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
m_LogFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); if (logFile->is_open ())
if (m_LogFile->is_open ())
LogPrint("Logging to file ", fullFilePath, " enabled.");
else
{ {
delete m_LogFile; SetLogStream (logFile);
m_LogFile = nullptr; LogPrint("Logging to file ", fullFilePath, " enabled.");
} }
else
delete logFile;
}
void Log::SetLogStream (std::ostream * logStream)
{
if (m_LogStream) delete m_LogStream;
m_LogStream = logStream;
} }

21
Log.h
View File

@@ -32,11 +32,12 @@ class Log: public i2p::util::MsgQueue<LogMsg>
{ {
public: public:
Log (): m_LogFile (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); }; Log (): m_LogStream (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); };
~Log () { delete m_LogFile; }; ~Log () { delete m_LogStream; };
void SetLogFile (const std::string& fullFilePath); void SetLogFile (const std::string& fullFilePath);
std::ofstream * GetLogFile () const { return m_LogFile; }; void SetLogStream (std::ostream * logStream);
std::ostream * GetLogStream () const { return m_LogStream; };
private: private:
@@ -44,7 +45,7 @@ class Log: public i2p::util::MsgQueue<LogMsg>
private: private:
std::ofstream * m_LogFile; std::ostream * m_LogStream;
}; };
extern Log * g_Log; extern Log * g_Log;
@@ -59,6 +60,16 @@ inline void StartLog (const std::string& fullFilePath)
} }
} }
inline void StartLog (std::ostream * s)
{
if (!g_Log)
{
g_Log = new Log ();
if (s)
g_Log->SetLogStream (s);
}
}
inline void StopLog () inline void StopLog ()
{ {
if (g_Log) if (g_Log)
@@ -84,7 +95,7 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
template<typename... TArgs> template<typename... TArgs>
void LogPrint (LogLevel level, TArgs... args) void LogPrint (LogLevel level, TArgs... args)
{ {
LogMsg * msg = (g_Log && g_Log->GetLogFile ()) ? new LogMsg (*g_Log->GetLogFile (), level) : LogMsg * msg = (g_Log && g_Log->GetLogStream ()) ? new LogMsg (*g_Log->GetLogStream (), level) :
new LogMsg (std::cout, level); new LogMsg (std::cout, level);
LogPrint (msg->s, args...); LogPrint (msg->s, args...);
msg->s << std::endl; msg->s << std::endl;

View File

@@ -1,29 +1,52 @@
UNAME := $(shell uname -s) UNAME := $(shell uname -s)
SHLIB := libi2pd.so
I2PD := i2p
include filelist.mk
USE_AESNI := yes
USE_STATIC := no
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.osx include Makefile.osx
else ifeq ($(UNAME), FreeBSD) else ifeq ($(UNAME),FreeBSD)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.bsd include Makefile.bsd
else else ifeq ($(UNAME),Linux)
DAEMON_SRC += DaemonLinux.cpp
include Makefile.linux include Makefile.linux
else # win32
DAEMON_SRC += DaemonWin32.cpp
endif endif
all: obj i2p all: obj $(SHLIB) $(I2PD)
i2p: $(OBJECTS:obj/%=obj/%)
$(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : %.cpp
$(CXX) -o $@ $< -c $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS)
obj: obj:
mkdir -p obj mkdir -p obj
obj/%.o : %.cpp %.h
$(CXX) $(CXXFLAGS) $(INCFLAGS) -c -o $@ $<
# weaker rule for building files without headers
obj/%.o : %.cpp
$(CXX) $(CXXFLAGS) $(INCFLAGS) -c -o $@ $<
$(I2PD): $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
$(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS)
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
$(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS) -shared
clean: clean:
rm -fr obj i2p rm -fr obj $(I2PD) $(SHLIB)
LATEST_TAG=$(shell git describe --tags --abbrev=0 master)
dist:
git archive --format=tar.gz -9 --worktree-attributes \
--prefix=i2pd_$(LATEST_TAG)/ $(LATEST_TAG) -o i2pd_$(LATEST_TAG).tar.gz
.PHONY: all .PHONY: all
.PHONY: clean .PHONY: clean
.PHONY: dist

View File

@@ -1,8 +1,5 @@
CXX = g++ CXX = g++
CXXFLAGS = -O2 CXXFLAGS = -g -Wall -O2 -std=c++11
NEEDED_CXXFLAGS = -std=c++11
include filelist.mk
INCFLAGS = -I/usr/include/ -I/usr/local/include/ INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib 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 LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =

View File

@@ -1,43 +1,43 @@
CXXFLAGS = -g -Wall CXXFLAGS = -g -Wall -fPIC
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
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
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 = INCFLAGS =
ifeq ($(STATIC),yes)
LDLIBS += $(LIBDIR)/libcryptopp.a $(LIBDIR)/libboost_system.a # detect proper flag for c++11 support by gcc
LDLIBS += $(LIBDIR)/libboost_date_time.a $(LIBDIR)/libboost_filesystem.a CXXVER := $(shell $(CXX) -dumpversion)
LDLIBS += $(LIBDIR)/libboost_regex.a $(LIBDIR)/libboost_program_options.a ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # >= 4.10
LDLIBS += -lpthread -static-libstdc++ -static-libgcc CXXFLAGS += -std=c++11
USE_AESNI := no else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
else CXXFLAGS += -std=c++11
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
CXXFLAGS += -std=c++0x
else ifeq ($(shell expr match $(CXX) 'clang'),5)
CXXFLAGS += -std=c++11
else # not supported
$(error Compiler too old)
endif endif
LIBS =
ifeq ($(USE_STATIC),yes)
LIBDIR := /usr/lib
LDLIBS = $(LIBDIR)/libboost_system.a
LDLIBS += $(LIBDIR)/libboost_date_time.a
LDLIBS += $(LIBDIR)/libboost_filesystem.a
LDLIBS += $(LIBDIR)/libboost_regex.a
LDLIBS += $(LIBDIR)/libboost_program_options.a
LDLIBS += $(LIBDIR)/libcryptopp.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
GREP = fgrep
IS_64 := $(shell $(CXX) -dumpmachine 2>&1 | $(GREP) -c "64")
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
ifeq ($(IS_64),1) ifeq ($(IS_64),1)
#check if AES-NI is supported by CPU #check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0) ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
CPU_FLAGS = -maes -DAESNI CXXFLAGS += -maes -DAESNI
else
$(warning "AESNI support enabled requested but not supported by this CPU")
endif endif
endif endif
endif endif

View File

@@ -1,18 +1,17 @@
CXX = clang++ CXX = clang++
CXXFLAGS = -g -Wall -std=c++11 -lstdc++ -I/usr/local/include CXXFLAGS = -g -Wall -std=c++11 -lstdc++ -DCRYPTOPP_DISABLE_ASM
include filelist.mk INCFLAGS = -I/usr/local/include
INCFLAGS = -DCRYPTOPP_DISABLE_ASM
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib 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 LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =
# OSX Notes # OSX Notes
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html # 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 # 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 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
CXXFLAGS += -maes -DAESNI ifeq ($(USE_AESNI),yes)
CXXFLAGS += -maes -DAESNI
# Apple Mac OSX
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
endif endif
install: all
mkdir -p ${PREFIX}/
cp -r i2p ${PREFIX}/

View File

@@ -1,7 +1,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include <boost/bind.hpp>
#include <cryptopp/dh.h> #include <cryptopp/dh.h>
#include "base64.h" #include "base64.h"
#include "Log.h" #include "Log.h"
@@ -19,7 +18,7 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
NTCPSession::NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter): NTCPSession::NTCPSession (boost::asio::io_service& service, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
TransportSession (in_RemoteRouter), m_Socket (service), TransportSession (in_RemoteRouter), m_Socket (service),
m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0), m_TerminationTimer (service), m_IsEstablished (false), m_ReceiveBufferOffset (0),
m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0) m_NextMessage (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0)
@@ -44,7 +43,7 @@ namespace transport
uint8_t sharedKey[256]; uint8_t sharedKey[256];
if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey))
{ {
LogPrint ("Couldn't create shared key"); LogPrint (eLogError, "Couldn't create shared key");
Terminate (); Terminate ();
return; return;
}; };
@@ -66,7 +65,7 @@ namespace transport
nonZero++; nonZero++;
if (nonZero - sharedKey > 32) if (nonZero - sharedKey > 32)
{ {
LogPrint ("First 32 bytes of shared key is all zeros. Ignored"); LogPrint (eLogWarning, "First 32 bytes of shared key is all zeros. Ignored");
return; return;
} }
} }
@@ -78,7 +77,6 @@ namespace transport
{ {
m_IsEstablished = false; m_IsEstablished = false;
m_Socket.close (); m_Socket.close ();
transports.RemoveNTCPSession (this);
int numDelayed = 0; int numDelayed = 0;
for (auto it :m_DelayedMessages) for (auto it :m_DelayedMessages)
{ {
@@ -89,16 +87,14 @@ namespace transport
} }
m_DelayedMessages.clear (); m_DelayedMessages.clear ();
if (numDelayed > 0) if (numDelayed > 0)
LogPrint ("NTCP session ", numDelayed, " not sent"); LogPrint (eLogWarning, "NTCP session ", numDelayed, " not sent");
// TODO: notify tunnels // TODO: notify tunnels
transports.RemoveNTCPSession (shared_from_this ());
delete this;
LogPrint ("NTCP session terminated"); LogPrint ("NTCP session terminated");
} }
void NTCPSession::Connected () void NTCPSession::Connected ()
{ {
LogPrint ("NTCP session connected");
m_IsEstablished = true; m_IsEstablished = true;
delete m_Establisher; delete m_Establisher;
@@ -131,31 +127,31 @@ namespace transport
m_Establisher->phase1.HXxorHI[i] ^= ident[i]; m_Establisher->phase1.HXxorHI[i] ^= ident[i];
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase1Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::bind(&NTCPSession::HandlePhase1Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
void NTCPSession::ServerLogin () void NTCPSession::ServerLogin ()
{ {
// receive Phase1 // receive Phase1
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase1, sizeof (NTCPPhase1)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase1Received, this, std::bind(&NTCPSession::HandlePhase1Received, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void NTCPSession::HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred) void NTCPSession::HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 1 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 1 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 1 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 1 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase2Received, this, std::bind(&NTCPSession::HandlePhase2Received, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
} }
@@ -163,13 +159,13 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 1 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 1 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 1 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 1 received: ", bytes_transferred);
// verify ident // verify ident
uint8_t digest[32]; uint8_t digest[32];
CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256); CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256);
@@ -178,7 +174,7 @@ namespace transport
{ {
if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i]) if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
{ {
LogPrint ("Wrong ident"); LogPrint (eLogError, "Wrong ident");
Terminate (); Terminate ();
return; return;
} }
@@ -211,7 +207,7 @@ namespace transport
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted); m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase2Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB)); std::bind(&NTCPSession::HandlePhase2Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsB));
} }
@@ -219,16 +215,16 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 2 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 2 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 2 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 2 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, NTCP_DEFAULT_PHASE3_SIZE), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3Received, this, std::bind(&NTCPSession::HandlePhase3Received, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB)); std::placeholders::_1, std::placeholders::_2, tsB));
} }
} }
@@ -248,7 +244,7 @@ namespace transport
} }
else else
{ {
LogPrint ("Phase 2 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 2 received: ", bytes_transferred);
i2p::crypto::AESKey aesKey; i2p::crypto::AESKey aesKey;
CreateAESKey (m_Establisher->phase2.pubKey, aesKey); CreateAESKey (m_Establisher->phase2.pubKey, aesKey);
@@ -265,7 +261,7 @@ namespace transport
CryptoPP::SHA256().CalculateDigest(hxy, xy, 512); CryptoPP::SHA256().CalculateDigest(hxy, xy, 512);
if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32)) if (memcmp (hxy, m_Establisher->phase2.encrypted.hxy, 32))
{ {
LogPrint ("Incorrect hash"); LogPrint (eLogError, "Incorrect hash");
transports.ReuseDHKeysPair (m_DHKeysPair); transports.ReuseDHKeysPair (m_DHKeysPair);
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
Terminate (); Terminate ();
@@ -277,39 +273,56 @@ namespace transport
void NTCPSession::SendPhase3 () void NTCPSession::SendPhase3 ()
{ {
m_Establisher->phase3.size = htons (i2p::data::DEFAULT_IDENTITY_SIZE); auto keys = i2p::context.GetPrivateKeys ();
memcpy (&m_Establisher->phase3.ident, &i2p::context.GetIdentity ().GetStandardIdentity (), i2p::data::DEFAULT_IDENTITY_SIZE); // TODO: uint8_t * buf = m_ReceiveBuffer;
*(uint16_t *)buf = htobe16 (keys.GetPublic ().GetFullLen ());
buf += 2;
buf += i2p::context.GetIdentity ().ToBuffer (buf, NTCP_BUFFER_SIZE);
uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ()); uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ());
m_Establisher->phase3.timestamp = tsA; *(uint32_t *)buf = tsA;
buf += 4;
size_t signatureLen = keys.GetPublic ().GetSignatureLen ();
size_t len = (buf - m_ReceiveBuffer) + signatureLen;
size_t paddingSize = len & 0x0F; // %16
if (paddingSize > 0)
{
paddingSize = 16 - paddingSize;
// TODO: fill padding with random data
buf += paddingSize;
len += paddingSize;
}
SignedData s; SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (tsA); // tsA s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase3.signature); s.Sign (keys, buf);
m_Encryption.Encrypt((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, len), boost::asio::transfer_all (),
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase3, sizeof (NTCPPhase3)), boost::asio::transfer_all (), std::bind(&NTCPSession::HandlePhase3Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsA));
boost::bind(&NTCPSession::HandlePhase3Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA));
} }
void NTCPSession::HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA) void NTCPSession::HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA)
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 3 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 3 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 3 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 3 sent: ", bytes_transferred);
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (), // wait for phase4
boost::bind(&NTCPSession::HandlePhase4Received, this, auto signatureLen = m_RemoteIdentity.GetSignatureLen ();
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA)); size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) signatureLen += (16 - paddingSize);
boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
std::bind(&NTCPSession::HandlePhase4Received, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, tsA));
} }
} }
@@ -317,59 +330,106 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 3 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 3 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 3 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 3 received: ", bytes_transferred);
m_Decryption.Decrypt ((uint8_t *)&m_Establisher->phase3, sizeof(NTCPPhase3), (uint8_t *)&m_Establisher->phase3); m_Decryption.Decrypt (m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
m_RemoteIdentity = m_Establisher->phase3.ident; uint8_t * buf = m_ReceiveBuffer;
uint16_t size = be16toh (*(uint16_t *)buf);
SignedData s; m_RemoteIdentity.FromBuffer (buf + 2, size);
s.Insert (m_Establisher->phase1.pubKey, 256); // x size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity.GetSignatureLen ();
s.Insert (m_Establisher->phase2.pubKey, 256); // y size_t paddingLen = expectedSize & 0x0F;
s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident if (paddingLen) paddingLen = (16 - paddingLen);
s.Insert (m_Establisher->phase3.timestamp); // tsA if (expectedSize > NTCP_DEFAULT_PHASE3_SIZE)
s.Insert (tsB); // tsB {
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase3.signature)) // we need more bytes for Phase3
{ expectedSize += paddingLen;
LogPrint ("signature verification failed"); LogPrint (eLogDebug, "Wait for ", expectedSize, " more bytes for Phase3");
Terminate (); boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, expectedSize), boost::asio::transfer_all (),
return; std::bind(&NTCPSession::HandlePhase3ExtraReceived, shared_from_this (),
} std::placeholders::_1, std::placeholders::_2, tsB, paddingLen));
}
SendPhase4 (tsB); else
HandlePhase3 (tsB, paddingLen);
} }
} }
void NTCPSession::SendPhase4 (uint32_t tsB) void NTCPSession::HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen)
{
if (ecode)
{
LogPrint (eLogError, "Phase 3 extra read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
}
else
{
LogPrint (eLogDebug, "Phase 3 extra received: ", bytes_transferred);
m_Decryption.Decrypt (m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, bytes_transferred, m_ReceiveBuffer+ NTCP_DEFAULT_PHASE3_SIZE);
HandlePhase3 (tsB, paddingLen);
}
}
void NTCPSession::HandlePhase3 (uint32_t tsB, size_t paddingLen)
{
uint8_t * buf = m_ReceiveBuffer + m_RemoteIdentity.GetFullLen () + 2 /*size*/;
uint32_t tsA = *(uint32_t *)buf;
buf += 4;
buf += paddingLen;
SignedData s;
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 (tsB); // tsB
if (!s.Verify (m_RemoteIdentity, buf))
{
LogPrint (eLogError, "signature verification failed");
Terminate ();
return;
}
SendPhase4 (tsA, tsB);
}
void NTCPSession::SendPhase4 (uint32_t tsA, uint32_t tsB)
{ {
SignedData s; SignedData s;
s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase1.pubKey, 256); // x
s.Insert (m_Establisher->phase2.pubKey, 256); // y s.Insert (m_Establisher->phase2.pubKey, 256); // y
s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident
s.Insert (m_Establisher->phase3.timestamp); // tsA s.Insert (tsA); // tsA
s.Insert (tsB); // tsB s.Insert (tsB); // tsB
s.Sign (i2p::context.GetPrivateKeys (), m_Establisher->phase4.signature); auto keys = i2p::context.GetPrivateKeys ();
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4); auto signatureLen = keys.GetPublic ().GetSignatureLen ();
s.Sign (keys, m_ReceiveBuffer);
size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) signatureLen += (16 - paddingSize);
m_Encryption.Encrypt (m_ReceiveBuffer, signatureLen, m_ReceiveBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase4, sizeof (NTCPPhase4)), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase4Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::bind(&NTCPSession::HandlePhase4Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
void NTCPSession::HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred) void NTCPSession::HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send Phase 4 message: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send Phase 4 message: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
LogPrint ("Phase 4 sent: ", bytes_transferred); LogPrint (eLogDebug, "Phase 4 sent: ", bytes_transferred);
LogPrint ("NTCP server session connected");
transports.AddNTCPSession (shared_from_this ());
Connected (); Connected ();
m_ReceiveBufferOffset = 0; m_ReceiveBufferOffset = 0;
m_NextMessage = nullptr; m_NextMessage = nullptr;
@@ -381,7 +441,7 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Phase 4 read error: ", ecode.message ()); LogPrint (eLogError, "Phase 4 read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
// this router doesn't like us // this router doesn't like us
@@ -391,8 +451,8 @@ namespace transport
} }
else else
{ {
LogPrint ("Phase 4 received: ", bytes_transferred); LogPrint (eLogDebug, "Phase 4 received: ", bytes_transferred);
m_Decryption.Decrypt((uint8_t *)&m_Establisher->phase4, sizeof(NTCPPhase4), (uint8_t *)&m_Establisher->phase4); m_Decryption.Decrypt(m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer);
// verify signature // verify signature
SignedData s; SignedData s;
@@ -402,12 +462,13 @@ namespace transport
s.Insert (tsA); // tsA s.Insert (tsA); // tsA
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
if (!s.Verify (m_RemoteIdentity, m_Establisher->phase4.signature)) if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
{ {
LogPrint ("signature verification failed"); LogPrint (eLogError, "signature verification failed");
Terminate (); Terminate ();
return; return;
} }
LogPrint ("NTCP session connected");
Connected (); Connected ();
m_ReceiveBufferOffset = 0; m_ReceiveBufferOffset = 0;
@@ -419,15 +480,15 @@ namespace transport
void NTCPSession::Receive () void NTCPSession::Receive ()
{ {
m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, NTCP_BUFFER_SIZE - m_ReceiveBufferOffset), m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, NTCP_BUFFER_SIZE - m_ReceiveBufferOffset),
boost::bind(&NTCPSession::HandleReceived, this, std::bind(&NTCPSession::HandleReceived, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if (ecode) if (ecode)
{ {
LogPrint ("Read error: ", ecode.message ()); LogPrint (eLogError, "Read error: ", ecode.message ());
//if (ecode != boost::asio::error::operation_aborted) //if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
@@ -472,7 +533,7 @@ namespace transport
// new message // new message
if (dataSize > NTCP_MAX_MESSAGE_SIZE) if (dataSize > NTCP_MAX_MESSAGE_SIZE)
{ {
LogPrint ("NTCP data size ", dataSize, " exceeds max size"); LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size");
i2p::DeleteI2NPMessage (m_NextMessage); i2p::DeleteI2NPMessage (m_NextMessage);
m_NextMessage = nullptr; m_NextMessage = nullptr;
return false; return false;
@@ -515,7 +576,7 @@ namespace transport
// regular I2NP // regular I2NP
if (msg->offset < 2) if (msg->offset < 2)
{ {
LogPrint ("Malformed I2NP message"); LogPrint (eLogError, "Malformed I2NP message");
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
} }
sendBuffer = msg->GetBuffer () - 2; sendBuffer = msg->GetBuffer () - 2;
@@ -540,7 +601,7 @@ namespace transport
m_Encryption.Encrypt(sendBuffer, l, sendBuffer); m_Encryption.Encrypt(sendBuffer, l, sendBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (sendBuffer, l), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (sendBuffer, l), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandleSent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, msg)); std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msg));
} }
void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, i2p::I2NPMessage * msg) void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, i2p::I2NPMessage * msg)
@@ -549,7 +610,7 @@ namespace transport
i2p::DeleteI2NPMessage (msg); i2p::DeleteI2NPMessage (msg);
if (ecode) if (ecode)
{ {
LogPrint ("Couldn't send msg: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send msg: ", ecode.message ());
// we shouldn't call Terminate () here, because HandleReceive takes care // we shouldn't call Terminate () here, because HandleReceive takes care
// TODO: 'delete this' statement in Terminate () must be eliminated later // TODO: 'delete this' statement in Terminate () must be eliminated later
// Terminate (); // Terminate ();
@@ -581,8 +642,8 @@ namespace transport
{ {
m_TerminationTimer.cancel (); m_TerminationTimer.cancel ();
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT)); m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP_TERMINATION_TIMEOUT));
m_TerminationTimer.async_wait (boost::bind (&NTCPSession::HandleTerminationTimer, m_TerminationTimer.async_wait (std::bind (&NTCPSession::HandleTerminationTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void NTCPSession::HandleTerminationTimer (const boost::system::error_code& ecode) void NTCPSession::HandleTerminationTimer (const boost::system::error_code& ecode)
@@ -594,47 +655,5 @@ namespace transport
m_Socket.close ();// invoke Terminate () from HandleReceive m_Socket.close ();// invoke Terminate () from HandleReceive
} }
} }
NTCPClient::NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address,
int port, const i2p::data::RouterInfo& in_RouterInfo):
NTCPSession (service, &in_RouterInfo), m_Endpoint (address, port)
{
Connect ();
}
void NTCPClient::Connect ()
{
LogPrint ("Connecting to ", m_Endpoint.address ().to_string (),":", m_Endpoint.port ());
GetSocket ().async_connect (m_Endpoint, boost::bind (&NTCPClient::HandleConnect,
this, boost::asio::placeholders::error));
}
void NTCPClient::HandleConnect (const boost::system::error_code& ecode)
{
if (ecode)
{
LogPrint ("Connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
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 ();
}
}
void NTCPServerConnection::Connected ()
{
LogPrint ("NTCP server session connected");
transports.AddNTCPSession (this);
NTCPSession::Connected ();
}
} }
} }

View File

@@ -3,7 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <list> #include <list>
#include <boost/asio.hpp> #include <memory>
#include <cryptopp/modes.h> #include <cryptopp/modes.h>
#include <cryptopp/aes.h> #include <cryptopp/aes.h>
#include <cryptopp/adler32.h> #include <cryptopp/adler32.h>
@@ -35,35 +35,21 @@ namespace transport
uint8_t filler[12]; uint8_t filler[12];
} encrypted; } encrypted;
}; };
struct NTCPPhase3
{
uint16_t size;
i2p::data::Identity ident;
uint32_t timestamp;
uint8_t padding[15];
uint8_t signature[40];
};
struct NTCPPhase4
{
uint8_t signature[40];
uint8_t padding[8];
};
#pragma pack() #pragma pack()
const size_t NTCP_MAX_MESSAGE_SIZE = 16384; const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028) const size_t NTCP_BUFFER_SIZE = 1040; // fits one tunnel message (1028)
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448
class NTCPSession: public TransportSession class NTCPSession: public TransportSession, public std::enable_shared_from_this<NTCPSession>
{ {
public: public:
NTCPSession (boost::asio::io_service& service, const i2p::data::RouterInfo * in_RemoteRouter = nullptr); NTCPSession (boost::asio::io_service& service, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
~NTCPSession (); ~NTCPSession ();
void Terminate ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
bool IsEstablished () const { return m_IsEstablished; }; bool IsEstablished () const { return m_IsEstablished; };
@@ -77,8 +63,7 @@ namespace transport
protected: protected:
void Terminate (); void Connected ();
virtual void Connected ();
void SendTimeSyncMessage (); void SendTimeSyncMessage ();
void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; } void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; }
@@ -95,10 +80,12 @@ namespace transport
//server //server
void SendPhase2 (); void SendPhase2 ();
void SendPhase4 (uint32_t tsB); void SendPhase4 (uint32_t tsA, uint32_t tsB);
void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB); void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
void HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB); void HandlePhase3Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
void HandlePhase3ExtraReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB, size_t paddingLen);
void HandlePhase3 (uint32_t tsB, size_t paddingLen);
void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandlePhase4Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
// common // common
@@ -128,11 +115,10 @@ namespace transport
{ {
NTCPPhase1 phase1; NTCPPhase1 phase1;
NTCPPhase2 phase2; NTCPPhase2 phase2;
NTCPPhase3 phase3;
NTCPPhase4 phase4;
} * m_Establisher; } * m_Establisher;
uint8_t m_ReceiveBuffer[NTCP_BUFFER_SIZE + 16], m_TimeSyncBuffer[16]; i2p::crypto::AESAlignedBuffer<NTCP_BUFFER_SIZE + 16> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
int m_ReceiveBufferOffset; int m_ReceiveBufferOffset;
i2p::I2NPMessage * m_NextMessage; i2p::I2NPMessage * m_NextMessage;
@@ -141,34 +127,6 @@ namespace transport
size_t m_NumSentBytes, m_NumReceivedBytes; size_t m_NumSentBytes, m_NumReceivedBytes;
}; };
class NTCPClient: public NTCPSession
{
public:
NTCPClient (boost::asio::io_service& service, const boost::asio::ip::address& address, int port, const i2p::data::RouterInfo& in_RouterInfo);
private:
void Connect ();
void HandleConnect (const boost::system::error_code& ecode);
private:
boost::asio::ip::tcp::endpoint m_Endpoint;
};
class NTCPServerConnection: public NTCPSession
{
public:
NTCPServerConnection (boost::asio::io_service& service):
NTCPSession (service) {};
protected:
virtual void Connected ();
};
} }
} }

130
NetDb.cpp
View File

@@ -21,7 +21,7 @@ namespace i2p
{ {
namespace data namespace data
{ {
I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router, I2NPMessage * RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
const i2p::tunnel::InboundTunnel * replyTunnel) const i2p::tunnel::InboundTunnel * replyTunnel)
{ {
I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination,
@@ -29,8 +29,8 @@ namespace data
&m_ExcludedPeers, m_IsLeaseSet, m_Pool); &m_ExcludedPeers, m_IsLeaseSet, m_Pool);
if (m_IsLeaseSet) // wrap lookup message into garlic if (m_IsLeaseSet) // wrap lookup message into garlic
{ {
if (m_Pool) if (m_Pool && m_Pool->GetLocalDestination ())
msg = m_Pool->GetGarlicDestination ().WrapMessage (*router, msg); msg = m_Pool->GetLocalDestination ()->WrapMessage (*router, msg);
else else
LogPrint ("Can't create garlic message without destination"); LogPrint ("Can't create garlic message without destination");
} }
@@ -62,7 +62,7 @@ namespace data
#endif #endif
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_ReseedRetries (0), m_Thread (0) NetDb::NetDb (): m_IsRunning (false), m_Thread (0)
{ {
} }
@@ -78,12 +78,27 @@ namespace data
void NetDb::Start () void NetDb::Start ()
{ {
Load (m_NetDbPath); Load (m_NetDbPath);
while (m_RouterInfos.size () < 100 && m_ReseedRetries < 10) if (m_RouterInfos.size () < 100) // reseed if # of router less than 100
{ {
Reseeder reseeder; Reseeder reseeder;
reseeder.reseedNow(); reseeder.LoadCertificates (); // we need certificates for SU3 verification
m_ReseedRetries++;
Load (m_NetDbPath); // try SU3 first
int reseedRetries = 0;
while (m_RouterInfos.size () < 100 && reseedRetries < 10)
{
reseeder.ReseedNowSU3();
reseedRetries++;
}
// if still not enough download .dat files
reseedRetries = 0;
while (m_RouterInfos.size () < 100 && reseedRetries < 10)
{
reseeder.reseedNow();
reseedRetries++;
Load (m_NetDbPath);
}
} }
m_Thread = new std::thread (std::bind (&NetDb::Run, this)); m_Thread = new std::thread (std::bind (&NetDb::Run, this));
} }
@@ -165,26 +180,36 @@ namespace data
} }
} }
void NetDb::AddRouterInfo (const uint8_t * buf, int len)
{
IdentityEx identity;
if (identity.FromBuffer (buf, len))
AddRouterInfo (identity.GetIdentHash (), buf, len);
}
void NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) void NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
{ {
DeleteRequestedDestination (ident); DeleteRequestedDestination (ident);
auto it = m_RouterInfos.find(ident); auto r = FindRouter (ident);
if (it != m_RouterInfos.end ()) if (r)
{ {
auto ts = it->second->GetTimestamp (); auto ts = r->GetTimestamp ();
it->second->Update (buf, len); r->Update (buf, len);
if (it->second->GetTimestamp () > ts) if (r->GetTimestamp () > ts)
LogPrint ("RouterInfo updated"); LogPrint ("RouterInfo updated");
} }
else else
{ {
LogPrint ("New RouterInfo added"); LogPrint ("New RouterInfo added");
auto r = std::make_shared<RouterInfo> (buf, len); auto newRouter = std::make_shared<RouterInfo> (buf, len);
m_RouterInfos[r->GetIdentHash ()] = r; {
if (r->IsFloodfill ()) std::unique_lock<std::mutex> l(m_RouterInfosMutex);
m_RouterInfos[newRouter->GetIdentHash ()] = newRouter;
}
if (newRouter->IsFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.push_back (newRouter);
} }
} }
} }
@@ -209,11 +234,12 @@ namespace data
} }
} }
RouterInfo * NetDb::FindRouter (const IdentHash& ident) const std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
{ {
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
auto it = m_RouterInfos.find (ident); auto it = m_RouterInfos.find (ident);
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
return it->second.get (); return it->second;
else else
return nullptr; return nullptr;
} }
@@ -354,18 +380,36 @@ namespace data
if (it.second->IsUnreachable ()) if (it.second->IsUnreachable ())
{ {
// delete RI file
if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ()))) if (boost::filesystem::exists (GetFilePath (fullDirectory, it.second.get ())))
{ {
boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ())); boost::filesystem::remove (GetFilePath (fullDirectory, it.second.get ()));
deletedCount++; deletedCount++;
} }
// delete from floodfills list
if (it.second->IsFloodfill ())
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.remove (it.second);
}
} }
} }
} }
if (count > 0) if (count > 0)
LogPrint (count," new/updated routers saved"); LogPrint (count," new/updated routers saved");
if (deletedCount > 0) if (deletedCount > 0)
{
LogPrint (deletedCount," routers deleted"); LogPrint (deletedCount," routers deleted");
// clean up RouterInfos table
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{
if (it->second->IsUnreachable ())
it = m_RouterInfos.erase (it);
else
it++;
}
}
} }
void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet, i2p::tunnel::TunnelPool * pool) void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet, i2p::tunnel::TunnelPool * pool)
@@ -611,7 +655,7 @@ namespace data
LogPrint ("Requested RouterInfo ", key, " found"); LogPrint ("Requested RouterInfo ", key, " found");
router->LoadBuffer (); router->LoadBuffer ();
if (router->GetBuffer ()) if (router->GetBuffer ())
replyMsg = CreateDatabaseStoreMsg (router); replyMsg = CreateDatabaseStoreMsg (router.get ());
} }
} }
if (!replyMsg) if (!replyMsg)
@@ -633,7 +677,7 @@ namespace data
excludedRouters.insert (excluded); excludedRouters.insert (excluded);
excluded += 32; excluded += 32;
} }
replyMsg = CreateDatabaseSearchReply (buf, GetClosestFloodfill (buf, excludedRouters)); replyMsg = CreateDatabaseSearchReply (buf, GetClosestFloodfill (buf, excludedRouters).get ());
} }
else else
excluded += numExcluded*32; // we don't care about exluded excluded += numExcluded*32; // we don't care about exluded
@@ -697,9 +741,9 @@ namespace data
rnd.GenerateBlock (randomHash, 32); rnd.GenerateBlock (randomHash, 32);
RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true, exploratoryPool); RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true, exploratoryPool);
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill && !floodfills.count (floodfill)) // request floodfill only once if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once
{ {
floodfills.insert (floodfill); floodfills.insert (floodfill.get ());
if (throughTunnels) if (throughTunnels)
{ {
msgs.push_back (i2p::tunnel::TunnelMessageBlock msgs.push_back (i2p::tunnel::TunnelMessageBlock
@@ -787,22 +831,22 @@ namespace data
}); });
} }
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (const RouterInfo * compatibleWith) const std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const
{ {
return GetRandomRouter ( return GetRandomRouter (
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router.get () != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
router->IsCompatible (*compatibleWith); router->IsCompatible (*compatibleWith);
}); });
} }
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const
{ {
return GetRandomRouter ( return GetRandomRouter (
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router.get () != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth); router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth);
}); });
} }
@@ -815,6 +859,7 @@ namespace data
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
uint32_t i = 0; uint32_t i = 0;
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
for (auto it: m_RouterInfos) for (auto it: m_RouterInfos)
{ {
if (i >= ind) if (i >= ind)
@@ -836,10 +881,10 @@ namespace data
if (msg) m_Queue.Put (msg); if (msg) m_Queue.Put (msg);
} }
const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const const std::set<IdentHash>& excluded) const
{ {
RouterInfo * r = nullptr; std::shared_ptr<const RouterInfo> r;
XORMetric minMetric; XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
minMetric.SetMax (); minMetric.SetMax ();
@@ -852,7 +897,7 @@ namespace data
if (m < minMetric) if (m < minMetric)
{ {
minMetric = m; minMetric = m;
r = it.get (); r = it;
} }
} }
} }
@@ -873,26 +918,5 @@ namespace data
it++; it++;
} }
} }
void NetDb::PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool)
{
if (!leaseSet || !pool) return;
auto outbound = pool->GetNextOutboundTunnel ();
if (!outbound)
{
LogPrint ("Can't publish LeaseSet. No outbound tunnels");
return;
}
std::set<IdentHash> excluded;
auto floodfill = GetClosestFloodfill (leaseSet->GetIdentHash (), excluded);
if (!floodfill)
{
LogPrint ("Can't publish LeaseSet. No floodfills found");
return;
}
uint32_t replyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
auto msg = pool->GetGarlicDestination ().WrapMessage (*floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, replyToken));
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
}
} }
} }

24
NetDb.h
View File

@@ -4,7 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <map> #include <map>
#include <vector> #include <list>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@@ -27,19 +27,19 @@ namespace data
RequestedDestination (const IdentHash& destination, bool isLeaseSet, RequestedDestination (const IdentHash& destination, bool isLeaseSet,
bool isExploratory = false, i2p::tunnel::TunnelPool * pool = nullptr): bool isExploratory = false, i2p::tunnel::TunnelPool * pool = nullptr):
m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory), m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory),
m_Pool (pool), m_LastRouter (nullptr), m_CreationTime (0) {}; m_Pool (pool), m_CreationTime (0) {};
const IdentHash& GetDestination () const { return m_Destination; }; const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; }; const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
void ClearExcludedPeers (); void ClearExcludedPeers ();
const RouterInfo * GetLastRouter () const { return m_LastRouter; }; std::shared_ptr<const RouterInfo> GetLastRouter () const { return m_LastRouter; };
i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; }; i2p::tunnel::TunnelPool * GetTunnelPool () { return m_Pool; };
bool IsExploratory () const { return m_IsExploratory; }; bool IsExploratory () const { return m_IsExploratory; };
bool IsLeaseSet () const { return m_IsLeaseSet; }; bool IsLeaseSet () const { return m_IsLeaseSet; };
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
uint64_t GetCreationTime () const { return m_CreationTime; }; uint64_t GetCreationTime () const { return m_CreationTime; };
I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel); I2NPMessage * CreateRequestMessage (std::shared_ptr<const RouterInfo>, const i2p::tunnel::InboundTunnel * replyTunnel);
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill); I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
private: private:
@@ -48,7 +48,7 @@ namespace data
bool m_IsLeaseSet, m_IsExploratory; bool m_IsLeaseSet, m_IsExploratory;
i2p::tunnel::TunnelPool * m_Pool; i2p::tunnel::TunnelPool * m_Pool;
std::set<IdentHash> m_ExcludedPeers; std::set<IdentHash> m_ExcludedPeers;
const RouterInfo * m_LastRouter; std::shared_ptr<const RouterInfo> m_LastRouter;
uint64_t m_CreationTime; uint64_t m_CreationTime;
}; };
@@ -62,12 +62,12 @@ namespace data
void Start (); void Start ();
void Stop (); void Stop ();
void AddRouterInfo (const uint8_t * buf, int len);
void AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len); void AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from); void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, i2p::tunnel::InboundTunnel * from);
RouterInfo * FindRouter (const IdentHash& ident) const; std::shared_ptr<RouterInfo> FindRouter (const IdentHash& ident) const;
LeaseSet * FindLeaseSet (const IdentHash& destination) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const;
void PublishLeaseSet (const LeaseSet * leaseSet, i2p::tunnel::TunnelPool * pool);
void RequestDestination (const IdentHash& destination, bool isLeaseSet = false, void RequestDestination (const IdentHash& destination, bool isLeaseSet = false,
i2p::tunnel::TunnelPool * pool = nullptr); i2p::tunnel::TunnelPool * pool = nullptr);
@@ -76,8 +76,9 @@ namespace data
void HandleDatabaseLookupMsg (I2NPMessage * msg); void HandleDatabaseLookupMsg (I2NPMessage * msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (const RouterInfo * compatibleWith) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (const RouterInfo * compatibleWith) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (I2NPMessage * msg); void PostI2NPMsg (I2NPMessage * msg);
@@ -95,7 +96,6 @@ namespace data
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish (); void Publish ();
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
void ManageLeaseSets (); void ManageLeaseSets ();
RequestedDestination * CreateRequestedDestination (const IdentHash& dest, RequestedDestination * CreateRequestedDestination (const IdentHash& dest,
@@ -109,14 +109,14 @@ namespace data
private: private:
std::map<IdentHash, LeaseSet *> m_LeaseSets; std::map<IdentHash, LeaseSet *> m_LeaseSets;
mutable std::mutex m_RouterInfosMutex;
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos; std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
std::vector<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
std::mutex m_RequestedDestinationsMutex; std::mutex m_RequestedDestinationsMutex;
std::map<IdentHash, RequestedDestination *> m_RequestedDestinations; std::map<IdentHash, RequestedDestination *> m_RequestedDestinations;
bool m_IsRunning; bool m_IsRunning;
int m_ReseedRetries;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg

View File

@@ -142,8 +142,8 @@ namespace util
private: private:
volatile bool m_IsRunning; volatile bool m_IsRunning;
std::thread m_Thread;
OnEmpty m_OnEmpty; OnEmpty m_OnEmpty;
std::thread m_Thread;
}; };
} }
} }

View File

@@ -48,8 +48,8 @@ This should resulting in for example:
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p
Options Cmdline options
------- ---------------
* --host= - The external IP * --host= - The external IP
* --port= - The port to listen on * --port= - The port to listen on
@@ -64,8 +64,22 @@ Options
* --ircport= - The local port of IRC tunnel to listen on. 6668 by default * --ircport= - The local port of IRC tunnel to listen on. 6668 by default
* --ircdest= - I2P destination address of IRC server. For example irc.postman.i2p * --ircdest= - I2P destination address of IRC server. For example irc.postman.i2p
* --irckeys= - optional keys file for local destination * --irckeys= - optional keys file for local destination
* --eepkeys= - File name containing destination keys. For example privKeys.dat * --eepkeys= - File name containing destination keys, for example privKeys.dat.
The file will be created if it does not already exist (issue #110).
* --eephost= - Address incoming trafic forward to. 127.0.0.1 by default * --eephost= - Address incoming trafic forward to. 127.0.0.1 by default
* --eepport= - Port incoming trafic forward to. 80 by default * --eepport= - Port incoming trafic forward to. 80 by default
* --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified * --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified
* --bobport= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)
This parameter will be silently ignored if the specified config file does not exist.
Options specified on the command line take precedence over those in the config file.
Config file
-----------
INI-like, syntax is the following : <key> = <value>.
All command-line parameters are allowed as keys, for example:
log = 1
v6 = 0
ircdest = irc.postman.i2p

View File

@@ -1,11 +1,19 @@
#include <iostream> #include <string.h>
#include <fstream> #include <fstream>
#include <sstream>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <cryptopp/gzip.h> #include <cryptopp/osrng.h>
#include <cryptopp/asn.h>
#include <cryptopp/base64.h>
#include <cryptopp/crc.h>
#include <cryptopp/zinflate.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Reseed.h" #include "Reseed.h"
#include "Log.h" #include "Log.h"
#include "Identity.h"
#include "CryptoConst.h"
#include "NetDb.h"
#include "util.h" #include "util.h"
@@ -121,59 +129,374 @@ namespace data
return false; return false;
} }
void ProcessSU3File (const char * filename) int Reseeder::ReseedNowSU3 ()
{ {
static uint32_t headerSignature = htole32 (0x04044B50); CryptoPP::AutoSeededRandomPool rnd;
auto ind = rnd.GenerateWord32 (0, httpReseedHostList.size() - 1);
std::string reseedHost = httpReseedHostList[ind];
return ReseedFromSU3 (reseedHost);
}
int Reseeder::ReseedFromSU3 (const std::string& host)
{
std::string url = host + "i2pseeds.su3";
LogPrint (eLogInfo, "Dowloading SU3 from ", host);
std::string su3 = i2p::util::http::httpRequest (url);
if (su3.length () > 0)
{
std::stringstream s(su3);
return ProcessSU3Stream (s);
}
else
{
LogPrint (eLogWarning, "SU3 download failed");
return 0;
}
}
int Reseeder::ProcessSU3File (const char * filename)
{
std::ifstream s(filename, std::ifstream::binary); std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
{ return ProcessSU3Stream (s);
while (!s.eof ()) else
{
LogPrint (eLogError, "Can't open file ", filename);
return 0;
}
}
const char SU3_MAGIC_NUMBER[]="I2Psu3";
const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50;
const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008;
int Reseeder::ProcessSU3Stream (std::istream& s)
{
char magicNumber[7];
s.read (magicNumber, 7); // magic number and zero byte 6
if (strcmp (magicNumber, SU3_MAGIC_NUMBER))
{
LogPrint (eLogError, "Unexpected SU3 magic number");
return 0;
}
s.seekg (1, std::ios::cur); // su3 file format version
SigningKeyType signatureType;
s.read ((char *)&signatureType, 2); // signature type
signatureType = be16toh (signatureType);
uint16_t signatureLength;
s.read ((char *)&signatureLength, 2); // signature length
signatureLength = be16toh (signatureLength);
s.seekg (1, std::ios::cur); // unused
uint8_t versionLength;
s.read ((char *)&versionLength, 1); // version length
s.seekg (1, std::ios::cur); // unused
uint8_t signerIDLength;
s.read ((char *)&signerIDLength, 1); // signer ID length
uint64_t contentLength;
s.read ((char *)&contentLength, 8); // content length
contentLength = be64toh (contentLength);
s.seekg (1, std::ios::cur); // unused
uint8_t fileType;
s.read ((char *)&fileType, 1); // file type
if (fileType != 0x00) // zip file
{
LogPrint (eLogError, "Can't handle file type ", (int)fileType);
return 0;
}
s.seekg (1, std::ios::cur); // unused
uint8_t contentType;
s.read ((char *)&contentType, 1); // content type
if (contentType != 0x03) // reseed data
{
LogPrint (eLogError, "Unexpected content type ", (int)contentType);
return 0;
}
s.seekg (12, std::ios::cur); // unused
s.seekg (versionLength, std::ios::cur); // skip version
char signerID[256];
s.read (signerID, signerIDLength); // signerID
signerID[signerIDLength] = 0;
//try to verify signature
auto it = m_SigningKeys.find (signerID);
if (it != m_SigningKeys.end ())
{
// TODO: implement all signature types
if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096)
{ {
uint32_t signature; size_t pos = s.tellg ();
s.read ((char *)&signature, 4); size_t tbsLen = pos + contentLength;
if (signature == headerSignature) uint8_t * tbs = new uint8_t[tbsLen];
s.seekg (0, std::ios::beg);
s.read ((char *)tbs, tbsLen);
uint8_t * signature = new uint8_t[signatureLength];
s.read ((char *)signature, signatureLength);
// RSA-raw
i2p::crypto::RSASHA5124096RawVerifier verifier(it->second);
verifier.Update (tbs, tbsLen);
if (!verifier.Verify (signature))
LogPrint (eLogWarning, "SU3 signature verification failed");
delete[] signature;
delete[] tbs;
s.seekg (pos, std::ios::beg);
}
else
LogPrint (eLogWarning, "Signature type ", signatureType, " is not supported");
}
else
LogPrint (eLogWarning, "Certificate for ", signerID, " not loaded");
// handle content
int numFiles = 0;
size_t contentPos = s.tellg ();
while (!s.eof ())
{
uint32_t signature;
s.read ((char *)&signature, 4);
signature = le32toh (signature);
if (signature == ZIP_HEADER_SIGNATURE)
{
// next local file
s.seekg (2, std::ios::cur); // version
uint16_t bitFlag;
s.read ((char *)&bitFlag, 2);
bitFlag = le16toh (bitFlag);
uint16_t compressionMethod;
s.read ((char *)&compressionMethod, 2);
compressionMethod = le16toh (compressionMethod);
s.seekg (4, std::ios::cur); // skip fields we don't care about
uint32_t crc32, compressedSize, uncompressedSize;
s.read ((char *)&crc32, 4);
crc32 = le32toh (crc32);
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 = le16toh (fileNameLength);
s.read ((char *)&extraFieldLength, 2);
extraFieldLength = le16toh (extraFieldLength);
char localFileName[255];
s.read (localFileName, fileNameLength);
localFileName[fileNameLength] = 0;
s.seekg (extraFieldLength, std::ios::cur);
// take care about data desriptor if presented
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
{ {
// next local file size_t pos = s.tellg ();
s.seekg (14, std::ios::cur); // skip field we don't care about if (!FindZipDataDescriptor (s))
uint32_t compressedSize, uncompressedSize; {
LogPrint (eLogError, "SU3 archive data descriptor not found");
return numFiles;
}
s.read ((char *)&crc32, 4);
crc32 = le32toh (crc32);
s.read ((char *)&compressedSize, 4); s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize); compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data
s.read ((char *)&uncompressedSize, 4); s.read ((char *)&uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize); 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]; // now we know compressed and uncompressed size
s.read ((char *)compressed, compressedSize); s.seekg (pos, std::ios::beg); // back to compressed data
CryptoPP::Gunzip decompressor; }
decompressor.Put (compressed, compressedSize);
delete[] compressed; LogPrint (eLogDebug, "Proccessing file ", localFileName, " ", compressedSize, " bytes");
if (!compressedSize)
{
LogPrint (eLogWarning, "Unexpected size 0. Skipped");
continue;
}
uint8_t * compressed = new uint8_t[compressedSize];
s.read ((char *)compressed, compressedSize);
if (compressionMethod) // we assume Deflate
{
CryptoPP::Inflator decompressor;
decompressor.Put (compressed, compressedSize);
decompressor.MessageEnd();
if (decompressor.MaxRetrievable () <= uncompressedSize) if (decompressor.MaxRetrievable () <= uncompressedSize)
{ {
uint8_t * uncompressed = new uint8_t[uncompressedSize]; uint8_t * uncompressed = new uint8_t[uncompressedSize];
decompressor.Get (uncompressed, decompressor.MaxRetrievable ()); decompressor.Get (uncompressed, uncompressedSize);
// TODO: save file if (CryptoPP::CRC32().VerifyDigest ((uint8_t *)&crc32, uncompressed, uncompressedSize))
{
i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
numFiles++;
}
else
LogPrint (eLogError, "CRC32 verification failed");
delete[] uncompressed; delete[] uncompressed;
} }
else else
LogPrint (eLogError, "Actual uncompressed size ", decompressor.MaxRetrievable (), " exceed ", uncompressedSize, " from header"); LogPrint (eLogError, "Actual uncompressed size ", decompressor.MaxRetrievable (), " exceed ", uncompressedSize, " from header");
} }
else else // no compression
break; // no more files {
i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
numFiles++;
}
delete[] compressed;
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
} }
else
{
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
LogPrint (eLogWarning, "Missing zip central directory header");
break; // no more files
}
size_t end = s.tellg ();
if (end - contentPos >= contentLength)
break; // we are beyond contentLength
} }
else return numFiles;
LogPrint (eLogError, "Can't open file ", filename);
} }
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
bool Reseeder::FindZipDataDescriptor (std::istream& s)
{
size_t nextInd = 0;
while (!s.eof ())
{
uint8_t nextByte;
s.read ((char *)&nextByte, 1);
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
{
nextInd++;
if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
return true;
}
else
nextInd = 0;
}
return s;
}
const char CERTIFICATE_HEADER[] = "-----BEGIN CERTIFICATE-----";
const char CERTIFICATE_FOOTER[] = "-----END CERTIFICATE-----";
void Reseeder::LoadCertificate (const std::string& filename)
{
std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ())
{
s.seekg (0, std::ios::end);
size_t len = s.tellg ();
s.seekg (0, std::ios::beg);
char buf[2048];
s.read (buf, len);
std::string cert (buf, len);
// assume file in pem format
auto pos1 = cert.find (CERTIFICATE_HEADER);
auto pos2 = cert.find (CERTIFICATE_FOOTER);
if (pos1 == std::string::npos || pos2 == std::string::npos)
{
LogPrint (eLogError, "Malformed certificate file");
return;
}
pos1 += strlen (CERTIFICATE_HEADER);
pos2 -= pos1;
std::string base64 = cert.substr (pos1, pos2);
CryptoPP::ByteQueue queue;
CryptoPP::Base64Decoder decoder; // regular base64 rather than I2P
decoder.Attach (new CryptoPP::Redirector (queue));
decoder.Put ((const uint8_t *)base64.data(), base64.length());
decoder.MessageEnd ();
// extract X.509
CryptoPP::BERSequenceDecoder x509Cert (queue);
CryptoPP::BERSequenceDecoder tbsCert (x509Cert);
// version
uint32_t ver;
CryptoPP::BERGeneralDecoder context (tbsCert, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED);
CryptoPP::BERDecodeUnsigned<uint32_t>(context, ver, CryptoPP::INTEGER);
// serial
CryptoPP::Integer serial;
serial.BERDecode(tbsCert);
// signature
CryptoPP::BERSequenceDecoder signature (tbsCert);
signature.SkipAll();
// issuer
std::string name;
CryptoPP::BERSequenceDecoder issuer (tbsCert);
{
CryptoPP::BERSetDecoder c (issuer); c.SkipAll();
CryptoPP::BERSetDecoder st (issuer); st.SkipAll();
CryptoPP::BERSetDecoder l (issuer); l.SkipAll();
CryptoPP::BERSetDecoder o (issuer); o.SkipAll();
CryptoPP::BERSetDecoder ou (issuer); ou.SkipAll();
CryptoPP::BERSetDecoder cn (issuer);
{
CryptoPP::BERSequenceDecoder attributes (cn);
{
CryptoPP::BERGeneralDecoder ident(attributes, CryptoPP::OBJECT_IDENTIFIER);
ident.SkipAll ();
CryptoPP::BERDecodeTextString (attributes, name, CryptoPP::UTF8_STRING);
}
}
}
issuer.SkipAll();
// validity
CryptoPP::BERSequenceDecoder validity (tbsCert);
validity.SkipAll();
// subject
CryptoPP::BERSequenceDecoder subject (tbsCert);
subject.SkipAll();
// public key
CryptoPP::BERSequenceDecoder publicKey (tbsCert);
{
CryptoPP::BERSequenceDecoder ident (publicKey);
ident.SkipAll ();
CryptoPP::BERGeneralDecoder key (publicKey, CryptoPP::BIT_STRING);
key.Skip (1); // FIXME: probably bug in crypto++
CryptoPP::BERSequenceDecoder keyPair (key);
CryptoPP::Integer n;
n.BERDecode (keyPair);
if (name.length () > 0)
{
PublicKey value;
n.Encode (value, 512);
m_SigningKeys[name] = value;
}
else
LogPrint (eLogWarning, "Unknown issuer. Skipped");
}
publicKey.SkipAll();
tbsCert.SkipAll();
x509Cert.SkipAll();
}
else
LogPrint (eLogError, "Can't open certificate file ", filename);
}
void Reseeder::LoadCertificates ()
{
boost::filesystem::path reseedDir = i2p::util::filesystem::GetCertificatesDir() / "reseed";
if (!boost::filesystem::exists (reseedDir))
{
LogPrint (eLogWarning, "Reseed certificates not loaded. ", reseedDir, " doesn't exist");
return;
}
int numCertificates = 0;
boost::filesystem::directory_iterator end; // empty
for (boost::filesystem::directory_iterator it (reseedDir); it != end; ++it)
{
if (boost::filesystem::is_regular_file (it->status()) && it->path ().extension () == ".crt")
{
LoadCertificate (it->path ().string ());
numCertificates++;
}
}
LogPrint (eLogInfo, numCertificates, " certificates loaded");
}
} }
} }

View File

@@ -1,8 +1,11 @@
#ifndef RESEED_H #ifndef RESEED_H
#define RESEED_H #define RESEED_H
#include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include "Identity.h"
namespace i2p namespace i2p
{ {
@@ -11,13 +14,31 @@ namespace data
class Reseeder class Reseeder
{ {
typedef Tag<512> PublicKey;
public: public:
Reseeder(); Reseeder();
~Reseeder(); ~Reseeder();
bool reseedNow(); bool reseedNow(); // depreacted
}; int ReseedNowSU3 ();
void ProcessSU3File (const char * filename); void LoadCertificates ();
private:
void LoadCertificate (const std::string& filename);
int ReseedFromSU3 (const std::string& host);
int ProcessSU3File (const char * filename);
int ProcessSU3Stream (std::istream& s);
bool FindZipDataDescriptor (std::istream& s);
private:
std::map<std::string, PublicKey> m_SigningKeys;
};
} }
} }

View File

@@ -101,8 +101,12 @@ namespace data
{ {
// verify signature // verify signature
int l = m_BufferLen - m_RouterIdentity.GetSignatureLen (); int l = m_BufferLen - m_RouterIdentity.GetSignatureLen ();
if (!m_RouterIdentity.Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l)) if (!m_RouterIdentity.Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
LogPrint (eLogError, "signature verification failed"); {
LogPrint (eLogError, "signature verification failed");
m_IsUnreachable = true;
}
m_RouterIdentity.DropVerifier ();
} }
} }

270
SAM.cpp
View File

@@ -3,7 +3,7 @@
#ifdef _MSC_VER #ifdef _MSC_VER
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#include <boost/bind.hpp> #include <boost/lexical_cast.hpp>
#include "base64.h" #include "base64.h"
#include "Identity.h" #include "Identity.h"
#include "Log.h" #include "Log.h"
@@ -25,22 +25,22 @@ namespace client
SAMSocket::~SAMSocket () SAMSocket::~SAMSocket ()
{ {
if (m_Stream) Terminate ();
{
m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream);
m_Stream = nullptr;
}
} }
void SAMSocket::Terminate () void SAMSocket::CloseStream ()
{ {
if (m_Stream) if (m_Stream)
{ {
m_Stream->Close (); m_Stream->Close ();
i2p::stream::DeleteStream (m_Stream); m_Stream.reset ();
m_Stream = nullptr; }
} }
void SAMSocket::Terminate ()
{
CloseStream ();
switch (m_SocketType) switch (m_SocketType)
{ {
case eSAMSocketTypeSession: case eSAMSocketTypeSession:
@@ -49,14 +49,14 @@ namespace client
case eSAMSocketTypeStream: case eSAMSocketTypeStream:
{ {
if (m_Session) if (m_Session)
m_Session->sockets.remove (this); m_Session->sockets.remove (shared_from_this ());
break; break;
} }
case eSAMSocketTypeAcceptor: case eSAMSocketTypeAcceptor:
{ {
if (m_Session) if (m_Session)
{ {
m_Session->sockets.remove (this); m_Session->sockets.remove (shared_from_this ());
m_Session->localDestination->StopAcceptingStreams (); m_Session->localDestination->StopAcceptingStreams ();
} }
break; break;
@@ -64,15 +64,15 @@ namespace client
default: default:
; ;
} }
m_SocketType = eSAMSocketTypeTerminated;
m_Socket.close (); m_Socket.close ();
// delete this;
} }
void SAMSocket::ReceiveHandshake () void SAMSocket::ReceiveHandshake ()
{ {
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind(&SAMSocket::HandleHandshakeReceived, this, std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -87,12 +87,41 @@ namespace client
{ {
m_Buffer[bytes_transferred] = 0; m_Buffer[bytes_transferred] = 0;
LogPrint ("SAM handshake ", m_Buffer); LogPrint ("SAM handshake ", m_Buffer);
if (!memcmp (m_Buffer, SAM_HANDSHAKE, strlen (SAM_HANDSHAKE))) char * separator = strchr (m_Buffer, ' ');
if (separator)
{ {
// TODO: check version separator = strchr (separator + 1, ' ');
boost::asio::async_write (m_Socket, boost::asio::buffer (SAM_HANDSHAKE_REPLY, strlen (SAM_HANDSHAKE_REPLY)), boost::asio::transfer_all (), if (separator)
boost::bind(&SAMSocket::HandleHandshakeReplySent, this, *separator = 0;
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); }
if (!strcmp (m_Buffer, SAM_HANDSHAKE))
{
std::string version("3.0");
// try to find MIN and MAX, 3.0 if not found
if (separator)
{
separator++;
std::map<std::string, std::string> params;
ExtractParams (separator, bytes_transferred - (separator - m_Buffer), params);
auto it = params.find (SAM_PARAM_MAX);
// TODO: check MIN as well
if (it != params.end ())
version = it->second;
}
if (version[0] == '3') // we support v3 (3.0 and 3.1) only
{
#ifdef _MSC_VER
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
#else
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
#endif
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (),
std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2));
}
else
SendMessageReply (SAM_HANDSHAKE_I2P_ERROR, strlen (SAM_HANDSHAKE_I2P_ERROR), true);
} }
else else
{ {
@@ -113,8 +142,8 @@ namespace client
else else
{ {
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind(&SAMSocket::HandleMessage, this, std::bind(&SAMSocket::HandleMessage, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
} }
@@ -122,8 +151,8 @@ namespace client
{ {
if (!m_IsSilent || m_SocketType == eSAMSocketTypeAcceptor) if (!m_IsSilent || m_SocketType == eSAMSocketTypeAcceptor)
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
boost::bind(&SAMSocket::HandleMessageReplySent, this, std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, close)); std::placeholders::_1, std::placeholders::_2, close));
else else
{ {
if (close) if (close)
@@ -212,14 +241,16 @@ namespace client
std::string& style = params[SAM_PARAM_STYLE]; std::string& style = params[SAM_PARAM_STYLE];
std::string& id = params[SAM_PARAM_ID]; std::string& id = params[SAM_PARAM_ID];
std::string& destination = params[SAM_PARAM_DESTINATION]; std::string& destination = params[SAM_PARAM_DESTINATION];
m_ID = id; m_ID = id;
if (m_Owner.FindSession (id)) if (m_Owner.FindSession (id))
{ {
// session exists // session exists
SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), true); SendMessageReply (SAM_SESSION_CREATE_DUPLICATED_ID, strlen(SAM_SESSION_CREATE_DUPLICATED_ID), true);
return; return;
} }
m_Session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination);
// create destination
m_Session = m_Owner.CreateSession (id, destination == SAM_VALUE_TRANSIENT ? "" : destination, &params);
if (m_Session) if (m_Session)
{ {
m_SocketType = eSAMSocketTypeSession; m_SocketType = eSAMSocketTypeSession;
@@ -228,7 +259,7 @@ namespace client
if (style == SAM_VALUE_DATAGRAM) if (style == SAM_VALUE_DATAGRAM)
{ {
auto dest = m_Session->localDestination->CreateDatagramDestination (); auto dest = m_Session->localDestination->CreateDatagramDestination ();
dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, this, dest->SetReceiver (std::bind (&SAMSocket::HandleI2PDatagramReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
} }
SendSessionCreateReplyOk (); SendSessionCreateReplyOk ();
@@ -236,8 +267,8 @@ namespace client
else else
{ {
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleSessionReadinessCheckTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
} }
else else
@@ -253,8 +284,8 @@ namespace client
else else
{ {
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_SESSION_READINESS_CHECK_INTERVAL));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleSessionReadinessCheckTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleSessionReadinessCheckTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
} }
} }
@@ -287,10 +318,9 @@ namespace client
m_Session = m_Owner.FindSession (id); m_Session = m_Owner.FindSession (id);
if (m_Session) if (m_Session)
{ {
uint8_t ident[1024];
size_t l = i2p::data::Base64ToByteStream (destination.c_str (), destination.length (), ident, 1024);
i2p::data::IdentityEx dest; i2p::data::IdentityEx dest;
dest.FromBuffer (ident, l); dest.FromBase64 (destination);
context.GetAddressBook ().InsertAddress (dest);
auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ()); auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ());
if (leaseSet) if (leaseSet)
Connect (*leaseSet); Connect (*leaseSet);
@@ -298,8 +328,8 @@ namespace client
{ {
i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, m_Session->localDestination->GetTunnelPool ()); i2p::data::netdb.RequestDestination (dest.GetIdentHash (), true, m_Session->localDestination->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SAM_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleStreamDestinationRequestTimer, m_Timer.async_wait (std::bind (&SAMSocket::HandleStreamDestinationRequestTimer,
this, boost::asio::placeholders::error, dest.GetIdentHash ())); shared_from_this (), std::placeholders::_1, dest.GetIdentHash ()));
} }
} }
else else
@@ -309,7 +339,7 @@ namespace client
void SAMSocket::Connect (const i2p::data::LeaseSet& remote) void SAMSocket::Connect (const i2p::data::LeaseSet& remote)
{ {
m_SocketType = eSAMSocketTypeStream; m_SocketType = eSAMSocketTypeStream;
m_Session->sockets.push_back (this); m_Session->sockets.push_back (shared_from_this ());
m_Stream = m_Session->localDestination->CreateStream (remote); m_Stream = m_Session->localDestination->CreateStream (remote);
m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect m_Stream->Send ((uint8_t *)m_Buffer, 0); // connect
I2PReceive (); I2PReceive ();
@@ -331,26 +361,6 @@ namespace client
} }
} }
void SAMSocket::HandleNamingLookupDestinationRequestTimer (const boost::system::error_code& ecode, i2p::data::IdentHash ident)
{
if (!ecode) // timeout expired
{
auto leaseSet = m_Session->localDestination->FindLeaseSet (ident);
if (leaseSet)
SendNamingLookupReply (leaseSet);
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);
}
}
}
void SAMSocket::ProcessStreamAccept (char * buf, size_t len) void SAMSocket::ProcessStreamAccept (char * buf, size_t len)
{ {
LogPrint ("SAM stream accept: ", buf); LogPrint ("SAM stream accept: ", buf);
@@ -366,8 +376,8 @@ namespace client
if (!m_Session->localDestination->IsAcceptingStreams ()) if (!m_Session->localDestination->IsAcceptingStreams ())
{ {
m_SocketType = eSAMSocketTypeAcceptor; m_SocketType = eSAMSocketTypeAcceptor;
m_Session->sockets.push_back (this); m_Session->sockets.push_back (shared_from_this ());
m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, this, std::placeholders::_1)); m_Session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PAccept, shared_from_this (), std::placeholders::_1));
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
else else
@@ -383,19 +393,12 @@ namespace client
auto localDestination = i2p::client::context.CreateNewLocalDestination (); auto localDestination = i2p::client::context.CreateNewLocalDestination ();
if (localDestination) if (localDestination)
{ {
uint8_t buf[1024]; auto priv = localDestination->GetPrivateKeys ().ToBase64 ();
char priv[1024], pub[1024]; auto pub = localDestination->GetIdentity ().ToBase64 ();
size_t l = localDestination->GetPrivateKeys ().ToBuffer (buf, 1024);
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, priv, 1024);
priv[l1] = 0;
l = localDestination->GetIdentity ().ToBuffer (buf, 1024);
l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024);
pub[l1] = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub.c_str (), priv.c_str ());
#else #else
size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub, priv); size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, pub.c_str (), priv.c_str ());
#endif #endif
SendMessageReply (m_Buffer, len, true); SendMessageReply (m_Buffer, len, true);
} }
@@ -410,22 +413,12 @@ namespace client
ExtractParams (buf, len, params); ExtractParams (buf, len, params);
std::string& name = params[SAM_PARAM_NAME]; std::string& name = params[SAM_PARAM_NAME];
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
i2p::data::IdentityEx identity;
if (name == "ME") if (name == "ME")
SendNamingLookupReply (nullptr); SendNamingLookupReply (nullptr);
else if (m_Session && context.GetAddressBook ().GetIdentHash (name, ident)) else if (context.GetAddressBook ().GetAddress (name, identity))
{ SendNamingLookupReply (identity);
auto leaseSet = m_Session->localDestination->FindLeaseSet (ident); else
if (leaseSet)
SendNamingLookupReply (leaseSet);
else
{
i2p::data::netdb.RequestDestination (ident, true, m_Session->localDestination->GetTunnelPool ());
m_Timer.expires_from_now (boost::posix_time::seconds(SAM_NAMING_LOOKUP_TIMEOUT));
m_Timer.async_wait (boost::bind (&SAMSocket::HandleNamingLookupDestinationRequestTimer,
this, boost::asio::placeholders::error, ident));
}
}
else
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str()); size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
@@ -438,18 +431,22 @@ namespace client
void SAMSocket::SendNamingLookupReply (const i2p::data::LeaseSet * leaseSet) void SAMSocket::SendNamingLookupReply (const i2p::data::LeaseSet * leaseSet)
{ {
uint8_t buf[1024];
char pub[1024];
const i2p::data::IdentityEx& identity = leaseSet ? leaseSet->GetIdentity () : m_Session->localDestination->GetIdentity (); const i2p::data::IdentityEx& identity = leaseSet ? leaseSet->GetIdentity () : m_Session->localDestination->GetIdentity ();
size_t l = identity.ToBuffer (buf, 1024); if (leaseSet)
size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, pub, 1024); // we found LeaseSet for our address, store it to addressbook
pub[l1] = 0; context.GetAddressBook ().InsertAddress (identity);
SendNamingLookupReply (identity);
}
void SAMSocket::SendNamingLookupReply (const i2p::data::IdentityEx& identity)
{
auto base64 = identity.ToBase64 ();
#ifdef _MSC_VER #ifdef _MSC_VER
size_t l2 = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ());
#else #else
size_t l2 = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, pub); size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ());
#endif #endif
SendMessageReply (m_Buffer, l2, false); SendMessageReply (m_Buffer, l, false);
} }
void SAMSocket::ExtractParams (char * buf, size_t len, std::map<std::string, std::string>& params) void SAMSocket::ExtractParams (char * buf, size_t len, std::map<std::string, std::string>& params)
@@ -474,8 +471,8 @@ namespace client
void SAMSocket::Receive () void SAMSocket::Receive ()
{ {
m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived, std::bind((m_SocketType == eSAMSocketTypeSession) ? &SAMSocket::HandleMessage : &SAMSocket::HandleReceived,
this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -498,8 +495,8 @@ namespace client
{ {
if (m_Stream) if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE), m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE),
boost::bind (&SAMSocket::HandleI2PReceive, this, std::bind (&SAMSocket::HandleI2PReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), std::placeholders::_1, std::placeholders::_2),
SAM_SOCKET_CONNECTION_MAX_IDLE); SAM_SOCKET_CONNECTION_MAX_IDLE);
} }
@@ -514,7 +511,7 @@ namespace client
else else
{ {
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred),
boost::bind (&SAMSocket::HandleWriteI2PData, this, boost::asio::placeholders::error)); std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
} }
} }
@@ -530,12 +527,13 @@ namespace client
I2PReceive (); I2PReceive ();
} }
void SAMSocket::HandleI2PAccept (i2p::stream::Stream * stream) void SAMSocket::HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{ {
LogPrint ("SAM incoming I2P connection for session ", m_ID); LogPrint ("SAM incoming I2P connection for session ", m_ID);
m_Stream = stream; m_Stream = stream;
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
auto session = m_Owner.FindSession (m_ID); auto session = m_Owner.FindSession (m_ID);
if (session) if (session)
session->localDestination->StopAcceptingStreams (); session->localDestination->StopAcceptingStreams ();
@@ -554,20 +552,17 @@ namespace client
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len) void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len)
{ {
uint8_t identBuf[1024]; auto base64 = ident.ToBase64 ();
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 #ifdef _MSC_VER
size_t l2 = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, m_Buffer, len); size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
#else #else
size_t l2 = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, m_Buffer, len); size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
#endif #endif
if (len < SAM_SOCKET_BUFFER_SIZE - l2) if (len < SAM_SOCKET_BUFFER_SIZE - l)
{ {
memcpy (m_StreamBuffer + l2, buf, len); memcpy (m_StreamBuffer + l, buf, len);
boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l2), boost::asio::async_write (m_Socket, boost::asio::buffer (m_StreamBuffer, len + l),
boost::bind (&SAMSocket::HandleWriteI2PData, this, boost::asio::placeholders::error)); std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
} }
else else
LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer"); LogPrint (eLogWarning, "Datagram size ", len," exceeds buffer");
@@ -576,15 +571,13 @@ namespace client
SAMBridge::SAMBridge (int port): SAMBridge::SAMBridge (int port):
m_IsRunning (false), m_Thread (nullptr), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)), 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_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
m_NewSocket (nullptr)
{ {
} }
SAMBridge::~SAMBridge () SAMBridge::~SAMBridge ()
{ {
Stop (); Stop ();
delete m_NewSocket;
} }
void SAMBridge::Start () void SAMBridge::Start ()
@@ -624,43 +617,48 @@ namespace client
void SAMBridge::Accept () void SAMBridge::Accept ()
{ {
m_NewSocket = new SAMSocket (*this); auto newSocket = std::make_shared<SAMSocket> (*this);
m_Acceptor.async_accept (m_NewSocket->GetSocket (), boost::bind (&SAMBridge::HandleAccept, this, m_Acceptor.async_accept (newSocket->GetSocket (), std::bind (&SAMBridge::HandleAccept, this,
boost::asio::placeholders::error)); std::placeholders::_1, newSocket));
} }
void SAMBridge::HandleAccept(const boost::system::error_code& ecode) void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
{ {
if (!ecode) if (!ecode)
{ {
LogPrint ("New SAM connection from ", m_NewSocket->GetSocket ().remote_endpoint ()); LogPrint ("New SAM connection from ", socket->GetSocket ().remote_endpoint ());
m_NewSocket->ReceiveHandshake (); socket->ReceiveHandshake ();
} }
else else
{
LogPrint ("SAM accept error: ", ecode.message ()); LogPrint ("SAM accept error: ", ecode.message ());
delete m_NewSocket;
m_NewSocket = nullptr;
}
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Accept (); Accept ();
} }
SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination) SAMSession * SAMBridge::CreateSession (const std::string& id, const std::string& destination,
const std::map<std::string, std::string> * params)
{ {
ClientDestination * localDestination = nullptr; ClientDestination * localDestination = nullptr;
if (destination != "") if (destination != "")
{ {
uint8_t * buf = new uint8_t[destination.length ()];
size_t l = i2p::data::Base64ToByteStream (destination.c_str (), destination.length (), buf, destination.length ());
i2p::data::PrivateKeys keys; i2p::data::PrivateKeys keys;
keys.FromBuffer (buf, l); keys.FromBase64 (destination);
delete[] buf; localDestination = i2p::client::context.CreateNewLocalDestination (keys, true, params);
localDestination = i2p::client::context.CreateNewLocalDestination (keys);
} }
else // transient else // transient
localDestination = i2p::client::context.CreateNewLocalDestination (); {
// extract signature type
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
if (params)
{
auto it = params->find (SAM_PARAM_SIGNATURE_TYPE);
if (it != params->end ())
// TODO: extract string values
signatureType = boost::lexical_cast<int> (it->second);
}
localDestination = i2p::client::context.CreateNewLocalDestination (false, signatureType, params);
}
if (localDestination) if (localDestination)
{ {
SAMSession session; SAMSession session;
@@ -680,10 +678,10 @@ namespace client
auto it = m_Sessions.find (id); auto it = m_Sessions.find (id);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
{ {
for (auto it1 : it->second.sockets) for (auto it1: it->second.sockets)
delete it1; it1->CloseStream ();
it->second.sockets.clear (); it->second.sockets.clear ();
it->second.localDestination->Stop (); i2p::client::context.DeleteLocalDestination (it->second.localDestination);
m_Sessions.erase (it); m_Sessions.erase (it);
} }
} }
@@ -702,7 +700,7 @@ namespace client
m_DatagramSocket.async_receive_from ( m_DatagramSocket.async_receive_from (
boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE), boost::asio::buffer (m_DatagramReceiveBuffer, i2p::datagram::MAX_DATAGRAM_SIZE),
m_SenderEndpoint, m_SenderEndpoint,
boost::bind (&SAMBridge::HandleReceivedDatagram, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::bind (&SAMBridge::HandleReceivedDatagram, this, std::placeholders::_1, std::placeholders::_2));
} }
void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred) void SAMBridge::HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -725,10 +723,8 @@ namespace client
auto session = FindSession (sessionID); auto session = FindSession (sessionID);
if (session) if (session)
{ {
uint8_t ident[1024];
size_t l = i2p::data::Base64ToByteStream (destination, strlen(destination), ident, 1024);
i2p::data::IdentityEx dest; i2p::data::IdentityEx dest;
dest.FromBuffer (ident, l); dest.FromBase64 (destination);
auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ()); auto leaseSet = i2p::data::netdb.FindLeaseSet (dest.GetIdentHash ());
if (leaseSet) if (leaseSet)
session->localDestination->GetDatagramDestination ()-> session->localDestination->GetDatagramDestination ()->

42
SAM.h
View File

@@ -7,6 +7,7 @@
#include <list> #include <list>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -23,7 +24,8 @@ namespace client
const int SAM_NAMING_LOOKUP_TIMEOUT = 5; // in seconds const int SAM_NAMING_LOOKUP_TIMEOUT = 5; // in seconds
const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds const int SAM_SESSION_READINESS_CHECK_INTERVAL = 20; // in seconds
const char SAM_HANDSHAKE[] = "HELLO VERSION"; const char SAM_HANDSHAKE[] = "HELLO VERSION";
const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=3.0\n"; const char SAM_HANDSHAKE_REPLY[] = "HELLO REPLY RESULT=OK VERSION=%s\n";
const char SAM_HANDSHAKE_I2P_ERROR[] = "HELLO REPLY RESULT=I2P_ERROR\n";
const char SAM_SESSION_CREATE[] = "SESSION CREATE"; const char SAM_SESSION_CREATE[] = "SESSION CREATE";
const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n"; const char SAM_SESSION_CREATE_REPLY_OK[] = "SESSION STATUS RESULT=OK DESTINATION=%s\n";
const char SAM_SESSION_CREATE_DUPLICATED_ID[] = "SESSION STATUS RESULT=DUPLICATED_ID\n"; const char SAM_SESSION_CREATE_DUPLICATED_ID[] = "SESSION STATUS RESULT=DUPLICATED_ID\n";
@@ -39,14 +41,17 @@ namespace client
const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n"; const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n";
const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP"; const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP";
const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n"; 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_DATAGRAM_RECEIVED[] = "DATAGRAM_RECEIVED DESTINATION=%s SIZE=%lu\n";
const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\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_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n";
const char SAM_PARAM_MIN[] = "MIN";
const char SAM_PARAM_MAX[] = "MAX";
const char SAM_PARAM_STYLE[] = "STYLE"; const char SAM_PARAM_STYLE[] = "STYLE";
const char SAM_PARAM_ID[] = "ID"; const char SAM_PARAM_ID[] = "ID";
const char SAM_PARAM_SILENT[] = "SILENT"; const char SAM_PARAM_SILENT[] = "SILENT";
const char SAM_PARAM_DESTINATION[] = "DESTINATION"; const char SAM_PARAM_DESTINATION[] = "DESTINATION";
const char SAM_PARAM_NAME[] = "NAME"; const char SAM_PARAM_NAME[] = "NAME";
const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_STREAM[] = "STREAM";
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
@@ -59,24 +64,27 @@ namespace client
eSAMSocketTypeUnknown, eSAMSocketTypeUnknown,
eSAMSocketTypeSession, eSAMSocketTypeSession,
eSAMSocketTypeStream, eSAMSocketTypeStream,
eSAMSocketTypeAcceptor eSAMSocketTypeAcceptor,
eSAMSocketTypeTerminated
}; };
class SAMBridge; class SAMBridge;
class SAMSession; class SAMSession;
class SAMSocket class SAMSocket: public std::enable_shared_from_this<SAMSocket>
{ {
public: public:
SAMSocket (SAMBridge& owner); SAMSocket (SAMBridge& owner);
~SAMSocket (); ~SAMSocket ();
void CloseStream (); // TODO: implement it better
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
void ReceiveHandshake (); void ReceiveHandshake ();
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
private: private:
void Terminate (); void Terminate ();
void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@@ -87,7 +95,7 @@ namespace client
void I2PReceive (); void I2PReceive ();
void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleI2PAccept (i2p::stream::Stream * stream); void HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream);
void HandleWriteI2PData (const boost::system::error_code& ecode); void HandleWriteI2PData (const boost::system::error_code& ecode);
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len); void HandleI2PDatagramReceive (const i2p::data::IdentityEx& ident, const uint8_t * buf, size_t len);
@@ -100,8 +108,8 @@ namespace client
void Connect (const i2p::data::LeaseSet& remote); void Connect (const i2p::data::LeaseSet& remote);
void HandleStreamDestinationRequestTimer (const boost::system::error_code& ecode, i2p::data::IdentHash ident); void HandleStreamDestinationRequestTimer (const boost::system::error_code& ecode, i2p::data::IdentHash ident);
void HandleNamingLookupDestinationRequestTimer (const boost::system::error_code& ecode, i2p::data::IdentHash ident);
void SendNamingLookupReply (const i2p::data::LeaseSet * leaseSet); void SendNamingLookupReply (const i2p::data::LeaseSet * leaseSet);
void SendNamingLookupReply (const i2p::data::IdentityEx& identity);
void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode); void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
void SendSessionCreateReplyOk (); void SendSessionCreateReplyOk ();
@@ -115,14 +123,20 @@ namespace client
SAMSocketType m_SocketType; SAMSocketType m_SocketType;
std::string m_ID; // nickname std::string m_ID; // nickname
bool m_IsSilent; bool m_IsSilent;
i2p::stream::Stream * m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
SAMSession * m_Session; SAMSession * m_Session;
}; };
struct SAMSession struct SAMSession
{ {
ClientDestination * localDestination; ClientDestination * localDestination;
std::list<SAMSocket *> sockets; std::list<std::shared_ptr<SAMSocket> > sockets;
~SAMSession ()
{
for (auto it: sockets)
it->SetSocketType (eSAMSocketTypeTerminated);
}
}; };
class SAMBridge class SAMBridge
@@ -136,7 +150,8 @@ namespace client
void Stop (); void Stop ();
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
SAMSession * CreateSession (const std::string& id, const std::string& destination = ""); // empty string means transient SAMSession * CreateSession (const std::string& id, const std::string& destination, // empty string means transient
const std::map<std::string, std::string> * params);
void CloseSession (const std::string& id); void CloseSession (const std::string& id);
SAMSession * FindSession (const std::string& id); SAMSession * FindSession (const std::string& id);
@@ -145,7 +160,7 @@ namespace client
void Run (); void Run ();
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket);
void ReceiveDatagram (); void ReceiveDatagram ();
void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@@ -158,7 +173,6 @@ namespace client
boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint; boost::asio::ip::udp::endpoint m_DatagramEndpoint, m_SenderEndpoint;
boost::asio::ip::udp::socket m_DatagramSocket; boost::asio::ip::udp::socket m_DatagramSocket;
SAMSocket * m_NewSocket;
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::map<std::string, SAMSession> m_Sessions; std::map<std::string, SAMSession> m_Sessions;
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];

View File

@@ -77,8 +77,7 @@ namespace proxy
{ {
if (m_stream) { if (m_stream) {
LogPrint("--- socks4a close stream"); LogPrint("--- socks4a close stream");
delete m_stream; m_stream.reset ();
m_stream = nullptr;
} }
} }

View File

@@ -5,7 +5,7 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <vector> #include <vector>
#include <mutex> #include <mutex>
#include <memory>
#include "Identity.h" #include "Identity.h"
#include "Streaming.h" #include "Streaming.h"
@@ -47,7 +47,7 @@ namespace proxy
boost::asio::io_service * m_ios; boost::asio::io_service * m_ios;
boost::asio::ip::tcp::socket * m_sock; boost::asio::ip::tcp::socket * m_sock;
boost::asio::deadline_timer m_ls_timer; boost::asio::deadline_timer m_ls_timer;
i2p::stream::Stream * m_stream; std::shared_ptr<i2p::stream::Stream> m_stream;
i2p::data::LeaseSet * m_ls; i2p::data::LeaseSet * m_ls;
i2p::data::IdentHash m_dest; i2p::data::IdentHash m_dest;
state m_state; state m_state;

93
SSU.cpp
View File

@@ -9,9 +9,10 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
SSUServer::SSUServer (int port): m_Thread (nullptr), m_Work (m_Service), SSUServer::SSUServer (int port): m_Thread (nullptr), m_ThreadV6 (nullptr), m_Work (m_Service),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_WorkV6 (m_ServiceV6),m_Endpoint (boost::asio::ip::udp::v4 (), port),
m_Socket (m_Service, m_Endpoint), m_SocketV6 (m_Service), m_IntroducersUpdateTimer (m_Service) m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Socket (m_Service, m_Endpoint),
m_SocketV6 (m_ServiceV6), m_IntroducersUpdateTimer (m_Service)
{ {
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535));
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535));
@@ -27,17 +28,18 @@ namespace transport
SSUServer::~SSUServer () SSUServer::~SSUServer ()
{ {
for (auto it: m_Sessions)
delete it.second;
} }
void SSUServer::Start () void SSUServer::Start ()
{ {
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_Service.post (boost::bind (&SSUServer::Receive, this)); m_Service.post (std::bind (&SSUServer::Receive, this));
if (context.SupportsV6 ()) if (context.SupportsV6 ())
m_Service.post (boost::bind (&SSUServer::ReceiveV6, this)); {
m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this));
m_ServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
}
if (i2p::context.IsUnreachable ()) if (i2p::context.IsUnreachable ())
ScheduleIntroducersUpdateTimer (); ScheduleIntroducersUpdateTimer ();
} }
@@ -48,12 +50,20 @@ namespace transport
m_IsRunning = false; m_IsRunning = false;
m_Service.stop (); m_Service.stop ();
m_Socket.close (); m_Socket.close ();
m_ServiceV6.stop ();
m_SocketV6.close ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = nullptr;
} }
if (m_ThreadV6)
{
m_ThreadV6->join ();
delete m_ThreadV6;
m_ThreadV6 = nullptr;
}
} }
void SSUServer::Run () void SSUServer::Run ()
@@ -70,13 +80,28 @@ namespace transport
} }
} }
} }
void SSUServer::RunV6 ()
{
while (m_IsRunning)
{
try
{
m_ServiceV6.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU V6 server: ", ex.what ());
}
}
}
void SSUServer::AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay) void SSUServer::AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay)
{ {
m_Relays[tag] = relay; m_Relays[tag] = relay;
} }
SSUSession * SSUServer::FindRelaySession (uint32_t tag) std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
{ {
auto it = m_Relays.find (tag); auto it = m_Relays.find (tag);
if (it != m_Relays.end ()) if (it != m_Relays.end ())
@@ -128,20 +153,21 @@ namespace transport
void SSUServer::HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred) void SSUServer::HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred)
{ {
SSUSession * session = nullptr; std::shared_ptr<SSUSession> session;
auto it = m_Sessions.find (from); auto it = m_Sessions.find (from);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
session = it->second; session = it->second;
if (!session) if (!session)
{ {
session = new SSUSession (*this, from); session = std::make_shared<SSUSession> (*this, from);
session->WaitForConnect ();
m_Sessions[from] = session; m_Sessions[from] = session;
LogPrint ("New SSU session from ", from.address ().to_string (), ":", from.port (), " created"); LogPrint ("New SSU session from ", from.address ().to_string (), ":", from.port (), " created");
} }
session->ProcessNextMessage (buf, bytes_transferred, from); session->ProcessNextMessage (buf, bytes_transferred, from);
} }
SSUSession * SSUServer::FindSession (const i2p::data::RouterInfo * router) std::shared_ptr<SSUSession> SSUServer::FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const
{ {
if (!router) return nullptr; if (!router) return nullptr;
auto address = router->GetSSUAddress (true); // v4 only auto address = router->GetSSUAddress (true); // v4 only
@@ -155,7 +181,7 @@ namespace transport
return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
} }
SSUSession * SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{ {
auto it = m_Sessions.find (e); auto it = m_Sessions.find (e);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
@@ -164,9 +190,9 @@ namespace transport
return nullptr; return nullptr;
} }
SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router, bool peerTest) std::shared_ptr<SSUSession> SSUServer::GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{ {
SSUSession * session = nullptr; std::shared_ptr<SSUSession> session;
if (router) if (router)
{ {
auto address = router->GetSSUAddress (!context.SupportsV6 ()); auto address = router->GetSSUAddress (!context.SupportsV6 ());
@@ -179,7 +205,7 @@ namespace transport
else else
{ {
// otherwise create new session // otherwise create new session
session = new SSUSession (*this, remoteEndpoint, router, peerTest); session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
m_Sessions[remoteEndpoint] = session; m_Sessions[remoteEndpoint] = session;
if (!router->UsesIntroducer ()) if (!router->UsesIntroducer ())
@@ -195,7 +221,7 @@ namespace transport
int numIntroducers = address->introducers.size (); int numIntroducers = address->introducers.size ();
if (numIntroducers > 0) if (numIntroducers > 0)
{ {
SSUSession * introducerSession = nullptr; std::shared_ptr<SSUSession> introducerSession;
const i2p::data::RouterInfo::Introducer * introducer = nullptr; const i2p::data::RouterInfo::Introducer * introducer = nullptr;
// we might have a session to introducer already // we might have a session to introducer already
for (int i = 0; i < numIntroducers; i++) for (int i = 0; i < numIntroducers; i++)
@@ -216,7 +242,7 @@ namespace transport
LogPrint ("Creating new session to introducer"); LogPrint ("Creating new session to introducer");
introducer = &(address->introducers[0]); // TODO: introducer = &(address->introducers[0]); // TODO:
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = new SSUSession (*this, introducerEndpoint, router); introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession; m_Sessions[introducerEndpoint] = introducerSession;
} }
// introduce // introduce
@@ -231,8 +257,7 @@ namespace transport
{ {
LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented"); LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented");
m_Sessions.erase (remoteEndpoint); m_Sessions.erase (remoteEndpoint);
delete session; session.reset ();
session = nullptr;
} }
} }
} }
@@ -243,30 +268,26 @@ namespace transport
return session; return session;
} }
void SSUServer::DeleteSession (SSUSession * session) void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
{ {
if (session) if (session)
{ {
session->Close (); session->Close ();
m_Sessions.erase (session->GetRemoteEndpoint ()); m_Sessions.erase (session->GetRemoteEndpoint ());
delete session;
} }
} }
void SSUServer::DeleteAllSessions () void SSUServer::DeleteAllSessions ()
{ {
for (auto it: m_Sessions) for (auto it: m_Sessions)
{
it.second->Close (); it.second->Close ();
delete it.second;
}
m_Sessions.clear (); m_Sessions.clear ();
} }
template<typename Filter> template<typename Filter>
SSUSession * SSUServer::GetRandomSession (Filter filter) std::shared_ptr<SSUSession> SSUServer::GetRandomSession (Filter filter)
{ {
std::vector<SSUSession *> filteredSessions; std::vector<std::shared_ptr<SSUSession> > filteredSessions;
for (auto s :m_Sessions) for (auto s :m_Sessions)
if (filter (s.second)) filteredSessions.push_back (s.second); if (filter (s.second)) filteredSessions.push_back (s.second);
if (filteredSessions.size () > 0) if (filteredSessions.size () > 0)
@@ -277,10 +298,10 @@ namespace transport
return nullptr; return nullptr;
} }
SSUSession * SSUServer::GetRandomEstablishedSession (const SSUSession * excluded) std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded)
{ {
return GetRandomSession ( return GetRandomSession (
[excluded](SSUSession * session)->bool [excluded](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetState () == eSessionStateEstablished && return session->GetState () == eSessionStateEstablished &&
session != excluded; session != excluded;
@@ -295,16 +316,16 @@ namespace transport
for (int i = 0; i < maxNumIntroducers; i++) for (int i = 0; i < maxNumIntroducers; i++)
{ {
auto session = GetRandomSession ( auto session = GetRandomSession (
[&ret, ts](SSUSession * session)->bool [&ret, ts](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetRelayTag () && !ret.count (session) && return session->GetRelayTag () && !ret.count (session.get ()) &&
session->GetState () == eSessionStateEstablished && session->GetState () == eSessionStateEstablished &&
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
} }
); );
if (session) if (session)
{ {
ret.insert (session); ret.insert (session.get ());
break; break;
} }
} }
@@ -314,8 +335,8 @@ namespace transport
void SSUServer::ScheduleIntroducersUpdateTimer () void SSUServer::ScheduleIntroducersUpdateTimer ()
{ {
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
m_IntroducersUpdateTimer.async_wait (boost::bind (&SSUServer::HandleIntroducersUpdateTimer, m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, boost::asio::placeholders::error)); this, std::placeholders::_1));
} }
void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode) void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode)

23
SSU.h
View File

@@ -31,22 +31,23 @@ namespace transport
~SSUServer (); ~SSUServer ();
void Start (); void Start ();
void Stop (); void Stop ();
SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false); std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
SSUSession * FindSession (const i2p::data::RouterInfo * router); std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
SSUSession * FindSession (const boost::asio::ip::udp::endpoint& e); std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
SSUSession * GetRandomEstablishedSession (const SSUSession * excluded); std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (SSUSession * session); void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions (); void DeleteAllSessions ();
boost::asio::io_service& GetService () { return m_Socket.get_io_service(); }; boost::asio::io_service& GetService () { return m_Socket.get_io_service(); };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay); void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay);
SSUSession * FindRelaySession (uint32_t tag); std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
private: private:
void Run (); void Run ();
void RunV6 ();
void Receive (); void Receive ();
void ReceiveV6 (); void ReceiveV6 ();
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@@ -54,7 +55,7 @@ namespace transport
void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred); void HandleReceivedBuffer (boost::asio::ip::udp::endpoint& from, uint8_t * buf, std::size_t bytes_transferred);
template<typename Filter> template<typename Filter>
SSUSession * GetRandomSession (Filter filter); std::shared_ptr<SSUSession> GetRandomSession (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers); std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer (); void ScheduleIntroducersUpdateTimer ();
@@ -63,9 +64,9 @@ namespace transport
private: private:
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread, * m_ThreadV6;
boost::asio::io_service m_Service; boost::asio::io_service m_Service, m_ServiceV6;
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work, m_WorkV6;
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6; boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
boost::asio::ip::udp::socket m_Socket, m_SocketV6; boost::asio::ip::udp::socket m_Socket, m_SocketV6;
boost::asio::ip::udp::endpoint m_SenderEndpoint, m_SenderEndpointV6; boost::asio::ip::udp::endpoint m_SenderEndpoint, m_SenderEndpointV6;
@@ -73,7 +74,7 @@ namespace transport
std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer; i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V4> m_ReceiveBuffer;
i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6; i2p::crypto::AESAlignedBuffer<2*SSU_MTU_V6> m_ReceiveBufferV6;
std::map<boost::asio::ip::udp::endpoint, SSUSession *> m_Sessions; std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions;
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer
public: public:

View File

@@ -401,8 +401,9 @@ namespace transport
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL)); m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
m_ResendTimer.async_wait (boost::bind (&SSUData::HandleResendTimer, auto s = m_Session.shared_from_this();
this, boost::asio::placeholders::error)); m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
{ s->m_Data.HandleResendTimer (ecode); });
} }
void SSUData::HandleResendTimer (const boost::system::error_code& ecode) void SSUData::HandleResendTimer (const boost::system::error_code& ecode)

View File

@@ -14,15 +14,13 @@ namespace i2p
namespace transport namespace transport
{ {
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router, bool peerTest ): TransportSession (router), std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ): TransportSession (router),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_Server (server), m_RemoteEndpoint (remoteEndpoint),
m_Timer (m_Server.GetService ()), m_PeerTest (peerTest), m_Timer (m_Server.GetService ()), m_PeerTest (peerTest),
m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0), m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0),
m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0) m_Data (*this), m_NumSentBytes (0), m_NumReceivedBytes (0)
{ {
m_CreationTime = i2p::util::GetSecondsSinceEpoch (); m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
if (!router) // incoming session
ScheduleConnectTimer ();
} }
SSUSession::~SSUSession () SSUSession::~SSUSession ()
@@ -111,7 +109,7 @@ namespace transport
else else
{ {
LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint); LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint);
m_Server.DeleteSession (this); m_Server.DeleteSession (shared_from_this ());
return; return;
} }
} }
@@ -146,13 +144,13 @@ namespace transport
case PAYLOAD_TYPE_SESSION_DESTROYED: case PAYLOAD_TYPE_SESSION_DESTROYED:
{ {
LogPrint (eLogDebug, "SSU session destroy received"); LogPrint (eLogDebug, "SSU session destroy received");
m_Server.DeleteSession (this); // delete this m_Server.DeleteSession (shared_from_this ());
break; break;
} }
case PAYLOAD_TYPE_RELAY_RESPONSE: case PAYLOAD_TYPE_RELAY_RESPONSE:
ProcessRelayResponse (buf, len); ProcessRelayResponse (buf, len);
if (m_State != eSessionStateEstablished) if (m_State != eSessionStateEstablished)
m_Server.DeleteSession (this); m_Server.DeleteSession (shared_from_this ());
break; break;
case PAYLOAD_TYPE_RELAY_REQUEST: case PAYLOAD_TYPE_RELAY_REQUEST:
LogPrint (eLogDebug, "SSU relay request received"); LogPrint (eLogDebug, "SSU relay request received");
@@ -461,7 +459,7 @@ namespace transport
buf += 32; // introkey buf += 32; // introkey
uint32_t nonce = be32toh (*(uint32_t *)buf); uint32_t nonce = be32toh (*(uint32_t *)buf);
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint); SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
SendRelayIntro (session, from); SendRelayIntro (session.get (), from);
} }
} }
@@ -701,12 +699,20 @@ namespace transport
} }
} }
void SSUSession::WaitForConnect ()
{
if (!m_RemoteRouter) // incoming session
ScheduleConnectTimer ();
else
LogPrint (eLogError, "SSU wait for connect for outgoing session");
}
void SSUSession::ScheduleConnectTimer () void SSUSession::ScheduleConnectTimer ()
{ {
m_Timer.cancel (); m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode) void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode)
@@ -725,8 +731,8 @@ namespace transport
{ {
// set connect timer // set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
SendRelayRequest (iTag, iKey); SendRelayRequest (iTag, iKey);
} }
@@ -736,8 +742,8 @@ namespace transport
m_State = eSessionStateIntroduced; m_State = eSessionStateIntroduced;
// set connect timer // set connect timer
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleConnectTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::Close () void SSUSession::Close ()
@@ -776,7 +782,7 @@ namespace transport
if (m_State != eSessionStateFailed) if (m_State != eSessionStateFailed)
{ {
m_State = eSessionStateFailed; m_State = eSessionStateFailed;
m_Server.DeleteSession (this); // delete this m_Server.DeleteSession (shared_from_this ());
} }
} }
@@ -784,8 +790,8 @@ namespace transport
{ {
m_Timer.cancel (); m_Timer.cancel ();
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_TIMEOUT));
m_Timer.async_wait (boost::bind (&SSUSession::HandleTerminationTimer, m_Timer.async_wait (std::bind (&SSUSession::HandleTerminationTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode) void SSUSession::HandleTerminationTimer (const boost::system::error_code& ecode)
@@ -815,7 +821,7 @@ namespace transport
void SSUSession::SendI2NPMessage (I2NPMessage * msg) void SSUSession::SendI2NPMessage (I2NPMessage * msg)
{ {
m_Server.GetService ().post (boost::bind (&SSUSession::PostI2NPMessage, this, msg)); m_Server.GetService ().post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg));
} }
void SSUSession::PostI2NPMessage (I2NPMessage * msg) void SSUSession::PostI2NPMessage (I2NPMessage * msg)
@@ -891,7 +897,7 @@ namespace transport
else else
{ {
LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob"); LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob");
auto session = m_Server.GetRandomEstablishedSession (this); // charlie auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // charlie
if (session) if (session)
session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
senderEndpoint.port (), introKey, false); senderEndpoint.port (), introKey, false);

View File

@@ -4,7 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <list> #include <list>
#include <boost/asio.hpp> #include <memory>
#include "aes.h" #include "aes.h"
#include "hmac.h" #include "hmac.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@@ -50,16 +50,17 @@ namespace transport
}; };
class SSUServer; class SSUServer;
class SSUSession: public TransportSession class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
{ {
public: public:
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router = nullptr, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession (); ~SSUSession ();
void Connect (); void Connect ();
void WaitForConnect ();
void Introduce (uint32_t iTag, const uint8_t * iKey); void Introduce (uint32_t iTag, const uint8_t * iKey);
void WaitForIntroduction (); void WaitForIntroduction ();
void Close (); void Close ();

View File

@@ -3,6 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#include <cryptopp/rsa.h>
#include <cryptopp/asn.h> #include <cryptopp/asn.h>
#include <cryptopp/oids.h> #include <cryptopp/oids.h>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
@@ -21,6 +22,7 @@ namespace crypto
virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0; virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0;
virtual size_t GetPublicKeyLen () const = 0; virtual size_t GetPublicKeyLen () const = 0;
virtual size_t GetSignatureLen () const = 0; virtual size_t GetSignatureLen () const = 0;
virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; };
}; };
class Signer class Signer
@@ -87,67 +89,327 @@ namespace crypto
publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH); publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
} }
template<typename Hash, size_t keyLen>
const size_t ECDSAP256_PUBLIC_KEY_LENGTH = 64; class ECDSAVerifier: public Verifier
const size_t ECDSAP256_PUBLIC_KEY_HALF_LENGTH = ECDSAP256_PUBLIC_KEY_LENGTH/2; {
const size_t ECDSAP256_SIGNATURE_LENGTH = 64;
const size_t ECDSAP256_PRIVATE_KEY_LENGTH = ECDSAP256_SIGNATURE_LENGTH/2;
class ECDSAP256Verifier: public Verifier
{
public: public:
ECDSAP256Verifier (const uint8_t * signingKey) template<typename Curve>
ECDSAVerifier (Curve curve, const uint8_t * signingKey)
{ {
m_PublicKey.Initialize (CryptoPP::ASN1::secp256r1(), m_PublicKey.Initialize (curve,
CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, ECDSAP256_PUBLIC_KEY_HALF_LENGTH), CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, keyLen/2),
CryptoPP::Integer (signingKey + ECDSAP256_PUBLIC_KEY_HALF_LENGTH, ECDSAP256_PUBLIC_KEY_HALF_LENGTH))); CryptoPP::Integer (signingKey + keyLen/2, keyLen/2)));
} }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::Verifier verifier (m_PublicKey); typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Verifier verifier (m_PublicKey);
return verifier.VerifyMessage (buf, len, signature, ECDSAP256_SIGNATURE_LENGTH); return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
} }
size_t GetPublicKeyLen () const { return ECDSAP256_PUBLIC_KEY_LENGTH; }; size_t GetPublicKeyLen () const { return keyLen; };
size_t GetSignatureLen () const { return ECDSAP256_SIGNATURE_LENGTH; }; size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
private: private:
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey m_PublicKey; typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey m_PublicKey;
}; };
class ECDSAP256Signer: public Signer template<typename Hash>
class ECDSASigner: public Signer
{ {
public: public:
ECDSAP256Signer (const uint8_t * signingPrivateKey) template<typename Curve>
ECDSASigner (Curve curve, const uint8_t * signingPrivateKey, size_t keyLen)
{ {
m_PrivateKey.Initialize (CryptoPP::ASN1::secp256r1(), CryptoPP::Integer (signingPrivateKey, ECDSAP256_PRIVATE_KEY_LENGTH)); m_PrivateKey.Initialize (curve, CryptoPP::Integer (signingPrivateKey, keyLen/2)); // private key length
} }
void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
{ {
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::Signer signer (m_PrivateKey); typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::Signer signer (m_PrivateKey);
signer.SignMessage (rnd, buf, len, signature); signer.SignMessage (rnd, buf, len, signature);
} }
private: private:
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey m_PrivateKey; typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey m_PrivateKey;
};
template<typename Hash, typename Curve>
inline void CreateECDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, Curve curve,
size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PrivateKey privateKey;
typename CryptoPP::ECDSA<CryptoPP::ECP, Hash>::PublicKey publicKey;
privateKey.Initialize (rnd, curve);
privateKey.MakePublicKey (publicKey);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, keyLen/2);
auto q = publicKey.GetPublicElement ();
q.x.Encode (signingPublicKey, keyLen/2);
q.y.Encode (signingPublicKey + keyLen/2, keyLen/2);
}
// ECDSA_SHA256_P256
const size_t ECDSAP256_KEY_LENGTH = 64;
class ECDSAP256Verifier: public ECDSAVerifier<CryptoPP::SHA256, ECDSAP256_KEY_LENGTH>
{
public:
ECDSAP256Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp256r1(), signingKey)
{
}
};
class ECDSAP256Signer: public ECDSASigner<CryptoPP::SHA256>
{
public:
ECDSAP256Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp256r1(), signingPrivateKey, ECDSAP256_KEY_LENGTH)
{
}
}; };
inline void CreateECDSAP256RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP256RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PrivateKey privateKey; CreateECDSARandomKeys<CryptoPP::SHA256> (rnd, CryptoPP::ASN1::secp256r1(), ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256>::PublicKey publicKey;
privateKey.Initialize (rnd, CryptoPP::ASN1::secp256r1());
privateKey.MakePublicKey (publicKey);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey, ECDSAP256_PRIVATE_KEY_LENGTH);
auto q = publicKey.GetPublicElement ();
q.x.Encode (signingPublicKey, ECDSAP256_PUBLIC_KEY_HALF_LENGTH);
q.y.Encode (signingPublicKey + ECDSAP256_PUBLIC_KEY_HALF_LENGTH, ECDSAP256_PUBLIC_KEY_HALF_LENGTH);
} }
// ECDSA_SHA384_P384
const size_t ECDSAP384_KEY_LENGTH = 96;
class ECDSAP384Verifier: public ECDSAVerifier<CryptoPP::SHA384, ECDSAP384_KEY_LENGTH>
{
public:
ECDSAP384Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp384r1(), signingKey)
{
}
};
class ECDSAP384Signer: public ECDSASigner<CryptoPP::SHA384>
{
public:
ECDSAP384Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp384r1(), signingPrivateKey, ECDSAP384_KEY_LENGTH)
{
}
};
inline void CreateECDSAP384RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys<CryptoPP::SHA384> (rnd, CryptoPP::ASN1::secp384r1(), ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
// ECDSA_SHA512_P521
const size_t ECDSAP521_KEY_LENGTH = 132;
class ECDSAP521Verifier: public ECDSAVerifier<CryptoPP::SHA512, ECDSAP521_KEY_LENGTH>
{
public:
ECDSAP521Verifier (const uint8_t * signingKey):
ECDSAVerifier (CryptoPP::ASN1::secp521r1(), signingKey)
{
}
};
class ECDSAP521Signer: public ECDSASigner<CryptoPP::SHA512>
{
public:
ECDSAP521Signer (const uint8_t * signingPrivateKey):
ECDSASigner (CryptoPP::ASN1::secp521r1(), signingPrivateKey, ECDSAP521_KEY_LENGTH)
{
}
};
inline void CreateECDSAP521RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys<CryptoPP::SHA512> (rnd, CryptoPP::ASN1::secp521r1(), ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
// RSA
template<typename Hash, size_t keyLen>
class RSAVerifier: public Verifier
{
public:
RSAVerifier (const uint8_t * signingKey)
{
m_PublicKey.Initialize (CryptoPP::Integer (signingKey, keyLen), CryptoPP::Integer (rsae));
}
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
typename CryptoPP::RSASS<CryptoPP::PKCS1v15, Hash>::Verifier verifier (m_PublicKey);
return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length
}
size_t GetPublicKeyLen () const { return keyLen; }
size_t GetSignatureLen () const { return keyLen; }
size_t GetPrivateKeyLen () const { return GetSignatureLen ()*2; };
private:
CryptoPP::RSA::PublicKey m_PublicKey;
};
template<typename Hash>
class RSASigner: public Signer
{
public:
RSASigner (const uint8_t * signingPrivateKey, size_t keyLen)
{
m_PrivateKey.Initialize (CryptoPP::Integer (signingPrivateKey, keyLen/2),
rsae,
CryptoPP::Integer (signingPrivateKey + keyLen/2, keyLen/2));
}
void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
{
typename CryptoPP::RSASS<CryptoPP::PKCS1v15, Hash>::Signer signer (m_PrivateKey);
signer.SignMessage (rnd, buf, len, signature);
}
private:
CryptoPP::RSA::PrivateKey m_PrivateKey;
};
inline void CreateRSARandomKeys (CryptoPP::RandomNumberGenerator& rnd,
size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CryptoPP::RSA::PrivateKey privateKey;
privateKey.Initialize (rnd, publicKeyLen*8, rsae);
privateKey.GetModulus ().Encode (signingPrivateKey, publicKeyLen);
privateKey.GetPrivateExponent ().Encode (signingPrivateKey + publicKeyLen, publicKeyLen);
privateKey.GetModulus ().Encode (signingPublicKey, publicKeyLen);
}
// RSA_SHA256_2048
const size_t RSASHA2562048_KEY_LENGTH = 256;
class RSASHA2562048Verifier: public RSAVerifier<CryptoPP::SHA256, RSASHA2562048_KEY_LENGTH>
{
public:
RSASHA2562048Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
{
}
};
class RSASHA2562048Signer: public RSASigner<CryptoPP::SHA256>
{
public:
RSASHA2562048Signer (const uint8_t * signingPrivateKey):
RSASigner (signingPrivateKey, RSASHA2562048_KEY_LENGTH*2)
{
}
};
// RSA_SHA384_3072
const size_t RSASHA3843072_KEY_LENGTH = 384;
class RSASHA3843072Verifier: public RSAVerifier<CryptoPP::SHA384, RSASHA3843072_KEY_LENGTH>
{
public:
RSASHA3843072Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
{
}
};
class RSASHA3843072Signer: public RSASigner<CryptoPP::SHA384>
{
public:
RSASHA3843072Signer (const uint8_t * signingPrivateKey):
RSASigner (signingPrivateKey, RSASHA3843072_KEY_LENGTH*2)
{
}
};
// RSA_SHA512_4096
const size_t RSASHA5124096_KEY_LENGTH = 512;
class RSASHA5124096Verifier: public RSAVerifier<CryptoPP::SHA512, RSASHA5124096_KEY_LENGTH>
{
public:
RSASHA5124096Verifier (const uint8_t * signingKey): RSAVerifier (signingKey)
{
}
};
class RSASHA5124096Signer: public RSASigner<CryptoPP::SHA512>
{
public:
RSASHA5124096Signer (const uint8_t * signingPrivateKey):
RSASigner (signingPrivateKey, RSASHA5124096_KEY_LENGTH*2)
{
}
};
// Raw verifiers
class RawVerifier
{
public:
virtual ~RawVerifier () {};
virtual void Update (const uint8_t * buf, size_t len) = 0;
virtual bool Verify (const uint8_t * signature) = 0;
};
template<typename Hash, size_t keyLen>
class RSARawVerifier: public RawVerifier
{
public:
RSARawVerifier (const uint8_t * signingKey):
n (signingKey, keyLen)
{
}
void Update (const uint8_t * buf, size_t len)
{
m_Hash.Update (buf, len);
}
bool Verify (const uint8_t * signature)
{
// RSA encryption first
CryptoPP::Integer enSig (a_exp_b_mod_c (CryptoPP::Integer (signature, keyLen),
CryptoPP::Integer (i2p::crypto::rsae), n)); // s^e mod n
uint8_t enSigBuf[keyLen];
enSig.Encode (enSigBuf, keyLen);
uint8_t digest[Hash::DIGESTSIZE];
m_Hash.Final (digest);
if ((int)keyLen < Hash::DIGESTSIZE) return false; // can't verify digest longer than key
// we assume digest is right aligned, at least for PKCS#1 v1.5 padding
return !memcmp (enSigBuf + (keyLen - Hash::DIGESTSIZE), digest, Hash::DIGESTSIZE);
}
private:
CryptoPP::Integer n; // RSA modulus
Hash m_Hash;
};
class RSASHA5124096RawVerifier: public RSARawVerifier<CryptoPP::SHA512, RSASHA5124096_KEY_LENGTH>
{
public:
RSASHA5124096RawVerifier (const uint8_t * signingKey): RSARawVerifier (signingKey)
{
}
};
} }
} }

View File

@@ -15,9 +15,9 @@ namespace stream
const i2p::data::LeaseSet& remote, int port): 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_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_IsOpen (false),
m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service), m_RemoteLeaseSet (&remote), m_RoutingSession (nullptr), m_CurrentOutboundTunnel (nullptr),
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumReceivedBytes (0), m_Port (port) m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port)
{ {
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
UpdateCurrentRemoteLease (); UpdateCurrentRemoteLease ();
@@ -26,9 +26,9 @@ namespace stream
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): Stream::Stream (boost::asio::io_service& service, StreamingDestination& local):
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), 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_IsOpen (false), m_IsReset (false), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_ReceiveTimer (m_Service), m_RemoteLeaseSet (nullptr), m_RoutingSession (nullptr), m_CurrentOutboundTunnel (nullptr),
m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumReceivedBytes (0), m_Port (0) m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0)
{ {
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
} }
@@ -52,8 +52,7 @@ namespace stream
for (auto it: m_SavedPackets) for (auto it: m_SavedPackets)
delete it; delete it;
m_SavedPackets.clear (); m_SavedPackets.clear ();
LogPrint (eLogDebug, "Stream deleted");
Close ();
} }
void Stream::HandleNextPacket (Packet * packet) void Stream::HandleNextPacket (Packet * packet)
@@ -70,12 +69,12 @@ namespace stream
if (!receivedSeqn && !isSyn) if (!receivedSeqn && !isSyn)
{ {
// plain ack // plain ack
LogPrint ("Plain ACK received"); LogPrint (eLogDebug, "Plain ACK received");
delete packet; delete packet;
return; return;
} }
LogPrint ("Received seqn=", receivedSeqn); LogPrint (eLogDebug, "Received seqn=", receivedSeqn);
if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1) if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
{ {
// we have received next in sequence message // we have received next in sequence message
@@ -102,8 +101,8 @@ namespace stream
{ {
m_IsAckSendScheduled = true; m_IsAckSendScheduled = true;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT)); m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT));
m_AckSendTimer.async_wait (boost::bind (&Stream::HandleAckSendTimer, m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
} }
else if (isSyn) else if (isSyn)
@@ -115,17 +114,24 @@ namespace stream
if (receivedSeqn <= m_LastReceivedSequenceNumber) if (receivedSeqn <= m_LastReceivedSequenceNumber)
{ {
// we have received duplicate. Most likely our outbound tunnel is dead // we have received duplicate. Most likely our outbound tunnel is dead
LogPrint ("Duplicate message ", receivedSeqn, " received"); LogPrint (eLogWarning, "Duplicate message ", receivedSeqn, " received");
m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel m_CurrentOutboundTunnel = nullptr; // pick another outbound tunnel
UpdateCurrentRemoteLease (); // pick another lease UpdateCurrentRemoteLease (); // pick another lease
SendQuickAck (); // resend ack for previous message again SendQuickAck (); // resend ack for previous message again
delete packet; // packet dropped delete packet; // packet dropped
} }
else else
{ {
LogPrint ("Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1); LogPrint (eLogWarning, "Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
// save message and wait for missing message again // save message and wait for missing message again
SavePacket (packet); SavePacket (packet);
// send NACKs for missing messages ASAP
if (m_IsAckSendScheduled)
{
m_IsAckSendScheduled = false;
m_AckSendTimer.cancel ();
}
SendQuickAck ();
} }
} }
} }
@@ -140,11 +146,11 @@ namespace stream
// process flags // process flags
uint32_t receivedSeqn = packet->GetSeqn (); uint32_t receivedSeqn = packet->GetSeqn ();
uint16_t flags = packet->GetFlags (); uint16_t flags = packet->GetFlags ();
LogPrint ("Process seqn=", receivedSeqn, ", flags=", flags); LogPrint (eLogDebug, "Process seqn=", receivedSeqn, ", flags=", flags);
const uint8_t * optionData = packet->GetOptionData (); const uint8_t * optionData = packet->GetOptionData ();
if (flags & PACKET_FLAG_SYNCHRONIZE) if (flags & PACKET_FLAG_SYNCHRONIZE)
LogPrint ("Synchronize"); LogPrint (eLogDebug, "Synchronize");
if (flags & PACKET_FLAG_DELAY_REQUESTED) if (flags & PACKET_FLAG_DELAY_REQUESTED)
{ {
@@ -154,28 +160,28 @@ namespace stream
if (flags & PACKET_FLAG_FROM_INCLUDED) if (flags & PACKET_FLAG_FROM_INCLUDED)
{ {
optionData += m_RemoteIdentity.FromBuffer (optionData, packet->GetOptionSize ()); optionData += m_RemoteIdentity.FromBuffer (optionData, packet->GetOptionSize ());
LogPrint ("From identity ", m_RemoteIdentity.GetIdentHash ().ToBase64 ()); LogPrint (eLogInfo, "From identity ", m_RemoteIdentity.GetIdentHash ().ToBase64 ());
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
LogPrint ("Incoming stream from ", m_RemoteIdentity.GetIdentHash ().ToBase64 ()); LogPrint (eLogDebug, "Incoming stream from ", m_RemoteIdentity.GetIdentHash ().ToBase64 ());
} }
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED) if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
{ {
uint16_t maxPacketSize = be16toh (*(uint16_t *)optionData); uint16_t maxPacketSize = be16toh (*(uint16_t *)optionData);
LogPrint ("Max packet size ", maxPacketSize); LogPrint (eLogDebug, "Max packet size ", maxPacketSize);
optionData += 2; optionData += 2;
} }
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
{ {
LogPrint ("Signature"); LogPrint (eLogDebug, "Signature");
uint8_t signature[256]; uint8_t signature[256];
auto signatureLen = m_RemoteIdentity.GetSignatureLen (); auto signatureLen = m_RemoteIdentity.GetSignatureLen ();
memcpy (signature, optionData, signatureLen); memcpy (signature, optionData, signatureLen);
memset (const_cast<uint8_t *>(optionData), 0, signatureLen); memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
if (!m_RemoteIdentity.Verify (packet->GetBuffer (), packet->GetLength (), signature)) if (!m_RemoteIdentity.Verify (packet->GetBuffer (), packet->GetLength (), signature))
{ {
LogPrint ("Signature verification failed"); LogPrint (eLogError, "Signature verification failed");
Close (); Close ();
flags |= PACKET_FLAG_CLOSE; flags |= PACKET_FLAG_CLOSE;
} }
@@ -196,13 +202,10 @@ namespace stream
if (flags & PACKET_FLAG_CLOSE) if (flags & PACKET_FLAG_CLOSE)
{ {
LogPrint ("Closed"); LogPrint (eLogInfo, "Closed");
SendQuickAck (); // send ack for close explicitly? Close ();
m_IsOpen = false; m_IsOpen = false;
m_IsReset = true; m_IsReset = true;
m_ReceiveTimer.cancel ();
m_ResendTimer.cancel ();
m_AckSendTimer.cancel ();
} }
} }
@@ -226,13 +229,13 @@ namespace stream
} }
if (nacked) if (nacked)
{ {
LogPrint ("Packet ", seqn, " NACK"); LogPrint (eLogDebug, "Packet ", seqn, " NACK");
it++; it++;
continue; continue;
} }
} }
auto sentPacket = *it; auto sentPacket = *it;
LogPrint ("Packet ", seqn, " acknowledged"); LogPrint (eLogDebug, "Packet ", seqn, " acknowledged");
m_SentPackets.erase (it++); m_SentPackets.erase (it++);
delete sentPacket; delete sentPacket;
} }
@@ -246,6 +249,7 @@ namespace stream
size_t Stream::Send (const uint8_t * buf, size_t len) size_t Stream::Send (const uint8_t * buf, size_t len)
{ {
bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet
std::vector<Packet *> packets;
while (!m_IsOpen || len > 0) while (!m_IsOpen || len > 0)
{ {
Packet * p = new Packet (); Packet * p = new Packet ();
@@ -309,15 +313,28 @@ namespace stream
size += sentLen; // payload size += sentLen; // payload
} }
p->len = size; p->len = size;
m_Service.post (boost::bind (&Stream::SendPacket, this, p)); packets.push_back (p);
} }
if (packets.size () > 0)
m_Service.post (std::bind (&Stream::PostPackets, shared_from_this (), packets));
return len; return len;
} }
void Stream::SendQuickAck () void Stream::SendQuickAck ()
{ {
int32_t lastReceivedSeqn = m_LastReceivedSequenceNumber;
if (!m_SavedPackets.empty ())
{
int32_t seqn = (*m_SavedPackets.rbegin ())->GetSeqn ();
if (seqn > lastReceivedSeqn) lastReceivedSeqn = seqn;
}
if (lastReceivedSeqn < 0)
{
LogPrint (eLogError, "No packets have been received yet");
return;
}
Packet p; Packet p;
uint8_t * packet = p.GetBuffer (); uint8_t * packet = p.GetBuffer ();
size_t size = 0; size_t size = 0;
@@ -327,10 +344,35 @@ namespace stream
size += 4; // receiveStreamID size += 4; // receiveStreamID
*(uint32_t *)(packet + size) = 0; // this is plain Ack message *(uint32_t *)(packet + size) = 0; // this is plain Ack message
size += 4; // sequenceNum size += 4; // sequenceNum
*(uint32_t *)(packet + size) = htobe32 (m_LastReceivedSequenceNumber); *(uint32_t *)(packet + size) = htobe32 (lastReceivedSeqn);
size += 4; // ack Through size += 4; // ack Through
packet[size] = 0; if (lastReceivedSeqn > m_LastReceivedSequenceNumber)
size++; // NACK count {
// fill NACKs
uint8_t * nacks = packet + size + 1;
uint8_t numNacks = 0;
auto nextSeqn = m_LastReceivedSequenceNumber + 1;
for (auto it: m_SavedPackets)
{
auto seqn = it->GetSeqn ();
for (uint32_t i = nextSeqn; i < seqn; i++)
{
*(uint32_t *)nacks = htobe32 (i);
nacks += 4;
numNacks++;
}
nextSeqn = seqn + 1;
}
packet[size] = numNacks;
size++; // NACK count
size += numNacks*4; // NACKs
}
else
{
// No NACKs
packet[size] = 0;
size++; // NACK count
}
size++; // resend delay size++; // resend delay
*(uint16_t *)(packet + size) = 0; // nof flags set *(uint16_t *)(packet + size) = 0; // nof flags set
size += 2; // flags size += 2; // flags
@@ -372,8 +414,10 @@ namespace stream
m_LocalDestination.GetOwner ().Sign (packet, size, signature); m_LocalDestination.GetOwner ().Sign (packet, size, signature);
p->len = size; p->len = size;
SendPacket (p); m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p));
LogPrint ("FIN sent"); LogPrint ("FIN sent");
m_ReceiveTimer.cancel ();
m_LocalDestination.DeleteStream (shared_from_this ());
} }
} }
@@ -420,7 +464,31 @@ namespace stream
else else
return false; return false;
} }
void Stream::PostPackets (const std::vector<Packet *> packets)
{
if (m_IsOpen)
{
if (packets.size () > 0)
{
m_IsAckSendScheduled = false;
m_AckSendTimer.cancel ();
}
bool isEmpty = m_SentPackets.empty ();
for (auto it: packets)
m_SentPackets.insert (it);
SendPackets (packets);
if (isEmpty)
ScheduleResend ();
}
else
{
// delete
for (auto it: packets)
delete it;
}
}
void Stream::SendPackets (const std::vector<Packet *>& packets) void Stream::SendPackets (const std::vector<Packet *>& packets)
{ {
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
@@ -432,6 +500,12 @@ namespace stream
return; return;
} }
} }
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
if (!m_CurrentOutboundTunnel)
{
LogPrint ("No outbound tunnels in the pool");
return;
}
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts >= m_CurrentRemoteLease.endDate) if (ts >= m_CurrentRemoteLease.endDate)
@@ -450,7 +524,7 @@ namespace stream
}); });
m_NumSentBytes += it->GetLength (); m_NumSentBytes += it->GetLength ();
} }
m_LocalDestination.GetOwner ().SendTunnelDataMsgs (msgs); m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
} }
else else
LogPrint ("All leases are expired"); LogPrint ("All leases are expired");
@@ -460,8 +534,8 @@ namespace stream
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_TIMEOUT)); m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_TIMEOUT));
m_ResendTimer.async_wait (boost::bind (&Stream::HandleResendTimer, m_ResendTimer.async_wait (std::bind (&Stream::HandleResendTimer,
this, boost::asio::placeholders::error)); shared_from_this (), std::placeholders::_1));
} }
void Stream::HandleResendTimer (const boost::system::error_code& ecode) void Stream::HandleResendTimer (const boost::system::error_code& ecode)
@@ -476,7 +550,8 @@ namespace stream
packets.push_back (it); packets.push_back (it);
else else
{ {
Close (); LogPrint (eLogWarning, "Packet ", it->GetSeqn (), "was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts. Terminate");
m_IsOpen = false;
m_IsReset = true; m_IsReset = true;
m_ReceiveTimer.cancel (); m_ReceiveTimer.cancel ();
return; return;
@@ -484,7 +559,7 @@ namespace stream
} }
if (packets.size () > 0) if (packets.size () > 0)
{ {
m_LocalDestination.GetOwner ().ResetCurrentOutboundTunnel (); // pick another outbound tunnel m_CurrentOutboundTunnel = nullptr; // pick another outbound tunnel
UpdateCurrentRemoteLease (); // pick another lease UpdateCurrentRemoteLease (); // pick another lease
SendPackets (packets); SendPackets (packets);
} }
@@ -563,8 +638,6 @@ namespace stream
ResetAcceptor (); ResetAcceptor ();
{ {
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams)
delete it.second;
m_Streams.clear (); m_Streams.clear ();
} }
} }
@@ -597,36 +670,30 @@ namespace stream
} }
} }
Stream * StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port) std::shared_ptr<Stream> StreamingDestination::CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port)
{ {
Stream * s = new Stream (*m_Owner.GetService (), *this, remote, port); auto s = std::make_shared<Stream> (m_Owner.GetService (), *this, remote, port);
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams[s->GetRecvStreamID ()] = s;
return s; return s;
} }
Stream * StreamingDestination::CreateNewIncomingStream () std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream ()
{ {
Stream * s = new Stream (*m_Owner.GetService (), *this); auto s = std::make_shared<Stream> (m_Owner.GetService (), *this);
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
m_Streams[s->GetRecvStreamID ()] = s; m_Streams[s->GetRecvStreamID ()] = s;
return s; return s;
} }
void StreamingDestination::DeleteStream (Stream * stream) void StreamingDestination::DeleteStream (std::shared_ptr<Stream> stream)
{ {
if (stream) if (stream)
{ {
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
auto it = m_Streams.find (stream->GetRecvStreamID ()); auto it = m_Streams.find (stream->GetRecvStreamID ());
if (it != m_Streams.end ()) if (it != m_Streams.end ())
{
m_Streams.erase (it); m_Streams.erase (it);
if (m_Owner.GetService ())
m_Owner.GetService ()->post ([stream](void) { delete stream; });
else
delete stream;
}
} }
} }
@@ -650,11 +717,5 @@ namespace stream
delete uncompressed; delete uncompressed;
} }
} }
void DeleteStream (Stream * stream)
{
if (stream)
stream->GetLocalDestination ().DeleteStream (stream);
}
} }
} }

View File

@@ -7,8 +7,8 @@
#include <set> #include <set>
#include <queue> #include <queue>
#include <functional> #include <functional>
#include <memory>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
@@ -45,8 +45,8 @@ namespace stream
struct Packet struct Packet
{ {
uint8_t buf[MAX_PACKET_SIZE];
size_t len, offset; size_t len, offset;
uint8_t buf[MAX_PACKET_SIZE];
int numResendAttempts; int numResendAttempts;
Packet (): len (0), offset (0), numResendAttempts (0) {}; Packet (): len (0), offset (0), numResendAttempts (0) {};
@@ -78,7 +78,7 @@ namespace stream
}; };
class StreamingDestination; class StreamingDestination;
class Stream class Stream: public std::enable_shared_from_this<Stream>
{ {
public: public:
@@ -112,6 +112,7 @@ namespace stream
void SendQuickAck (); void SendQuickAck ();
bool SendPacket (Packet * packet); bool SendPacket (Packet * packet);
void PostPackets (const std::vector<Packet *> packets);
void SendPackets (const std::vector<Packet *>& packets); void SendPackets (const std::vector<Packet *>& packets);
void SavePacket (Packet * packet); void SavePacket (Packet * packet);
@@ -141,6 +142,7 @@ namespace stream
const i2p::data::LeaseSet * m_RemoteLeaseSet; const i2p::data::LeaseSet * m_RemoteLeaseSet;
i2p::garlic::GarlicRoutingSession * m_RoutingSession; i2p::garlic::GarlicRoutingSession * m_RoutingSession;
i2p::data::Lease m_CurrentRemoteLease; i2p::data::Lease m_CurrentRemoteLease;
i2p::tunnel::OutboundTunnel * m_CurrentOutboundTunnel;
std::queue<Packet *> m_ReceiveQueue; std::queue<Packet *> m_ReceiveQueue;
std::set<Packet *, PacketCmp> m_SavedPackets; std::set<Packet *, PacketCmp> m_SavedPackets;
std::set<Packet *, PacketCmp> m_SentPackets; std::set<Packet *, PacketCmp> m_SentPackets;
@@ -153,7 +155,7 @@ namespace stream
{ {
public: public:
typedef std::function<void (Stream *)> Acceptor; typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {}; StreamingDestination (i2p::client::ClientDestination& owner): m_Owner (owner) {};
~StreamingDestination () {}; ~StreamingDestination () {};
@@ -161,8 +163,8 @@ namespace stream
void Start (); void Start ();
void Stop (); void Stop ();
Stream * CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0); std::shared_ptr<Stream> CreateNewOutgoingStream (const i2p::data::LeaseSet& remote, int port = 0);
void DeleteStream (Stream * stream); void DeleteStream (std::shared_ptr<Stream> stream);
void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; }; void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; };
void ResetAcceptor () { m_Acceptor = nullptr; }; void ResetAcceptor () { m_Acceptor = nullptr; };
bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
@@ -173,13 +175,13 @@ namespace stream
private: private:
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
Stream * CreateNewIncomingStream (); std::shared_ptr<Stream> CreateNewIncomingStream ();
private: private:
i2p::client::ClientDestination& m_Owner; i2p::client::ClientDestination& m_Owner;
std::mutex m_StreamsMutex; std::mutex m_StreamsMutex;
std::map<uint32_t, Stream *> m_Streams; std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
Acceptor m_Acceptor; Acceptor m_Acceptor;
public: public:
@@ -188,8 +190,6 @@ namespace stream
const decltype(m_Streams)& GetStreams () const { return m_Streams; }; const decltype(m_Streams)& GetStreams () const { return m_Streams; };
}; };
void DeleteStream (Stream * stream);
//------------------------------------------------- //-------------------------------------------------
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
@@ -197,15 +197,17 @@ namespace stream
{ {
if (!m_ReceiveQueue.empty ()) if (!m_ReceiveQueue.empty ())
{ {
m_Service.post ([=](void) { this->HandleReceiveTimer ( auto s = shared_from_this();
m_Service.post ([=](void) { s->HandleReceiveTimer (
boost::asio::error::make_error_code (boost::asio::error::operation_aborted), boost::asio::error::make_error_code (boost::asio::error::operation_aborted),
buffer, handler); }); buffer, handler); });
} }
else else
{ {
m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout)); m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
auto s = shared_from_this();
m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ this->HandleReceiveTimer (ecode, buffer, handler); }); { s->HandleReceiveTimer (ecode, buffer, handler); });
} }
} }

View File

@@ -3,6 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <iostream> #include <iostream>
#include <memory>
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@@ -51,7 +52,7 @@ namespace transport
{ {
public: public:
TransportSession (const i2p::data::RouterInfo * in_RemoteRouter): TransportSession (std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr) m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr)
{ {
if (m_RemoteRouter) if (m_RemoteRouter)
@@ -60,12 +61,12 @@ namespace transport
virtual ~TransportSession () { delete m_DHKeysPair; }; virtual ~TransportSession () { delete m_DHKeysPair; };
const i2p::data::RouterInfo * GetRemoteRouter () { return m_RemoteRouter; }; std::shared_ptr<const i2p::data::RouterInfo> GetRemoteRouter () { return m_RemoteRouter; };
const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; }; const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; };
protected: protected:
const i2p::data::RouterInfo * m_RemoteRouter; std::shared_ptr<const i2p::data::RouterInfo> m_RemoteRouter;
i2p::data::IdentityEx m_RemoteIdentity; i2p::data::IdentityEx m_RemoteIdentity;
DHKeysPair * m_DHKeysPair; // X - for client and Y - for server DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
}; };

View File

@@ -121,7 +121,7 @@ namespace transport
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port)); boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
LogPrint ("Start listening TCP port ", address.port); LogPrint ("Start listening TCP port ", address.port);
auto conn = new NTCPServerConnection (m_Service); auto conn = std::make_shared<NTCPSession>(m_Service);
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error)); conn, boost::asio::placeholders::error));
@@ -134,7 +134,7 @@ namespace transport
m_NTCPV6Acceptor->listen (); m_NTCPV6Acceptor->listen ();
LogPrint ("Start listening V6 TCP port ", address.port); LogPrint ("Start listening V6 TCP port ", address.port);
auto conn = new NTCPServerConnection (m_Service); auto conn = std::make_shared<NTCPSession> (m_Service);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6,
this, conn, boost::asio::placeholders::error)); this, conn, boost::asio::placeholders::error));
} }
@@ -162,10 +162,8 @@ namespace transport
delete m_SSUServer; delete m_SSUServer;
m_SSUServer = nullptr; m_SSUServer = nullptr;
} }
for (auto session: m_NTCPSessions)
delete session.second;
m_NTCPSessions.clear (); m_NTCPSessions.clear ();
delete m_NTCPAcceptor; delete m_NTCPAcceptor;
m_NTCPAcceptor = nullptr; m_NTCPAcceptor = nullptr;
delete m_NTCPV6Acceptor; delete m_NTCPV6Acceptor;
@@ -197,55 +195,79 @@ namespace transport
} }
} }
void Transports::AddNTCPSession (NTCPSession * session) void Transports::AddNTCPSession (std::shared_ptr<NTCPSession> session)
{ {
if (session) if (session)
m_NTCPSessions[session->GetRemoteIdentity ().GetIdentHash ()] = session; m_NTCPSessions[session->GetRemoteIdentity ().GetIdentHash ()] = session;
} }
void Transports::RemoveNTCPSession (NTCPSession * session) void Transports::RemoveNTCPSession (std::shared_ptr<NTCPSession> session)
{ {
if (session) if (session)
m_NTCPSessions.erase (session->GetRemoteIdentity ().GetIdentHash ()); m_NTCPSessions.erase (session->GetRemoteIdentity ().GetIdentHash ());
} }
void Transports::HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error) void Transports::HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error)
{ {
if (!error) if (!error)
{ {
LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ()); LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ());
conn->ServerLogin (); conn->ServerLogin ();
} }
else
delete conn;
if (error != boost::asio::error::operation_aborted) if (error != boost::asio::error::operation_aborted)
{ {
conn = new NTCPServerConnection (m_Service); conn = std::make_shared<NTCPSession> (m_Service);
m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this, m_NTCPAcceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAccept, this,
conn, boost::asio::placeholders::error)); conn, boost::asio::placeholders::error));
} }
} }
void Transports::HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error) void Transports::HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error)
{ {
if (!error) if (!error)
{ {
LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ()); LogPrint ("Connected from ", conn->GetSocket ().remote_endpoint().address ().to_string ());
conn->ServerLogin (); conn->ServerLogin ();
} }
else
delete conn;
if (error != boost::asio::error::operation_aborted) if (error != boost::asio::error::operation_aborted)
{ {
conn = new NTCPServerConnection (m_Service); conn = std::make_shared<NTCPSession> (m_Service);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, this, m_NTCPV6Acceptor->async_accept(conn->GetSocket (), boost::bind (&Transports::HandleAcceptV6, this,
conn, boost::asio::placeholders::error)); conn, boost::asio::placeholders::error));
} }
} }
NTCPSession * Transports::GetNextNTCPSession () void Transports::Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn)
{
LogPrint ("Connecting to ", address ,":", port);
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port),
boost::bind (&Transports::HandleConnect, this, boost::asio::placeholders::error, conn));
}
void Transports::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn)
{
if (ecode)
{
LogPrint ("Connect error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted)
{
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ().GetIdentHash (), true);
conn->Terminate ();
}
}
else
{
LogPrint ("Connected");
if (conn->GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
context.UpdateNTCPV6Address (conn->GetSocket ().local_endpoint ().address ());
conn->ClientLogin ();
}
}
std::shared_ptr<NTCPSession> Transports::GetNextNTCPSession ()
{ {
for (auto session: m_NTCPSessions) for (auto session: m_NTCPSessions)
if (session.second->IsEstablished ()) if (session.second->IsEstablished ())
@@ -253,7 +275,7 @@ namespace transport
return 0; return 0;
} }
NTCPSession * Transports::FindNTCPSession (const i2p::data::IdentHash& ident) std::shared_ptr<NTCPSession> Transports::FindNTCPSession (const i2p::data::IdentHash& ident)
{ {
auto it = m_NTCPSessions.find (ident); auto it = m_NTCPSessions.find (ident);
if (it != m_NTCPSessions.end ()) if (it != m_NTCPSessions.end ())
@@ -277,7 +299,7 @@ namespace transport
session->SendI2NPMessage (msg); session->SendI2NPMessage (msg);
else else
{ {
RouterInfo * r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
if (r) if (r)
{ {
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (r) : nullptr; auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (r) : nullptr;
@@ -290,9 +312,10 @@ namespace transport
auto address = r->GetNTCPAddress (!context.SupportsV6 ()); auto address = r->GetNTCPAddress (!context.SupportsV6 ());
if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE) if (address && !r->UsesIntroducer () && !r->IsUnreachable () && msg->GetLength () < NTCP_MAX_MESSAGE_SIZE)
{ {
auto s = new NTCPClient (m_Service, address->host, address->port, *r); auto s = std::make_shared<NTCPSession> (m_Service, r);
AddNTCPSession (s); AddNTCPSession (s);
s->SendI2NPMessage (msg); s->SendI2NPMessage (msg);
Connect (address->host, address->port, s);
} }
else else
{ {
@@ -323,7 +346,7 @@ namespace transport
void Transports::HandleResendTimer (const boost::system::error_code& ecode, void Transports::HandleResendTimer (const boost::system::error_code& ecode,
boost::asio::deadline_timer * timer, const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg) boost::asio::deadline_timer * timer, const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg)
{ {
RouterInfo * r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
if (r) if (r)
{ {
LogPrint ("Router found. Sending message"); LogPrint ("Router found. Sending message");
@@ -337,13 +360,13 @@ namespace transport
delete timer; delete timer;
} }
void Transports::CloseSession (const i2p::data::RouterInfo * router) void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{ {
if (!router) return; if (!router) return;
m_Service.post (boost::bind (&Transports::PostCloseSession, this, router)); m_Service.post (boost::bind (&Transports::PostCloseSession, this, router));
} }
void Transports::PostCloseSession (const i2p::data::RouterInfo * router) void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
{ {
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr; auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
if (ssuSession) // try SSU first if (ssuSession) // try SSU first
@@ -360,7 +383,7 @@ namespace transport
{ {
auto router = i2p::data::netdb.GetRandomRouter (); auto router = i2p::data::netdb.GetRandomRouter ();
if (router && router->IsSSU () && m_SSUServer) if (router && router->IsSSU () && m_SSUServer)
m_SSUServer->GetSession (router.get (), true); // peer test m_SSUServer->GetSession (router, true); // peer test
} }
} }

View File

@@ -8,6 +8,7 @@
#include <map> #include <map>
#include <queue> #include <queue>
#include <string> #include <string>
#include <memory>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "TransportSession.h" #include "TransportSession.h"
@@ -63,25 +64,28 @@ namespace transport
i2p::transport::DHKeysPair * GetNextDHKeysPair (); i2p::transport::DHKeysPair * GetNextDHKeysPair ();
void ReuseDHKeysPair (DHKeysPair * pair); void ReuseDHKeysPair (DHKeysPair * pair);
void AddNTCPSession (NTCPSession * session); void AddNTCPSession (std::shared_ptr<NTCPSession> session);
void RemoveNTCPSession (NTCPSession * session); void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
NTCPSession * GetNextNTCPSession (); std::shared_ptr<NTCPSession> GetNextNTCPSession ();
NTCPSession * FindNTCPSession (const i2p::data::IdentHash& ident); std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void CloseSession (const i2p::data::RouterInfo * router); void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
private: private:
void Run (); void Run ();
void HandleAccept (NTCPServerConnection * conn, const boost::system::error_code& error); void HandleAccept (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
void HandleAcceptV6 (NTCPServerConnection * conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr<NTCPSession> conn, const boost::system::error_code& error);
void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer, void HandleResendTimer (const boost::system::error_code& ecode, boost::asio::deadline_timer * timer,
const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg);
void PostCloseSession (const i2p::data::RouterInfo * router); void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn);
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn);
void DetectExternalIP (); void DetectExternalIP ();
private: private:
@@ -92,7 +96,7 @@ namespace transport
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work;
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor; boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
std::map<i2p::data::IdentHash, NTCPSession *> m_NTCPSessions; std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions;
SSUServer * m_SSUServer; SSUServer * m_SSUServer;
DHKeysPairSupplier m_DHKeysPairSupplier; DHKeysPairSupplier m_DHKeysPairSupplier;

View File

@@ -221,7 +221,7 @@ namespace tunnel
m_PendingTunnels.clear ();*/ m_PendingTunnels.clear ();*/
for (auto& it: m_Pools) for (auto& it: m_Pools)
delete it.second; delete it;
m_Pools.clear (); m_Pools.clear ();
} }
@@ -287,11 +287,11 @@ namespace tunnel
return tunnel; return tunnel;
} }
TunnelPool * Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination& localDestination, int numHops) TunnelPool * Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops)
{ {
auto pool = new TunnelPool (localDestination, numHops); auto pool = new TunnelPool (localDestination, numInboundHops, numOutboundHops);
std::unique_lock<std::mutex> l(m_PoolsMutex); std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools[pool->GetIdentHash ()] = pool; m_Pools.push_back (pool);
return pool; return pool;
} }
@@ -300,7 +300,10 @@ namespace tunnel
if (pool) if (pool)
{ {
StopTunnelPool (pool); StopTunnelPool (pool);
m_Pools.erase (pool->GetLocalDestination ().GetIdentHash ()); {
std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.remove (pool);
}
for (auto it: m_PendingTunnels) for (auto it: m_PendingTunnels)
if (it.second->GetTunnelPool () == pool) if (it.second->GetTunnelPool () == pool)
it.second->SetTunnelPool (nullptr); it.second->SetTunnelPool (nullptr);
@@ -466,9 +469,9 @@ namespace tunnel
if (!inboundTunnel) return; if (!inboundTunnel) return;
LogPrint ("Creating one hop outbound tunnel..."); LogPrint ("Creating one hop outbound tunnel...");
CreateTunnel<OutboundTunnel> ( CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
i2p::data::netdb.GetRandomRouter ().get () i2p::data::netdb.GetRandomRouter ()
}, },
inboundTunnel->GetTunnelConfig ())); inboundTunnel->GetTunnelConfig ()));
} }
@@ -510,7 +513,7 @@ namespace tunnel
LogPrint ("Creating zero hops inbound tunnel..."); LogPrint ("Creating zero hops inbound tunnel...");
CreateZeroHopsInboundTunnel (); CreateZeroHopsInboundTunnel ();
if (!m_ExploratoryPool) if (!m_ExploratoryPool)
m_ExploratoryPool = CreateTunnelPool (i2p::context, 2); // 2-hop exploratory m_ExploratoryPool = CreateTunnelPool (&i2p::context, 2, 2); // 2-hop exploratory
return; return;
} }
@@ -519,9 +522,9 @@ namespace tunnel
// trying to create one more inbound tunnel // trying to create one more inbound tunnel
LogPrint ("Creating one hop inbound tunnel..."); LogPrint ("Creating one hop inbound tunnel...");
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
i2p::data::netdb.GetRandomRouter ().get () i2p::data::netdb.GetRandomRouter ()
})); }));
} }
} }
@@ -551,7 +554,7 @@ namespace tunnel
std::unique_lock<std::mutex> l(m_PoolsMutex); std::unique_lock<std::mutex> l(m_PoolsMutex);
for (auto it: m_Pools) for (auto it: m_Pools)
{ {
TunnelPool * pool = it.second; TunnelPool * pool = it;
if (pool->IsActive ()) if (pool->IsActive ())
{ {
pool->CreateTunnels (); pool->CreateTunnels ();
@@ -609,9 +612,9 @@ namespace tunnel
void Tunnels::CreateZeroHopsInboundTunnel () void Tunnels::CreateZeroHopsInboundTunnel ()
{ {
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *> new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
&i2p::context.GetRouterInfo () i2p::context.GetSharedRouterInfo ()
})); }));
} }
} }

View File

@@ -79,7 +79,7 @@ namespace tunnel
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg);
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::RouterInfo * GetEndpointRouter () const std::shared_ptr<const i2p::data::RouterInfo> GetEndpointRouter () const
{ return GetTunnelConfig ()->GetLastHop ()->router; }; { return GetTunnelConfig ()->GetLastHop ()->router; };
size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
@@ -129,7 +129,7 @@ namespace tunnel
void PostTunnelData (I2NPMessage * msg); void PostTunnelData (I2NPMessage * msg);
template<class TTunnel> template<class TTunnel>
TTunnel * CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel = 0); TTunnel * CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel = 0);
TunnelPool * CreateTunnelPool (i2p::garlic::GarlicDestination& localDestination, int numHops); TunnelPool * CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops);
void DeleteTunnelPool (TunnelPool * pool); void DeleteTunnelPool (TunnelPool * pool);
void StopTunnelPool (TunnelPool * pool); void StopTunnelPool (TunnelPool * pool);
@@ -157,7 +157,7 @@ namespace tunnel
std::mutex m_TransitTunnelsMutex; std::mutex m_TransitTunnelsMutex;
std::map<uint32_t, TransitTunnel *> m_TransitTunnels; std::map<uint32_t, TransitTunnel *> m_TransitTunnels;
std::mutex m_PoolsMutex; std::mutex m_PoolsMutex;
std::map<i2p::data::IdentHash, TunnelPool *> m_Pools; std::list<TunnelPool *> m_Pools;
TunnelPool * m_ExploratoryPool; TunnelPool * m_ExploratoryPool;
i2p::util::Queue<I2NPMessage> m_Queue; i2p::util::Queue<I2NPMessage> m_Queue;

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <memory>
#include "aes.h" #include "aes.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "RouterContext.h" #include "RouterContext.h"
@@ -14,7 +15,7 @@ namespace tunnel
{ {
struct TunnelHopConfig struct TunnelHopConfig
{ {
const i2p::data::RouterInfo * router, * nextRouter; std::shared_ptr<const i2p::data::RouterInfo> router, nextRouter;
uint32_t tunnelID, nextTunnelID; uint32_t tunnelID, nextTunnelID;
uint8_t layerKey[32]; uint8_t layerKey[32];
uint8_t ivKey[32]; uint8_t ivKey[32];
@@ -26,7 +27,7 @@ namespace tunnel
i2p::crypto::TunnelDecryption decryption; i2p::crypto::TunnelDecryption decryption;
int recordIndex; // record # in tunnel build message int recordIndex; // record # in tunnel build message
TunnelHopConfig (const i2p::data::RouterInfo * r) TunnelHopConfig (std::shared_ptr<const i2p::data::RouterInfo> r)
{ {
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (layerKey, 32); rnd.GenerateBlock (layerKey, 32);
@@ -36,14 +37,14 @@ namespace tunnel
isGateway = true; isGateway = true;
isEndpoint = true; isEndpoint = true;
router = r; router = r;
nextRouter = 0; //nextRouter = nullptr;
nextTunnelID = 0; nextTunnelID = 0;
next = 0; next = nullptr;
prev = 0; prev = nullptr;
} }
void SetNextRouter (const i2p::data::RouterInfo * r) void SetNextRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
{ {
nextRouter = r; nextRouter = r;
isEndpoint = false; isEndpoint = false;
@@ -88,7 +89,7 @@ namespace tunnel
public: public:
TunnelConfig (std::vector<const i2p::data::RouterInfo *> peers, TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers,
const TunnelConfig * replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound const TunnelConfig * replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound
{ {
TunnelHopConfig * prev = nullptr; TunnelHopConfig * prev = nullptr;
@@ -109,7 +110,7 @@ namespace tunnel
m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ());
} }
else // inbound else // inbound
m_LastHop->SetNextRouter (&i2p::context.GetRouterInfo ()); m_LastHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
} }
~TunnelConfig () ~TunnelConfig ()
@@ -184,7 +185,7 @@ namespace tunnel
if (hop->isGateway) // inbound tunnel if (hop->isGateway) // inbound tunnel
newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel
else else
newHop->SetNextRouter (&i2p::context.GetRouterInfo ()); newHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
} }
if (!hop->next) newConfig->m_FirstHop = newHop; // last hop if (!hop->next) newConfig->m_FirstHop = newHop; // last hop
@@ -195,7 +196,7 @@ namespace tunnel
TunnelConfig * Clone (const TunnelConfig * replyTunnelConfig = nullptr) const TunnelConfig * Clone (const TunnelConfig * replyTunnelConfig = nullptr) const
{ {
std::vector<const i2p::data::RouterInfo *> peers; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers;
TunnelHopConfig * hop = m_FirstHop; TunnelHopConfig * hop = m_FirstHop;
while (hop) while (hop)
{ {

View File

@@ -132,6 +132,7 @@ namespace tunnel
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage () void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
{ {
m_CurrentTunnelDataMsg = NewI2NPMessage (); m_CurrentTunnelDataMsg = NewI2NPMessage ();
m_CurrentTunnelDataMsg->Align (12);
// we reserve space for padding // we reserve space for padding
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + sizeof (I2NPHeader); m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + sizeof (I2NPHeader);
m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset; m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset;

View File

@@ -10,9 +10,9 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelPool::TunnelPool (i2p::garlic::GarlicDestination& localDestination, int numHops, int numTunnels): TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numTunnels):
m_LocalDestination (localDestination), m_NumHops (numHops), m_NumTunnels (numTunnels), m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_IsActive (true) m_NumTunnels (numTunnels), m_IsActive (true)
{ {
} }
@@ -45,7 +45,8 @@ namespace tunnel
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
m_InboundTunnels.insert (createdTunnel); m_InboundTunnels.insert (createdTunnel);
} }
m_LocalDestination.SetLeaseSetUpdated (); if (m_LocalDestination)
m_LocalDestination->SetLeaseSetUpdated ();
} }
void TunnelPool::TunnelExpired (InboundTunnel * expiredTunnel) void TunnelPool::TunnelExpired (InboundTunnel * expiredTunnel)
@@ -183,13 +184,15 @@ namespace tunnel
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
m_InboundTunnels.erase (it.second.second); m_InboundTunnels.erase (it.second.second);
} }
m_LocalDestination.SetLeaseSetUpdated (); if (m_LocalDestination)
m_LocalDestination->SetLeaseSetUpdated ();
} }
else else
it.second.second->SetState (eTunnelStateTestFailed); it.second.second->SetState (eTunnelStateTestFailed);
} }
} }
m_Tests.clear (); m_Tests.clear ();
// new tests
auto it1 = m_OutboundTunnels.begin (); auto it1 = m_OutboundTunnels.begin ();
auto it2 = m_InboundTunnels.begin (); auto it2 = m_InboundTunnels.begin ();
while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ())
@@ -207,15 +210,26 @@ namespace tunnel
} }
if (!failed) if (!failed)
{ {
uint32_t msgID = rnd.GenerateWord32 (); uint32_t msgID = rnd.GenerateWord32 ();
m_Tests[msgID] = std::make_pair (*it1, *it2); m_Tests[msgID] = std::make_pair (*it1, *it2);
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID)); CreateDeliveryStatusMsg (msgID));
it1++; it2++; it1++; it2++;
} }
} }
} }
void TunnelPool::ProcessGarlicMessage (I2NPMessage * msg)
{
if (m_LocalDestination)
m_LocalDestination->ProcessGarlicMessage (msg);
else
{
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
DeleteI2NPMessage (msg);
}
}
void TunnelPool::ProcessDeliveryStatus (I2NPMessage * msg) void TunnelPool::ProcessDeliveryStatus (I2NPMessage * msg)
{ {
I2NPDeliveryStatusMsg * deliveryStatus = (I2NPDeliveryStatusMsg *)msg->GetPayload (); I2NPDeliveryStatusMsg * deliveryStatus = (I2NPDeliveryStatusMsg *)msg->GetPayload ();
@@ -232,15 +246,25 @@ namespace tunnel
DeleteI2NPMessage (msg); DeleteI2NPMessage (msg);
} }
else else
m_LocalDestination.ProcessDeliveryStatusMessage (msg); {
if (m_LocalDestination)
m_LocalDestination->ProcessDeliveryStatusMessage (msg);
else
{
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
DeleteI2NPMessage (msg);
}
}
} }
const i2p::data::RouterInfo * TunnelPool::SelectNextHop (const i2p::data::RouterInfo * prevHop) const std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
{ {
auto hop = m_NumHops >= 3 ? i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop).get () : bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better
i2p::data::netdb.GetRandomRouter (prevHop).get (); auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
if (!hop) if (!hop)
hop = i2p::data::netdb.GetRandomRouter ().get (); hop = i2p::data::netdb.GetRandomRouter ();
return hop; return hop;
} }
@@ -250,9 +274,9 @@ namespace tunnel
if (!outboundTunnel) if (!outboundTunnel)
outboundTunnel = tunnels.GetNextOutboundTunnel (); outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint ("Creating destination inbound tunnel..."); LogPrint ("Creating destination inbound tunnel...");
const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo (); auto prevHop = i2p::context.GetSharedRouterInfo ();
std::vector<const i2p::data::RouterInfo *> hops; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
int numHops = m_NumHops; int numHops = m_NumInboundHops;
if (outboundTunnel) if (outboundTunnel)
{ {
// last hop // last hop
@@ -294,9 +318,9 @@ namespace tunnel
{ {
LogPrint ("Creating destination outbound tunnel..."); LogPrint ("Creating destination outbound tunnel...");
const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo (); auto prevHop = i2p::context.GetSharedRouterInfo ();
std::vector<const i2p::data::RouterInfo *> hops; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
for (int i = 0; i < m_NumHops; i++) for (int i = 0; i < m_NumOutboundHops; i++)
{ {
auto hop = SelectNextHop (prevHop); auto hop = SelectNextHop (prevHop);
prevHop = hop; prevHop = hop;

View File

@@ -26,14 +26,11 @@ namespace tunnel
{ {
public: public:
TunnelPool (i2p::garlic::GarlicDestination& localDestination, int numHops, int numTunnels = 5); TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numTunnels = 5);
~TunnelPool (); ~TunnelPool ();
const uint8_t * GetEncryptionPrivateKey () const { return m_LocalDestination.GetEncryptionPrivateKey (); }; i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; };
const uint8_t * GetEncryptionPublicKey () const { return m_LocalDestination.GetEncryptionPublicKey (); }; void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; };
const i2p::data::LocalDestination& GetLocalDestination () const { return m_LocalDestination; };
i2p::garlic::GarlicDestination& GetGarlicDestination () const { return m_LocalDestination; };
bool IsExploratory () const { return GetIdentHash () == i2p::context.GetIdentHash (); };
void CreateTunnels (); void CreateTunnels ();
void TunnelCreated (InboundTunnel * createdTunnel); void TunnelCreated (InboundTunnel * createdTunnel);
@@ -42,10 +39,10 @@ namespace tunnel
void TunnelExpired (OutboundTunnel * expiredTunnel); void TunnelExpired (OutboundTunnel * expiredTunnel);
std::vector<InboundTunnel *> GetInboundTunnels (int num) const; std::vector<InboundTunnel *> GetInboundTunnels (int num) const;
OutboundTunnel * GetNextOutboundTunnel (OutboundTunnel * suggested = nullptr) const; OutboundTunnel * GetNextOutboundTunnel (OutboundTunnel * suggested = nullptr) const;
InboundTunnel * GetNextInboundTunnel (InboundTunnel * suggested = nullptr) const; InboundTunnel * GetNextInboundTunnel (InboundTunnel * suggested = nullptr) const;
const i2p::data::IdentHash& GetIdentHash () const { return m_LocalDestination.GetIdentHash (); };
void TestTunnels (); void TestTunnels ();
void ProcessGarlicMessage (I2NPMessage * msg);
void ProcessDeliveryStatus (I2NPMessage * msg); void ProcessDeliveryStatus (I2NPMessage * msg);
bool IsActive () const { return m_IsActive; }; bool IsActive () const { return m_IsActive; };
@@ -61,12 +58,12 @@ namespace tunnel
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels,
typename TTunnels::value_type suggested = nullptr) const; typename TTunnels::value_type suggested = nullptr) const;
const i2p::data::RouterInfo * SelectNextHop (const i2p::data::RouterInfo * prevHop) const; std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
private: private:
i2p::garlic::GarlicDestination& m_LocalDestination; i2p::garlic::GarlicDestination * m_LocalDestination;
int m_NumHops, m_NumTunnels; int m_NumInboundHops, m_NumOutboundHops, m_NumTunnels;
mutable std::mutex m_InboundTunnelsMutex; mutable std::mutex m_InboundTunnelsMutex;
std::set<InboundTunnel *, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first std::set<InboundTunnel *, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
mutable std::mutex m_OutboundTunnelsMutex; mutable std::mutex m_OutboundTunnelsMutex;

View File

@@ -1,6 +1,6 @@
# NSIS Installer script. (Tested with NSIS 2.64 on Windows 7) # NSIS Installer script. (Tested with NSIS 2.64 on Windows 7)
# Author: Mikal Villa (Meeh) # Author: Mikal Villa (Meeh)
# Version: 1.0 # Version: 1.1
Name PurpleI2P Name PurpleI2P
RequestExecutionLevel highest RequestExecutionLevel highest
@@ -9,7 +9,7 @@ ShowInstDetails show
# General Symbol Definitions # General Symbol Definitions
!define REGKEY "SOFTWARE\$(^Name)" !define REGKEY "SOFTWARE\$(^Name)"
!define VERSION 0.2.0.0 !define VERSION 0.3.0.0
!define COMPANY "The Privacy Solutions Project" !define COMPANY "The Privacy Solutions Project"
!define URL "https://i2p.io" !define URL "https://i2p.io"
@@ -64,13 +64,13 @@ Var StartMenuGroup
!insertmacro MUI_LANGUAGE English !insertmacro MUI_LANGUAGE English
# Installer attributes # Installer attributes
OutFile PurpleI2P-0.2.0.0-win32-setup.exe OutFile PurpleI2P-0.3.0.0-win32-setup.exe
InstallDir $PROGRAMFILES\PurpleI2P InstallDir $PROGRAMFILES\PurpleI2P
CRCCheck on CRCCheck on
XPStyle on XPStyle on
BrandingText " " BrandingText " "
ShowInstDetails show ShowInstDetails show
VIProductVersion 0.2.0.0 VIProductVersion 0.3.0.0
VIAddVersionKey ProductName PurpleI2P VIAddVersionKey ProductName PurpleI2P
VIAddVersionKey ProductVersion "${VERSION}" VIAddVersionKey ProductVersion "${VERSION}"
VIAddVersionKey CompanyName "${COMPANY}" VIAddVersionKey CompanyName "${COMPANY}"

View File

@@ -22,6 +22,7 @@
<ClCompile Include="..\AddressBook.cpp" /> <ClCompile Include="..\AddressBook.cpp" />
<ClCompile Include="..\aes.cpp" /> <ClCompile Include="..\aes.cpp" />
<ClCompile Include="..\base64.cpp" /> <ClCompile Include="..\base64.cpp" />
<ClCompile Include="..\BOB.cpp" />
<ClCompile Include="..\CryptoConst.cpp" /> <ClCompile Include="..\CryptoConst.cpp" />
<ClCompile Include="..\Daemon.cpp" /> <ClCompile Include="..\Daemon.cpp" />
<ClCompile Include="..\DaemonWin32.cpp" /> <ClCompile Include="..\DaemonWin32.cpp" />
@@ -62,6 +63,7 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="..\AddressBook.h" /> <ClInclude Include="..\AddressBook.h" />
<ClInclude Include="..\base64.h" /> <ClInclude Include="..\base64.h" />
<ClInclude Include="..\BOB.h" />
<ClInclude Include="..\CryptoConst.h" /> <ClInclude Include="..\CryptoConst.h" />
<ClInclude Include="..\Daemon.h" /> <ClInclude Include="..\Daemon.h" />
<ClInclude Include="..\ElGamal.h" /> <ClInclude Include="..\ElGamal.h" />
@@ -278,4 +280,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

18
aes.cpp
View File

@@ -25,7 +25,7 @@ namespace crypto
"movaps %%xmm3, %%xmm4 \n" \ "movaps %%xmm3, %%xmm4 \n" \
"pslldq $4, %%xmm4 \n" \ "pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \ "pxor %%xmm4, %%xmm3 \n" \
"pslldq $4, %%xmm4 \n" \ "pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \ "pxor %%xmm4, %%xmm3 \n" \
"pslldq $4, %%xmm4 \n" \ "pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \ "pxor %%xmm4, %%xmm3 \n" \
@@ -163,7 +163,7 @@ namespace crypto
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"block_e: \n" "1: \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
@@ -172,7 +172,7 @@ namespace crypto
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"dec %[num] \n" "dec %[num] \n"
"jnz block_e; \n" "jnz 1b \n"
"movups %%xmm1, (%[iv]) \n" "movups %%xmm1, (%[iv]) \n"
: :
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), : [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
@@ -222,7 +222,7 @@ namespace crypto
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"block_d: \n" "1: \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched) DecryptAES256(sched)
@@ -232,7 +232,7 @@ namespace crypto
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"dec %[num] \n" "dec %[num] \n"
"jnz block_d; \n" "jnz 1b \n"
"movups %%xmm1, (%[iv]) \n" "movups %%xmm1, (%[iv]) \n"
: :
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), : [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
@@ -289,7 +289,7 @@ namespace crypto
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[payload]) \n"
// encrypt data, IV is xmm1 // encrypt data, IV is xmm1
"block_et: \n" "1: \n"
"add $16, %[payload] \n" "add $16, %[payload] \n"
"movups (%[payload]), %%xmm0 \n" "movups (%[payload]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
@@ -297,7 +297,7 @@ namespace crypto
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[payload]) \n"
"dec %[num] \n" "dec %[num] \n"
"jnz block_et; \n" "jnz 1b \n"
: :
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()), : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()),
[payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes [payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes
@@ -324,7 +324,7 @@ namespace crypto
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[payload]) \n"
// decrypt data, IV is xmm1 // decrypt data, IV is xmm1
"block_dt: \n" "1: \n"
"add $16, %[payload] \n" "add $16, %[payload] \n"
"movups (%[payload]), %%xmm0 \n" "movups (%[payload]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
@@ -333,7 +333,7 @@ namespace crypto
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[payload]) \n"
"movaps %%xmm2, %%xmm1 \n" "movaps %%xmm2, %%xmm1 \n"
"dec %[num] \n" "dec %[num] \n"
"jnz block_dt; \n" "jnz 1b \n"
: :
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()), : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()),
[payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes [payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes

2
aes.h
View File

@@ -45,7 +45,7 @@ namespace crypto
AESAlignedBuffer () AESAlignedBuffer ()
{ {
m_Buf = m_UnalignedBuffer; m_Buf = m_UnalignedBuffer;
uint8_t rem = ((uint64_t)m_Buf) & 0x0f; uint8_t rem = ((size_t)m_Buf) & 0x0f;
if (rem) if (rem)
m_Buf += (16 - rem); m_Buf += (16 - rem);
} }

View File

@@ -21,9 +21,12 @@ namespace api
i2p::context.Init (); i2p::context.Init ();
} }
void StartI2P () void StartI2P (std::ostream * logStream)
{ {
StartLog (i2p::util::filesystem::GetAppName () + ".log"); if (logStream)
StartLog (logStream);
else
StartLog (i2p::util::filesystem::GetAppName () + ".log");
i2p::data::netdb.Start(); i2p::data::netdb.Start();
LogPrint("NetDB started"); LogPrint("NetDB started");
i2p::transport::transports.Start(); i2p::transport::transports.Start();
@@ -44,16 +47,19 @@ namespace api
StopLog (); StopLog ();
} }
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic) i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
const std::map<std::string, std::string> * params)
{ {
auto localDestination = new i2p::client::ClientDestination (keys, isPublic); auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params);
localDestination->Start (); localDestination->Start ();
return localDestination; return localDestination;
} }
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType) i2p::client::ClientDestination * CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
const std::map<std::string, std::string> * params)
{ {
auto localDestination = new i2p::client::ClientDestination (isPublic, sigType); i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params);
localDestination->Start (); localDestination->Start ();
return localDestination; return localDestination;
} }
@@ -73,9 +79,10 @@ namespace api
i2p::data::netdb.RequestDestination (remote, true, dest->GetTunnelPool ()); i2p::data::netdb.RequestDestination (remote, true, dest->GetTunnelPool ());
} }
i2p::stream::Stream * CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote) std::shared_ptr<i2p::stream::Stream> CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote)
{ {
auto leaseSet = i2p::data::netdb.FindLeaseSet (remote); if (!dest) return nullptr;
auto leaseSet = dest->FindLeaseSet (remote);
if (leaseSet) if (leaseSet)
{ {
auto stream = dest->CreateStream (*leaseSet); auto stream = dest->CreateStream (*leaseSet);
@@ -95,13 +102,10 @@ namespace api
dest->AcceptStreams (acceptor); dest->AcceptStreams (acceptor);
} }
void DestroyStream (i2p::stream::Stream * stream) void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{
stream->Close (); stream->Close ();
i2p::stream::DeleteStream (stream);
}
} }
} }
} }

36
api.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef API_H__
#define API_H__
#include <memory>
#include <iostream>
#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 (std::ostream * logStream = nullptr);
// write system log to logStream, if not specified to <appName>.log in application's folder
void StopI2P ();
// destinations
i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
const std::map<std::string, std::string> * params = nullptr);
i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256,
const std::map<std::string, std::string> * params = nullptr); // transient destinations usually not published
void DestroyLocalDestination (i2p::client::ClientDestination * dest);
// streams
void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote);
std::shared_ptr<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 (std::shared_ptr<i2p::stream::Stream> stream);
}
}
#endif

View File

@@ -1,33 +0,0 @@
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

View File

@@ -1,31 +0,0 @@
#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

View File

@@ -1,19 +0,0 @@
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

@@ -79,7 +79,7 @@ namespace data
outCount = 4*n; outCount = 4*n;
else else
outCount = 4*(n+1); outCount = 4*(n+1);
if (outCount > len) return -1; if (outCount > len) return 0;
pd = (unsigned char *)OutBuffer; pd = (unsigned char *)OutBuffer;
for ( i = 0; i<n; i++ ){ for ( i = 0; i<n; i++ ){
acc_1 = *ps++; acc_1 = *ps++;
@@ -158,7 +158,7 @@ namespace data
outCount = 3*n; outCount = 3*n;
else { else {
outCount = 0; outCount = 0;
return -1; return 0;
} }
ps = (unsigned char *)(InBuffer + InCount - 1); ps = (unsigned char *)(InBuffer + InCount - 1);

View File

@@ -4,20 +4,18 @@ project ( "i2pd" )
# configurale options # configurale options
option(WITH_AESNI "Use AES-NI instructions set" OFF) option(WITH_AESNI "Use AES-NI instructions set" OFF)
option(WITH_HARDENING "Use hardening compiler flags" OFF) option(WITH_HARDENING "Use hardening compiler flags" OFF)
option(WITH_LIBRARY "Build library" ON)
option(WITH_STATIC "Static build" OFF)
# paths # paths
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
set ( CMAKE_SOURCE_DIR ".." ) set ( CMAKE_SOURCE_DIR ".." )
set (SOURCES set (COMMON_SRC
"${CMAKE_SOURCE_DIR}/AddressBook.cpp" "${CMAKE_SOURCE_DIR}/AddressBook.cpp"
"${CMAKE_SOURCE_DIR}/CryptoConst.cpp" "${CMAKE_SOURCE_DIR}/CryptoConst.cpp"
"${CMAKE_SOURCE_DIR}/Daemon.cpp"
"${CMAKE_SOURCE_DIR}/Garlic.cpp" "${CMAKE_SOURCE_DIR}/Garlic.cpp"
"${CMAKE_SOURCE_DIR}/HTTPProxy.cpp"
"${CMAKE_SOURCE_DIR}/HTTPServer.cpp"
"${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp" "${CMAKE_SOURCE_DIR}/I2NPProtocol.cpp"
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
"${CMAKE_SOURCE_DIR}/Identity.cpp" "${CMAKE_SOURCE_DIR}/Identity.cpp"
"${CMAKE_SOURCE_DIR}/LeaseSet.cpp" "${CMAKE_SOURCE_DIR}/LeaseSet.cpp"
"${CMAKE_SOURCE_DIR}/Log.cpp" "${CMAKE_SOURCE_DIR}/Log.cpp"
@@ -26,9 +24,9 @@ set (SOURCES
"${CMAKE_SOURCE_DIR}/Reseed.cpp" "${CMAKE_SOURCE_DIR}/Reseed.cpp"
"${CMAKE_SOURCE_DIR}/RouterContext.cpp" "${CMAKE_SOURCE_DIR}/RouterContext.cpp"
"${CMAKE_SOURCE_DIR}/RouterInfo.cpp" "${CMAKE_SOURCE_DIR}/RouterInfo.cpp"
"${CMAKE_SOURCE_DIR}/SOCKS.cpp"
"${CMAKE_SOURCE_DIR}/SSU.cpp" "${CMAKE_SOURCE_DIR}/SSU.cpp"
"${CMAKE_SOURCE_DIR}/SSUData.cpp" "${CMAKE_SOURCE_DIR}/SSUData.cpp"
"${CMAKE_SOURCE_DIR}/SSUSession.cpp"
"${CMAKE_SOURCE_DIR}/Streaming.cpp" "${CMAKE_SOURCE_DIR}/Streaming.cpp"
"${CMAKE_SOURCE_DIR}/Destination.cpp" "${CMAKE_SOURCE_DIR}/Destination.cpp"
"${CMAKE_SOURCE_DIR}/TransitTunnel.cpp" "${CMAKE_SOURCE_DIR}/TransitTunnel.cpp"
@@ -37,21 +35,34 @@ set (SOURCES
"${CMAKE_SOURCE_DIR}/Transports.cpp" "${CMAKE_SOURCE_DIR}/Transports.cpp"
"${CMAKE_SOURCE_DIR}/TunnelEndpoint.cpp" "${CMAKE_SOURCE_DIR}/TunnelEndpoint.cpp"
"${CMAKE_SOURCE_DIR}/TunnelPool.cpp" "${CMAKE_SOURCE_DIR}/TunnelPool.cpp"
"${CMAKE_SOURCE_DIR}/UPnP.cpp"
"${CMAKE_SOURCE_DIR}/aes.cpp" "${CMAKE_SOURCE_DIR}/aes.cpp"
"${CMAKE_SOURCE_DIR}/base64.cpp" "${CMAKE_SOURCE_DIR}/base64.cpp"
"${CMAKE_SOURCE_DIR}/i2p.cpp"
"${CMAKE_SOURCE_DIR}/util.cpp" "${CMAKE_SOURCE_DIR}/util.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.cpp"
"${CMAKE_SOURCE_DIR}/Datagram.cpp" "${CMAKE_SOURCE_DIR}/Datagram.cpp"
) )
set (DAEMON_SRC
"${CMAKE_SOURCE_DIR}/BOB.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.cpp"
"${CMAKE_SOURCE_DIR}/Daemon.cpp"
"${CMAKE_SOURCE_DIR}/HTTPProxy.cpp"
"${CMAKE_SOURCE_DIR}/HTTPServer.cpp"
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp"
"${CMAKE_SOURCE_DIR}/SOCKS.cpp"
"${CMAKE_SOURCE_DIR}/UPnP.cpp"
"${CMAKE_SOURCE_DIR}/i2p.cpp"
)
set (LIBRARY_SRC
"${CMAKE_SOURCE_DIR}/api.cpp"
)
file (GLOB HEADERS "${CMAKE_SOURCE_DIR}/*.h") file (GLOB HEADERS "${CMAKE_SOURCE_DIR}/*.h")
# MSVS grouping # MSVS grouping
source_group ("Header Files" FILES ${HEADERS}) source_group ("Header Files" FILES ${HEADERS})
source_group ("Source Files" FILES ${SOURCES}) source_group ("Source Files" FILES ${COMMON_SRC} ${DAEMON_SRC} ${LIBRARY_SRC})
# Default build is Debug # Default build is Debug
if (CMAKE_BUILD_TYPE STREQUAL "Release") if (CMAKE_BUILD_TYPE STREQUAL "Release")
@@ -61,7 +72,7 @@ else ()
endif () endif ()
# compiler flags customization (by vendor) # compiler flags customization (by vendor)
add_definitions ( "-Wall -Wextra" ) add_definitions ( "-Wall -Wextra -fPIC" )
# check for c++11 support # check for c++11 support
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@@ -80,7 +91,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_definitions( "-D_FORTIFY_SOURCE=2" ) add_definitions( "-D_FORTIFY_SOURCE=2" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security -Werror=format-security" ) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security -Werror=format-security" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector --param ssp-buffer-size=4" ) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector --param ssp-buffer-size=4" )
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE -pie" )
endif () endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# more tweaks # more tweaks
@@ -88,13 +98,15 @@ endif ()
# compiler flags customization (by system) # compiler flags customization (by system)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
list (APPEND SOURCES "../DaemonLinux.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
list (APPEND SOURCES "../DaemonLinux.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8 # "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" ) add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
list (APPEND SOURCES "../DaemonWin32.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp")
endif () endif ()
if (WITH_AESNI) if (WITH_AESNI)
@@ -115,7 +127,7 @@ if(NOT DEFINED CRYPTO++_INCLUDE_DIR)
endif() endif()
# load includes # load includes
include_directories( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR}) include_directories( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR} "${CMAKE_SOURCE_DIR}/..")
# show summary # show summary
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
@@ -127,14 +139,26 @@ message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}")
message(STATUS "Options:") message(STATUS "Options:")
message(STATUS " AESNI : ${WITH_AESNI}") message(STATUS " AESNI : ${WITH_AESNI}")
message(STATUS " HARDENING : ${WITH_HARDENING}") message(STATUS " HARDENING : ${WITH_HARDENING}")
message(STATUS " LIBRARY : ${WITH_LIBRARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
add_executable ( ${PROJECT_NAME} ${SOURCES} ) add_executable ( ${PROJECT_NAME} ${COMMON_SRC} ${DAEMON_SRC})
if (WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if (WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-z relro -z now" ) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-z relro -z now" )
endif () endif ()
if (WITH_STATIC)
set(BUILD_SHARED_LIBS OFF)
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-static" )
endif ()
target_link_libraries( ${PROJECT_NAME} ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) target_link_libraries( ${PROJECT_NAME} ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} )
install(TARGETS i2pd RUNTIME DESTINATION "bin") install(TARGETS i2pd RUNTIME DESTINATION "bin")
if (WITH_LIBRARY)
add_library("lib${PROJECT_NAME}" SHARED ${COMMON_SRC} ${LIBRARY_SRC})
install(TARGETS "lib${PROJECT_NAME}" LIBRARY DESTINATION "lib")
endif ()

View File

@@ -115,7 +115,7 @@ am_i2p_OBJECTS = AddressBook.$(OBJEXT) CryptoConst.$(OBJEXT) \
TunnelGateway.$(OBJEXT) TunnelPool.$(OBJEXT) UPnP.$(OBJEXT) \ TunnelGateway.$(OBJEXT) TunnelPool.$(OBJEXT) UPnP.$(OBJEXT) \
aes.$(OBJEXT) base64.$(OBJEXT) i2p.$(OBJEXT) util.$(OBJEXT) \ aes.$(OBJEXT) base64.$(OBJEXT) i2p.$(OBJEXT) util.$(OBJEXT) \
SAM.$(OBJEXT) Destination.$(OBJEXT) ClientContext.$(OBJEXT) \ SAM.$(OBJEXT) Destination.$(OBJEXT) ClientContext.$(OBJEXT) \
Datagram.$(OBJEXT) SSUSession.$(OBJEXT) Datagram.$(OBJEXT) SSUSession.$(OBJEXT) BOB.$(OBJEXT)
i2p_OBJECTS = $(am_i2p_OBJECTS) i2p_OBJECTS = $(am_i2p_OBJECTS)
i2p_LDADD = $(LDADD) i2p_LDADD = $(LDADD)
AM_V_P = $(am__v_P_@AM_V@) AM_V_P = $(am__v_P_@AM_V@)
@@ -326,7 +326,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp \
TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \ TunnelGateway.cpp TunnelPool.cpp UPnP.cpp aes.cpp \
base64.cpp i2p.cpp util.cpp SAM.cpp Destination.cpp \ base64.cpp i2p.cpp util.cpp SAM.cpp Destination.cpp \
ClientContext.cpp DataFram.cpp SSUSession.cpp \ ClientContext.cpp DataFram.cpp SSUSession.cpp BOB.cpp \
\ \
AddressBook.h CryptoConst.h Daemon.h ElGamal.h \ AddressBook.h CryptoConst.h Daemon.h ElGamal.h \
Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.h \ Garlic.h HTTPProxy.h HTTPServer.h I2NPProtocol.h \
@@ -338,7 +338,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \ TunnelConfig.h TunnelEndpoint.h TunnelGateway.h \
TunnelPool.h UPnP.h aes.h base64.h config.h hmac.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 TransportSession.h Datagram.h SSUSession.h BOB.h
AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \ AM_LDFLAGS = @BOOST_DATE_TIME_LIB@ @BOOST_FILESYSTEM_LIB@ \
@BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_LIB@ \ @BOOST_PROGRAM_OPTIONS_LIB@ @BOOST_REGEX_LIB@ \
@@ -486,6 +486,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i2p.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i2p.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @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)/SAM.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BOB.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClientContext.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)/Datagram.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSUSession.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SSUSession.Po@am__quote@

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFezCCA2OgAwIBAgIEUQYyQjANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOYnVnbWVAbWFpbC5p
MnAwHhcNMTQxMTA2MDkxMTE0WhcNMjQxMTA1MDkxMTE0WjBuMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOYnVnbWVAbWFpbC5p
MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCrThOH0eSDT0VnCSBC
sqYmAydWH+O8eNttDXr2mSvZLhvAW+6/xHTkKhaWvkIvvS0Vh8hujMnD90Cgp4Fk
TKCxMj9K527o5xIZwWW05OevbjlBwIpVLO1PjmsfsoD1nIX14eEzJSEoAulKsv7V
jGUC/6hC11mmVvH9buQLSRv6sCjuAcMszmw3TAD+XYBIs+z57KuwYXtX3+OA543c
l1/ZKLYkkwY8cwzZqWDVWqTKP5TfVae58t40HhJk3bOsr21FZsaOjlmao3GO+d/3
exKuUGJRcolSqskL3sZ1ovFqko81obvvx0upI0YA0iMr/NRGl3VPuf/LJvRppYGc
LsJHgy9TIgtHvaXRi5Nt4CbKl9sZh/7WkkTTI5YGvevu00btlabAN+DSAZZqdsB3
wY8HhM1MHiA9SWsqwU65TwErcRrjNna2FiDHEu0xk5+/iAGl6CSKHZBmNcYKXSv8
cwShB0jjmciK0a05nC638RPgj0fng7KRrSglyzfjXRrljmZ40LSBL/GGMZMWpOM7
mEsBH5UZJ/2BEmjc9X9257zBdx8BK8y1TXpAligpNBsERcTw1WP1PJ35einZvlXW
qI3GwMf0sl26sn+evcK0gDl27jVDZ45MtNQEq64M4NV3Tn9zq0eg/39YvjVeqrI5
l7sxmYqYGR6BuSncwdc4x+t6swIDAQABoyEwHzAdBgNVHQ4EFgQU/REZ7NMbVZHr
Xkao6Q8Ccqv2kAMwDQYJKoZIhvcNAQENBQADggIBACc2YjLVNbl1kJUdg2klCLJt
5LjNTiIZa2Cha5GStlC/lyoRRge6+q/y9TN3tTptlzLPS9pI9EE1GfIQaE+HAk+e
/bC3KUOAHgVuETvsNAbfpaVsPCdWpFuXmp/4b9iDN7qZy4afTKUPA/Ir/cLfNp14
JULfP4z2yFOsCQZ5viNFAs1u99FrwobV2LBzUSIJQewsksuOwj96zIyau0Y629oJ
k+og88Tifd9EH3MVZNGhdpojQDDdwHQSITnCDgfRP5yER1WIA4jg6l+mM90QkvLY
5NjWTna5kJ3X6UizvgCk365yzT2sbN3R9UGXfCJa9GBcnnviJtJF3+/gC0abwY2f
NtVYp32Xky45NY/NdRhDg0bjHP3psxmX+Sc0M9NuQcDQ+fUR+CzM0IGeiszkzXOs
RG+bOou2cZ81G4oxWdAALHIRrn7VvLGlkFMxiIZyhYcTGQZzsTPT6n18dY99+DAV
yQWZfIRdm8DOnt0G+cwfeohc/9ZwDmj4jJAAi0aeTXdY6NEGIVydk6MAycEhg2Hx
9EV96kRwZNIW0AGY8CozECFL3Eyo2ClQVV4Q35SsBibsitDjM03usc2DJ/qjynXA
C8HoOSWgbddiBvqZueqK8GdhykOy3J3ysr+MNN/lbG48LqkQr1OWxev9rGGQ6RJT
wpBgPyAFAwouPy1whmnx
-----END CERTIFICATE-----

View File

@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIESzCCAzOgAwIBAgIJAKII1waVnWddMA0GCSqGSIb3DQEBCwUAMIG7MQswCQYD
VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll
Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG
A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u
Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDExMjIx
MzQzNThaFw0yMDA1MTQxMzQzNThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR
aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow
GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v
by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB
FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMhcnkSifOMw5bd66UlvYVsc42H22Nuy64qhtJHtggofrwBooF38kRCBVFL8
9Xjzr0xsSshvO6p7E+CEUtA8v55l5vNbUTAvGP9WmzeZyZuCFg9Heo3orNMbIK7m
ppwKhwh6tFEIEpUTz/+xF5NRt0+CqcS4aNHuH3JPwNugfTBuSa86GeSaqL7K4eEZ
bZXqQ16Onvi0yyMqRJDp/ijRFxr2eKGPWb55kuRSET9PxVhlgRKULZkr39Dh9q1c
wb9lAMLMRZIzPVnyvC9jWkIqSDl5bkAAto0n1Jkw92rRp6EVKgSLA/4vl9wTb6xf
WfT5cs7pykAE0WXBr9TqpS3okncCAwEAAaNQME4wHQYDVR0OBBYEFGeEOHhWiKwZ
TGbc7uuK3DD7YjYZMB8GA1UdIwQYMBaAFGeEOHhWiKwZTGbc7uuK3DD7YjYZMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAzRA/0OpJtCO4kQkTn/hux9
dRi9T6B54Xav5jG53iAPLTeMxsaLkvweh2pZ3kvEUrQhvW0JF8QBrHTsgxzb4Wd6
FNDHSgJbZv3uCjFtWeuUh+GTG1k9uwgNIEnx7J9Vp0JCi4ezi/HMNI7c+LjinM9f
hrAzclkeRPLYg645DkxckLyDUbrc9v1qWFoTpezXSBPO7n3Wk4sCytdoA1FkTdXh
RF4BWCl/3uOxcrn0TqoC9vCh8RcxnllOiOO5j4+PQ1Z6NkQ/5oRCK/jjaWc3Lr6/
FicOZJe29BVnrPGynqe0Ky1o+kTdXFflKowfr7g8dwn8k9YavjtGbl1ZSHeuMF8=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,24 @@
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIJAMsPNG1k0yV4MA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD
VQQGEwJERTEVMBMGA1UECAwMbGluay5teDI0LmV1MRUwEwYDVQQHDAxsaW5rLm14
MjQuZXUxFTATBgNVBAoMDGxpbmsubXgyNC5ldTEVMBMGA1UECwwMbGluay5teDI0
LmV1MRUwEwYDVQQDDAxsaW5rLm14MjQuZXUxGzAZBgkqhkiG9w0BCQEWDGxpbmsu
bXgyNC5ldTAeFw0xNDExMTkxOTE4NTRaFw0yMDA1MTExOTE4NTRaMIGdMQswCQYD
VQQGEwJERTEVMBMGA1UECAwMbGluay5teDI0LmV1MRUwEwYDVQQHDAxsaW5rLm14
MjQuZXUxFTATBgNVBAoMDGxpbmsubXgyNC5ldTEVMBMGA1UECwwMbGluay5teDI0
LmV1MRUwEwYDVQQDDAxsaW5rLm14MjQuZXUxGzAZBgkqhkiG9w0BCQEWDGxpbmsu
bXgyNC5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL8modDBRkyh
SHSm92pTfguO3F6n5ocsBJ4vaVoosYq3ILCsapjqmynMHZUef6gEB7+Gn5cKXsH2
JaKOeb8DHrOFCaxfj187x1QfZj1UNMQblx2T9q4th12tqp+k4JuLwgemr+2uAUpM
xx/uHRJXD0hf67+fHQFYNVfa+WvT46xlKGsWDQ0LBsA/z4YGnyeaV4PrS5nj3euA
IbdfDj7rJea3bfhSqYA1ZH1cquKlsXOOYO5cIcXsa5dxDWX51QS+i7+ocph+JN1X
dRh6ZirE9OXZVXwXXVRnJSYjgBlP/DQBdE7YkE1R3LyCVZsgxJaaLV/ujijOIK61
SqEhHvFNRe0CAwEAAaNQME4wHQYDVR0OBBYEFB6XRz6VZlrAE+3xL6AyKrkq+y2X
MB8GA1UdIwQYMBaAFB6XRz6VZlrAE+3xL6AyKrkq+y2XMAwGA1UdEwQFMAMBAf8w
DQYJKoZIhvcNAQELBQADggEBADhxBA5GHisDVf5a+1hIi7FBGBjJJLqzlaKh+bFB
gTCYfk3F4wYzndr1HpdCZSSYDtY3mXFNMWQCpwvwvy1DM+9AMRY68wKNXHa/WypW
zQSqTfEH8cdaIXUALB7pdWFVr3rx0f7/8I0Gj/ByUbJ94rzd22vduX5riY0Rag6B
dPtW0M9bJrC1AIjexzDcStupj9v/ceGYZQYC4zb2tZ7Ek/6q+vei8TxWZjku7Dl4
YRPXXufyB24uQ1hJVy2fSyIJ63tIRJoEFLBNaKDOB53i10xLWBcsJpXKY57AOQMn
flqW4HG8uGJ/o1WjhiOB9eI7T9toy08zNzt+kSI/blFIoek=
-----END CERTIFICATE-----

View File

@@ -1,41 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290
IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB
IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA
Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO
BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi
MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ
ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ
8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6
zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y
fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7
w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc
G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k
epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q
laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ
QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU
fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826
YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w
ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY
gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe
MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0
IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy
dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw
czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0
dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl
aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC
AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg
b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB
ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc
nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg
18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c
gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl
Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY
sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T
SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF
CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum
GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk
zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW
omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD
-----END CERTIFICATE-----

View File

@@ -1,20 +1,14 @@
COMMON_SRC = \
AddressBook.cpp CryptoConst.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp \
LeaseSet.cpp Log.cpp NTCPSession.cpp NetDb.cpp Reseed.cpp RouterContext.cpp \
RouterInfo.cpp SSU.cpp SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp \
TransitTunnel.cpp Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp \
TunnelGateway.cpp Destination.cpp util.cpp aes.cpp base64.cpp
# also: Daemon{Linux,Win32}.cpp will be added later
DAEMON_SRC = $(COMMON_SRC) \
BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp SAM.cpp SOCKS.cpp UPnP.cpp \
HTTPServer.cpp HTTPProxy.cpp i2p.cpp
CPP_FILES := CryptoConst.cpp base64.cpp NTCPSession.cpp RouterInfo.cpp Transports.cpp \ LIB_SRC := $(COMMON_SRC) \
RouterContext.cpp NetDb.cpp LeaseSet.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelGateway.cpp \ api.cpp
TransitTunnel.cpp I2NPProtocol.cpp Log.cpp Garlic.cpp HTTPServer.cpp Streaming.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 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)))

View File

@@ -1,6 +1,7 @@
#include <thread> #include <thread>
#include <stdlib.h> #include <stdlib.h>
#include "Daemon.h" #include "Daemon.h"
#include "Reseed.h"
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {

View File

@@ -211,6 +211,11 @@ namespace filesystem
#endif #endif
#endif #endif
} }
boost::filesystem::path GetCertificatesDir()
{
return GetDataDir () / "certificates";
}
} }
namespace http namespace http

1
util.h
View File

@@ -34,6 +34,7 @@ namespace util
boost::filesystem::path GetConfigFile(); boost::filesystem::path GetConfigFile();
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet); std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet);
boost::filesystem::path GetCertificatesDir();
} }
namespace http namespace http

View File

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