Compare commits

...

179 Commits

Author SHA1 Message Date
orignal
73d4025256 version 0.10.0 2015-07-06 12:11:17 -04:00
orignal
3405ffd8d8 check for buffer size 2015-07-05 07:59:38 -04:00
orignal
e03f1597a0 don't send DatabaseStore until time sync complete 2015-07-03 21:50:26 -04:00
orignal
c5644e0e32 const I2NP messages 2015-07-03 21:27:40 -04:00
orignal
bf14b7da9a move FillI2NPMessageHeader into I2NPMessage 2015-07-03 11:11:07 -04:00
orignal
0c8fb376db some cleanup 2015-07-03 10:11:55 -04:00
orignal
17acdcc4d5 temporary fix of crash 2015-07-02 14:11:30 -04:00
orignal
654357f5ce copy shared_ptr 2015-07-02 13:43:03 -04:00
orignal
fbebdd3055 fixed race condition 2015-07-01 17:20:41 -04:00
orignal
83e76c6b53 use shared flood message 2015-07-01 14:13:42 -04:00
orignal
adf12b6084 handle DeliveryStatus garlic clove directly 2015-06-29 21:40:43 -04:00
orignal
047c6a93a3 don't copy transit DatabaseStore 2015-06-27 22:02:00 -04:00
orignal
bf4c33325c random non-zero padding 2015-06-26 16:06:59 -04:00
orignal
be1a4548e6 pass const I2NP message to HandleTunnelDataMsg 2015-06-25 21:49:16 -04:00
orignal
d8cd2afd12 different input anf output I2NP message for tunnel encryption 2015-06-24 22:19:56 -04:00
orignal
6ff3f8df87 Merge pull request #218 from mlt/fix208
Check for invalid SAM destination
2015-06-24 15:49:25 -04:00
Mikhail Titov
95c4a87ccc Check for invalid SAM destination
This closes #208
2015-06-24 14:20:16 -05:00
orignal
206f094dd4 use shared_ptr for DeliverStatus 2015-06-24 10:45:58 -04:00
orignal
a05a20440e deleted deprecated SendMessage 2015-06-24 10:25:05 -04:00
orignal
ff12421d60 shared_ptr for lookup messages 2015-06-22 15:47:45 -04:00
orignal
2cbd6e85c6 use shared_ptr for garlic messages 2015-06-21 22:29:50 -04:00
orignal
1fc50a59f5 different in and out buffers for tunnel encryption 2015-06-21 17:05:01 -04:00
orignal
9c9401ce2f use shared_ptr for all incoming I2NP messages 2015-06-21 15:08:22 -04:00
orignal
f732a84a7c Merge pull request #214 from mlt/cmake-upnp-libdl
Missing libdl for UPnP
2015-06-20 14:39:41 -04:00
Mikhail Titov
efe7e469ce Missing libdl for UPnP 2015-06-20 12:16:36 -05:00
orignal
ed136c9d8b Merge pull request #213 from mlt/fix-upnp
fixup! Fix UPnP for Win32
2015-06-20 06:56:01 -04:00
Mikhail Titov
60e2722a21 fixup! Fix UPnP for Win32 2015-06-20 00:50:12 -05:00
orignal
4fab07b4da fixed build error 2015-06-19 16:06:14 -04:00
orignal
d07c68bd9a Merge pull request #210 from mlt/fixes
Few fixes
2015-06-19 16:00:12 -04:00
Mikhail Titov
2738169a9d Use static for now while returning HTTP 500 error 2015-06-19 14:47:44 -05:00
Mikhail Titov
490b65dfe2 Materialize temporary string obtained from boost path 2015-06-19 14:47:33 -05:00
Mikhail Titov
38ebe28923 Rearrange eol removal for handshake 2015-06-19 14:47:20 -05:00
orignal
4ed7e29896 use shared_ptr for I2NP messages through tunnels 2015-06-19 14:38:31 -04:00
orignal
122b8c2a84 use shared_ptr for transit tunnel participant 2015-06-17 12:31:28 -04:00
orignal
98c91a01e3 use shared_ptr for outbound tunnel build messages 2015-06-17 12:26:07 -04:00
orignal
a7cd16c159 use shared_ptr for direct DatabaseLookup message 2015-06-17 12:25:02 -04:00
orignal
5ca86b87f5 create shared I2NP tunnel message in OBGW 2015-06-17 12:08:06 -04:00
orignal
25a163cdeb send I2NP messages as shared_ptr 2015-06-17 11:41:07 -04:00
orignal
3a63f6775a pass I2NP message to transport session as shared_ptr 2015-06-17 10:47:26 -04:00
orignal
d65257c7b0 pass I2NP as shared_ptr to netDB 2015-06-16 13:32:42 -04:00
orignal
465945f8a8 more generic queue 2015-06-16 13:14:33 -04:00
orignal
a0de60e179 use share_ptr for garlic messages 2015-06-16 10:14:14 -04:00
orignal
b48682012d verify adler checksum 2015-06-14 10:37:15 -04:00
orignal
e624cb31bd Merge branch 'master' of https://github.com/PurpleI2P/i2pd 2015-06-11 11:43:58 -04:00
orignal
20e43951e5 reduce CPU usage 2015-06-11 11:43:35 -04:00
orignal
576802a1d6 Merge pull request #202 from mlt/fix201
This closes #201
2015-06-10 17:18:36 -04:00
Mikhail Titov
23a3d48611 This closes #201 2015-06-10 16:11:13 -05:00
orignal
b6ec0a3526 Merge pull request #200 from mlt/cmake
Cmake: fix static, precompiled headers, fix crypto++ include dir search
2015-06-10 15:40:42 -04:00
orignal
ef6a038451 handle explicitPeers I2CP parameter 2015-06-10 15:32:55 -04:00
Mikhail Titov
0354685e35 Precompiled headers
Sample times:
MSVC 2013, debug x64: 5min 15sec -> 2min 15sec
Ubuntu 15.04, with hardening, static, release: 5min 21sec -> 3min 24sec
2015-06-10 13:41:08 -05:00
Mikhail Titov
ba2b792916 Cleanup cryptopp headers path search 2015-06-10 13:41:07 -05:00
Mikhail Titov
44768e92ad CMake: fix static builds, add LTO for MinSizeRel 2015-06-10 13:41:06 -05:00
orignal
0e8bdf8299 fixed race condition 2015-06-09 22:14:31 -04:00
orignal
09298d7457 changed profiling algorithm 2015-06-09 14:04:25 -04:00
orignal
e8d80e16ba very hash in one pass 2015-06-09 13:02:37 -04:00
orignal
e461982a31 support multiple transport sessions to the same peer 2015-06-09 11:00:37 -04:00
orignal
c896f6d0d7 select first hop for inbound tunnel from connected peers 2015-06-07 08:37:34 -04:00
orignal
9a9b38a8c3 Merge pull request #199 from mlt/cmake-msvc
MSVC specific debug symbols don't belong to other platforms
2015-06-06 21:47:49 -04:00
orignal
b26b52cca8 Merge pull request #198 from mlt/upnp
Fix UPnP for Win32
2015-06-06 21:47:28 -04:00
Mikhail Titov
b5ee997da9 MSVC specific debug symbols don't belong to other platforms 2015-06-06 14:16:29 -05:00
Mikhail Titov
046ffd8648 Fix UPnP for Win32
* find_package for headers
* Swap includes order to pass compilation with MSVC 2013
* Enforce SO address resolution checks
* Change SO/DLL name on Windows
* Portable sleep from C++11

This closes #186
2015-06-06 13:53:22 -05:00
orignal
d7e7823606 Merge pull request #197 from mlt/cmake-msvc
Fix Win32 build with CMake and MSVC
2015-06-06 14:19:38 -04:00
Mikhail Titov
2d3493a225 Perhaps bitness detection is an introspection
http://www.cmake.org/cmake/help/v3.0/command/find_library.html
2015-06-06 12:34:06 -05:00
Mikhail Titov
a3b08c0016 Fix Win32 build with CMake and MSVC 2015-06-06 12:21:35 -05:00
orignal
d9c0f52846 don't pick node for 5 minutes if declined 2015-06-05 22:09:16 -04:00
orignal
a96482b186 skip missing sections 2015-06-05 21:15:02 -04:00
orignal
10e78785cd additional statistics for profiling 2015-06-05 15:55:21 -04:00
orignal
da56397b39 fixed bug with zero-size clove 2015-06-04 11:31:22 -04:00
orignal
abc05b4485 version 0.9.20 2015-06-04 09:54:46 -04:00
orignal
09fd0baf78 replace Host: for server http tunnels 2015-06-03 12:30:15 -04:00
orignal
d7deb938c5 catch HTTP header of HTTP server tunnel connection 2015-06-02 16:21:38 -04:00
orignal
68834df271 use addresses in server tunnel configuration 2015-06-02 13:18:41 -04:00
orignal
8a3c276e66 I2PTunnelConnectionHTTP added 2015-06-02 13:03:22 -04:00
orignal
6a043649f5 use random msg_id for I2NP messages 2015-05-27 13:35:54 -04:00
orignal
019af7bd3a http server tunnel added 2015-05-20 16:00:09 -04:00
orignal
4f2f67d5b1 Merge branch 'master' of https://github.com/PurpleI2P/i2pd 2015-05-17 19:40:57 -04:00
orignal
2a59ae294d check length of garlic message 2015-05-17 19:40:46 -04:00
Kill Your TV
6d586bde6c Note that Boost 1.58 works 2015-05-14 08:29:17 +00:00
orignal
9510bba3b0 excluded dead reseeds 2015-05-12 11:56:42 -04:00
orignal
eb559f7b6a excluded dead reseeds 2015-05-12 11:51:03 -04:00
orignal
64dbd9abdf Merge pull request #195 from ipslot/master
Update Log.cpp
2015-05-12 06:28:47 -04:00
ipslot
dfd41385b1 Update Log.cpp
set default log to std::cerr stream
2015-05-12 13:27:02 +06:00
orignal
2b797fcd54 use shared_ptr for NetDb's I2NPMessages 2015-05-11 15:17:43 -04:00
orignal
5cd557ef9d check for I2NP message buffer boudary 2015-05-11 12:53:08 -04:00
orignal
8baab2de37 Merge pull request #191 from apprb/dev
CMakeLists.txt: compilation speed up
2015-05-11 06:33:36 -04:00
apprb
c266cff956 CMakeLists.txt: compilation speed up 2015-05-11 15:56:13 +06:00
orignal
53affa3303 Merge pull request #190 from multikatt/patch-1
typo: Gralic -> Garlic
2015-05-09 19:28:22 -04:00
David
ec772c5d46 typo: Gralic -> Garlic 2015-05-09 19:25:11 -04:00
orignal
7b5a7e10a9 fixed log crash at shutdown 2015-05-08 21:42:28 -04:00
orignal
188f1fcff8 rewrite tunnel path inversion code 2015-05-08 14:07:33 -04:00
orignal
39c346df10 created paired inbound tunnel after outbound 2015-05-07 16:03:12 -04:00
orignal
490e829083 Merge pull request #189 from hagen-i2p/gcc5-makefile
* add gcc 5.* to supported compilers
2015-05-07 11:16:20 -04:00
hagen
846128a791 * add gcc5 to supported compilers 2015-05-07 03:40:19 +00:00
orignal
6bad2daa62 fixed build errors for gcc 4.6 2015-05-06 19:18:00 -04:00
orignal
4c91d08cea pass TunnelConfig as shared_ptr 2015-05-06 16:17:48 -04:00
orignal
2442d0e910 moved UPnP instance to Transports. Use actual port from RouterContext 2015-05-06 12:19:20 -04:00
orignal
7c13194d5a don't recalculate timestamp for each log message 2015-05-06 11:24:35 -04:00
orignal
0ae7bbd34d Update README.md 2015-05-05 17:30:32 -04:00
orignal
0b2654f6b1 Update README.md 2015-05-05 17:30:14 -04:00
orignal
42d49bde86 handle tunnels quantity params 2015-05-05 12:32:13 -04:00
orignal
d2b4a6fd50 select first hop from existing connections if applicable 2015-05-05 10:33:19 -04:00
orignal
7f172964f6 check profile only once 2015-05-04 13:01:27 -04:00
Kill Your TV
b8b8d70c7f reseed certificate updates 2015-05-02 21:00:43 +00:00
orignal
969695f318 check garlic clove length 2015-04-21 18:59:35 -04:00
orignal
7ec701a816 uin32_t for elapsed time 2015-04-21 18:33:04 -04:00
orignal
c96b81206d changed some profiling parameters 2015-04-21 15:59:40 -04:00
orignal
5f8356741e fixed potential memory leak 2015-04-18 13:55:15 -04:00
orignal
3987d5e5a0 recreate tunnel after 9.5 minutes 2015-04-17 11:36:42 -04:00
orignal
fcb56db224 try to pick an outbound tunnel with same endpoint instead expired 2015-04-17 10:11:51 -04:00
orignal
873754c6ca select next lease with same gateway if possible 2015-04-16 11:38:36 -04:00
orignal
12465f840a check outbound tunnles for readiness 2015-04-15 18:25:05 -04:00
orignal
e8c9d2db10 double RTO after every resend attempt 2015-04-15 11:52:49 -04:00
orignal
a8b4f38865 router don't expire if less than 75 2015-04-15 07:30:37 -04:00
orignal
27bd193708 re-create tunnel before expiration 2015-04-14 21:37:21 -04:00
orignal
c56ddce2f6 some cleanup 2015-04-14 10:46:44 -04:00
orignal
5d2f9f9f0b fixed potential memory leak 2015-04-14 10:40:46 -04:00
orignal
864aba9f4e version 0.9.19 2015-04-13 18:54:13 -04:00
orignal
4d27399ce3 check profile for high bandwidth peer selection only 2015-04-13 18:51:31 -04:00
orignal
76c54ffdef always check profile for peer selection 2015-04-13 18:41:19 -04:00
orignal
c873e9dd68 don't send reset message due problem at other side 2015-04-13 11:38:23 -04:00
orignal
ce99357ebe check for zero ident 2015-04-12 16:59:59 -04:00
orignal
562de3514a check database lookup type 2015-04-12 15:54:28 -04:00
orignal
128a8f3b48 delete obsolete profiles 2015-04-11 15:39:23 -04:00
orignal
1839b85d97 Merge pull request #180 from 7histle/master
Fix for #179
2015-04-11 07:03:10 -04:00
7histle
f0f154cd10 Fix for #179 2015-04-11 13:47:49 +03:00
orignal
624bff3036 reduced log file size 2015-04-10 19:58:32 -04:00
orignal
1d2950b4a7 reduced CPU load at floodfill 2015-04-10 19:49:58 -04:00
orignal
9072a018dd reduced CPU load at floodfill 2015-04-10 18:13:11 -04:00
orignal
2a997d94bf GetClosestFloodfills added 2015-04-10 16:15:13 -04:00
orignal
2741e94a72 fixed infinite loop 2015-04-10 13:19:23 -04:00
orignal
7c660ee556 show local destination for SAM sessions 2015-04-10 12:11:10 -04:00
orignal
51b850aa85 show windows size and connection status 2015-04-10 11:52:14 -04:00
orignal
b29e94005d fixed crash 2015-04-10 09:58:08 -04:00
orignal
ddd506fde7 Merge pull request #178 from yuri-sevatz/master
Fix -lboost_date_time missing from CMakeLists.txt
2015-04-10 06:57:37 -04:00
Yuri Sevatz
20310cb109 Fix -lboost_date_time missing from CMakeLists.txt 2015-04-10 00:10:35 -04:00
orignal
11177d37ea send and handle RESET flag 2015-04-09 21:09:30 -04:00
orignal
da006a1d6e use AsyncSend 2015-04-09 18:40:23 -04:00
orignal
451b0382ea implemented AsyncSend 2015-04-09 15:07:25 -04:00
orignal
950f250d66 NetDb/NetDbRequests split 2015-04-09 12:45:00 -04:00
orignal
01913d2b14 EdDSA signer added 2015-04-09 10:03:21 -04:00
orignal
e0b19a6383 fixed crash 2015-04-08 19:06:47 -04:00
orignal
48289845df EdDSA signature type added 2015-04-08 16:28:52 -04:00
orignal
454f2dabbd EdDSA signature type added 2015-04-08 16:18:16 -04:00
orignal
8891d9aa4d Decode point 2015-04-08 15:31:13 -04:00
orignal
49d59fc116 IsOnCurve added 2015-04-08 14:07:45 -04:00
orignal
8c92c50f9a multiplication by integer 2015-04-08 13:49:27 -04:00
orignal
75d45ae988 initial code for Ed25519 added 2015-04-08 13:21:49 -04:00
orignal
d5e1d5db9c validate leaseset for zero leases 2015-04-08 10:34:16 -04:00
orignal
9ce9d9b7fc variable length buffer for LeaseSet 2015-04-08 09:39:02 -04:00
orignal
e9edc7b205 Merge pull request #177 from robertfoss/asan_1
Fixed memory leak: delete -> delete[]
2015-04-07 17:27:18 -04:00
orignal
56822d9424 fixed null pointer exception 2015-04-07 17:22:14 -04:00
Robert Foss
2c480bee9a Fixed memory leak: delete -> delete[] 2015-04-07 22:37:24 +02:00
orignal
3983838694 use unique_ptr for ElGamalEncryption 2015-04-07 16:02:07 -04:00
orignal
1e74ff8a85 use shared_ptr for CreateDatabaseStore 2015-04-07 15:15:27 -04:00
orignal
8c47bf9dd3 use shared_ptr for local LeaseSet 2015-04-07 15:02:00 -04:00
orignal
3a26383c4d made Encrypt const 2015-04-07 14:40:36 -04:00
orignal
634976cdde pass LeaseSet to callback of RequestDestination 2015-04-07 12:02:25 -04:00
orignal
bc21f5955f use shared_ptr for AddressReceiver 2015-04-06 15:02:37 -04:00
orignal
e72eb35cc2 use shared_ptr for socket in I2PTunnelConnection 2015-04-06 14:41:07 -04:00
orignal
fbe4e64e44 lookup always takes full address from LeaseSet 2015-04-06 12:22:13 -04:00
orignal
be301dc090 4 tags for LeaseSet request 2015-04-05 20:07:32 -04:00
orignal
250af7f247 fixed race condition 2015-04-05 13:56:41 -04:00
orignal
10577cd1e5 select tunnel from TunnelPool rather than from LeaseSet for DeliveryStatus 2015-04-05 12:54:15 -04:00
orignal
62593f60c5 fixed memory leak 2015-04-04 15:44:29 -04:00
orignal
89ed8c2173 set datagram receiver per port 2015-04-03 20:34:37 -04:00
orignal
321dd252ea fixed crash if no routers available 2015-04-03 10:02:45 -04:00
orignal
19325d552a fixed race condition 2015-04-02 15:10:02 -04:00
orignal
43f8ec46cc fixed crash if can't connect to a reseed 2015-04-02 10:27:07 -04:00
orignal
cb9f78540a Update README.md 2015-04-02 09:01:15 -04:00
orignal
0a15088572 RC4_SHA cipher suite 2015-04-01 20:23:06 -04:00
orignal
ec68338a20 fixed typo 2015-04-01 15:42:26 -04:00
orignal
173b35f77d https://netdb.rows.io:444/ added 2015-04-01 15:07:45 -04:00
orignal
f47831c339 RSA_WITH_AES_256_CBC_SHA support 2015-04-01 14:41:36 -04:00
orignal
e7d4f63884 use SendFinished 2015-04-01 13:55:50 -04:00
orignal
4e81083bb4 AES256 cipher template 2015-04-01 12:56:41 -04:00
orignal
0446a5ae73 moved encryption/decryption to TlsCipher 2015-04-01 12:03:58 -04:00
orignal
a2aec4340d Merge pull request #173 from hagen-i2p/readme-fix
* README.md
2015-04-01 10:37:05 -04:00
hagen
fda68c114c * README.md 2015-04-01 13:48:54 +00:00
orignal
de5c55160b count tunnel acceptance ratio for peer selection 2015-03-31 17:13:01 -04:00
97 changed files with 2706 additions and 1667 deletions

View File

@@ -460,18 +460,15 @@ namespace client
auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident); auto leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident);
if (!leaseSet) if (!leaseSet)
{ {
bool found = false;
std::unique_lock<std::mutex> l(newDataReceivedMutex); std::unique_lock<std::mutex> l(newDataReceivedMutex);
i2p::client::context.GetSharedLocalDestination ()->RequestDestination (ident, i2p::client::context.GetSharedLocalDestination ()->RequestDestination (ident,
[&newDataReceived, &found](bool success) [&newDataReceived, &leaseSet](std::shared_ptr<i2p::data::LeaseSet> ls)
{ {
found = success; leaseSet = ls;
newDataReceived.notify_all (); newDataReceived.notify_all ();
}); });
if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout)
LogPrint (eLogError, "Subscription LeseseSet request timeout expired"); LogPrint (eLogError, "Subscription LeseseSet request timeout expired");
if (found)
leaseSet = i2p::client::context.GetSharedLocalDestination ()->FindLeaseSet (ident);
} }
if (leaseSet) if (leaseSet)
{ {

75
BOB.cpp
View File

@@ -33,27 +33,22 @@ namespace client
void BOBI2PInboundTunnel::Accept () void BOBI2PInboundTunnel::Accept ()
{ {
auto receiver = new AddressReceiver (); auto receiver = std::make_shared<AddressReceiver> ();
receiver->socket = new boost::asio::ip::tcp::socket (GetService ()); receiver->socket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this, m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this,
std::placeholders::_1, receiver)); std::placeholders::_1, receiver));
} }
void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, AddressReceiver * receiver) void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver)
{ {
if (!ecode) if (!ecode)
{ {
Accept (); Accept ();
ReceiveAddress (receiver); ReceiveAddress (receiver);
} }
else
{
delete receiver->socket;
delete receiver;
}
} }
void BOBI2PInboundTunnel::ReceiveAddress (AddressReceiver * receiver) void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver)
{ {
receiver->socket->async_read_some (boost::asio::buffer( receiver->socket->async_read_some (boost::asio::buffer(
receiver->buffer + receiver->bufferOffset, receiver->buffer + receiver->bufferOffset,
@@ -63,14 +58,10 @@ namespace client
} }
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred, void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
AddressReceiver * receiver) std::shared_ptr<AddressReceiver> receiver)
{ {
if (ecode) if (ecode)
{
LogPrint ("BOB inbound tunnel read error: ", ecode.message ()); LogPrint ("BOB inbound tunnel read error: ", ecode.message ());
delete receiver->socket;
delete receiver;
}
else else
{ {
receiver->bufferOffset += bytes_transferred; receiver->bufferOffset += bytes_transferred;
@@ -86,8 +77,6 @@ namespace client
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident)) if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
{ {
LogPrint (eLogError, "BOB address ", receiver->buffer, " not found"); LogPrint (eLogError, "BOB address ", receiver->buffer, " not found");
delete receiver->socket;
delete receiver;
return; return;
} }
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident); auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
@@ -96,46 +85,32 @@ namespace client
else else
GetLocalDestination ()->RequestDestination (ident, GetLocalDestination ()->RequestDestination (ident,
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete, std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
this, std::placeholders::_1, receiver, ident)); this, std::placeholders::_1, receiver));
} }
else else
{ {
if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE) if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE)
ReceiveAddress (receiver); ReceiveAddress (receiver);
else else
{
LogPrint ("BOB missing inbound address "); LogPrint ("BOB missing inbound address ");
delete receiver->socket;
delete receiver;
}
} }
} }
} }
void BOBI2PInboundTunnel::HandleDestinationRequestComplete (bool success, AddressReceiver * receiver, i2p::data::IdentHash ident) void BOBI2PInboundTunnel::HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver)
{ {
if (success) if (leaseSet)
{ CreateConnection (receiver, leaseSet);
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident); else
if (leaseSet) LogPrint ("LeaseSet for BOB inbound destination not found");
{
CreateConnection (receiver, leaseSet);
return;
}
else
LogPrint ("LeaseSet for BOB inbound destination not found");
}
delete receiver->socket;
delete receiver;
} }
void BOBI2PInboundTunnel::CreateConnection (AddressReceiver * receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet) void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
{ {
LogPrint ("New BOB inbound connection"); LogPrint ("New BOB inbound connection");
auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet); auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet);
AddHandler (connection); AddHandler (connection);
connection->I2PConnect (receiver->data, receiver->dataLen); connection->I2PConnect (receiver->data, receiver->dataLen);
delete receiver;
} }
BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& address, int port, BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& address, int port,
@@ -167,7 +142,7 @@ namespace client
{ {
if (stream) if (stream)
{ {
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint, m_IsQuiet); auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet);
AddHandler (conn); AddHandler (conn);
conn->Connect (); conn->Connect ();
} }
@@ -493,13 +468,29 @@ namespace client
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len) void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: lookup ", operand); LogPrint (eLogDebug, "BOB: lookup ", operand);
i2p::data::IdentityEx addr; i2p::data::IdentHash ident;
if (!context.GetAddressBook ().GetAddress (operand, addr)) if (!context.GetAddressBook ().GetIdentHash (operand, ident) || !m_CurrentDestination)
{ {
SendReplyError ("Address Not found"); SendReplyError ("Address Not found");
return; return;
} }
SendReplyOK (addr.ToBase64 ().c_str ()); auto localDestination = m_CurrentDestination->GetLocalDestination ();
auto leaseSet = localDestination->FindLeaseSet (ident);
if (leaseSet)
SendReplyOK (leaseSet->GetIdentity ().ToBase64 ().c_str ());
else
{
auto s = shared_from_this ();
localDestination->RequestDestination (ident,
[s](std::shared_ptr<i2p::data::LeaseSet> ls)
{
if (ls)
s->SendReplyOK (ls->GetIdentity ().ToBase64 ().c_str ());
else
s->SendReplyError ("LeaseSet Not found");
}
);
}
} }
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len) void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)

15
BOB.h
View File

@@ -57,9 +57,9 @@ namespace client
{ {
struct AddressReceiver struct AddressReceiver
{ {
boost::asio::ip::tcp::socket * socket; std::shared_ptr<boost::asio::ip::tcp::socket> socket;
char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address
uint8_t * data; uint8_t * data; // pointer to buffer
size_t dataLen, bufferOffset; size_t dataLen, bufferOffset;
AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {}; AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {};
@@ -76,15 +76,15 @@ namespace client
private: private:
void Accept (); void Accept ();
void HandleAccept (const boost::system::error_code& ecode, AddressReceiver * receiver); void HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver);
void ReceiveAddress (AddressReceiver * receiver); void ReceiveAddress (std::shared_ptr<AddressReceiver> receiver);
void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred, void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
AddressReceiver * receiver); std::shared_ptr<AddressReceiver> receiver);
void HandleDestinationRequestComplete (bool success, AddressReceiver * receiver, i2p::data::IdentHash ident); void HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver);
void CreateConnection (AddressReceiver * receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet); void CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet);
private: private:
@@ -127,6 +127,7 @@ namespace client
void CreateInboundTunnel (int port); void CreateInboundTunnel (int port);
void CreateOutboundTunnel (const std::string& address, int port, bool quiet); void CreateOutboundTunnel (const std::string& address, int port, bool quiet);
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); }; const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDestination; };
private: private:

View File

@@ -295,7 +295,7 @@ namespace client
LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists"); LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists");
numClientTunnels++; numClientTunnels++;
} }
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER) else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP)
{ {
// mandatory params // mandatory params
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST); std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
@@ -306,7 +306,7 @@ namespace client
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, ""); std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
auto localDestination = LoadLocalDestination (keys, true); auto localDestination = LoadLocalDestination (keys, true);
auto serverTunnel = new I2PServerTunnel (host, port, localDestination, inPort); I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (host, port, localDestination, inPort) : new I2PServerTunnel (host, port, localDestination, inPort);
if (accessList.length () > 0) if (accessList.length () > 0)
{ {
std::set<i2p::data::IdentHash> idents; std::set<i2p::data::IdentHash> idents;

View File

@@ -20,6 +20,7 @@ namespace client
const char I2P_TUNNELS_SECTION_TYPE[] = "type"; const char I2P_TUNNELS_SECTION_TYPE[] = "type";
const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client"; const char I2P_TUNNELS_SECTION_TYPE_CLIENT[] = "client";
const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server"; const char I2P_TUNNELS_SECTION_TYPE_SERVER[] = "server";
const char I2P_TUNNELS_SECTION_TYPE_HTTP[] = "http";
const char I2P_CLIENT_TUNNEL_PORT[] = "port"; const char I2P_CLIENT_TUNNEL_PORT[] = "port";
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys"; const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";

View File

@@ -18,11 +18,6 @@
#include "HTTPServer.h" #include "HTTPServer.h"
#include "ClientContext.h" #include "ClientContext.h"
#ifdef USE_UPNP
#include "UPnP.h"
#endif
namespace i2p namespace i2p
{ {
namespace util namespace util
@@ -122,10 +117,6 @@ namespace i2p
LogPrint("Tunnels started"); LogPrint("Tunnels started");
i2p::client::context.Start (); i2p::client::context.Start ();
LogPrint("Client started"); LogPrint("Client started");
#ifdef USE_UPNP
i2p::UPnP::upnpc.Start();
LogPrint("UPnP module loaded");
#endif
return true; return true;
} }
@@ -142,9 +133,7 @@ namespace i2p
LogPrint("NetDB stopped"); LogPrint("NetDB stopped");
d.httpServer->Stop(); d.httpServer->Stop();
LogPrint("HTTP Server stopped"); LogPrint("HTTP Server stopped");
#ifdef USE_UPNP
i2p::UPnP::upnpc.Stop();
#endif
StopLog (); StopLog ();
delete d.httpServer; d.httpServer = nullptr; delete d.httpServer; d.httpServer = nullptr;

View File

@@ -62,7 +62,8 @@ namespace i2p
LogPrint("Error, could not create process group."); LogPrint("Error, could not create process group.");
return false; return false;
} }
chdir(i2p::util::filesystem::GetDataDir().string().c_str()); std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy
chdir(d.c_str());
// close stdin/stdout/stderr descriptors // close stdin/stdout/stderr descriptors
::close (0); ::close (0);

View File

@@ -16,7 +16,7 @@ namespace datagram
m_Owner (owner), m_Receiver (nullptr) m_Owner (owner), m_Receiver (nullptr)
{ {
} }
void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort) void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort)
{ {
uint8_t buf[MAX_DATAGRAM_SIZE]; uint8_t buf[MAX_DATAGRAM_SIZE];
@@ -41,22 +41,15 @@ namespace datagram
if (remote) if (remote)
m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote)); m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote));
else else
m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg));
this, std::placeholders::_1, msg, ident));
} }
void DatagramDestination::HandleLeaseSetRequestComplete (bool success, I2NPMessage * msg, i2p::data::IdentHash ident) void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, I2NPMessage * msg)
{ {
if (success) if (remote)
{ SendMsg (msg, remote);
auto remote = m_Owner.FindLeaseSet (ident); else
if (remote) DeleteI2NPMessage (msg);
{
SendMsg (msg, remote);
return;
}
}
DeleteI2NPMessage (msg);
} }
void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote) void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
@@ -67,7 +60,7 @@ namespace datagram
{ {
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);
auto garlic = m_Owner.WrapMessage (remote, msg, true); auto garlic = m_Owner.WrapMessage (remote, ToSharedI2NPMessage (msg), true);
msgs.push_back (i2p::tunnel::TunnelMessageBlock msgs.push_back (i2p::tunnel::TunnelMessageBlock
{ {
i2p::tunnel::eDeliveryTypeTunnel, i2p::tunnel::eDeliveryTypeTunnel,
@@ -105,7 +98,10 @@ namespace datagram
if (verified) if (verified)
{ {
if (m_Receiver != nullptr) auto it = m_ReceiversByPorts.find (toPort);
if (it != m_ReceiversByPorts.end ())
it->second (identity, fromPort, toPort, buf + headerLen, len -headerLen);
else if (m_Receiver != nullptr)
m_Receiver (identity, fromPort, toPort, buf + headerLen, len -headerLen); m_Receiver (identity, fromPort, toPort, buf + headerLen, len -headerLen);
else else
LogPrint (eLogWarning, "Receiver for datagram is not set"); LogPrint (eLogWarning, "Receiver for datagram is not set");
@@ -147,7 +143,7 @@ namespace datagram
htobe16buf (buf + 6, toPort); // destination port htobe16buf (buf + 6, toPort); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
msg->len += size + 4; msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData); msg->FillI2NPMessageHeader (eI2NPData);
return msg; return msg;
} }
} }

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <map>
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
@@ -32,9 +33,12 @@ namespace datagram
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
void ResetReceiver () { m_Receiver = nullptr; }; void ResetReceiver () { m_Receiver = nullptr; };
void SetReceiver (const Receiver& receiver, uint16_t port) { m_ReceiversByPorts[port] = receiver; };
void ResetReceiver (uint16_t port) { m_ReceiversByPorts.erase (port); };
private: private:
void HandleLeaseSetRequestComplete (bool success, I2NPMessage * msg, i2p::data::IdentHash ident); void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, I2NPMessage * msg);
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote); void SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
@@ -43,7 +47,8 @@ namespace datagram
private: private:
i2p::client::ClientDestination& m_Owner; i2p::client::ClientDestination& m_Owner;
Receiver m_Receiver; Receiver m_Receiver; // default
std::map<uint16_t, Receiver> m_ReceiversByPorts;
}; };
} }
} }

View File

@@ -16,12 +16,15 @@ namespace client
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
const std::map<std::string, std::string> * params): const std::map<std::string, std::string> * params):
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_Keys (keys), m_LeaseSet (nullptr), m_IsPublic (isPublic), m_PublishReplyToken (0), m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0),
m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service) m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service)
{ {
i2p::crypto::GenerateElGamalKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); i2p::crypto::GenerateElGamalKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH; int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY;
int outboundTunnelsQuantity = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
if (params) if (params)
{ {
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
@@ -44,8 +47,44 @@ namespace client
LogPrint (eLogInfo, "Outbound tunnel length set to ", len); LogPrint (eLogInfo, "Outbound tunnel length set to ", len);
} }
} }
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
{
int quantity = boost::lexical_cast<int>(it->second);
if (quantity > 0)
{
inboundTunnelsQuantity = quantity;
LogPrint (eLogInfo, "Inbound tunnels quantity set to ", quantity);
}
}
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
if (it != params->end ())
{
int quantity = boost::lexical_cast<int>(it->second);
if (quantity > 0)
{
outboundTunnelsQuantity = quantity;
LogPrint (eLogInfo, "Outbound tunnels quantity set to ", quantity);
}
}
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
if (it != params->end ())
{
explicitPeers = std::make_shared<std::vector<i2p::data::IdentHash> >();
std::stringstream ss(it->second);
std::string b64;
while (std::getline (ss, b64, ','))
{
i2p::data::IdentHash ident;
ident.FromBase64 (b64);
explicitPeers->push_back (ident);
}
LogPrint (eLogInfo, "Explicit peers set to ", it->second);
}
} }
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen); m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
if (explicitPeers)
m_Pool->SetExplicitPeers (explicitPeers);
if (m_IsPublic) if (m_IsPublic)
LogPrint (eLogInfo, "Local address ", i2p::client::GetB32Address(GetIdentHash()), " created"); LogPrint (eLogInfo, "Local address ", i2p::client::GetB32Address(GetIdentHash()), " created");
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (*this); // TODO: m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (*this); // TODO:
@@ -148,7 +187,7 @@ namespace client
return nullptr; return nullptr;
} }
const i2p::data::LeaseSet * ClientDestination::GetLeaseSet () std::shared_ptr<const i2p::data::LeaseSet> ClientDestination::GetLeaseSet ()
{ {
if (!m_Pool) return nullptr; if (!m_Pool) return nullptr;
if (!m_LeaseSet) if (!m_LeaseSet)
@@ -158,15 +197,7 @@ namespace client
void ClientDestination::UpdateLeaseSet () void ClientDestination::UpdateLeaseSet ()
{ {
auto newLeaseSet = new i2p::data::LeaseSet (*m_Pool); m_LeaseSet.reset (new i2p::data::LeaseSet (*m_Pool));
if (!m_LeaseSet)
m_LeaseSet = newLeaseSet;
else
{
// TODO: implement it better
*m_LeaseSet = *newLeaseSet;
delete newLeaseSet;
}
} }
bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
@@ -184,12 +215,12 @@ namespace client
return true; return true;
} }
void ClientDestination::ProcessGarlicMessage (I2NPMessage * msg) void ClientDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg)); m_Service.post (std::bind (&ClientDestination::HandleGarlicMessage, this, msg));
} }
void ClientDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg) void ClientDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg)); m_Service.post (std::bind (&ClientDestination::HandleDeliveryStatusMessage, this, msg));
} }
@@ -202,6 +233,10 @@ namespace client
case eI2NPData: case eI2NPData:
HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
break; break;
case eI2NPDeliveryStatus:
// we assume tunnel tests non-encrypted
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
break;
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
break; break;
@@ -222,19 +257,37 @@ namespace client
LogPrint (eLogInfo, "Reply token is ignored for DatabaseStore"); LogPrint (eLogInfo, "Reply token is ignored for DatabaseStore");
offset += 36; offset += 36;
} }
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet if (buf[DATABASE_STORE_TYPE_OFFSET] == 1) // LeaseSet
{ {
LogPrint (eLogDebug, "Remote LeaseSet"); LogPrint (eLogDebug, "Remote LeaseSet");
auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET); auto it = m_RemoteLeaseSets.find (buf + DATABASE_STORE_KEY_OFFSET);
if (it != m_RemoteLeaseSets.end ()) if (it != m_RemoteLeaseSets.end ())
{ {
it->second->Update (buf + offset, len - offset); leaseSet = it->second;
LogPrint (eLogDebug, "Remote LeaseSet updated"); leaseSet->Update (buf + offset, len - offset);
if (leaseSet->IsValid ())
LogPrint (eLogDebug, "Remote LeaseSet updated");
else
{
LogPrint (eLogDebug, "Remote LeaseSet update failed");
m_RemoteLeaseSets.erase (it);
leaseSet = nullptr;
}
} }
else else
{ {
LogPrint (eLogDebug, "New remote LeaseSet added"); leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset);
m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset); if (leaseSet->IsValid ())
{
LogPrint (eLogDebug, "New remote LeaseSet added");
m_RemoteLeaseSets[buf + DATABASE_STORE_KEY_OFFSET] = leaseSet;
}
else
{
LogPrint (eLogError, "New remote LeaseSet verification failed");
leaseSet = nullptr;
}
} }
} }
else else
@@ -244,7 +297,7 @@ namespace client
if (it1 != m_LeaseSetRequests.end ()) if (it1 != m_LeaseSetRequests.end ())
{ {
it1->second->requestTimeoutTimer.cancel (); it1->second->requestTimeoutTimer.cancel ();
if (it1->second->requestComplete) it1->second->requestComplete (true); if (it1->second->requestComplete) it1->second->requestComplete (leaseSet);
delete it1->second; delete it1->second;
m_LeaseSetRequests.erase (it1); m_LeaseSetRequests.erase (it1);
} }
@@ -285,7 +338,7 @@ namespace client
LogPrint (eLogInfo, key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST," floodfills"); LogPrint (eLogInfo, key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST," floodfills");
if (!found) if (!found)
{ {
if (request->requestComplete) request->requestComplete (false); if (request->requestComplete) request->requestComplete (nullptr);
delete request; delete request;
m_LeaseSetRequests.erase (key); m_LeaseSetRequests.erase (key);
} }
@@ -294,7 +347,7 @@ namespace client
LogPrint ("Request for ", key.ToBase64 (), " not found"); LogPrint ("Request for ", key.ToBase64 (), " not found");
} }
void ClientDestination::HandleDeliveryStatusMessage (I2NPMessage * msg) void ClientDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET); uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
if (msgID == m_PublishReplyToken) if (msgID == m_PublishReplyToken)
@@ -302,7 +355,6 @@ namespace client
LogPrint (eLogDebug, "Publishing confirmed"); LogPrint (eLogDebug, "Publishing confirmed");
m_ExcludedFloodfills.clear (); m_ExcludedFloodfills.clear ();
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
i2p::DeleteI2NPMessage (msg);
} }
else else
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg); i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
@@ -345,7 +397,7 @@ namespace client
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
m_PublishReplyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); m_PublishReplyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken)); auto msg = WrapMessage (floodfill, ToSharedI2NPMessage (i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken)));
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer, m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer,
this, std::placeholders::_1)); this, std::placeholders::_1));
@@ -404,18 +456,12 @@ namespace client
else else
{ {
RequestDestination (dest, RequestDestination (dest,
[this, streamRequestComplete, dest, port](bool success) [this, streamRequestComplete, port](std::shared_ptr<i2p::data::LeaseSet> ls)
{ {
if (!success) if (ls)
streamRequestComplete (nullptr); streamRequestComplete(CreateStream (ls, port));
else else
{ streamRequestComplete (nullptr);
auto leaseSet = FindLeaseSet (dest);
if (leaseSet)
streamRequestComplete(CreateStream (leaseSet, port));
else
streamRequestComplete (nullptr);
}
}); });
} }
} }
@@ -501,7 +547,7 @@ namespace client
if (!SendLeaseSetRequest (dest, floodfill, request)) if (!SendLeaseSetRequest (dest, floodfill, request))
{ {
// request failed // request failed
if (request->requestComplete) request->requestComplete (false); if (request->requestComplete) request->requestComplete (nullptr);
delete request; delete request;
m_LeaseSetRequests.erase (dest); m_LeaseSetRequests.erase (dest);
} }
@@ -510,7 +556,7 @@ namespace client
{ {
LogPrint (eLogError, "Request of ", dest.ToBase64 (), " is pending already"); LogPrint (eLogError, "Request of ", dest.ToBase64 (), " is pending already");
// TODO: queue up requests // TODO: queue up requests
if (request->requestComplete) request->requestComplete (false); if (request->requestComplete) request->requestComplete (nullptr);
delete request; delete request;
} }
} }
@@ -539,9 +585,9 @@ namespace client
rnd.GenerateBlock (replyTag, 32); // random session tag rnd.GenerateBlock (replyTag, 32); // random session tag
AddSessionKey (replyKey, replyTag); AddSessionKey (replyKey, replyTag);
I2NPMessage * msg = WrapMessage (nextFloodfill, auto msg = WrapMessage (nextFloodfill,
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, ToSharedI2NPMessage (CreateLeaseSetDatabaseLookupMsg (dest, request->excluded,
replyTunnel.get (), replyKey, replyTag)); replyTunnel.get (), replyKey, replyTag)));
outboundTunnel->SendTunnelDataMsg ( outboundTunnel->SendTunnelDataMsg (
{ {
i2p::tunnel::TunnelMessageBlock i2p::tunnel::TunnelMessageBlock

View File

@@ -36,13 +36,19 @@ namespace client
const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3; const int DEFAULT_INBOUND_TUNNEL_LENGTH = 3;
const char I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH[] = "outbound.length"; const char I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH[] = "outbound.length";
const int DEFAULT_OUTBOUND_TUNNEL_LENGTH = 3; const int DEFAULT_OUTBOUND_TUNNEL_LENGTH = 3;
const char I2CP_PARAM_INBOUND_TUNNELS_QUANTITY[] = "inbound.quantity";
const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5;
const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity";
const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5;
const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers";
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete; typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
class ClientDestination: public i2p::garlic::GarlicDestination class ClientDestination: public i2p::garlic::GarlicDestination
{ {
typedef std::function<void (bool success)> RequestComplete; typedef std::function<void (std::shared_ptr<i2p::data::LeaseSet> leaseSet)> RequestComplete;
// leaseSet = nullptr means not found
struct LeaseSetRequest struct LeaseSetRequest
{ {
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {}; LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
@@ -63,7 +69,7 @@ namespace client
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; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; }; std::shared_ptr<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 () && m_Pool->GetOutboundTunnels ().size () > 0; };
std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident); std::shared_ptr<const i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
@@ -87,13 +93,14 @@ namespace client
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
// implements GarlicDestination // implements GarlicDestination
const i2p::data::LeaseSet * GetLeaseSet (); std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet ();
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
// override GarlicDestination // override GarlicDestination
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
void ProcessGarlicMessage (I2NPMessage * msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (I2NPMessage * msg); void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SetLeaseSetUpdated (); void SetLeaseSetUpdated ();
// I2CP // I2CP
@@ -107,7 +114,7 @@ namespace client
void HandlePublishConfirmationTimer (const boost::system::error_code& ecode); void HandlePublishConfirmationTimer (const boost::system::error_code& ecode);
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len); void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
void HandleDeliveryStatusMessage (I2NPMessage * msg); void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete); void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete);
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, LeaseSetRequest * request); bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, LeaseSetRequest * request);
@@ -127,7 +134,7 @@ namespace client
std::map<i2p::data::IdentHash, LeaseSetRequest *> m_LeaseSetRequests; std::map<i2p::data::IdentHash, LeaseSetRequest *> m_LeaseSetRequests;
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool; std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
i2p::data::LeaseSet * m_LeaseSet; std::shared_ptr<i2p::data::LeaseSet> m_LeaseSet;
bool m_IsPublic; bool m_IsPublic;
uint32_t m_PublishReplyToken; uint32_t m_PublishReplyToken;
std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing

View File

@@ -26,7 +26,7 @@ namespace crypto
b1 = a_exp_b_mod_c (y, k, elgp); b1 = a_exp_b_mod_c (y, k, elgp);
} }
void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const
{ {
// calculate b = b1*m mod p // calculate b = b1*m mod p
uint8_t m[255]; uint8_t m[255];
@@ -60,15 +60,13 @@ namespace crypto
{ {
CryptoPP::Integer x(key, 256), a(zeroPadding? encrypted +1 : encrypted, 256), CryptoPP::Integer x(key, 256), a(zeroPadding? encrypted +1 : encrypted, 256),
b(zeroPadding? encrypted + 258 :encrypted + 256, 256); b(zeroPadding? encrypted + 258 :encrypted + 256, 256);
uint8_t m[255], hash[32]; uint8_t m[255];
a_times_b_mod_c (b, a_exp_b_mod_c (a, elgp - x - 1, elgp), elgp).Encode (m, 255); a_times_b_mod_c (b, a_exp_b_mod_c (a, elgp - x - 1, elgp), elgp).Encode (m, 255);
CryptoPP::SHA256().CalculateDigest(hash, m+33, 222); if (!CryptoPP::SHA256().VerifyDigest (m + 1, m + 33, 222))
for (int i = 0; i < 32; i++) {
if (hash[i] != m[i+1]) LogPrint ("ElGamal decrypt hash doesn't match");
{ return false;
LogPrint ("ElGamal decrypt hash doesn't match"); }
return false;
}
memcpy (data, m + 33, 222); memcpy (data, m + 33, 222);
return true; return true;
} }

View File

@@ -15,9 +15,9 @@ namespace i2p
namespace garlic namespace garlic
{ {
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags): std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
m_Owner (owner), m_Destination (destination), m_NumTags (numTags), m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
m_LeaseSetUpdateStatus (numTags > 0 ? eLeaseSetUpdated : eLeaseSetUpToDate) m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend)
{ {
// create new session tags and session key // create new session tags and session key
m_Rnd.GenerateBlock (m_SessionKey, 32); m_Rnd.GenerateBlock (m_SessionKey, 32);
@@ -25,7 +25,7 @@ namespace garlic
} }
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetUpToDate) m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend)
{ {
memcpy (m_SessionKey, sessionKey, 32); memcpy (m_SessionKey, sessionKey, 32);
m_Encryption.SetKey (m_SessionKey); m_Encryption.SetKey (m_SessionKey);
@@ -107,9 +107,9 @@ namespace garlic
return !m_SessionTags.empty () || m_UnconfirmedTagsMsgs.empty (); return !m_SessionTags.empty () || m_UnconfirmedTagsMsgs.empty ();
} }
I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg) std::shared_ptr<I2NPMessage> GarlicRoutingSession::WrapSingleMessage (std::shared_ptr<I2NPMessage> msg)
{ {
I2NPMessage * m = NewI2NPMessage (); auto m = ToSharedI2NPMessage(NewI2NPMessage ());
m->Align (12); // in order to get buf aligned to 16 (12 + 4) 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
@@ -164,12 +164,10 @@ namespace garlic
len += 32; len += 32;
} }
// AES block // AES block
len += CreateAESBlock (buf, msg); len += CreateAESBlock (buf, msg.get ()); // TODO
htobe32buf (m->GetPayload (), len); htobe32buf (m->GetPayload (), len);
m->len += len + 4; m->len += len + 4;
FillI2NPMessageHeader (m, eI2NPGarlic); m->FillI2NPMessageHeader (eI2NPGarlic);
if (msg)
DeleteI2NPMessage (msg);
return m; return m;
} }
@@ -225,9 +223,10 @@ namespace garlic
if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated
{ {
// clove is DeliveryStatus // clove is DeliveryStatus
size += CreateDeliveryStatusClove (payload + size, msgID); auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID);
if (size > 0) // successive? if (cloveSize > 0) // successive?
{ {
size += cloveSize;
(*numCloves)++; (*numCloves)++;
if (newTags) // new tags created if (newTags) // new tags created
m_UnconfirmedTagsMsgs[msgID] = newTags; m_UnconfirmedTagsMsgs[msgID] = newTags;
@@ -297,19 +296,18 @@ namespace garlic
size_t size = 0; size_t size = 0;
if (m_Owner) if (m_Owner)
{ {
auto leases = m_Owner->GetLeaseSet ()->GetNonExpiredLeases (); auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel ();
if (!leases.empty ()) if (inboundTunnel)
{ {
buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel
size++; size++;
uint32_t i = m_Rnd.GenerateWord32 (0, leases.size () - 1);
// hash and tunnelID sequence is reversed for Garlic // hash and tunnelID sequence is reversed for Garlic
memcpy (buf + size, leases[i].tunnelGateway, 32); // To Hash memcpy (buf + size, inboundTunnel->GetNextIdentHash (), 32); // To Hash
size += 32; size += 32;
htobe32buf (buf + size, leases[i].tunnelID); // tunnelID htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
size += 4; size += 4;
// create msg // create msg
I2NPMessage * msg = CreateDeliveryStatusMsg (msgID); auto msg = CreateDeliveryStatusMsg (msgID);
if (m_Owner) if (m_Owner)
{ {
//encrypt //encrypt
@@ -322,7 +320,6 @@ namespace garlic
} }
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength (); size += msg->GetLength ();
DeleteI2NPMessage (msg);
// fill clove // fill clove
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec
htobe32buf (buf + size, m_Rnd.GenerateWord32 ()); // CloveID htobe32buf (buf + size, m_Rnd.GenerateWord32 ()); // CloveID
@@ -333,7 +330,7 @@ namespace garlic
size += 3; size += 3;
} }
else else
LogPrint ("All tunnels of local LeaseSet expired"); LogPrint (eLogError, "No inbound tunnels in the pool for DeliveryStatus");
} }
else else
LogPrint ("Missing local LeaseSet"); LogPrint ("Missing local LeaseSet");
@@ -362,27 +359,37 @@ namespace garlic
return true; return true;
} }
void GarlicDestination::HandleGarlicMessage (I2NPMessage * msg) void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
uint32_t length = bufbe32toh (buf); uint32_t length = bufbe32toh (buf);
if (length > msg->GetLength ())
{
LogPrint (eLogError, "Garlic message length ", length, " exceeds I2NP message length ", msg->GetLength ());
return;
}
buf += 4; // length buf += 4; // length
auto it = m_Tags.find (SessionTag(buf)); auto it = m_Tags.find (SessionTag(buf));
if (it != m_Tags.end ()) if (it != m_Tags.end ())
{ {
// tag found. Use AES // tag found. Use AES
uint8_t iv[32]; // IV is first 16 bytes if (length >= 32)
CryptoPP::SHA256().CalculateDigest(iv, buf, 32); {
it->second->SetIV (iv); uint8_t iv[32]; // IV is first 16 bytes
it->second->Decrypt (buf + 32, length - 32, buf + 32); CryptoPP::SHA256().CalculateDigest(iv, buf, 32);
HandleAESBlock (buf + 32, length - 32, it->second, msg->from); it->second->SetIV (iv);
m_Tags.erase (it); // tag might be used only once it->second->Decrypt (buf + 32, length - 32, buf + 32);
HandleAESBlock (buf + 32, length - 32, it->second, msg->from);
}
else
LogPrint (eLogError, "Garlic message length ", length, " is less than 32 bytes");
m_Tags.erase (it); // tag might be used only once
} }
else else
{ {
// tag not found. Use ElGamal // tag not found. Use ElGamal
ElGamalBlock elGamal; ElGamalBlock elGamal;
if (i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, true)) if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, true))
{ {
auto decryption = std::make_shared<i2p::crypto::CBCDecryption>(); auto decryption = std::make_shared<i2p::crypto::CBCDecryption>();
decryption->SetKey (elGamal.sessionKey); decryption->SetKey (elGamal.sessionKey);
@@ -393,9 +400,8 @@ namespace garlic
HandleAESBlock (buf + 514, length - 514, decryption, msg->from); HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
} }
else else
LogPrint ("Failed to decrypt garlic"); LogPrint (eLogError, "Failed to decrypt garlic");
} }
DeleteI2NPMessage (msg);
// cleanup expired tags // cleanup expired tags
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
@@ -462,6 +468,7 @@ namespace garlic
void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
const uint8_t * buf1 = buf;
int numCloves = buf[0]; int numCloves = buf[0];
LogPrint (numCloves," cloves"); LogPrint (numCloves," cloves");
buf++; buf++;
@@ -501,7 +508,7 @@ namespace garlic
tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel (); tunnel = from->GetTunnelPool ()->GetNextOutboundTunnel ();
if (tunnel) // we have send it through an outbound tunnel if (tunnel) // we have send it through an outbound tunnel
{ {
I2NPMessage * msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from); auto msg = CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from);
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
} }
else else
@@ -519,26 +526,23 @@ namespace garlic
buf += 4; // CloveID buf += 4; // CloveID
buf += 8; // Date buf += 8; // Date
buf += 3; // Certificate buf += 3; // Certificate
if (buf - buf1 > (int)len)
{
LogPrint (eLogError, "Garlic clove is too long");
break;
}
} }
} }
I2NPMessage * GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination, std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
I2NPMessage * msg, bool attachLeaseSet) std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet)
{ {
if (attachLeaseSet) // we should maintain this session auto session = GetRoutingSession (destination, attachLeaseSet); // 32 tags by default
{ return session->WrapSingleMessage (msg);
auto session = GetRoutingSession (destination, 32); // 32 tags by default
return session->WrapSingleMessage (msg);
}
else // one time session
{
GarlicRoutingSession session (this, destination, 0); // don't use tag if no LeaseSet
return session.WrapSingleMessage (msg);
}
} }
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession ( std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags) std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
{ {
auto it = m_Sessions.find (destination->GetIdentHash ()); auto it = m_Sessions.find (destination->GetIdentHash ());
std::shared_ptr<GarlicRoutingSession> session; std::shared_ptr<GarlicRoutingSession> session;
@@ -546,7 +550,8 @@ namespace garlic
session = it->second; session = it->second;
if (!session) if (!session)
{ {
session = std::make_shared<GarlicRoutingSession> (this, destination, numTags); session = std::make_shared<GarlicRoutingSession> (this, destination,
attachLeaseSet ? 40 : 4, attachLeaseSet); // 40 tags for connections and 4 for LS requests
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[destination->GetIdentHash ()] = session; m_Sessions[destination->GetIdentHash ()] = session;
} }
@@ -578,7 +583,7 @@ namespace garlic
m_CreatedSessions[msgID] = session; m_CreatedSessions[msgID] = session;
} }
void GarlicDestination::HandleDeliveryStatusMessage (I2NPMessage * msg) void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
uint32_t msgID = bufbe32toh (msg->GetPayload ()); uint32_t msgID = bufbe32toh (msg->GetPayload ());
{ {
@@ -590,7 +595,6 @@ namespace garlic
LogPrint (eLogInfo, "Garlic message ", msgID, " acknowledged"); LogPrint (eLogInfo, "Garlic message ", msgID, " acknowledged");
} }
} }
DeleteI2NPMessage (msg);
} }
void GarlicDestination::SetLeaseSetUpdated () void GarlicDestination::SetLeaseSetUpdated ()
@@ -600,12 +604,12 @@ namespace garlic
it.second->SetLeaseSetUpdated (); it.second->SetLeaseSetUpdated ();
} }
void GarlicDestination::ProcessGarlicMessage (I2NPMessage * msg) void GarlicDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
HandleGarlicMessage (msg); HandleGarlicMessage (msg);
} }
void GarlicDestination::ProcessDeliveryStatusMessage (I2NPMessage * msg) void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
HandleDeliveryStatusMessage (msg); HandleDeliveryStatusMessage (msg);
} }

View File

@@ -61,7 +61,8 @@ namespace garlic
{ {
eLeaseSetUpToDate = 0, eLeaseSetUpToDate = 0,
eLeaseSetUpdated, eLeaseSetUpdated,
eLeaseSetSubmitted eLeaseSetSubmitted,
eLeaseSetDoNotSend
}; };
struct UnconfirmedTags struct UnconfirmedTags
@@ -75,14 +76,18 @@ namespace garlic
public: public:
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags); GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
int numTags, bool attachLeaseSet);
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
~GarlicRoutingSession (); ~GarlicRoutingSession ();
I2NPMessage * WrapSingleMessage (I2NPMessage * msg); std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<I2NPMessage> msg);
void MessageConfirmed (uint32_t msgID); void MessageConfirmed (uint32_t msgID);
bool CleanupExpiredTags (); // returns true if something left bool CleanupExpiredTags (); // returns true if something left
void SetLeaseSetUpdated () { m_LeaseSetUpdateStatus = eLeaseSetUpdated; }; void SetLeaseSetUpdated ()
{
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
};
private: private:
@@ -110,7 +115,7 @@ namespace garlic
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
CryptoPP::AutoSeededRandomPool m_Rnd; CryptoPP::AutoSeededRandomPool m_Rnd;
}; };
class GarlicDestination: public i2p::data::LocalDestination class GarlicDestination: public i2p::data::LocalDestination
{ {
public: public:
@@ -118,27 +123,28 @@ namespace garlic
GarlicDestination (): m_LastTagsCleanupTime (0) {}; GarlicDestination (): m_LastTagsCleanupTime (0) {};
~GarlicDestination (); ~GarlicDestination ();
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags); std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
void CleanupRoutingSessions (); void CleanupRoutingSessions ();
void RemoveCreatedSession (uint32_t msgID); void RemoveCreatedSession (uint32_t msgID);
I2NPMessage * WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination, std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
I2NPMessage * msg, bool attachLeaseSet = false); std::shared_ptr<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 virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
void DeliveryStatusSent (std::shared_ptr<GarlicRoutingSession> session, uint32_t msgID); void DeliveryStatusSent (std::shared_ptr<GarlicRoutingSession> session, uint32_t msgID);
virtual void ProcessGarlicMessage (I2NPMessage * msg); virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (I2NPMessage * msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated (); virtual void SetLeaseSetUpdated ();
virtual const i2p::data::LeaseSet * GetLeaseSet () = 0; // TODO virtual std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () = 0; // TODO
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0; virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
protected: protected:
void HandleGarlicMessage (I2NPMessage * msg); void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void HandleDeliveryStatusMessage (I2NPMessage * msg); void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
private: private:

View File

@@ -44,7 +44,7 @@ namespace proxy
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream); void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
uint8_t m_http_buff[http_buffer_size]; uint8_t m_http_buff[http_buffer_size];
boost::asio::ip::tcp::socket * m_sock; std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
std::string m_request; //Data left to be sent std::string m_request; //Data left to be sent
std::string m_url; //URL std::string m_url; //URL
std::string m_method; //Method std::string m_method; //Method
@@ -56,7 +56,7 @@ namespace proxy
public: public:
HTTPProxyHandler(HTTPProxyServer * parent, boost::asio::ip::tcp::socket * sock) : HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
I2PServiceHandler(parent), m_sock(sock) I2PServiceHandler(parent), m_sock(sock)
{ EnterState(GET_METHOD); } { EnterState(GET_METHOD); }
~HTTPProxyHandler() { Terminate(); } ~HTTPProxyHandler() { Terminate(); }
@@ -77,10 +77,10 @@ namespace proxy
void HTTPProxyHandler::Terminate() { void HTTPProxyHandler::Terminate() {
if (Kill()) return; if (Kill()) return;
if (m_sock) { if (m_sock)
{
LogPrint(eLogDebug,"--- HTTP Proxy close sock"); LogPrint(eLogDebug,"--- HTTP Proxy close sock");
m_sock->close(); m_sock->close();
delete m_sock;
m_sock = nullptr; m_sock = nullptr;
} }
Done(shared_from_this()); Done(shared_from_this());
@@ -90,7 +90,7 @@ namespace proxy
//TODO: handle this apropriately //TODO: handle this apropriately
void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/) void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/)
{ {
std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n"; static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n";
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()), boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
@@ -290,7 +290,7 @@ namespace proxy
{ {
} }
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(boost::asio::ip::tcp::socket * socket) std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{ {
return std::make_shared<HTTPProxyHandler> (this, socket); return std::make_shared<HTTPProxyHandler> (this, socket);
} }

View File

@@ -21,7 +21,7 @@ namespace proxy
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(boost::asio::ip::tcp::socket * socket); std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "HTTP Proxy"; } const char* GetName() { return "HTTP Proxy"; }
}; };

View File

@@ -526,15 +526,14 @@ namespace util
{ {
m_Stream.reset (); m_Stream.reset ();
m_Stream = nullptr; m_Stream = nullptr;
// delete this
}); });
} }
void HTTPConnection::Receive () void HTTPConnection::Receive ()
{ {
m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE),
boost::bind(&HTTPConnection::HandleReceive, this, std::bind(&HTTPConnection::HandleReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::placeholders::_1, std::placeholders::_2));
} }
void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
@@ -831,17 +830,17 @@ namespace util
{ {
for (auto& it: i2p::client::context.GetDestinations ()) for (auto& it: i2p::client::context.GetDestinations ())
{ {
std::string b32 = it.first.ToBase32 (); auto ident = it.second->GetIdentHash ();;
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION; s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << b32 << ">"; s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
s << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetIdentHash()) << "</a><br>" << std::endl; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>" << std::endl;
} }
} }
void HTTPConnection::ShowLocalDestination (const std::string& b32, std::stringstream& s) void HTTPConnection::ShowLocalDestination (const std::string& b32, std::stringstream& s)
{ {
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), ident, 32); ident.FromBase32 (b32);
auto dest = i2p::client::context.FindLocalDestination (ident); auto dest = i2p::client::context.FindLocalDestination (ident);
if (dest) if (dest)
{ {
@@ -879,7 +878,9 @@ namespace util
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]"; s << " [out:" << it.second->GetSendQueueSize () << "][in:" << it.second->GetReceiveQueueSize () << "]";
s << "[buf:" << it.second->GetSendBufferSize () << "]"; s << "[buf:" << it.second->GetSendBufferSize () << "]";
s << "[RTT:" << it.second->GetRTT () << "]"; s << "[RTT:" << it.second->GetRTT () << "]";
s << "[Window:" << it.second->GetWindowSize () << "]";
s << "[Status:" << (int)it.second->GetStatus () << "]";
s << "<br>"<< std::endl; s << "<br>"<< std::endl;
} }
} }
@@ -907,6 +908,11 @@ namespace util
auto session = sam->FindSession (id); auto session = sam->FindSession (id);
if (session) if (session)
{ {
auto& ident = session->localDestination->GetIdentHash();
s << "<a href=/?" << HTTP_COMMAND_LOCAL_DESTINATION;
s << "&" << HTTP_PARAM_BASE32_ADDRESS << "=" << ident.ToBase32 () << ">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>" << std::endl;
s << "<b>Streams:</b><br>";
for (auto it: session->sockets) for (auto it: session->sockets)
{ {
switch (it->GetSocketType ()) switch (it->GetSocketType ())
@@ -968,8 +974,8 @@ namespace util
m_BufferLen = len; m_BufferLen = len;
i2p::client::context.GetSharedLocalDestination ()->RequestDestination (destination); i2p::client::context.GetSharedLocalDestination ()->RequestDestination (destination);
m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT)); m_Timer.expires_from_now (boost::posix_time::seconds(HTTP_DESTINATION_REQUEST_TIMEOUT));
m_Timer.async_wait (boost::bind (&HTTPConnection::HandleDestinationRequestTimeout, m_Timer.async_wait (std::bind (&HTTPConnection::HandleDestinationRequestTimeout,
this, boost::asio::placeholders::error, destination, port, m_Buffer, m_BufferLen)); shared_from_this (), std::placeholders::_1, destination, port, m_Buffer, m_BufferLen));
} }
} }
@@ -1002,8 +1008,8 @@ namespace util
{ {
if (m_Stream) if (m_Stream)
m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192), m_Stream->AsyncReceive (boost::asio::buffer (m_StreamBuffer, 8192),
boost::bind (&HTTPConnection::HandleStreamReceive, this, std::bind (&HTTPConnection::HandleStreamReceive, shared_from_this (),
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred), std::placeholders::_1, std::placeholders::_2),
45); // 45 seconds timeout 45); // 45 seconds timeout
} }
@@ -1012,7 +1018,7 @@ namespace util
if (!ecode) if (!ecode)
{ {
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 (&HTTPConnection::HandleWrite, this, boost::asio::placeholders::error)); std::bind (&HTTPConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
} }
else else
{ {
@@ -1033,8 +1039,7 @@ namespace util
m_Reply.headers[1].value = "text/html"; m_Reply.headers[1].value = "text/html";
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status), boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status),
boost::bind (&HTTPConnection::HandleWriteReply, this, std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1));
boost::asio::placeholders::error));
} }
HTTPServer::HTTPServer (int port): HTTPServer::HTTPServer (int port):
@@ -1085,14 +1090,15 @@ namespace util
{ {
if (!ecode) if (!ecode)
{ {
CreateConnection(m_NewSocket); // new HTTPConnection(m_NewSocket); CreateConnection(m_NewSocket);
Accept (); Accept ();
} }
} }
void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket) void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket)
{ {
new HTTPConnection (m_NewSocket); auto conn = std::make_shared<HTTPConnection> (m_NewSocket);
conn->Receive ();
} }
} }
} }

View File

@@ -15,7 +15,7 @@ namespace util
{ {
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds const int HTTP_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
class HTTPConnection class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{ {
protected: protected:
@@ -48,13 +48,13 @@ namespace util
HTTPConnection (boost::asio::ip::tcp::socket * socket): HTTPConnection (boost::asio::ip::tcp::socket * socket):
m_Socket (socket), m_Timer (socket->get_io_service ()), m_Socket (socket), m_Timer (socket->get_io_service ()),
m_Stream (nullptr), m_BufferLen (0) { Receive (); }; m_Stream (nullptr), m_BufferLen (0) {};
virtual ~HTTPConnection() { delete m_Socket; } ~HTTPConnection() { delete m_Socket; }
void Receive ();
private: private:
void Terminate (); void Terminate ();
void Receive ();
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void AsyncStreamReceive (); void AsyncStreamReceive ();
void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleStreamReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);

View File

@@ -36,51 +36,58 @@ namespace i2p
delete msg; delete msg;
} }
static std::atomic<uint32_t> I2NPmsgID(0); // TODO: create class std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg)
void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID)
{ {
msg->SetTypeID (msgType); return std::shared_ptr<I2NPMessage>(msg, DeleteI2NPMessage);
}
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID)
{
SetTypeID (msgType);
if (replyMsgID) // for tunnel creation if (replyMsgID) // for tunnel creation
msg->SetMsgID (replyMsgID); SetMsgID (replyMsgID);
else else
{ SetMsgID (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ());
msg->SetMsgID (I2NPmsgID); SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); // TODO: 5 secs is a magic number
I2NPmsgID++; UpdateSize ();
} UpdateChks ();
msg->SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); // TODO: 5 secs is a magic number
msg->UpdateSize ();
msg->UpdateChks ();
} }
void RenewI2NPMessageHeader (I2NPMessage * msg) void I2NPMessage::RenewI2NPMessageHeader ()
{ {
if (msg) SetMsgID (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ());
{ SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000);
msg->SetMsgID (I2NPmsgID);
I2NPmsgID++;
msg->SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000);
}
} }
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID) I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID)
{ {
I2NPMessage * msg = NewI2NPMessage (len); I2NPMessage * msg = NewI2NPMessage (len);
memcpy (msg->GetPayload (), buf, len); if (msg->len + len < msg->maxLen)
msg->len += len; {
FillI2NPMessageHeader (msg, msgType, replyMsgID); memcpy (msg->GetPayload (), buf, len);
msg->len += len;
}
else
LogPrint (eLogError, "I2NP message length ", len, " exceeds max length");
msg->FillI2NPMessageHeader (msgType, replyMsgID);
return msg; return msg;
} }
I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
I2NPMessage * msg = NewI2NPMessage (); I2NPMessage * msg = NewI2NPMessage ();
memcpy (msg->GetBuffer (), buf, len); if (msg->offset + len < msg->maxLen)
msg->len = msg->offset + len; {
msg->from = from; memcpy (msg->GetBuffer (), buf, len);
return msg; msg->len = msg->offset + len;
msg->from = from;
}
else
LogPrint (eLogError, "I2NP message length ", len, " exceeds max length");
return ToSharedI2NPMessage(msg);
} }
I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID) std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
{ {
I2NPMessage * m = NewI2NPShortMessage (); I2NPMessage * m = NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload (); uint8_t * buf = m->GetPayload ();
@@ -95,14 +102,14 @@ namespace i2p
htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, 2); // netID = 2 htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, 2); // netID = 2
} }
m->len += DELIVERY_STATUS_SIZE; m->len += DELIVERY_STATUS_SIZE;
FillI2NPMessageHeader (m, eI2NPDeliveryStatus); m->FillI2NPMessageHeader (eI2NPDeliveryStatus);
return m; return ToSharedI2NPMessage (m);
} }
I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers) uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{ {
I2NPMessage * m = NewI2NPShortMessage (); I2NPMessage * m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload (); uint8_t * buf = m->GetPayload ();
memcpy (buf, key, 32); // key memcpy (buf, key, 32); // key
buf += 32; buf += 32;
@@ -140,7 +147,7 @@ namespace i2p
} }
m->len += (buf - m->GetPayload ()); m->len += (buf - m->GetPayload ());
FillI2NPMessageHeader (m, eI2NPDatabaseLookup); m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m; return m;
} }
@@ -148,7 +155,8 @@ namespace i2p
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag) const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
{ {
I2NPMessage * m = NewI2NPShortMessage (); int cnt = excludedFloodfills.size ();
I2NPMessage * m = cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload (); uint8_t * buf = m->GetPayload ();
memcpy (buf, dest, 32); // key memcpy (buf, dest, 32); // key
buf += 32; buf += 32;
@@ -159,7 +167,6 @@ namespace i2p
buf += 5; buf += 5;
// excluded // excluded
int cnt = excludedFloodfills.size ();
htobe16buf (buf, cnt); htobe16buf (buf, cnt);
buf += 2; buf += 2;
if (cnt > 0) if (cnt > 0)
@@ -177,11 +184,9 @@ namespace i2p
buf += 65; buf += 65;
m->len += (buf - m->GetPayload ()); m->len += (buf - m->GetPayload ());
FillI2NPMessageHeader (m, eI2NPDatabaseLookup); m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m; return m;
} }
I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
std::vector<i2p::data::IdentHash> routers) std::vector<i2p::data::IdentHash> routers)
@@ -201,14 +206,14 @@ namespace i2p
memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32); memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
len += 32; len += 32;
m->len += len; m->len += len;
FillI2NPMessageHeader (m, eI2NPDatabaseSearchReply); m->FillI2NPMessageHeader (eI2NPDatabaseSearchReply);
return m; return m;
} }
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router, uint32_t replyToken) I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, uint32_t replyToken)
{ {
if (!router) // we send own RouterInfo if (!router) // we send own RouterInfo
router = &context.GetRouterInfo (); router = context.GetSharedRouterInfo ();
I2NPMessage * m = NewI2NPShortMessage (); I2NPMessage * m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload (); uint8_t * payload = m->GetPayload ();
@@ -231,16 +236,24 @@ namespace i2p
auto size = compressor.MaxRetrievable (); auto size = compressor.MaxRetrievable ();
htobe16buf (buf, size); // size htobe16buf (buf, size); // size
buf += 2; buf += 2;
// TODO: check if size doesn't exceed buffer
compressor.Get (buf, size);
buf += size;
m->len += (buf - payload); // payload size m->len += (buf - payload); // payload size
FillI2NPMessageHeader (m, eI2NPDatabaseStore); if (m->len + size > m->maxLen)
{
LogPrint (eLogInfo, "DatabaseStore message size is not enough for ", m->len + size);
auto newMsg = NewI2NPMessage ();
*newMsg = *m;
DeleteI2NPMessage (m);
m = newMsg;
buf = m->buf + m->len;
}
compressor.Get (buf, size);
m->len += size;
m->FillI2NPMessageHeader (eI2NPDatabaseStore);
return m; return m;
} }
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet, uint32_t replyToken) I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken)
{ {
if (!leaseSet) return nullptr; if (!leaseSet) return nullptr;
I2NPMessage * m = NewI2NPShortMessage (); I2NPMessage * m = NewI2NPShortMessage ();
@@ -265,7 +278,7 @@ namespace i2p
memcpy (payload + size, leaseSet->GetBuffer (), leaseSet->GetBufferLen ()); memcpy (payload + size, leaseSet->GetBuffer (), leaseSet->GetBufferLen ());
size += leaseSet->GetBufferLen (); size += leaseSet->GetBufferLen ();
m->len += size; m->len += size;
FillI2NPMessageHeader (m, eI2NPDatabaseStore); m->FillI2NPMessageHeader (eI2NPDatabaseStore);
return m; return m;
} }
@@ -348,14 +361,14 @@ namespace i2p
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPVariableTunnelBuildReply, buf, len, eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
} }
else else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, ToSharedI2NPMessage (CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
} }
} }
} }
@@ -369,14 +382,14 @@ namespace i2p
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPTunnelBuildReply, buf, len, eI2NPTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
} }
else else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len, ToSharedI2NPMessage (CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
} }
} }
@@ -409,7 +422,7 @@ namespace i2p
I2NPMessage * msg = NewI2NPShortMessage (); I2NPMessage * msg = NewI2NPShortMessage ();
memcpy (msg->GetPayload (), buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE); memcpy (msg->GetPayload (), buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
FillI2NPMessageHeader (msg, eI2NPTunnelData); msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg; return msg;
} }
@@ -419,9 +432,16 @@ namespace i2p
memcpy (msg->GetPayload () + 4, payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4); memcpy (msg->GetPayload () + 4, payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
htobe32buf (msg->GetPayload (), tunnelID); htobe32buf (msg->GetPayload (), tunnelID);
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
FillI2NPMessageHeader (msg, eI2NPTunnelData); msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ()
{
I2NPMessage * msg = NewI2NPShortMessage ();
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
return ToSharedI2NPMessage (msg);
}
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len) I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
{ {
@@ -431,11 +451,11 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
memcpy (payload + TUNNEL_GATEWAY_HEADER_SIZE, buf, len); memcpy (payload + TUNNEL_GATEWAY_HEADER_SIZE, buf, len);
msg->len += TUNNEL_GATEWAY_HEADER_SIZE + len; msg->len += TUNNEL_GATEWAY_HEADER_SIZE + len;
FillI2NPMessageHeader (msg, eI2NPTunnelGateway); msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg; return msg;
} }
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg) std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg)
{ {
if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE) if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE)
{ {
@@ -446,14 +466,13 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE); msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE);
msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len; msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len;
FillI2NPMessageHeader (msg, eI2NPTunnelGateway); msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg; return msg;
} }
else else
{ {
I2NPMessage * msg1 = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ()); I2NPMessage * msg1 = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
DeleteI2NPMessage (msg); return ToSharedI2NPMessage (msg1);
return msg1;
} }
} }
@@ -466,13 +485,13 @@ namespace i2p
msg->len += gatewayMsgOffset; msg->len += gatewayMsgOffset;
memcpy (msg->GetPayload (), buf, len); memcpy (msg->GetPayload (), buf, len);
msg->len += len; msg->len += len;
FillI2NPMessageHeader (msg, msgType, replyMsgID); // create content message msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message
len = msg->GetLength (); len = msg->GetLength ();
msg->offset -= gatewayMsgOffset; msg->offset -= gatewayMsgOffset;
uint8_t * payload = msg->GetPayload (); uint8_t * payload = msg->GetPayload ();
htobe32buf (payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID); htobe32buf (payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID);
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
FillI2NPMessageHeader (msg, eI2NPTunnelGateway); // gateway message msg->FillI2NPMessageHeader (eI2NPTunnelGateway); // gateway message
return msg; return msg;
} }
@@ -512,7 +531,7 @@ namespace i2p
} }
} }
void HandleI2NPMessage (I2NPMessage * msg) void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) if (msg)
{ {
@@ -527,20 +546,19 @@ namespace i2p
i2p::tunnel::tunnels.PostTunnelData (msg); i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
case eI2NPGarlic: case eI2NPGarlic:
{
LogPrint ("Garlic"); LogPrint ("Garlic");
if (msg->from) if (msg->from)
{ {
if (msg->from->GetTunnelPool ()) if (msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg); msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
else else
{
LogPrint (eLogInfo, "Local destination for garlic doesn't exist anymore"); LogPrint (eLogInfo, "Local destination for garlic doesn't exist anymore");
DeleteI2NPMessage (msg);
}
} }
else else
i2p::context.ProcessGarlicMessage (msg); i2p::context.ProcessGarlicMessage (msg);
break; break;
}
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
case eI2NPDatabaseSearchReply: case eI2NPDatabaseSearchReply:
case eI2NPDatabaseLookup: case eI2NPDatabaseLookup:
@@ -548,12 +566,14 @@ namespace i2p
i2p::data::netdb.PostI2NPMsg (msg); i2p::data::netdb.PostI2NPMsg (msg);
break; break;
case eI2NPDeliveryStatus: case eI2NPDeliveryStatus:
{
LogPrint ("DeliveryStatus"); LogPrint ("DeliveryStatus");
if (msg->from && msg->from->GetTunnelPool ()) if (msg->from && msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg); msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg);
else else
i2p::context.ProcessDeliveryStatusMessage (msg); i2p::context.ProcessDeliveryStatusMessage (msg);
break; break;
}
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
@@ -563,7 +583,6 @@ namespace i2p
break; break;
default: default:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
DeleteI2NPMessage (msg);
} }
} }
} }
@@ -573,7 +592,7 @@ namespace i2p
Flush (); Flush ();
} }
void I2NPMessagesHandler::PutNextMessage (I2NPMessage * msg) void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) if (msg)
{ {

View File

@@ -138,6 +138,7 @@ namespace tunnel
// payload // payload
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; }; uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
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; };
@@ -183,6 +184,9 @@ namespace tunnel
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET); len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET); return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
} }
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
void RenewI2NPMessageHeader ();
}; };
template<int sz> template<int sz>
@@ -196,12 +200,12 @@ namespace tunnel
I2NPMessage * NewI2NPShortMessage (); I2NPMessage * NewI2NPShortMessage ();
I2NPMessage * NewI2NPMessage (size_t len); I2NPMessage * NewI2NPMessage (size_t len);
void DeleteI2NPMessage (I2NPMessage * msg); void DeleteI2NPMessage (I2NPMessage * msg);
void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0); std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg);
void RenewI2NPMessageHeader (I2NPMessage * msg);
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0);
I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID); I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr); uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
I2NPMessage * CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, I2NPMessage * CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
@@ -209,8 +213,8 @@ namespace tunnel
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag); const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::RouterInfo * router = nullptr, uint32_t replyToken = 0); I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
I2NPMessage * CreateDatabaseStoreMsg (const i2p::data::LeaseSet * leaseSet, uint32_t replyToken = 0); I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken = 0);
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
@@ -219,27 +223,28 @@ namespace tunnel
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf); I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf);
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload); I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ();
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len); I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
size_t GetI2NPMessageLength (const uint8_t * msg); size_t GetI2NPMessageLength (const uint8_t * msg);
void HandleI2NPMessage (uint8_t * msg, size_t len); void HandleI2NPMessage (uint8_t * msg, size_t len);
void HandleI2NPMessage (I2NPMessage * msg); void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
class I2NPMessagesHandler class I2NPMessagesHandler
{ {
public: public:
~I2NPMessagesHandler (); ~I2NPMessagesHandler ();
void PutNextMessage (I2NPMessage * msg); void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
void Flush (); void Flush ();
private: private:
std::vector<I2NPMessage *> m_TunnelMsgs, m_TunnelGatewayMsgs; std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
}; };
} }

View File

@@ -48,31 +48,30 @@ namespace client
void TCPIPAcceptor::Accept () void TCPIPAcceptor::Accept ()
{ {
auto newSocket = new boost::asio::ip::tcp::socket (GetService ()); auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this, m_Acceptor.async_accept (*newSocket, std::bind (&TCPIPAcceptor::HandleAccept, this,
std::placeholders::_1, newSocket)); std::placeholders::_1, newSocket));
} }
void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket) void TCPIPAcceptor::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{ {
if (!ecode) if (!ecode)
{ {
LogPrint(eLogDebug,"--- ",GetName()," accepted"); LogPrint(eLogDebug,"--- ",GetName()," accepted");
auto handler = CreateHandler(socket); auto handler = CreateHandler(socket);
if (handler) { if (handler)
{
AddHandler(handler); AddHandler(handler);
handler->Handle(); handler->Handle();
} else { }
else
socket->close(); socket->close();
delete socket;
}
Accept(); Accept();
} }
else else
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ()); LogPrint (eLogError,"--- ",GetName()," Closing socket on accept because: ", ecode.message ());
delete socket;
} }
} }

View File

@@ -95,11 +95,11 @@ namespace client
//If you override this make sure you call it from the children //If you override this make sure you call it from the children
void Stop (); void Stop ();
protected: protected:
virtual std::shared_ptr<I2PServiceHandler> CreateHandler(boost::asio::ip::tcp::socket * socket) = 0; virtual std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) = 0;
virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; } virtual const char* GetName() { return "Generic TCP/IP accepting daemon"; }
private: private:
void Accept(); void Accept();
void HandleAccept(const boost::system::error_code& ecode, boost::asio::ip::tcp::socket * socket); void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::tcp::acceptor m_Acceptor;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
}; };

View File

@@ -9,7 +9,7 @@ namespace i2p
{ {
namespace client namespace client
{ {
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port): std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port):
I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()), I2PServiceHandler(owner), m_Socket (socket), m_RemoteEndpoint (socket->remote_endpoint ()),
m_IsQuiet (true) m_IsQuiet (true)
@@ -18,14 +18,14 @@ namespace client
} }
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, I2PTunnelConnection::I2PTunnelConnection (I2PService * owner,
boost::asio::ip::tcp::socket * socket, std::shared_ptr<i2p::stream::Stream> stream): std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<i2p::stream::Stream> stream):
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true) m_RemoteEndpoint (socket->remote_endpoint ()), m_IsQuiet (true)
{ {
} }
I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, I2PTunnelConnection::I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
boost::asio::ip::tcp::socket * socket, const boost::asio::ip::tcp::endpoint& target, bool quiet): std::shared_ptr<boost::asio::ip::tcp::socket> socket, const boost::asio::ip::tcp::endpoint& target, bool quiet):
I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream), I2PServiceHandler(owner), m_Socket (socket), m_Stream (stream),
m_RemoteEndpoint (target), m_IsQuiet (quiet) m_RemoteEndpoint (target), m_IsQuiet (quiet)
{ {
@@ -85,8 +85,17 @@ namespace client
else else
{ {
if (m_Stream) if (m_Stream)
m_Stream->Send (m_Buffer, bytes_transferred); {
Receive (); auto s = shared_from_this ();
m_Stream->AsyncSend (m_Buffer, bytes_transferred,
[s](const boost::system::error_code& ecode)
{
if (!ecode)
s->Receive ();
else
s->Terminate ();
});
}
} }
} }
@@ -120,10 +129,13 @@ namespace client
Terminate (); Terminate ();
} }
else else
{ Write (m_StreamBuffer, bytes_transferred);
boost::asio::async_write (*m_Socket, boost::asio::buffer (m_StreamBuffer, bytes_transferred), }
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
} void I2PTunnelConnection::Write (const uint8_t * buf, size_t len)
{
m_Socket->async_send (boost::asio::buffer (buf, len),
std::bind (&I2PTunnelConnection::HandleWrite, shared_from_this (), std::placeholders::_1));
} }
void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode) void I2PTunnelConnection::HandleConnect (const boost::system::error_code& ecode)
@@ -150,12 +162,53 @@ namespace client
} }
} }
I2PTunnelConnectionHTTP::I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& host):
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false)
{
}
void I2PTunnelConnectionHTTP::Write (const uint8_t * buf, size_t len)
{
if (m_HeaderSent)
I2PTunnelConnection::Write (buf, len);
else
{
m_InHeader.clear ();
m_InHeader.write ((const char *)buf, len);
std::string line;
bool endOfHeader = false;
while (!endOfHeader)
{
std::getline(m_InHeader, line);
if (!m_InHeader.fail ())
{
if (line.find ("Host:") != std::string::npos)
m_OutHeader << "Host: " << m_Host << "\r\n";
else
m_OutHeader << line << "\n";
if (line == "\r") endOfHeader = true;
}
else
break;
}
if (endOfHeader)
{
m_OutHeader << m_InHeader.str (); // data right after header
m_HeaderSent = true;
I2PTunnelConnection::Write ((uint8_t *)m_OutHeader.str ().c_str (), m_OutHeader.str ().length ());
}
}
}
/* This handler tries to stablish a connection with the desired server and dies if it fails to do so */ /* This handler tries to stablish a connection with the desired server and dies if it fails to do so */
class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler> class I2PClientTunnelHandler: public I2PServiceHandler, public std::enable_shared_from_this<I2PClientTunnelHandler>
{ {
public: public:
I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination, I2PClientTunnelHandler (I2PClientTunnel * parent, i2p::data::IdentHash destination,
int destinationPort, boost::asio::ip::tcp::socket * socket): int destinationPort, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
I2PServiceHandler(parent), m_DestinationIdentHash(destination), I2PServiceHandler(parent), m_DestinationIdentHash(destination),
m_DestinationPort (destinationPort), m_Socket(socket) {}; m_DestinationPort (destinationPort), m_Socket(socket) {};
void Handle(); void Handle();
@@ -164,7 +217,7 @@ namespace client
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream); void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
i2p::data::IdentHash m_DestinationIdentHash; i2p::data::IdentHash m_DestinationIdentHash;
int m_DestinationPort; int m_DestinationPort;
boost::asio::ip::tcp::socket * m_Socket; std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
}; };
void I2PClientTunnelHandler::Handle() void I2PClientTunnelHandler::Handle()
@@ -198,7 +251,6 @@ namespace client
if (m_Socket) if (m_Socket)
{ {
m_Socket->close(); m_Socket->close();
delete m_Socket;
m_Socket = nullptr; m_Socket = nullptr;
} }
Done(shared_from_this()); Done(shared_from_this());
@@ -236,7 +288,7 @@ namespace client
return m_DestinationIdentHash; return m_DestinationIdentHash;
} }
std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(boost::asio::ip::tcp::socket * socket) std::shared_ptr<I2PServiceHandler> I2PClientTunnel::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{ {
const i2p::data::IdentHash *identHash = GetIdentHash(); const i2p::data::IdentHash *identHash = GetIdentHash();
if (identHash) if (identHash)
@@ -247,14 +299,28 @@ namespace client
I2PServerTunnel::I2PServerTunnel (const std::string& address, int port, I2PServerTunnel::I2PServerTunnel (const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, int inport): std::shared_ptr<ClientDestination> localDestination, int inport):
I2PService (localDestination), m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsAccessList (false) I2PService (localDestination), m_Address (address), m_Port (port), m_IsAccessList (false)
{ {
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port); m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port);
} }
void I2PServerTunnel::Start () void I2PServerTunnel::Start ()
{ {
Accept (); m_Endpoint.port (m_Port);
boost::system::error_code ec;
auto addr = boost::asio::ip::address::from_string (m_Address, ec);
if (!ec)
{
m_Endpoint.address (addr);
Accept ();
}
else
{
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(GetService ());
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (m_Address, ""),
std::bind (&I2PServerTunnel::HandleResolve, this,
std::placeholders::_1, std::placeholders::_2, resolver));
}
} }
void I2PServerTunnel::Stop () void I2PServerTunnel::Stop ()
@@ -262,6 +328,20 @@ namespace client
ClearHandlers (); ClearHandlers ();
} }
void I2PServerTunnel::HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
{
if (!ecode)
{
auto addr = (*it).endpoint ().address ();
LogPrint (eLogInfo, "server tunnel ", (*it).host_name (), " has been resolved to ", addr);
m_Endpoint.address (addr);
Accept ();
}
else
LogPrint (eLogError, "Unable to resolve server tunnel address: ", ecode.message ());
}
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList) void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
{ {
m_AccessList = accessList; m_AccessList = accessList;
@@ -296,10 +376,27 @@ namespace client
return; return;
} }
} }
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, new boost::asio::ip::tcp::socket (GetService ()), m_Endpoint); CreateI2PConnection (stream);
AddHandler (conn);
conn->Connect ();
} }
} }
void I2PServerTunnel::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint ());
AddHandler (conn);
conn->Connect ();
}
I2PServerTunnelHTTP::I2PServerTunnelHTTP (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int inport):
I2PServerTunnel (address, port, localDestination, inport)
{
}
void I2PServerTunnelHTTP::CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream)
{
auto conn = std::make_shared<I2PTunnelConnectionHTTP> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), GetEndpoint (), GetAddress ());
AddHandler (conn);
conn->Connect ();
}
} }
} }

View File

@@ -5,6 +5,7 @@
#include <string> #include <string>
#include <set> #include <set>
#include <memory> #include <memory>
#include <sstream>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "Destination.h" #include "Destination.h"
@@ -24,22 +25,23 @@ namespace client
{ {
public: public:
I2PTunnelConnection (I2PService * owner, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P std::shared_ptr<const i2p::data::LeaseSet> leaseSet, int port = 0); // to I2P
I2PTunnelConnection (I2PService * owner, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PService * owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API :) std::shared_ptr<i2p::stream::Stream> stream); // to I2P using simplified API
I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, boost::asio::ip::tcp::socket * socket, I2PTunnelConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, bool quiet = true); // from I2P 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 I2PConnect (const uint8_t * msg = nullptr, size_t len = 0);
void Connect (); void Connect ();
private: protected:
void Terminate (); void Terminate ();
void Receive (); void Receive ();
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
virtual void Write (const uint8_t * buf, size_t len); // can be overloaded
void HandleWrite (const boost::system::error_code& ecode); void HandleWrite (const boost::system::error_code& ecode);
void StreamReceive (); void StreamReceive ();
@@ -49,18 +51,37 @@ namespace client
private: private:
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];
std::unique_ptr<boost::asio::ip::tcp::socket> m_Socket; std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
std::shared_ptr<i2p::stream::Stream> m_Stream; std::shared_ptr<i2p::stream::Stream> m_Stream;
boost::asio::ip::tcp::endpoint m_RemoteEndpoint; boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
bool m_IsQuiet; // don't send destination bool m_IsQuiet; // don't send destination
}; };
class I2PTunnelConnectionHTTP: public I2PTunnelConnection
{
public:
I2PTunnelConnectionHTTP (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
std::shared_ptr<boost::asio::ip::tcp::socket> socket,
const boost::asio::ip::tcp::endpoint& target, const std::string& host);
protected:
void Write (const uint8_t * buf, size_t len);
private:
std::string m_Host;
std::stringstream m_InHeader, m_OutHeader;
bool m_HeaderSent;
};
class I2PClientTunnel: public TCPIPAcceptor class I2PClientTunnel: public TCPIPAcceptor
{ {
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<I2PServiceHandler> CreateHandler(boost::asio::ip::tcp::socket * socket); std::shared_ptr<I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "I2P Client Tunnel"; } const char* GetName() { return "I2P Client Tunnel"; }
public: public:
@@ -92,18 +113,40 @@ namespace client
void SetAccessList (const std::set<i2p::data::IdentHash>& accessList); void SetAccessList (const std::set<i2p::data::IdentHash>& accessList);
const std::string& GetAddress() const { return m_Address; }
int GetPort () const { return m_Port; };
const boost::asio::ip::tcp::endpoint& GetEndpoint () const { return m_Endpoint; }
private: private:
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void Accept (); void Accept ();
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream); void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
virtual void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
private: private:
std::string m_Address;
int m_Port;
boost::asio::ip::tcp::endpoint m_Endpoint; boost::asio::ip::tcp::endpoint m_Endpoint;
std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination; std::shared_ptr<i2p::stream::StreamingDestination> m_PortDestination;
std::set<i2p::data::IdentHash> m_AccessList; std::set<i2p::data::IdentHash> m_AccessList;
bool m_IsAccessList; bool m_IsAccessList;
}; };
class I2PServerTunnelHTTP: public I2PServerTunnel
{
public:
I2PServerTunnelHTTP (const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, int inport = 0);
private:
void CreateI2PConnection (std::shared_ptr<i2p::stream::Stream> stream);
};
} }
} }

View File

@@ -94,7 +94,14 @@ namespace data
excessBuf = new uint8_t[excessLen]; excessBuf = new uint8_t[excessLen];
memcpy (excessBuf, signingKey + 128, excessLen); memcpy (excessBuf, signingKey + 128, excessLen);
break; break;
} }
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
{
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
i2p::context.GetRandomNumberGenerator ().GenerateBlock (m_StandardIdentity.signingKey, padding);
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH);
break;
}
default: default:
LogPrint ("Signing key type ", (int)type, " is not supported"); LogPrint ("Signing key type ", (int)type, " is not supported");
} }
@@ -344,7 +351,13 @@ namespace data
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
m_Verifier = new i2p::crypto:: RSASHA5124096Verifier (signingKey); m_Verifier = new i2p::crypto:: RSASHA5124096Verifier (signingKey);
break; break;
} }
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
{
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
m_Verifier = new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding);
break;
}
default: default:
LogPrint ("Signing key type ", (int)keyType, " is not supported"); LogPrint ("Signing key type ", (int)keyType, " is not supported");
} }
@@ -457,6 +470,9 @@ namespace data
case SIGNING_KEY_TYPE_RSA_SHA512_4096: case SIGNING_KEY_TYPE_RSA_SHA512_4096:
m_Signer = new i2p::crypto::RSASHA5124096Signer (m_SigningPrivateKey); m_Signer = new i2p::crypto::RSASHA5124096Signer (m_SigningPrivateKey);
break; break;
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
m_Signer = new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey);
break;
default: default:
LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported"); LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported");
} }

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <memory>
#include "base64.h" #include "base64.h"
#include "ElGamal.h" #include "ElGamal.h"
#include "Signature.h" #include "Signature.h"
@@ -40,6 +41,13 @@ namespace data
bool operator== (const Tag<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; bool operator== (const Tag<sz>& other) const { return !memcmp (m_Buf, other.m_Buf, sz); };
bool operator< (const Tag<sz>& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; bool operator< (const Tag<sz>& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; };
bool IsZero () const
{
for (int i = 0; i < sz/8; i++)
if (ll[i]) return false;
return true;
}
std::string ToBase64 () const std::string ToBase64 () const
{ {
char str[sz*2]; char str[sz*2];
@@ -61,6 +69,11 @@ namespace data
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
} }
void FromBase64 (const std::string& s)
{
i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
}
private: private:
union // 8 bytes alignment union // 8 bytes alignment
@@ -116,6 +129,7 @@ namespace data
const uint16_t SIGNING_KEY_TYPE_RSA_SHA256_2048 = 4; 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_SHA384_3072 = 5;
const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6; const uint16_t SIGNING_KEY_TYPE_RSA_SHA512_4096 = 6;
const uint16_t SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 = 7;
typedef uint16_t SigningKeyType; typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType; typedef uint16_t CryptoKeyType;
@@ -219,23 +233,23 @@ namespace data
{ {
public: public:
RoutingDestination (): m_ElGamalEncryption (nullptr) {}; RoutingDestination () {};
virtual ~RoutingDestination () { delete m_ElGamalEncryption; }; virtual ~RoutingDestination () {};
virtual const IdentHash& GetIdentHash () const = 0; virtual const IdentHash& GetIdentHash () const = 0;
virtual const uint8_t * GetEncryptionPublicKey () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0;
virtual bool IsDestination () const = 0; // for garlic virtual bool IsDestination () const = 0; // for garlic
i2p::crypto::ElGamalEncryption * GetElGamalEncryption () const std::unique_ptr<const i2p::crypto::ElGamalEncryption>& GetElGamalEncryption () const
{ {
if (!m_ElGamalEncryption) if (!m_ElGamalEncryption)
m_ElGamalEncryption = new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()); m_ElGamalEncryption.reset (new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()));
return m_ElGamalEncryption; return m_ElGamalEncryption;
} }
private: private:
mutable i2p::crypto::ElGamalEncryption * m_ElGamalEncryption; // use lazy initialization mutable std::unique_ptr<const i2p::crypto::ElGamalEncryption> m_ElGamalEncryption; // use lazy initialization
}; };
class LocalDestination class LocalDestination

View File

@@ -14,23 +14,29 @@ namespace i2p
namespace data namespace data
{ {
LeaseSet::LeaseSet (const uint8_t * buf, int len) LeaseSet::LeaseSet (const uint8_t * buf, size_t len):
m_IsValid (true)
{ {
m_Buffer = new uint8_t[len];
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
m_BufferLen = len; m_BufferLen = len;
ReadFromBuffer (); ReadFromBuffer ();
} }
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool) LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool):
m_IsValid (true)
{ {
// header // header
const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination (); const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination ();
if (!localDestination) if (!localDestination)
{ {
m_Buffer = nullptr;
m_BufferLen = 0; m_BufferLen = 0;
m_IsValid = false;
LogPrint (eLogError, "Destination for local LeaseSet doesn't exist"); LogPrint (eLogError, "Destination for local LeaseSet doesn't exist");
return; return;
} }
m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE];
m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE);
memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256); memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256);
m_BufferLen += 256; m_BufferLen += 256;
@@ -62,9 +68,15 @@ namespace data
ReadFromBuffer (); ReadFromBuffer ();
} }
void LeaseSet::Update (const uint8_t * buf, int len) void LeaseSet::Update (const uint8_t * buf, size_t len)
{ {
m_Leases.clear (); m_Leases.clear ();
if (len > m_BufferLen)
{
auto oldBuffer = m_Buffer;
m_Buffer = new uint8_t[len];
delete[] oldBuffer;
}
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
m_BufferLen = len; m_BufferLen = len;
ReadFromBuffer (); ReadFromBuffer ();
@@ -79,6 +91,7 @@ namespace data
uint8_t num = m_Buffer[size]; uint8_t num = m_Buffer[size];
size++; // num size++; // num
LogPrint ("LeaseSet num=", (int)num); LogPrint ("LeaseSet num=", (int)num);
if (!num) m_IsValid = false;
// process leases // process leases
const uint8_t * leases = m_Buffer + size; const uint8_t * leases = m_Buffer + size;
@@ -97,14 +110,17 @@ namespace data
if (!netdb.FindRouter (lease.tunnelGateway)) if (!netdb.FindRouter (lease.tunnelGateway))
{ {
// if not found request it // if not found request it
LogPrint ("Lease's tunnel gateway not found. Requested"); LogPrint (eLogInfo, "Lease's tunnel gateway not found. Requested");
netdb.RequestDestination (lease.tunnelGateway); netdb.RequestDestination (lease.tunnelGateway);
} }
} }
// verify // verify
if (!m_Identity.Verify (m_Buffer, leases - m_Buffer, leases)) if (!m_Identity.Verify (m_Buffer, leases - m_Buffer, leases))
LogPrint ("LeaseSet verification failed"); {
LogPrint (eLogWarning, "LeaseSet verification failed");
m_IsValid = false;
}
} }
const std::vector<Lease> LeaseSet::GetNonExpiredLeases (bool withThreshold) const const std::vector<Lease> LeaseSet::GetNonExpiredLeases (bool withThreshold) const

View File

@@ -36,15 +36,15 @@ namespace data
{ {
public: public:
LeaseSet (const uint8_t * buf, int len); LeaseSet (const uint8_t * buf, size_t len);
LeaseSet (const LeaseSet& ) = default;
LeaseSet (const i2p::tunnel::TunnelPool& pool); LeaseSet (const i2p::tunnel::TunnelPool& pool);
LeaseSet& operator=(const LeaseSet& ) = default; ~LeaseSet () { delete[] m_Buffer; };
void Update (const uint8_t * buf, int len); void Update (const uint8_t * buf, size_t len);
const IdentityEx& GetIdentity () const { return m_Identity; }; const IdentityEx& GetIdentity () const { return m_Identity; };
const uint8_t * GetBuffer () const { return m_Buffer; }; const uint8_t * GetBuffer () const { return m_Buffer; };
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
bool IsValid () const { return m_IsValid; };
// implements RoutingDestination // implements RoutingDestination
const IdentHash& GetIdentHash () const { return m_Identity.GetIdentHash (); }; const IdentHash& GetIdentHash () const { return m_Identity.GetIdentHash (); };
@@ -61,10 +61,11 @@ namespace data
private: private:
bool m_IsValid;
std::vector<Lease> m_Leases; std::vector<Lease> m_Leases;
IdentityEx m_Identity; IdentityEx m_Identity;
uint8_t m_EncryptionKey[256]; uint8_t m_EncryptionKey[256];
uint8_t m_Buffer[MAX_LS_BUFFER_SIZE]; uint8_t * m_Buffer;
size_t m_BufferLen; size_t m_BufferLen;
}; };
} }

25
Log.cpp
View File

@@ -1,5 +1,5 @@
#include "Log.h"
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include "Log.h"
Log * g_Log = nullptr; Log * g_Log = nullptr;
@@ -13,11 +13,30 @@ static const char * g_LogLevelStr[eNumLogLevels] =
void LogMsg::Process() void LogMsg::Process()
{ {
output << boost::posix_time::second_clock::local_time().time_of_day () << auto& output = (log && log->GetLogStream ()) ? *log->GetLogStream () : std::cerr;
"/" << g_LogLevelStr[level] << " - "; if (log)
output << log->GetTimestamp ();
else
output << boost::posix_time::second_clock::local_time().time_of_day ();
output << "/" << g_LogLevelStr[level] << " - ";
output << s.str(); output << s.str();
} }
const std::string& Log::GetTimestamp ()
{
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6)
auto ts = std::chrono::monotonic_clock::now ();
#else
auto ts = std::chrono::steady_clock::now ();
#endif
if (ts > m_LastTimestampUpdate + std::chrono::milliseconds (500)) // 0.5 second
{
m_LastTimestampUpdate = ts;
m_Timestamp = boost::posix_time::to_simple_string (boost::posix_time::second_clock::local_time().time_of_day ());
}
return m_Timestamp;
}
void Log::Flush () void Log::Flush ()
{ {
if (m_LogStream) if (m_LogStream)

30
Log.h
View File

@@ -6,6 +6,7 @@
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#include <functional> #include <functional>
#include <chrono>
#include "Queue.h" #include "Queue.h"
enum LogLevel enum LogLevel
@@ -17,13 +18,14 @@ enum LogLevel
eNumLogLevels eNumLogLevels
}; };
class Log;
struct LogMsg struct LogMsg
{ {
std::stringstream s; std::stringstream s;
std::ostream& output; Log * log;
LogLevel level; LogLevel level;
LogMsg (std::ostream& o = std::cout, LogLevel l = eLogInfo): output (o), level (l) {}; LogMsg (Log * l = nullptr, LogLevel lv = eLogInfo): log (l), level (lv) {};
void Process(); void Process();
}; };
@@ -38,6 +40,7 @@ class Log: public i2p::util::MsgQueue<LogMsg>
void SetLogFile (const std::string& fullFilePath); void SetLogFile (const std::string& fullFilePath);
void SetLogStream (std::ostream * logStream); void SetLogStream (std::ostream * logStream);
std::ostream * GetLogStream () const { return m_LogStream; }; std::ostream * GetLogStream () const { return m_LogStream; };
const std::string& GetTimestamp ();
private: private:
@@ -46,6 +49,12 @@ class Log: public i2p::util::MsgQueue<LogMsg>
private: private:
std::ostream * m_LogStream; std::ostream * m_LogStream;
std::string m_Timestamp;
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) // gcc 4.6
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
#else
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
#endif
}; };
extern Log * g_Log; extern Log * g_Log;
@@ -54,9 +63,10 @@ inline void StartLog (const std::string& fullFilePath)
{ {
if (!g_Log) if (!g_Log)
{ {
g_Log = new Log (); auto log = new Log ();
if (fullFilePath.length () > 0) if (fullFilePath.length () > 0)
g_Log->SetLogFile (fullFilePath); log->SetLogFile (fullFilePath);
g_Log = log;
} }
} }
@@ -64,9 +74,10 @@ inline void StartLog (std::ostream * s)
{ {
if (!g_Log) if (!g_Log)
{ {
g_Log = new Log (); auto log = new Log ();
if (s) if (s)
g_Log->SetLogStream (s); log->SetLogStream (s);
g_Log = log;
} }
} }
@@ -74,8 +85,10 @@ inline void StopLog ()
{ {
if (g_Log) if (g_Log)
{ {
delete g_Log; auto log = g_Log;
g_Log = nullptr; g_Log = nullptr;
log->Stop ();
delete log;
} }
} }
@@ -95,8 +108,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->GetLogStream ()) ? new LogMsg (*g_Log->GetLogStream (), level) : LogMsg * msg = new LogMsg (g_Log, level);
new LogMsg (std::cout, level);
LogPrint (msg->s, args...); LogPrint (msg->s, args...);
msg->s << std::endl; msg->s << std::endl;
if (g_Log) if (g_Log)

View File

@@ -8,15 +8,17 @@ INCFLAGS =
## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## -std=c++11. If you want to remove this variable please do so in a way that allows setting
## custom FLAGS to work at build-time. ## custom FLAGS to work at build-time.
# detect proper flag for c++11 support by gcc # detect proper flag for c++11 support by compilers
CXXVER := $(shell $(CXX) -dumpversion) CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # >= 4.10 ifeq ($(shell expr match $(CXX) 'clang'),5)
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7 else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6 else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
NEEDED_CXXFLAGS += -std=c++0x NEEDED_CXXFLAGS += -std=c++0x
else ifeq ($(shell expr match $(CXX) 'clang'),5) else ifeq ($(shell expr match ${CXXVER} "5\.[0-9]"),3) # gcc >= 5.0
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else # not supported else # not supported
$(error Compiler too old) $(error Compiler too old)

View File

@@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include <cryptopp/dh.h> #include <cryptopp/dh.h>
#include <cryptopp/adler32.h>
#include "base64.h" #include "base64.h"
#include "Log.h" #include "Log.h"
#include "Timestamp.h" #include "Timestamp.h"
@@ -82,14 +83,8 @@ namespace transport
m_Socket.close (); m_Socket.close ();
transports.PeerDisconnected (shared_from_this ()); transports.PeerDisconnected (shared_from_this ());
m_Server.RemoveNTCPSession (shared_from_this ()); m_Server.RemoveNTCPSession (shared_from_this ());
for (auto it: m_SendQueue)
DeleteI2NPMessage (it);
m_SendQueue.clear (); m_SendQueue.clear ();
if (m_NextMessage) m_NextMessage = nullptr;
{
i2p::DeleteI2NPMessage (m_NextMessage);
m_NextMessage = nullptr;
}
m_TerminationTimer.cancel (); m_TerminationTimer.cancel ();
LogPrint (eLogInfo, "NTCP session terminated"); LogPrint (eLogInfo, "NTCP session terminated");
} }
@@ -106,7 +101,7 @@ namespace transport
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
SendTimeSyncMessage (); SendTimeSyncMessage ();
PostI2NPMessage (CreateDatabaseStoreMsg ()); // we tell immediately who we are m_SendQueue.push_back (ToSharedI2NPMessage(CreateDatabaseStoreMsg ())); // we tell immediately who we are
transports.PeerConnected (shared_from_this ()); transports.PeerConnected (shared_from_this ());
} }
@@ -565,7 +560,8 @@ namespace transport
LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size"); LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size");
return false; return false;
} }
m_NextMessage = dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage (); auto msg = dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage ();
m_NextMessage = ToSharedI2NPMessage (msg);
memcpy (m_NextMessage->buf, buf, 16); memcpy (m_NextMessage->buf, buf, 16);
m_NextMessageOffset = 16; m_NextMessageOffset = 16;
m_NextMessage->offset = 2; // size field m_NextMessage->offset = 2; // size field
@@ -587,20 +583,23 @@ namespace transport
if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum
{ {
// we have a complete I2NP message // we have a complete I2NP message
m_Handler.PutNextMessage (m_NextMessage); if (CryptoPP::Adler32().VerifyDigest (m_NextMessage->buf + m_NextMessageOffset - 4, m_NextMessage->buf, m_NextMessageOffset - 4))
m_Handler.PutNextMessage (m_NextMessage);
else
LogPrint (eLogWarning, "Incorrect adler checksum of NTCP message. Dropped");
m_NextMessage = nullptr; m_NextMessage = nullptr;
} }
return true; return true;
} }
void NTCPSession::Send (i2p::I2NPMessage * msg) void NTCPSession::Send (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
m_IsSending = true; m_IsSending = true;
boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, CreateMsgBuffer (msg), boost::asio::transfer_all (),
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector<I2NPMessage *>{ msg })); std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, std::vector<std::shared_ptr<I2NPMessage> >{ msg }));
} }
boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (I2NPMessage * msg) boost::asio::const_buffers_1 NTCPSession::CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg)
{ {
uint8_t * sendBuffer; uint8_t * sendBuffer;
int len; int len;
@@ -609,10 +608,7 @@ namespace transport
{ {
// regular I2NP // regular I2NP
if (msg->offset < 2) if (msg->offset < 2)
{ LogPrint (eLogError, "Malformed I2NP message"); // TODO:
LogPrint (eLogError, "Malformed I2NP message");
i2p::DeleteI2NPMessage (msg);
}
sendBuffer = msg->GetBuffer () - 2; sendBuffer = msg->GetBuffer () - 2;
len = msg->GetLength (); len = msg->GetLength ();
htobe16buf (sendBuffer, len); htobe16buf (sendBuffer, len);
@@ -629,7 +625,7 @@ namespace transport
int padding = 0; int padding = 0;
if (rem > 0) padding = 16 - rem; if (rem > 0) padding = 16 - rem;
// TODO: fill padding // TODO: fill padding
m_Adler.CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding); CryptoPP::Adler32().CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding);
int l = len + padding + 6; int l = len + padding + 6;
m_Encryption.Encrypt(sendBuffer, l, sendBuffer); m_Encryption.Encrypt(sendBuffer, l, sendBuffer);
@@ -637,7 +633,7 @@ namespace transport
} }
void NTCPSession::Send (const std::vector<I2NPMessage *>& msgs) void NTCPSession::Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{ {
m_IsSending = true; m_IsSending = true;
std::vector<boost::asio::const_buffer> bufs; std::vector<boost::asio::const_buffer> bufs;
@@ -647,11 +643,9 @@ namespace transport
std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs)); std::bind(&NTCPSession::HandleSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs));
} }
void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<I2NPMessage *> msgs) void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs)
{ {
m_IsSending = false; m_IsSending = false;
for (auto it: msgs)
if (it) i2p::DeleteI2NPMessage (it);
if (ecode) if (ecode)
{ {
LogPrint (eLogWarning, "Couldn't send msgs: ", ecode.message ()); LogPrint (eLogWarning, "Couldn't send msgs: ", ecode.message ());
@@ -679,40 +673,15 @@ namespace transport
Send (nullptr); Send (nullptr);
} }
void NTCPSession::SendI2NPMessage (I2NPMessage * msg)
{
m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessage, shared_from_this (), msg));
}
void NTCPSession::PostI2NPMessage (I2NPMessage * msg) void NTCPSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{
if (msg)
{
if (m_IsTerminated)
{
DeleteI2NPMessage (msg);
return;
}
if (m_IsSending)
m_SendQueue.push_back (msg);
else
Send (msg);
}
}
void NTCPSession::SendI2NPMessages (const std::vector<I2NPMessage *>& msgs)
{ {
m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessages, shared_from_this (), msgs)); m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessages, shared_from_this (), msgs));
} }
void NTCPSession::PostI2NPMessages (std::vector<I2NPMessage *> msgs) void NTCPSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
{ {
if (m_IsTerminated) if (m_IsTerminated) return;
{
for (auto it: msgs)
DeleteI2NPMessage (it);
return;
}
if (m_IsSending) if (m_IsSending)
{ {
for (auto it: msgs) for (auto it: msgs)

View File

@@ -9,7 +9,6 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <cryptopp/modes.h> #include <cryptopp/modes.h>
#include <cryptopp/aes.h> #include <cryptopp/aes.h>
#include <cryptopp/adler32.h>
#include "aes.h" #include "aes.h"
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
@@ -62,13 +61,11 @@ namespace transport
void ClientLogin (); void ClientLogin ();
void ServerLogin (); void ServerLogin ();
void SendI2NPMessage (I2NPMessage * msg); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void SendI2NPMessages (const std::vector<I2NPMessage *>& msgs);
private: private:
void PostI2NPMessage (I2NPMessage * msg); void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
void PostI2NPMessages (std::vector<I2NPMessage *> msgs);
void Connected (); void Connected ();
void SendTimeSyncMessage (); void SendTimeSyncMessage ();
void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; } void SetIsEstablished (bool isEstablished) { m_IsEstablished = isEstablished; }
@@ -97,10 +94,10 @@ namespace transport
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
bool DecryptNextBlock (const uint8_t * encrypted); bool DecryptNextBlock (const uint8_t * encrypted);
void Send (i2p::I2NPMessage * msg); void Send (std::shared_ptr<i2p::I2NPMessage> msg);
boost::asio::const_buffers_1 CreateMsgBuffer (I2NPMessage * msg); boost::asio::const_buffers_1 CreateMsgBuffer (std::shared_ptr<I2NPMessage> msg);
void Send (const std::vector<I2NPMessage *>& msgs); void Send (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<I2NPMessage *> msgs); void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs);
// timer // timer
@@ -116,7 +113,6 @@ namespace transport
i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCDecryption m_Decryption;
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
CryptoPP::Adler32 m_Adler;
struct Establisher struct Establisher
{ {
@@ -128,12 +124,12 @@ namespace transport
i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer; i2p::crypto::AESAlignedBuffer<16> m_TimeSyncBuffer;
int m_ReceiveBufferOffset; int m_ReceiveBufferOffset;
i2p::I2NPMessage * m_NextMessage; std::shared_ptr<I2NPMessage> m_NextMessage;
size_t m_NextMessageOffset; size_t m_NextMessageOffset;
i2p::I2NPMessagesHandler m_Handler; i2p::I2NPMessagesHandler m_Handler;
bool m_IsSending; bool m_IsSending;
std::vector<I2NPMessage *> m_SendQueue; std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
boost::asio::ip::address m_ConnectedFrom; // for ban boost::asio::ip::address m_ConnectedFrom; // for ban
}; };

447
NetDb.cpp
View File

@@ -21,54 +21,7 @@ namespace i2p
{ {
namespace data namespace data
{ {
I2NPMessage * RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router, const char NetDb::m_NetDbPath[] = "netDb";
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{
I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
&m_ExcludedPeers);
m_ExcludedPeers.insert (router->GetIdentHash ());
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return msg;
}
I2NPMessage * RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
{
I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
m_ExcludedPeers.insert (floodfill);
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return msg;
}
void RequestedDestination::ClearExcludedPeers ()
{
m_ExcludedPeers.clear ();
}
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
{
if (m_RequestComplete)
{
m_RequestComplete (r);
m_RequestComplete = nullptr;
}
}
void RequestedDestination::Fail ()
{
if (m_RequestComplete)
{
m_RequestComplete (nullptr);
m_RequestComplete = nullptr;
}
}
#ifndef _WIN32
const char NetDb::m_NetDbPath[] = "/netDb";
#else
const char NetDb::m_NetDbPath[] = "\\netDb";
#endif
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr) NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr)
@@ -83,8 +36,8 @@ namespace data
void NetDb::Start () void NetDb::Start ()
{ {
Load (m_NetDbPath); Load ();
if (m_RouterInfos.size () < 50) // reseed if # of router less than 50 if (m_RouterInfos.size () < 25) // reseed if # of router less than 50
{ {
// try SU3 first // try SU3 first
Reseed (); Reseed ();
@@ -94,11 +47,11 @@ namespace data
{ {
// if still not enough download .dat files // if still not enough download .dat files
int reseedRetries = 0; int reseedRetries = 0;
while (m_RouterInfos.size () < 50 && reseedRetries < 10) while (m_RouterInfos.size () < 25 && reseedRetries < 5)
{ {
m_Reseeder->reseedNow(); m_Reseeder->reseedNow();
reseedRetries++; reseedRetries++;
Load (m_NetDbPath); Load ();
} }
} }
} }
@@ -108,19 +61,24 @@ namespace data
void NetDb::Stop () void NetDb::Stop ()
{ {
for (auto it: m_RouterInfos) if (m_IsRunning)
it.second->SaveProfile ();
m_RouterInfos.clear ();
if (m_Thread)
{ {
m_IsRunning = false; for (auto it: m_RouterInfos)
m_Queue.WakeUp (); it.second->SaveProfile ();
m_Thread->join (); DeleteObsoleteProfiles ();
delete m_Thread; m_RouterInfos.clear ();
m_Thread = 0; m_Floodfills.clear ();
} if (m_Thread)
m_LeaseSets.clear(); {
m_RequestedDestinations.clear (); m_IsRunning = false;
m_Queue.WakeUp ();
m_Thread->join ();
delete m_Thread;
m_Thread = 0;
}
m_LeaseSets.clear();
m_Requests.Stop ();
}
} }
void NetDb::Run () void NetDb::Run ()
@@ -130,7 +88,7 @@ namespace data
{ {
try try
{ {
I2NPMessage * msg = m_Queue.GetNextWithTimeout (15000); // 15 sec auto msg = m_Queue.GetNextWithTimeout (15000); // 15 sec
if (msg) if (msg)
{ {
int numMsgs = 0; int numMsgs = 0;
@@ -151,8 +109,8 @@ namespace data
HandleDatabaseLookupMsg (msg); HandleDatabaseLookupMsg (msg);
break; break;
default: // WTF? default: // WTF?
LogPrint ("NetDb: unexpected message type ", msg->GetTypeID ()); LogPrint (eLogError, "NetDb: unexpected message type ", msg->GetTypeID ());
i2p::HandleI2NPMessage (msg); //i2p::HandleI2NPMessage (msg);
} }
if (numMsgs > 100) break; if (numMsgs > 100) break;
msg = m_Queue.Get (); msg = m_Queue.Get ();
@@ -164,14 +122,14 @@ namespace data
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastManageRequest >= 15) // manage requests every 15 seconds if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
{ {
ManageRequests (); m_Requests.ManageRequests ();
lastManageRequest = ts; lastManageRequest = ts;
} }
if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
{ {
if (lastSave) if (lastSave)
{ {
SaveUpdated (m_NetDbPath); SaveUpdated ();
ManageLeaseSets (); ManageLeaseSets ();
} }
lastSave = ts; lastSave = ts;
@@ -189,7 +147,7 @@ namespace data
numRouters = 800/numRouters; numRouters = 800/numRouters;
if (numRouters < 1) numRouters = 1; if (numRouters < 1) numRouters = 1;
if (numRouters > 9) numRouters = 9; if (numRouters > 9) numRouters = 9;
ManageRequests (); m_Requests.ManageRequests ();
Explore (numRouters); Explore (numRouters);
lastExploratory = ts; lastExploratory = ts;
} }
@@ -234,13 +192,7 @@ namespace data
} }
} }
// take care about requested destination // take care about requested destination
auto it = m_RequestedDestinations.find (ident); m_Requests.RequestComplete (ident, r);
if (it != m_RequestedDestinations.end ())
{
it->second->Success (r);
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
m_RequestedDestinations.erase (it);
}
} }
void NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, void NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len,
@@ -252,12 +204,24 @@ namespace data
if (it != m_LeaseSets.end ()) if (it != m_LeaseSets.end ())
{ {
it->second->Update (buf, len); it->second->Update (buf, len);
LogPrint ("LeaseSet updated"); if (it->second->IsValid ())
LogPrint (eLogInfo, "LeaseSet updated");
else
{
LogPrint (eLogInfo, "LeaseSet update failed");
m_LeaseSets.erase (it);
}
} }
else else
{ {
LogPrint ("New LeaseSet added"); auto leaseSet = std::make_shared<LeaseSet> (buf, len);
m_LeaseSets[ident] = std::make_shared<LeaseSet> (buf, len); if (leaseSet->IsValid ())
{
LogPrint (eLogInfo, "New LeaseSet added");
m_LeaseSets[ident] = leaseSet;
}
else
LogPrint (eLogError, "New LeaseSet validation failed");
} }
} }
} }
@@ -327,10 +291,9 @@ namespace data
LogPrint (eLogWarning, "Failed to reseed after 10 attempts"); LogPrint (eLogWarning, "Failed to reseed after 10 attempts");
} }
void NetDb::Load (const char * directory) void NetDb::Load ()
{ {
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); boost::filesystem::path p(i2p::util::filesystem::GetDataDir() / m_NetDbPath);
p /= (directory);
if (!boost::filesystem::exists (p)) if (!boost::filesystem::exists (p))
{ {
// seems netDb doesn't exist yet // seems netDb doesn't exist yet
@@ -377,27 +340,15 @@ namespace data
LogPrint (m_Floodfills.size (), " floodfills loaded"); LogPrint (m_Floodfills.size (), " floodfills loaded");
} }
void NetDb::SaveUpdated (const char * directory) void NetDb::SaveUpdated ()
{ {
auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo) auto GetFilePath = [](const boost::filesystem::path& directory, const RouterInfo * routerInfo)
{ {
#ifndef _WIN32 std::string s(routerInfo->GetIdentHashBase64());
return std::string (directory) + "/r" + return directory / (std::string("r") + s[0]) / ("routerInfo-" + s + ".dat");
routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" +
#else
return std::string (directory) + "\\r" +
routerInfo->GetIdentHashBase64 ()[0] + "\\routerInfo-" +
#endif
routerInfo->GetIdentHashBase64 () + ".dat";
}; };
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()); boost::filesystem::path fullDirectory (i2p::util::filesystem::GetDataDir() / m_NetDbPath);
p /= (directory);
#if BOOST_VERSION > 10500
const char * fullDirectory = p.string().c_str ();
#else
const char * fullDirectory = p.c_str ();
#endif
int count = 0, deletedCount = 0; int count = 0, deletedCount = 0;
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
@@ -405,7 +356,8 @@ namespace data
{ {
if (it.second->IsUpdated ()) if (it.second->IsUpdated ())
{ {
it.second->SaveToFile (GetFilePath(fullDirectory, it.second.get ())); std::string f = GetFilePath(fullDirectory, it.second.get()).string();
it.second->SaveToFile (f);
it.second->SetUpdated (false); it.second->SetUpdated (false);
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
it.second->DeleteBuffer (); it.second->DeleteBuffer ();
@@ -416,22 +368,31 @@ namespace data
// RouterInfo expires after 1 hour if uses introducer // RouterInfo expires after 1 hour if uses introducer
if (it.second->UsesIntroducer () && ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hour if (it.second->UsesIntroducer () && ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hour
it.second->SetUnreachable (true); it.second->SetUnreachable (true);
else if (total > 25 && ts > (i2p::context.GetStartupTime () + 600)*1000LL) // routers don't expire if less than 25 or uptime is less than 10 minutes else if (total > 75 && ts > (i2p::context.GetStartupTime () + 600)*1000LL) // routers don't expire if less than 25 or uptime is less than 10 minutes
{ {
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
{ {
if (ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hours if (ts > it.second->GetTimestamp () + 3600*1000LL) // 1 hours
{
it.second->SetUnreachable (true); it.second->SetUnreachable (true);
total--;
}
} }
else if (total > 300) else if (total > 300)
{ {
if (ts > it.second->GetTimestamp () + 30*3600*1000LL) // 30 hours if (ts > it.second->GetTimestamp () + 30*3600*1000LL) // 30 hours
{
it.second->SetUnreachable (true); it.second->SetUnreachable (true);
total--;
}
} }
else if (total > 120) else if (total > 120)
{ {
if (ts > it.second->GetTimestamp () + 72*3600*1000LL) // 72 hours if (ts > it.second->GetTimestamp () + 72*3600*1000LL) // 72 hours
{
it.second->SetUnreachable (true); it.second->SetUnreachable (true);
total--;
}
} }
} }
@@ -475,35 +436,33 @@ namespace data
void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete) void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete)
{ {
// request RouterInfo directly auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
auto dest = new RequestedDestination (destination, false); // non-exploratory if (!dest)
dest->SetRequestComplete (requestComplete);
{ {
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already");
if (!m_RequestedDestinations.insert (std::make_pair (destination, return;
std::unique_ptr<RequestedDestination> (dest))).second) // not inserted
{
LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already");
return;
}
} }
auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (destination, dest->GetExcludedPeers ());
if (floodfill) if (floodfill)
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
else else
{ {
LogPrint (eLogError, "No floodfills found"); LogPrint (eLogError, "No floodfills found");
dest->Fail (); m_Requests.RequestComplete (destination, nullptr);
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
m_RequestedDestinations.erase (destination);
} }
} }
void NetDb::HandleDatabaseStoreMsg (I2NPMessage * m) void NetDb::HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> m)
{ {
const uint8_t * buf = m->GetPayload (); const uint8_t * buf = m->GetPayload ();
size_t len = m->GetSize (); size_t len = m->GetSize ();
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
if (ident.IsZero ())
{
LogPrint (eLogError, "Database store with zero ident. Dropped");
return;
}
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
size_t offset = DATABASE_STORE_HEADER_SIZE; size_t offset = DATABASE_STORE_HEADER_SIZE;
if (replyToken) if (replyToken)
@@ -520,32 +479,26 @@ namespace data
if (outbound) if (outbound)
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus); outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
else else
{
LogPrint (eLogError, "No outbound tunnels for DatabaseStore reply found"); LogPrint (eLogError, "No outbound tunnels for DatabaseStore reply found");
DeleteI2NPMessage (deliveryStatus);
}
} }
offset += 32; offset += 32;
if (context.IsFloodfill ()) if (context.IsFloodfill ())
{ {
// flood it // flood it
auto floodMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
uint8_t * payload = floodMsg->GetPayload ();
memcpy (payload, buf, 33); // key + type
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, len - offset);
floodMsg->len += DATABASE_STORE_HEADER_SIZE + len -offset;
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
std::set<IdentHash> excluded; std::set<IdentHash> excluded;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
auto floodfill = GetClosestFloodfill (buf + DATABASE_STORE_KEY_OFFSET, excluded); auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill) if (floodfill)
{
excluded.insert (floodfill->GetIdentHash ());
auto floodMsg = NewI2NPShortMessage ();
uint8_t * payload = floodMsg->GetPayload ();
memcpy (payload, buf, 33); // key + type
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); // zero reply token
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, len - offset);
floodMsg->len += DATABASE_STORE_HEADER_SIZE + len -offset;
FillI2NPMessageHeader (floodMsg, eI2NPDatabaseStore);
transports.SendMessage (floodfill->GetIdentHash (), floodMsg); transports.SendMessage (floodfill->GetIdentHash (), floodMsg);
}
} }
} }
} }
@@ -553,7 +506,7 @@ namespace data
if (buf[DATABASE_STORE_TYPE_OFFSET]) // type if (buf[DATABASE_STORE_TYPE_OFFSET]) // type
{ {
LogPrint ("LeaseSet"); LogPrint ("LeaseSet");
AddLeaseSet (buf + DATABASE_STORE_KEY_OFFSET, buf + offset, len - offset, m->from); AddLeaseSet (ident, buf + offset, len - offset, m->from);
} }
else else
{ {
@@ -563,7 +516,6 @@ namespace data
if (size > 2048 || size > len - offset) if (size > 2048 || size > len - offset)
{ {
LogPrint ("Invalid RouterInfo length ", (int)size); LogPrint ("Invalid RouterInfo length ", (int)size);
i2p::DeleteI2NPMessage (m);
return; return;
} }
try try
@@ -576,7 +528,7 @@ namespace data
if (uncomressedSize <= 2048) if (uncomressedSize <= 2048)
{ {
decompressor.Get (uncompressed, uncomressedSize); decompressor.Get (uncompressed, uncomressedSize);
AddRouterInfo (buf + DATABASE_STORE_KEY_OFFSET, uncompressed, uncomressedSize); AddRouterInfo (ident, uncompressed, uncomressedSize);
} }
else else
LogPrint ("Invalid RouterInfo uncomressed length ", (int)uncomressedSize); LogPrint ("Invalid RouterInfo uncomressed length ", (int)uncomressedSize);
@@ -586,21 +538,20 @@ namespace data
LogPrint (eLogError, "DatabaseStore: ", ex.what ()); LogPrint (eLogError, "DatabaseStore: ", ex.what ());
} }
} }
i2p::DeleteI2NPMessage (m);
} }
void NetDb::HandleDatabaseSearchReplyMsg (I2NPMessage * msg) void NetDb::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
{ {
uint8_t * buf = msg->GetPayload (); const uint8_t * buf = msg->GetPayload ();
char key[48]; char key[48];
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
key[l] = 0; key[l] = 0;
int num = buf[32]; // num int num = buf[32]; // num
LogPrint ("DatabaseSearchReply for ", key, " num=", num); LogPrint ("DatabaseSearchReply for ", key, " num=", num);
auto it = m_RequestedDestinations.find (IdentHash (buf)); IdentHash ident (buf);
if (it != m_RequestedDestinations.end ()) auto dest = m_Requests.FindRequest (ident);
if (dest)
{ {
auto& dest = it->second;
bool deleteDest = true; bool deleteDest = true;
if (num > 0) if (num > 0)
{ {
@@ -624,7 +575,7 @@ namespace data
{ {
i2p::tunnel::eDeliveryTypeRouter, i2p::tunnel::eDeliveryTypeRouter,
nextFloodfill->GetIdentHash (), 0, nextFloodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg () ToSharedI2NPMessage (CreateDatabaseStoreMsg ())
}); });
// request destination // request destination
@@ -647,18 +598,12 @@ namespace data
} }
if (deleteDest) if (deleteDest)
{
// no more requests for the destinationation. delete it // no more requests for the destinationation. delete it
it->second->Fail (); m_Requests.RequestComplete (ident, nullptr);
m_RequestedDestinations.erase (it);
}
} }
else else
{
// no more requests for detination possible. delete it // no more requests for detination possible. delete it
it->second->Fail (); m_Requests.RequestComplete (ident, nullptr);
m_RequestedDestinations.erase (it);
}
} }
else else
LogPrint ("Requested destination for ", key, " not found"); LogPrint ("Requested destination for ", key, " not found");
@@ -666,7 +611,7 @@ namespace data
// try responses // try responses
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
uint8_t * router = buf + 33 + i*32; const uint8_t * router = buf + 33 + i*32;
char peerHash[48]; char peerHash[48];
int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48); int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48);
peerHash[l1] = 0; peerHash[l1] = 0;
@@ -682,20 +627,24 @@ namespace data
else else
LogPrint ("Bayan"); LogPrint ("Bayan");
} }
i2p::DeleteI2NPMessage (msg);
} }
void NetDb::HandleDatabaseLookupMsg (I2NPMessage * msg) void NetDb::HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg)
{ {
uint8_t * buf = msg->GetPayload (); const uint8_t * buf = msg->GetPayload ();
IdentHash ident (buf);
if (ident.IsZero ())
{
LogPrint (eLogError, "DatabaseLookup for zero ident. Ignored");
return;
}
char key[48]; char key[48];
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
key[l] = 0; key[l] = 0;
uint8_t flag = buf[64]; uint8_t flag = buf[64];
LogPrint ("DatabaseLookup for ", key, " recieved flags=", (int)flag); LogPrint ("DatabaseLookup for ", key, " recieved flags=", (int)flag);
uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK; uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
uint8_t * excluded = buf + 65; const uint8_t * excluded = buf + 65;
uint32_t replyTunnelID = 0; uint32_t replyTunnelID = 0;
if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel if (flag & DATABASE_LOOKUP_DELIVERY_FLAG) //reply to tunnel
{ {
@@ -710,7 +659,7 @@ namespace data
numExcluded = 0; // TODO: numExcluded = 0; // TODO:
} }
I2NPMessage * replyMsg = nullptr; std::shared_ptr<I2NPMessage> replyMsg;
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP) if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
{ {
LogPrint ("Exploratory close to ", key, " ", numExcluded, " excluded"); LogPrint ("Exploratory close to ", key, " ", numExcluded, " excluded");
@@ -723,55 +672,51 @@ namespace data
std::vector<IdentHash> routers; std::vector<IdentHash> routers;
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
auto r = GetClosestNonFloodfill (buf, excludedRouters); auto r = GetClosestNonFloodfill (ident, excludedRouters);
if (r) if (r)
{ {
routers.push_back (r->GetIdentHash ()); routers.push_back (r->GetIdentHash ());
excludedRouters.insert (r->GetIdentHash ()); excludedRouters.insert (r->GetIdentHash ());
} }
} }
replyMsg = CreateDatabaseSearchReply (buf, routers); replyMsg = ToSharedI2NPMessage (CreateDatabaseSearchReply (ident, routers));
} }
else else
{ {
auto router = FindRouter (buf); if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
if (router) lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
{ {
LogPrint ("Requested RouterInfo ", key, " found"); auto router = FindRouter (ident);
router->LoadBuffer (); if (router)
if (router->GetBuffer ()) {
replyMsg = CreateDatabaseStoreMsg (router.get ()); LogPrint ("Requested RouterInfo ", key, " found");
router->LoadBuffer ();
if (router->GetBuffer ())
replyMsg = ToSharedI2NPMessage (CreateDatabaseStoreMsg (router));
}
} }
if (!replyMsg) if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
{ {
auto leaseSet = FindLeaseSet (buf); auto leaseSet = FindLeaseSet (ident);
if (leaseSet) // we don't send back our LeaseSets if (leaseSet) // we don't send back our LeaseSets
{ {
LogPrint ("Requested LeaseSet ", key, " found"); LogPrint ("Requested LeaseSet ", key, " found");
replyMsg = CreateDatabaseStoreMsg (leaseSet.get ()); replyMsg = ToSharedI2NPMessage (CreateDatabaseStoreMsg (leaseSet));
} }
} }
if (!replyMsg) if (!replyMsg)
{ {
LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded"); LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded");
std::set<IdentHash> excludedRouters; std::set<IdentHash> excludedRouters;
for (int i = 0; i < numExcluded; i++) for (int i = 0; i < numExcluded; i++)
{ {
excludedRouters.insert (excluded); excludedRouters.insert (excluded);
excluded += 32; excluded += 32;
} }
std::vector<IdentHash> routers; replyMsg = ToSharedI2NPMessage (CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters)));
for (int i = 0; i < 3; i++)
{
auto floodfill = GetClosestFloodfill (buf, excludedRouters);
if (floodfill)
{
routers.push_back (floodfill->GetIdentHash ());
excludedRouters.insert (floodfill->GetIdentHash ());
}
}
replyMsg = CreateDatabaseSearchReply (buf, routers);
} }
} }
@@ -782,11 +727,11 @@ namespace data
// encryption might be used though tunnel only // encryption might be used though tunnel only
if (flag & DATABASE_LOOKUP_ENCYPTION_FLAG) // encrypted reply requested if (flag & DATABASE_LOOKUP_ENCYPTION_FLAG) // encrypted reply requested
{ {
uint8_t * sessionKey = excluded; const uint8_t * sessionKey = excluded;
uint8_t numTags = sessionKey[32]; uint8_t numTags = sessionKey[32];
if (numTags > 0) if (numTags > 0)
{ {
uint8_t * sessionTag = sessionKey + 33; // take first tag const uint8_t * sessionTag = sessionKey + 33; // take first tag
i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag); i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag);
replyMsg = garlic.WrapSingleMessage (replyMsg); replyMsg = garlic.WrapSingleMessage (replyMsg);
} }
@@ -801,7 +746,6 @@ namespace data
else else
transports.SendMessage (buf+32, replyMsg); transports.SendMessage (buf+32, replyMsg);
} }
i2p::DeleteI2NPMessage (msg);
} }
void NetDb::Explore (int numDestinations) void NetDb::Explore (int numDestinations)
@@ -820,15 +764,11 @@ namespace data
for (int i = 0; i < numDestinations; i++) for (int i = 0; i < numDestinations; i++)
{ {
rnd.GenerateBlock (randomHash, 32); rnd.GenerateBlock (randomHash, 32);
auto dest = new RequestedDestination (randomHash, true); // exploratory auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
{ if (!dest)
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); {
if (!m_RequestedDestinations.insert (std::make_pair (randomHash, LogPrint (eLogWarning, "Exploratory destination is requested already");
std::unique_ptr<RequestedDestination> (dest))).second) // not inserted return;
{
LogPrint (eLogWarning, "Exploratory destination is requested already");
return;
}
} }
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once if (floodfill && !floodfills.count (floodfill.get ())) // request floodfill only once
@@ -842,7 +782,7 @@ namespace data
{ {
i2p::tunnel::eDeliveryTypeRouter, i2p::tunnel::eDeliveryTypeRouter,
floodfill->GetIdentHash (), 0, floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg () // tell floodfill about us ToSharedI2NPMessage (CreateDatabaseStoreMsg ()) // tell floodfill about us
}); });
msgs.push_back (i2p::tunnel::TunnelMessageBlock msgs.push_back (i2p::tunnel::TunnelMessageBlock
{ {
@@ -855,10 +795,7 @@ namespace data
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
} }
else else
{ m_Requests.RequestComplete (randomHash, nullptr);
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
m_RequestedDestinations.erase (dest->GetDestination ());
}
} }
if (throughTunnels && msgs.size () > 0) if (throughTunnels && msgs.size () > 0)
outbound->SendTunnelDataMsg (msgs); outbound->SendTunnelDataMsg (msgs);
@@ -874,7 +811,7 @@ namespace data
{ {
uint32_t replyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); uint32_t replyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation (), ". reply token=", replyToken); LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation (), ". reply token=", replyToken);
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg ((RouterInfo *)nullptr, replyToken)); transports.SendMessage (floodfill->GetIdentHash (), ToSharedI2NPMessage (CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)));
excluded.insert (floodfill->GetIdentHash ()); excluded.insert (floodfill->GetIdentHash ());
} }
} }
@@ -923,7 +860,8 @@ namespace data
[compatibleWith](std::shared_ptr<const RouterInfo> router)->bool [compatibleWith](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
router->IsCompatible (*compatibleWith) && (router->GetCaps () & RouterInfo::eHighBandwidth); router->IsCompatible (*compatibleWith) &&
(router->GetCaps () & RouterInfo::eHighBandwidth);
}); });
} }
@@ -952,7 +890,7 @@ namespace data
return nullptr; // seems we have too few routers return nullptr; // seems we have too few routers
} }
void NetDb::PostI2NPMsg (I2NPMessage * msg) void NetDb::PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg)
{ {
if (msg) m_Queue.Put (msg); if (msg) m_Queue.Put (msg);
} }
@@ -967,10 +905,10 @@ namespace data
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it: m_Floodfills) for (auto it: m_Floodfills)
{ {
if (!it->IsUnreachable () && !excluded.count (it->GetIdentHash ())) if (!it->IsUnreachable ())
{ {
XORMetric m = destKey ^ it->GetIdentHash (); XORMetric m = destKey ^ it->GetIdentHash ();
if (m < minMetric) if (m < minMetric && !excluded.count (it->GetIdentHash ()))
{ {
minMetric = m; minMetric = m;
r = it; r = it;
@@ -980,6 +918,55 @@ namespace data
return r; return r;
} }
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded) const
{
struct Sorted
{
std::shared_ptr<const RouterInfo> r;
XORMetric metric;
bool operator< (const Sorted& other) const { return metric < other.metric; };
};
std::set<Sorted> sorted;
IdentHash destKey = CreateRoutingKey (destination);
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it: m_Floodfills)
{
if (!it->IsUnreachable ())
{
XORMetric m = destKey ^ it->GetIdentHash ();
if (sorted.size () < num)
sorted.insert ({it, m});
else if (m < sorted.rbegin ()->metric)
{
sorted.insert ({it, m});
sorted.erase (std::prev (sorted.end ()));
}
}
}
}
std::vector<IdentHash> res;
size_t i = 0;
for (auto it: sorted)
{
if (i < num)
{
auto& ident = it.r->GetIdentHash ();
if (!excluded.count (ident))
{
res.push_back (ident);
i++;
}
}
else
break;
}
return res;
}
std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestNonFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const const std::set<IdentHash>& excluded) const
{ {
@@ -990,10 +977,10 @@ namespace data
// must be called from NetDb thread only // must be called from NetDb thread only
for (auto it: m_RouterInfos) for (auto it: m_RouterInfos)
{ {
if (!it.second->IsFloodfill () && !excluded.count (it.first)) if (!it.second->IsFloodfill ())
{ {
XORMetric m = destKey ^ it.first; XORMetric m = destKey ^ it.first;
if (m < minMetric) if (m < minMetric && !excluded.count (it.first))
{ {
minMetric = m; minMetric = m;
r = it.second; r = it.second;
@@ -1016,53 +1003,5 @@ namespace data
it++; it++;
} }
} }
void NetDb::ManageRequests ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
{
auto& dest = it->second;
bool done = false;
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
{
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
{
auto count = dest->GetExcludedPeers ().size ();
if (!dest->IsExploratory () && count < 7)
{
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool->GetNextOutboundTunnel ();
auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound)
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (nextFloodfill, inbound));
else
{
done = true;
if (!inbound) LogPrint (eLogWarning, "No inbound tunnels");
if (!outbound) LogPrint (eLogWarning, "No outbound tunnels");
if (!nextFloodfill) LogPrint (eLogWarning, "No more floodfills");
}
}
else
{
if (!dest->IsExploratory ())
LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
done = true;
}
}
}
else // delete obsolete request
done = true;
if (done)
it = m_RequestedDestinations.erase (it);
else
it++;
}
}
} }
} }

57
NetDb.h
View File

@@ -16,44 +16,12 @@
#include "Tunnel.h" #include "Tunnel.h"
#include "TunnelPool.h" #include "TunnelPool.h"
#include "Reseed.h" #include "Reseed.h"
#include "NetDbRequests.h"
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
class RequestedDestination
{
public:
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
void ClearExcludedPeers ();
bool IsExploratory () const { return m_IsExploratory; };
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
uint64_t GetCreationTime () const { return m_CreationTime; };
I2NPMessage * CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
I2NPMessage * CreateRequestMessage (const IdentHash& floodfill);
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
void Success (std::shared_ptr<RouterInfo> r);
void Fail ();
private:
IdentHash m_Destination;
bool m_IsExploratory;
std::set<IdentHash> m_ExcludedPeers;
uint64_t m_CreationTime;
RequestComplete m_RequestComplete;
};
class NetDb class NetDb
{ {
@@ -73,9 +41,9 @@ namespace data
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
void HandleDatabaseStoreMsg (I2NPMessage * msg); void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (I2NPMessage * msg); void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
@@ -83,14 +51,16 @@ namespace data
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter () const; std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter () const;
std::shared_ptr<const RouterInfo> GetRandomIntroducer () const; std::shared_ptr<const RouterInfo> GetRandomIntroducer () const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (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 (std::shared_ptr<const I2NPMessage> msg);
void Reseed (); void Reseed ();
// for web interface and stats // for web interface
int GetNumRouters () const { return m_RouterInfos.size (); }; int GetNumRouters () const { return m_RouterInfos.size (); };
int GetNumFloodfills () const { return m_Floodfills.size (); }; int GetNumFloodfills () const { return m_Floodfills.size (); };
int GetNumLeaseSets () const { return m_LeaseSets.size (); }; int GetNumLeaseSets () const { return m_LeaseSets.size (); };
@@ -98,8 +68,8 @@ namespace data
private: private:
bool CreateNetDb(boost::filesystem::path directory); bool CreateNetDb(boost::filesystem::path directory);
void Load (const char * directory); void Load ();
void SaveUpdated (const char * directory); void SaveUpdated ();
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish (); void Publish ();
@@ -116,15 +86,16 @@ namespace data
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::list<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
std::mutex m_RequestedDestinationsMutex;
std::map<IdentHash, std::unique_ptr<RequestedDestination> > m_RequestedDestinations;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<I2NPMessage> m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
Reseeder * m_Reseeder; Reseeder * m_Reseeder;
friend class NetDbRequests;
NetDbRequests m_Requests;
static const char m_NetDbPath[]; static const char m_NetDbPath[];
}; };

149
NetDbRequests.cpp Normal file
View File

@@ -0,0 +1,149 @@
#include "Log.h"
#include "I2NPProtocol.h"
#include "Transports.h"
#include "NetDb.h"
#include "NetDbRequests.h"
namespace i2p
{
namespace data
{
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{
I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
&m_ExcludedPeers);
m_ExcludedPeers.insert (router->GetIdentHash ());
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return ToSharedI2NPMessage (msg);
}
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
{
I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
m_ExcludedPeers.insert (floodfill);
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return ToSharedI2NPMessage (msg);
}
void RequestedDestination::ClearExcludedPeers ()
{
m_ExcludedPeers.clear ();
}
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
{
if (m_RequestComplete)
{
m_RequestComplete (r);
m_RequestComplete = nullptr;
}
}
void RequestedDestination::Fail ()
{
if (m_RequestComplete)
{
m_RequestComplete (nullptr);
m_RequestComplete = nullptr;
}
}
void NetDbRequests::Start ()
{
}
void NetDbRequests::Stop ()
{
m_RequestedDestinations.clear ();
}
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
{
// request RouterInfo directly
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
dest->SetRequestComplete (requestComplete);
{
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
if (!m_RequestedDestinations.insert (std::make_pair (destination,
std::shared_ptr<RequestedDestination> (dest))).second) // not inserted
return nullptr;
}
return dest;
}
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
{
auto it = m_RequestedDestinations.find (ident);
if (it != m_RequestedDestinations.end ())
{
if (r)
it->second->Success (r);
else
it->second->Fail ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
m_RequestedDestinations.erase (it);
}
}
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
{
auto it = m_RequestedDestinations.find (ident);
if (it != m_RequestedDestinations.end ())
return it->second;
return nullptr;
}
void NetDbRequests::ManageRequests ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
{
auto& dest = it->second;
bool done = false;
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
{
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
{
auto count = dest->GetExcludedPeers ().size ();
if (!dest->IsExploratory () && count < 7)
{
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool->GetNextOutboundTunnel ();
auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound)
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (nextFloodfill, inbound));
else
{
done = true;
if (!inbound) LogPrint (eLogWarning, "No inbound tunnels");
if (!outbound) LogPrint (eLogWarning, "No outbound tunnels");
if (!nextFloodfill) LogPrint (eLogWarning, "No more floodfills");
}
}
else
{
if (!dest->IsExploratory ())
LogPrint (eLogWarning, dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
done = true;
}
}
}
else // delete obsolete request
done = true;
if (done)
it = m_RequestedDestinations.erase (it);
else
it++;
}
}
}
}

69
NetDbRequests.h Normal file
View File

@@ -0,0 +1,69 @@
#ifndef NETDB_REQUESTS_H__
#define NETDB_REQUESTS_H__
#include <memory>
#include <set>
#include <map>
#include "Identity.h"
#include "RouterInfo.h"
namespace i2p
{
namespace data
{
class RequestedDestination
{
public:
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
void ClearExcludedPeers ();
bool IsExploratory () const { return m_IsExploratory; };
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
uint64_t GetCreationTime () const { return m_CreationTime; };
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
void Success (std::shared_ptr<RouterInfo> r);
void Fail ();
private:
IdentHash m_Destination;
bool m_IsExploratory;
std::set<IdentHash> m_ExcludedPeers;
uint64_t m_CreationTime;
RequestComplete m_RequestComplete;
};
class NetDbRequests
{
public:
void Start ();
void Stop ();
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
void ManageRequests ();
private:
std::mutex m_RequestedDestinationsMutex;
std::map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
};
}
}
#endif

View File

@@ -11,14 +11,19 @@ namespace data
{ {
RouterProfile::RouterProfile (const IdentHash& identHash): RouterProfile::RouterProfile (const IdentHash& identHash):
m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()), m_IdentHash (identHash), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
m_NumTunnelsNonReplied (0) m_NumTimesTaken (0), m_NumTimesRejected (0)
{ {
} }
boost::posix_time::ptime RouterProfile::GetTime () const
{
return boost::posix_time::second_clock::local_time();
}
void RouterProfile::UpdateTime () void RouterProfile::UpdateTime ()
{ {
m_LastUpdateTime = boost::posix_time::second_clock::local_time(); m_LastUpdateTime = GetTime ();
} }
void RouterProfile::Save () void RouterProfile::Save ()
@@ -28,11 +33,15 @@ namespace data
participation.put (PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed); participation.put (PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed);
participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined); participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined);
participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied); participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied);
boost::property_tree::ptree usage;
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
// fill property tree // fill property tree
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime)); pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation); pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
// save to file // save to file
auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY; auto path = i2p::util::filesystem::GetDefaultDataDir() / PEER_PROFILES_DIRECTORY;
if (!boost::filesystem::exists (path)) if (!boost::filesystem::exists (path))
@@ -90,11 +99,34 @@ namespace data
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, ""); auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length () > 0) if (t.length () > 0)
m_LastUpdateTime = boost::posix_time::time_from_string (t); m_LastUpdateTime = boost::posix_time::time_from_string (t);
// read participations if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION); {
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0); try
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0); {
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0); // read participations
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_PARTICIPATION);
}
try
{
// read usage
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE);
}
}
else
*this = RouterProfile (m_IdentHash);
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
@@ -105,11 +137,11 @@ namespace data
void RouterProfile::TunnelBuildResponse (uint8_t ret) void RouterProfile::TunnelBuildResponse (uint8_t ret)
{ {
UpdateTime ();
if (ret > 0) if (ret > 0)
m_NumTunnelsDeclined++; m_NumTunnelsDeclined++;
else else
m_NumTunnelsAgreed++; m_NumTunnelsAgreed++;
UpdateTime ();
} }
void RouterProfile::TunnelNonReplied () void RouterProfile::TunnelNonReplied ()
@@ -117,6 +149,32 @@ namespace data
m_NumTunnelsNonReplied++; m_NumTunnelsNonReplied++;
UpdateTime (); UpdateTime ();
} }
bool RouterProfile::IsLowPartcipationRate () const
{
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
}
bool RouterProfile::IsLowReplyRate () const
{
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
return m_NumTunnelsNonReplied > 10*(total + 1);
}
bool RouterProfile::IsBad ()
{
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
{
// reset profile
m_NumTunnelsAgreed = 0;
m_NumTunnelsDeclined = 0;
m_NumTunnelsNonReplied = 0;
isBad = false;
}
if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
return isBad;
}
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash) std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
{ {
@@ -124,5 +182,32 @@ namespace data
profile->Load (); // if possible profile->Load (); // if possible
return profile; return profile;
} }
void DeleteObsoleteProfiles ()
{
int num = 0;
auto ts = boost::posix_time::second_clock::local_time();
boost::filesystem::path p (i2p::util::filesystem::GetDataDir()/PEER_PROFILES_DIRECTORY);
if (boost::filesystem::exists (p))
{
boost::filesystem::directory_iterator end;
for (boost::filesystem::directory_iterator it (p); it != end; ++it)
{
if (boost::filesystem::is_directory (it->status()))
{
for (boost::filesystem::directory_iterator it1 (it->path ()); it1 != end; ++it1)
{
auto lastModified = boost::posix_time::from_time_t (boost::filesystem::last_write_time (it1->path ()));
if ((ts - lastModified).hours () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
{
boost::filesystem::remove (it1->path ());
num++;
}
}
}
}
}
LogPrint (eLogInfo, num, " obsolete profiles deleted");
}
} }
} }

View File

@@ -13,29 +13,40 @@ namespace data
const char PEER_PROFILE_PREFIX[] = "profile-"; const char PEER_PROFILE_PREFIX[] = "profile-";
// sections // sections
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation"; const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
// params // params
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed"; const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined"; const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied"; const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
class RouterProfile class RouterProfile
{ {
public: public:
RouterProfile (const IdentHash& identHash); RouterProfile (const IdentHash& identHash);
RouterProfile& operator= (const RouterProfile& ) = default;
void Save (); void Save ();
void Load (); void Load ();
bool IsBad () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; bool IsBad ();
void TunnelBuildResponse (uint8_t ret); void TunnelBuildResponse (uint8_t ret);
void TunnelNonReplied (); void TunnelNonReplied ();
private: private:
boost::posix_time::ptime GetTime () const;
void UpdateTime (); void UpdateTime ();
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
bool IsLowPartcipationRate () const;
bool IsLowReplyRate () const;
private: private:
@@ -45,9 +56,13 @@ namespace data
uint32_t m_NumTunnelsAgreed; uint32_t m_NumTunnelsAgreed;
uint32_t m_NumTunnelsDeclined; uint32_t m_NumTunnelsDeclined;
uint32_t m_NumTunnelsNonReplied; uint32_t m_NumTunnelsNonReplied;
// usage
uint32_t m_NumTimesTaken;
uint32_t m_NumTimesRejected;
}; };
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash); std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void DeleteObsoleteProfiles ();
} }
} }

30
Queue.h
View File

@@ -17,14 +17,14 @@ namespace util
{ {
public: public:
void Put (Element * e) void Put (Element e)
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
m_Queue.push (e); m_Queue.push (e);
m_NonEmpty.notify_one (); m_NonEmpty.notify_one ();
} }
void Put (const std::vector<Element *>& vec) void Put (const std::vector<Element>& vec)
{ {
if (!vec.empty ()) if (!vec.empty ())
{ {
@@ -35,10 +35,10 @@ namespace util
} }
} }
Element * GetNext () Element GetNext ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
Element * el = GetNonThreadSafe (); auto el = GetNonThreadSafe ();
if (!el) if (!el)
{ {
m_NonEmpty.wait (l); m_NonEmpty.wait (l);
@@ -47,10 +47,10 @@ namespace util
return el; return el;
} }
Element * GetNextWithTimeout (int usec) Element GetNextWithTimeout (int usec)
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
Element * el = GetNonThreadSafe (); auto el = GetNonThreadSafe ();
if (!el) if (!el)
{ {
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec)); m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
@@ -85,13 +85,13 @@ namespace util
void WakeUp () { m_NonEmpty.notify_all (); }; void WakeUp () { m_NonEmpty.notify_all (); };
Element * Get () Element Get ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (); return GetNonThreadSafe ();
} }
Element * Peek () Element Peek ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (true); return GetNonThreadSafe (true);
@@ -99,11 +99,11 @@ namespace util
private: private:
Element * GetNonThreadSafe (bool peek = false) Element GetNonThreadSafe (bool peek = false)
{ {
if (!m_Queue.empty ()) if (!m_Queue.empty ())
{ {
Element * el = m_Queue.front (); auto el = m_Queue.front ();
if (!peek) if (!peek)
m_Queue.pop (); m_Queue.pop ();
return el; return el;
@@ -113,13 +113,13 @@ namespace util
private: private:
std::queue<Element *> m_Queue; std::queue<Element> m_Queue;
std::mutex m_QueueMutex; std::mutex m_QueueMutex;
std::condition_variable m_NonEmpty; std::condition_variable m_NonEmpty;
}; };
template<class Msg> template<class Msg>
class MsgQueue: public Queue<Msg> class MsgQueue: public Queue<Msg *>
{ {
public: public:
@@ -132,7 +132,7 @@ namespace util
if (m_IsRunning) if (m_IsRunning)
{ {
m_IsRunning = false; m_IsRunning = false;
Queue<Msg>::WakeUp (); Queue<Msg *>::WakeUp ();
m_Thread.join(); m_Thread.join();
} }
} }
@@ -145,7 +145,7 @@ namespace util
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
while (Msg * msg = Queue<Msg>::Get ()) while (auto msg = Queue<Msg *>::Get ())
{ {
msg->Process (); msg->Process ();
delete msg; delete msg;
@@ -153,7 +153,7 @@ namespace util
if (m_OnEmpty != nullptr) if (m_OnEmpty != nullptr)
m_OnEmpty (); m_OnEmpty ();
if (m_IsRunning) if (m_IsRunning)
Queue<Msg>::Wait (); Queue<Msg *>::Wait ();
} }
} }

View File

@@ -9,6 +9,12 @@ License
This project is licensed under the BSD 3-clause license, which can be found in the file This project is licensed under the BSD 3-clause license, which can be found in the file
LICENSE in the root of the project source code. LICENSE in the root of the project source code.
Donations
---------
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
Requirements for Linux/FreeBSD/OSX Requirements for Linux/FreeBSD/OSX
---------------------------------- ----------------------------------
@@ -104,21 +110,34 @@ i2p.conf:
tunnels.cfg (filename of this config is subject of change): tunnels.cfg (filename of this config is subject of change):
; outgoing tunnel, to remote service ; outgoing tunnel sample, to remote service
[tunnel1] ; mandatory parameters:
type = client ; mandatory ; * type -- always "client"
port = <integer> ; mandatory, bind our side of tunnel to this local port ; * port -- local port to listen to
keys = <filename> ; optional ; * destination -- i2p hostname
destination = <ident> ; mandatory ; optional parameters (may be omitted)
destinationport = <integer> ; optional, port of remote i2p service ; * keys -- our identity, if unset, will be generated on every startup,
; if set and file missing, keys will be generated and placed to this file
; incoming tunnel, for local service(s) [IRC]
[tunnel2] type = client
type = server ; mandatory port = 6668
host = <ident> ; mandatory, hostname of our i2p service destination = irc.echelon.i2p
keys = <filename> ; mandatory, hostname keys keys = irc-keys.dat
port = <integer> ; mandatory, forward incoming connections from i2p to this port
inport = <integer> ; optional, i2p service port ; incoming tunnel sample, for local service
accesslist = <ident>[,<ident>] ; optional, comma-separated list of i2p idents, allowed to connect to service ; mandatory parameters:
; * type -- always "server"
Note: '<ident>' type is a string like <hostname.i2p> or <abracadabra.b32.i2p> ; * host -- ip address of our service
; * port -- port of our service
; * keys -- file with LeaseSet of address in i2p
; optional parameters (may be omitted)
; * inport -- optional, i2p service port, if unset - the same as 'port'
; * accesslist -- comma-separated list of i2p addresses, allowed to connect
; every address is b32 without '.b32.i2p' part
[LOCALSITE]
type = server
host = 127.0.0.1
port = 80
keys = site-keys.dat
inport = 81
accesslist = <b32>[,<b32>]

View File

@@ -9,6 +9,8 @@
#include <cryptopp/crc.h> #include <cryptopp/crc.h>
#include <cryptopp/hmac.h> #include <cryptopp/hmac.h>
#include <cryptopp/zinflate.h> #include <cryptopp/zinflate.h>
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <cryptopp/arc4.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Reseed.h" #include "Reseed.h"
#include "Log.h" #include "Log.h"
@@ -24,22 +26,19 @@ namespace data
{ {
static std::vector<std::string> httpReseedHostList = { static std::vector<std::string> httpReseedHostList = {
// "http://193.150.121.66/netDb/", // unstable
// "http://us.reseed.i2p2.no/", // misconfigured, not serving reseed data
// "http://jp.reseed.i2p2.no/", // Really outdated RIs
"http://netdb.i2p2.no/", // only SU3 (v2) support "http://netdb.i2p2.no/", // only SU3 (v2) support
"http://i2p.mooo.com/netDb/", "http://i2p-netdb.innovatio.no/",
"http://uk.reseed.i2p2.no/", "http://193.150.121.66/netDb/"
"http://i2p-netdb.innovatio.no/"
}; };
//TODO: Remember to add custom port support. Not all serves on 443
static std::vector<std::string> httpsReseedHostList = { static std::vector<std::string> httpsReseedHostList = {
// "https://193.150.121.66/netDb/", // unstable // "https://193.150.121.66/netDb/", // unstable
// "https://i2p-netdb.innovatio.no/",// Vuln to POODLE // "https://i2p-netdb.innovatio.no/",// Vuln to POODLE
"https://netdb.i2p2.no/", // Only SU3 (v2) support "https://netdb.i2p2.no/", // Only SU3 (v2) support
"https://reseed.i2p-projekt.de/", // Only HTTPS "https://reseed.i2p-projekt.de/", // Only HTTPS
"https://cowpuncher.drollette.com/netdb/", // Only HTTPS and SU3 (v2) support -- will move to a new location //"https://cowpuncher.drollette.com/netdb/", // returns error
"https://netdb.rows.io:444/",
"https://uk.reseed.i2p2.no:444/"
// following hosts are fine but don't support AES256 // following hosts are fine but don't support AES256
/*"https://i2p.mooo.com/netDb/", /*"https://i2p.mooo.com/netDb/",
"https://link.mx24.eu/", // Only HTTPS and SU3 (v2) support "https://link.mx24.eu/", // Only HTTPS and SU3 (v2) support
@@ -494,43 +493,160 @@ namespace data
std::string Reseeder::HttpsRequest (const std::string& address) std::string Reseeder::HttpsRequest (const std::string& address)
{ {
i2p::util::http::url u(address); i2p::util::http::url u(address);
TlsSession session (u.host_, 443); if (u.port_ == 80) u.port_ = 443;
TlsSession session (u.host_, u.port_);
// send request if (session.IsEstablished ())
std::stringstream ss; {
ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ // send request
<< "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; std::stringstream ss;
session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ()); ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_
<< "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n";
session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ());
// read response // read response
std::stringstream rs; std::stringstream rs;
while (session.Receive (rs)) while (session.Receive (rs))
; ;
return i2p::util::http::GetHttpContent (rs); return i2p::util::http::GetHttpContent (rs);
}
else
return "";
} }
//-------------------------------------------------------------
template<class Hash>
class TlsCipherMAC: public TlsCipher
{
public:
TlsCipherMAC (const uint8_t * keys): m_Seqn (0)
{
memcpy (m_MacKey, keys, Hash::DIGESTSIZE);
}
void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac)
{
uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2)
htobe64buf (header, m_Seqn);
header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2
htobe16buf (header + 11, len);
CryptoPP::HMAC<Hash> hmac (m_MacKey, Hash::DIGESTSIZE);
hmac.Update (header, 13);
hmac.Update (buf, len);
hmac.Final (mac);
m_Seqn++;
}
private:
uint64_t m_Seqn;
uint8_t m_MacKey[Hash::DIGESTSIZE]; // client
};
template<class Hash>
class TlsCipher_AES_256_CBC: public TlsCipherMAC<Hash>
{
public:
TlsCipher_AES_256_CBC (const uint8_t * keys): TlsCipherMAC<Hash> (keys)
{
m_Encryption.SetKey (keys + 2*Hash::DIGESTSIZE);
m_Decryption.SetKey (keys + 2*Hash::DIGESTSIZE + 32);
}
size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out)
{
size_t size = 0;
m_Rnd.GenerateBlock (out, 16); // iv
size += 16;
m_Encryption.SetIV (out);
memcpy (out + size, in, len);
size += len;
memcpy (out + size, mac, Hash::DIGESTSIZE);
size += Hash::DIGESTSIZE;
uint8_t paddingSize = size + 1;
paddingSize &= 0x0F; // %16
if (paddingSize > 0) paddingSize = 16 - paddingSize;
memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size
size += paddingSize + 1;
m_Encryption.Encrypt (out + 16, size - 16, out + 16);
return size;
}
size_t Decrypt (uint8_t * buf, size_t len) // payload is buf + 16
{
m_Decryption.SetIV (buf);
m_Decryption.Decrypt (buf + 16, len - 16, buf + 16);
return len - 16 - Hash::DIGESTSIZE - buf[len -1] - 1; // IV(16), mac(32 or 20) and padding
}
size_t GetIVSize () const { return 16; };
private:
CryptoPP::AutoSeededRandomPool m_Rnd;
i2p::crypto::CBCEncryption m_Encryption;
i2p::crypto::CBCDecryption m_Decryption;
};
class TlsCipher_RC4_SHA: public TlsCipherMAC<CryptoPP::SHA1>
{
public:
TlsCipher_RC4_SHA (const uint8_t * keys): TlsCipherMAC (keys)
{
m_Encryption.SetKey (keys + 40, 16); // 20 + 20
m_Decryption.SetKey (keys + 56, 16); // 20 + 20 + 16
}
size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out)
{
memcpy (out, in, len);
memcpy (out + len, mac, 20);
m_Encryption.ProcessData (out, out, len + 20);
return len + 20;
}
size_t Decrypt (uint8_t * buf, size_t len)
{
m_Decryption.ProcessData (buf, buf, len);
return len - 20;
}
private:
CryptoPP::Weak1::ARC4 m_Encryption, m_Decryption;
};
TlsSession::TlsSession (const std::string& host, int port): TlsSession::TlsSession (const std::string& host, int port):
m_Seqn (0) m_IsEstablished (false), m_Cipher (nullptr)
{ {
m_Site.connect(host, boost::lexical_cast<std::string>(port)); m_Site.connect(host, boost::lexical_cast<std::string>(port));
if (m_Site.good ()) if (m_Site.good ())
{
Handshake (); Handshake ();
}
else else
LogPrint (eLogError, "Can't connect to ", host, ":", port); LogPrint (eLogError, "Can't connect to ", host, ":", port);
} }
TlsSession::~TlsSession ()
{
delete m_Cipher;
}
void TlsSession::Handshake () void TlsSession::Handshake ()
{ {
static uint8_t clientHello[] = static uint8_t clientHello[] =
{ {
0x16, // handshake 0x16, // handshake
0x03, 0x03, // version (TLS 1.2) 0x03, 0x03, // version (TLS 1.2)
0x00, 0x2F, // length of handshake 0x00, 0x33, // length of handshake
// handshake // handshake
0x01, // handshake type (client hello) 0x01, // handshake type (client hello)
0x00, 0x00, 0x2B, // length of handshake payload 0x00, 0x00, 0x2F, // length of handshake payload
// client hello // client hello
0x03, 0x03, // highest version supported (TLS 1.2) 0x03, 0x03, // highest version supported (TLS 1.2)
0x45, 0xFA, 0x01, 0x19, 0x74, 0x55, 0x18, 0x36, 0x45, 0xFA, 0x01, 0x19, 0x74, 0x55, 0x18, 0x36,
@@ -538,8 +654,10 @@ namespace data
0xEC, 0x37, 0x11, 0x93, 0x16, 0xF4, 0x66, 0x00, 0xEC, 0x37, 0x11, 0x93, 0x16, 0xF4, 0x66, 0x00,
0x12, 0x67, 0xAB, 0xBA, 0xFF, 0x29, 0x13, 0x9E, // 32 random bytes 0x12, 0x67, 0xAB, 0xBA, 0xFF, 0x29, 0x13, 0x9E, // 32 random bytes
0x00, // session id length 0x00, // session id length
0x00, 0x02, // chiper suites length 0x00, 0x06, // chiper suites length
0x00, 0x3D, // RSA_WITH_AES_256_CBC_SHA256 0x00, 0x3D, // RSA_WITH_AES_256_CBC_SHA256
0x00, 0x35, // RSA_WITH_AES_256_CBC_SHA
0x00, 0x05, // RSA_WITH_RC4_128_SHA
0x01, // compression methods length 0x01, // compression methods length
0x00, // no compression 0x00, // no compression
0x00, 0x00 // extensions length 0x00, 0x00 // extensions length
@@ -552,18 +670,6 @@ namespace data
0x00, 0x01, // length 0x00, 0x01, // length
0x01 // type 0x01 // type
}; };
static uint8_t finished[] =
{
0x16, // handshake
0x03, 0x03, // version (TLS 1.2)
0x00, 0x50, // length of handshake (80 bytes)
// handshake (encrypted)
// unencrypted context
// 0x14 handshake type (finished)
// 0x00, 0x00, 0x0C length of handshake payload
// 12 bytes of verified data
};
// send ClientHello // send ClientHello
m_Site.write ((char *)clientHello, sizeof (clientHello)); m_Site.write ((char *)clientHello, sizeof (clientHello));
@@ -584,7 +690,12 @@ namespace data
memcpy (serverRandom, serverHello + 6, 32); memcpy (serverRandom, serverHello + 6, 32);
else else
LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]);
delete[] serverHello; uint8_t sessionIDLen = serverHello[38]; // 6 + 32
char * cipherSuite = serverHello + 39 + sessionIDLen;
if (cipherSuite[1] == 0x3D || cipherSuite[1] == 0x35 || cipherSuite[1] == 0x05)
m_IsEstablished = true;
else
LogPrint (eLogError, "Unsupported cipher ", (int)cipherSuite[0], ",", (int)cipherSuite[1]);
// read Certificate // read Certificate
m_Site.read ((char *)&type, 1); m_Site.read ((char *)&type, 1);
m_Site.read ((char *)&version, 2); m_Site.read ((char *)&version, 2);
@@ -602,7 +713,6 @@ namespace data
publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10); publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10);
else else
LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]); LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]);
delete[] certificate;
// read ServerHelloDone // read ServerHelloDone
m_Site.read ((char *)&type, 1); m_Site.read ((char *)&type, 1);
m_Site.read ((char *)&version, 2); m_Site.read ((char *)&version, 2);
@@ -613,18 +723,18 @@ namespace data
m_FinishedHash.Update ((uint8_t *)serverHelloDone, length); m_FinishedHash.Update ((uint8_t *)serverHelloDone, length);
if (serverHelloDone[0] != 0x0E) // handshake type hello done if (serverHelloDone[0] != 0x0E) // handshake type hello done
LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]); LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]);
delete[] serverHelloDone;
// our turn now // our turn now
// generate secret key // generate secret key
uint8_t secret[48]; uint8_t secret[48];
secret[0] = 3; secret[1] = 3; // version secret[0] = 3; secret[1] = 3; // version
m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes CryptoPP::AutoSeededRandomPool rnd;
rnd.GenerateBlock (secret + 2, 46); // 46 random bytes
// encrypt RSA // encrypt RSA
CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey);
size_t encryptedLen = encryptor.CiphertextLength (48); // number of bytes for encrypted 48 bytes, usually 256 (2048 bits key) size_t encryptedLen = encryptor.CiphertextLength (48); // number of bytes for encrypted 48 bytes, usually 256 (2048 bits key)
uint8_t * encrypted = new uint8_t[encryptedLen + 2]; // + 2 bytes for length uint8_t * encrypted = new uint8_t[encryptedLen + 2]; // + 2 bytes for length
htobe16buf (encrypted, encryptedLen); // first two bytes means length htobe16buf (encrypted, encryptedLen); // first two bytes means length
encryptor.Encrypt (m_Rnd, secret, 48, encrypted + 2); encryptor.Encrypt (rnd, secret, 48, encrypted + 2);
// send ClientKeyExchange // send ClientKeyExchange
// 0x10 - handshake type "client key exchange" // 0x10 - handshake type "client key exchange"
SendHandshakeMsg (0x10, encrypted, encryptedLen + 2); SendHandshakeMsg (0x10, encrypted, encryptedLen + 2);
@@ -632,30 +742,35 @@ namespace data
// send ChangeCipherSpecs // send ChangeCipherSpecs
m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs)); m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs));
// calculate master secret // calculate master secret
uint8_t masterSecret[48], random[64]; uint8_t random[64];
memcpy (random, clientHello + 11, 32); memcpy (random, clientHello + 11, 32);
memcpy (random + 32, serverRandom, 32); memcpy (random + 32, serverRandom, 32);
PRF (secret, "master secret", random, 64, 48, masterSecret); PRF (secret, "master secret", random, 64, 48, m_MasterSecret);
// expand master secret // create keys
uint8_t keys[128]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32)
memcpy (random, serverRandom, 32); memcpy (random, serverRandom, 32);
memcpy (random + 32, clientHello + 11, 32); memcpy (random + 32, clientHello + 11, 32);
PRF (masterSecret, "key expansion", random, 64, 128, keys); uint8_t keys[128]; // clientMACKey(32 or 20), serverMACKey(32 or 20), clientKey(32), serverKey(32)
memcpy (m_MacKey, keys, 32); PRF (m_MasterSecret, "key expansion", random, 64, 128, keys);
m_Encryption.SetKey (keys + 64); // create cipher
m_Decryption.SetKey (keys + 96); if (cipherSuite[1] == 0x3D)
{
LogPrint (eLogInfo, "Chiper suite is RSA_WITH_AES_256_CBC_SHA256");
m_Cipher = new TlsCipher_AES_256_CBC<CryptoPP::SHA256> (keys);
}
else if (cipherSuite[1] == 0x35)
{
LogPrint (eLogInfo, "Chiper suite is RSA_WITH_AES_256_CBC_SHA");
m_Cipher = new TlsCipher_AES_256_CBC<CryptoPP::SHA1> (keys);
}
else
{
// TODO:
if (cipherSuite[1] == 0x05)
LogPrint (eLogInfo, "Chiper suite is RSA_WITH_RC4_128_SHA");
m_Cipher = new TlsCipher_RC4_SHA (keys);
}
// send finished // send finished
uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; SendFinishedMsg ();
finishedPayload[0] = 0x14; // handshake type (finished)
finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes
m_FinishedHash.Final (finishedHashDigest);
PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4);
uint8_t mac[32];
CalculateMAC (0x16, finishedPayload, 16, mac);
Encrypt (finishedPayload, 16, mac, encryptedPayload);
m_Site.write ((char *)finished, sizeof (finished));
m_Site.write ((char *)encryptedPayload, 80);
// read ChangeCipherSpecs // read ChangeCipherSpecs
uint8_t changeCipherSpecs1[6]; uint8_t changeCipherSpecs1[6];
m_Site.read ((char *)changeCipherSpecs1, 6); m_Site.read ((char *)changeCipherSpecs1, 6);
@@ -666,7 +781,12 @@ namespace data
length = be16toh (length); length = be16toh (length);
char * finished1 = new char[length]; char * finished1 = new char[length];
m_Site.read (finished1, length); m_Site.read (finished1, length);
m_Cipher->Decrypt ((uint8_t *)finished1, length); // for streaming ciphers
delete[] finished1; delete[] finished1;
delete[] serverHello;
delete[] certificate;
delete[] serverHelloDone;
} }
void TlsSession::SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len) void TlsSession::SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len)
@@ -685,6 +805,33 @@ namespace data
m_FinishedHash.Update (data, len); m_FinishedHash.Update (data, len);
} }
void TlsSession::SendFinishedMsg ()
{
// 0x16 handshake
// 0x03, 0x03 version (TLS 1.2)
// 2 bytes length of handshake (80 or 64 bytes)
// handshake (encrypted)
// unencrypted context
// 0x14 handshake type (finished)
// 0x00, 0x00, 0x0C length of handshake payload
// 12 bytes of verified data
uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80];
finishedPayload[0] = 0x14; // handshake type (finished)
finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes
m_FinishedHash.Final (finishedHashDigest);
PRF (m_MasterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4);
uint8_t mac[32];
m_Cipher->CalculateMAC (0x16, finishedPayload, 16, mac);
size_t encryptedPayloadSize = m_Cipher->Encrypt (finishedPayload, 16, mac, encryptedPayload);
uint8_t finished[5];
finished[0] = 0x16; // handshake
finished[1] = 0x03; finished[2] = 0x03; // version is always TLS 1.2 (3,3)
htobe16buf (finished + 3, encryptedPayloadSize); // length of payload
m_Site.write ((char *)finished, sizeof (finished));
m_Site.write ((char *)encryptedPayload, encryptedPayloadSize);
}
void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen,
size_t len, uint8_t * buf) size_t len, uint8_t * buf)
{ {
@@ -709,45 +856,6 @@ namespace data
} }
} }
size_t TlsSession::Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out)
{
size_t size = 0;
m_Rnd.GenerateBlock (out, 16); // iv
size += 16;
m_Encryption.SetIV (out);
memcpy (out + size, in, len);
size += len;
memcpy (out + size, mac, 32);
size += 32;
uint8_t paddingSize = len + 1;
paddingSize &= 0x0F; // %16
if (paddingSize > 0) paddingSize = 16 - paddingSize;
memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size
size += paddingSize + 1;
m_Encryption.Encrypt (out + 16, size - 16, out + 16);
return size;
}
size_t TlsSession::Decrypt (uint8_t * buf, size_t len)
{
m_Decryption.SetIV (buf);
m_Decryption.Decrypt (buf + 16, len - 16, buf + 16);
return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding
}
void TlsSession::CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac)
{
uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2)
htobe64buf (header, m_Seqn);
header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2
htobe16buf (header + 11, len);
CryptoPP::HMAC<CryptoPP::SHA256> hmac (m_MacKey, 32);
hmac.Update (header, 13);
hmac.Update (buf, len);
hmac.Final (mac);
m_Seqn++;
}
CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len)
{ {
CryptoPP::ByteQueue queue; CryptoPP::ByteQueue queue;
@@ -797,8 +905,8 @@ namespace data
out[0] = 0x17; // application data out[0] = 0x17; // application data
out[1] = 0x03; out[2] = 0x03; // version out[1] = 0x03; out[2] = 0x03; // version
uint8_t mac[32]; uint8_t mac[32];
CalculateMAC (0x17, buf, len, mac); m_Cipher->CalculateMAC (0x17, buf, len, mac);
size_t encryptedLen = Encrypt (buf, len, mac, out + 5); size_t encryptedLen = m_Cipher->Encrypt (buf, len, mac, out + 5);
htobe16buf (out + 3, encryptedLen); htobe16buf (out + 3, encryptedLen);
m_Site.write ((char *)out, encryptedLen + 5); m_Site.write ((char *)out, encryptedLen + 5);
delete[] out; delete[] out;
@@ -814,8 +922,8 @@ namespace data
length = be16toh (length); length = be16toh (length);
uint8_t * buf = new uint8_t[length]; uint8_t * buf = new uint8_t[length];
m_Site.read ((char *)buf, length); m_Site.read ((char *)buf, length);
size_t decryptedLen = Decrypt (buf, length); size_t decryptedLen = m_Cipher->Decrypt (buf, length);
rs.write ((char *)buf + 16, decryptedLen); rs.write ((char *)buf + m_Cipher->GetIVSize (), decryptedLen);
delete[] buf; delete[] buf;
return true; return true;
} }

View File

@@ -47,34 +47,47 @@ namespace data
std::map<std::string, PublicKey> m_SigningKeys; std::map<std::string, PublicKey> m_SigningKeys;
}; };
class TlsCipher
{
public:
virtual ~TlsCipher () {};
virtual void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) = 0;
virtual size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) = 0;
virtual size_t Decrypt (uint8_t * buf, size_t len) = 0;
virtual size_t GetIVSize () const { return 0; }; // override for AES
};
class TlsSession class TlsSession
{ {
public: public:
TlsSession (const std::string& host, int port); TlsSession (const std::string& host, int port);
~TlsSession ();
void Send (const uint8_t * buf, size_t len); void Send (const uint8_t * buf, size_t len);
bool Receive (std::ostream& rs); bool Receive (std::ostream& rs);
bool IsEstablished () const { return m_IsEstablished; };
private: private:
void Handshake (); void Handshake ();
void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len); void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len);
void SendFinishedMsg ();
CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len); CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len);
void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen,
size_t len, uint8_t * buf); size_t len, uint8_t * buf);
void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac);
size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out);
size_t Decrypt (uint8_t * buf, size_t len); // pyaload is buf + 16
private: private:
uint64_t m_Seqn; bool m_IsEstablished;
boost::asio::ip::tcp::iostream m_Site; boost::asio::ip::tcp::iostream m_Site;
CryptoPP::SHA256 m_FinishedHash; CryptoPP::SHA256 m_FinishedHash;
CryptoPP::AutoSeededRandomPool m_Rnd; uint8_t m_MasterSecret[64]; // actual size is 48, but must be multiple of 32
i2p::crypto::CBCEncryption m_Encryption; TlsCipher * m_Cipher;
i2p::crypto::CBCDecryption m_Decryption;
uint8_t m_MacKey[32]; // client
}; };
} }
} }

View File

@@ -289,11 +289,28 @@ namespace i2p
fk.write ((char *)&keys, sizeof (keys)); fk.write ((char *)&keys, sizeof (keys));
} }
std::shared_ptr<i2p::tunnel::TunnelPool> RouterContext::GetTunnelPool () const
{
return i2p::tunnel::tunnels.GetExploratoryPool ();
}
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from)); i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf), from));
} }
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
}
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{
std::unique_lock<std::mutex> l(m_GarlicMutex);
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
}
uint32_t RouterContext::GetUptime () const uint32_t RouterContext::GetUptime () const
{ {
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime; return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <mutex>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <cryptopp/dsa.h> #include <cryptopp/dsa.h>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
@@ -72,8 +73,13 @@ namespace i2p
void SetLeaseSetUpdated () {}; void SetLeaseSetUpdated () {};
// implements GarlicDestination // implements GarlicDestination
const i2p::data::LeaseSet * GetLeaseSet () { return nullptr; }; std::shared_ptr<const i2p::data::LeaseSet> GetLeaseSet () { return nullptr; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
// override GarlicDestination
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
private: private:
@@ -92,6 +98,7 @@ namespace i2p
bool m_AcceptsTunnels, m_IsFloodfill; bool m_AcceptsTunnels, m_IsFloodfill;
uint64_t m_StartupTime; // in seconds since epoch uint64_t m_StartupTime; // in seconds since epoch
RouterStatus m_Status; RouterStatus m_Status;
std::mutex m_GarlicMutex;
}; };
extern RouterContext context; extern RouterContext context;

View File

@@ -36,7 +36,7 @@ namespace data
RouterInfo::~RouterInfo () RouterInfo::~RouterInfo ()
{ {
delete m_Buffer; delete[] m_Buffer;
} }
void RouterInfo::Update (const uint8_t * buf, int len) void RouterInfo::Update (const uint8_t * buf, int len)
@@ -447,10 +447,13 @@ namespace data
if (m_Buffer) if (m_Buffer)
{ {
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
f.write ((char *)m_Buffer, m_BufferLen); if (f.is_open ())
} f.write ((char *)m_Buffer, m_BufferLen);
else
LogPrint(eLogError, "Can't save RouterInfo to ", fullPath);
}
else else
LogPrint (eLogError, "Can't save to file"); LogPrint (eLogError, "Can't save RouterInfo m_Buffer==NULL");
} }
size_t RouterInfo::ReadString (char * str, std::istream& s) size_t RouterInfo::ReadString (char * str, std::istream& s)

View File

@@ -142,7 +142,7 @@ namespace data
void SaveProfile () { if (m_Profile) m_Profile->Save (); }; void SaveProfile () { if (m_Profile) m_Profile->Save (); };
void Update (const uint8_t * buf, int len); void Update (const uint8_t * buf, int len);
void DeleteBuffer () { delete m_Buffer; m_Buffer = nullptr; }; void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
// implements RoutingDestination // implements RoutingDestination
const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); }; const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); };

51
SAM.cpp
View File

@@ -85,6 +85,9 @@ namespace client
else else
{ {
m_Buffer[bytes_transferred] = 0; m_Buffer[bytes_transferred] = 0;
char * eol = (char *)memchr (m_Buffer, '\n', bytes_transferred);
if (eol)
*eol = 0;
LogPrint ("SAM handshake ", m_Buffer); LogPrint ("SAM handshake ", m_Buffer);
char * separator = strchr (m_Buffer, ' '); char * separator = strchr (m_Buffer, ' ');
if (separator) if (separator)
@@ -340,19 +343,24 @@ namespace client
if (m_Session) if (m_Session)
{ {
i2p::data::IdentityEx dest; i2p::data::IdentityEx dest;
dest.FromBase64 (destination); size_t len = dest.FromBase64(destination);
context.GetAddressBook ().InsertAddress (dest); if (len > 0)
auto leaseSet = m_Session->localDestination->FindLeaseSet (dest.GetIdentHash ());
if (leaseSet)
Connect (leaseSet);
else
{ {
m_Session->localDestination->RequestDestination (dest.GetIdentHash (), context.GetAddressBook().InsertAddress(dest);
std::bind (&SAMSocket::HandleConnectLeaseSetRequestComplete, auto leaseSet = m_Session->localDestination->FindLeaseSet(dest.GetIdentHash());
shared_from_this (), std::placeholders::_1, dest.GetIdentHash ())); if (leaseSet)
Connect(leaseSet);
else
{
m_Session->localDestination->RequestDestination(dest.GetIdentHash(),
std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete,
shared_from_this(), std::placeholders::_1));
}
} }
else
SendMessageReply(SAM_SESSION_STATUS_INVALID_KEY, strlen(SAM_SESSION_STATUS_INVALID_KEY), true);
} }
else else
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
} }
@@ -366,11 +374,8 @@ namespace client
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
} }
void SAMSocket::HandleConnectLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident) void SAMSocket::HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet)
{ {
std::shared_ptr<const i2p::data::LeaseSet> leaseSet;
if (success)
leaseSet = m_Session->localDestination->FindLeaseSet (ident);
if (leaseSet) if (leaseSet)
Connect (leaseSet); Connect (leaseSet);
else else
@@ -486,11 +491,8 @@ namespace client
} }
} }
void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident) void SAMSocket::HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, i2p::data::IdentHash ident)
{ {
std::shared_ptr<const i2p::data::LeaseSet> leaseSet;
if (success)
leaseSet = m_Session->localDestination->FindLeaseSet (ident);
if (leaseSet) if (leaseSet)
{ {
context.GetAddressBook ().InsertAddress (leaseSet->GetIdentity ()); context.GetAddressBook ().InsertAddress (leaseSet->GetIdentity ());
@@ -564,8 +566,17 @@ namespace client
else else
{ {
if (m_Stream) if (m_Stream)
m_Stream->Send ((uint8_t *)m_Buffer, bytes_transferred); {
Receive (); auto s = shared_from_this ();
m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred,
[s](const boost::system::error_code& ecode)
{
if (!ecode)
s->Receive ();
else
s->Terminate ();
});
}
} }
} }

5
SAM.h
View File

@@ -28,6 +28,7 @@ namespace client
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";
const char SAM_SESSION_CREATE_DUPLICATED_DEST[] = "SESSION STATUS RESULT=DUPLICATED_DEST\n"; const char SAM_SESSION_CREATE_DUPLICATED_DEST[] = "SESSION STATUS RESULT=DUPLICATED_DEST\n";
const char SAM_SESSION_STATUS_INVALID_KEY[] = "SESSION STATUS RESULT=INVALID_KEY\n";
const char SAM_STREAM_CONNECT[] = "STREAM CONNECT"; const char SAM_STREAM_CONNECT[] = "STREAM CONNECT";
const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n"; const char SAM_STREAM_STATUS_OK[] = "STREAM STATUS RESULT=OK\n";
const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n"; const char SAM_STREAM_STATUS_INVALID_ID[] = "STREAM STATUS RESULT=INVALID_ID\n";
@@ -109,9 +110,9 @@ namespace client
void ExtractParams (char * buf, std::map<std::string, std::string>& params); void ExtractParams (char * buf, std::map<std::string, std::string>& params);
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote); void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
void HandleConnectLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident); void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
void SendNamingLookupReply (const i2p::data::IdentityEx& identity); void SendNamingLookupReply (const i2p::data::IdentityEx& identity);
void HandleNamingLookupLeaseSetRequestComplete (bool success, i2p::data::IdentHash ident); void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, i2p::data::IdentHash ident);
void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode); void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode);
void SendSessionCreateReplyOk (); void SendSessionCreateReplyOk ();

View File

@@ -118,7 +118,7 @@ namespace proxy
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream); void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
uint8_t m_sock_buff[socks_buffer_size]; uint8_t m_sock_buff[socks_buffer_size];
boost::asio::ip::tcp::socket * m_sock; std::shared_ptr<boost::asio::ip::tcp::socket> m_sock;
std::shared_ptr<i2p::stream::Stream> m_stream; std::shared_ptr<i2p::stream::Stream> m_stream;
uint8_t *m_remaining_data; //Data left to be sent uint8_t *m_remaining_data; //Data left to be sent
uint8_t m_response[7+max_socks_hostname_size]; uint8_t m_response[7+max_socks_hostname_size];
@@ -135,7 +135,7 @@ namespace proxy
state m_state; state m_state;
public: public:
SOCKSHandler(SOCKSServer * parent, boost::asio::ip::tcp::socket * sock) : SOCKSHandler(SOCKSServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
I2PServiceHandler(parent), m_sock(sock), m_stream(nullptr), I2PServiceHandler(parent), m_sock(sock), m_stream(nullptr),
m_authchosen(AUTH_UNACCEPTABLE), m_addrtype(ADDR_IPV4) m_authchosen(AUTH_UNACCEPTABLE), m_addrtype(ADDR_IPV4)
{ m_address.ip = 0; EnterState(GET_SOCKSV); } { m_address.ip = 0; EnterState(GET_SOCKSV); }
@@ -161,7 +161,6 @@ namespace proxy
{ {
LogPrint(eLogDebug,"--- SOCKS close sock"); LogPrint(eLogDebug,"--- SOCKS close sock");
m_sock->close(); m_sock->close();
delete m_sock;
m_sock = nullptr; m_sock = nullptr;
} }
if (m_stream) if (m_stream)
@@ -566,7 +565,7 @@ namespace proxy
{ {
} }
std::shared_ptr<i2p::client::I2PServiceHandler> SOCKSServer::CreateHandler(boost::asio::ip::tcp::socket * socket) std::shared_ptr<i2p::client::I2PServiceHandler> SOCKSServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{ {
return std::make_shared<SOCKSHandler> (this, socket); return std::make_shared<SOCKSHandler> (this, socket);
} }

View File

@@ -20,7 +20,7 @@ namespace proxy
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(boost::asio::ip::tcp::socket * socket); std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "SOCKS"; } const char* GetName() { return "SOCKS"; }
}; };

39
SSU.cpp
View File

@@ -217,24 +217,33 @@ namespace transport
for (auto it1: packets) for (auto it1: packets)
{ {
auto packet = it1; auto packet = it1;
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous try
{ {
if (session) session->FlushData (); if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
auto it = m_Sessions.find (packet->from);
if (it != m_Sessions.end ())
session = it->second;
if (!session)
{ {
session = std::make_shared<SSUSession> (*this, packet->from); if (session) session->FlushData ();
session->WaitForConnect (); auto it = m_Sessions.find (packet->from);
if (it != m_Sessions.end ())
session = it->second;
if (!session)
{ {
std::unique_lock<std::mutex> l(m_SessionsMutex); session = std::make_shared<SSUSession> (*this, packet->from);
m_Sessions[packet->from] = session; session->WaitForConnect ();
} {
LogPrint ("New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created"); std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[packet->from] = session;
}
LogPrint (eLogInfo, "New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
}
} }
} session->ProcessNextMessage (packet->buf, packet->len, packet->from);
session->ProcessNextMessage (packet->buf, packet->len, packet->from); }
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ());
if (session) session->FlushData ();
session = nullptr;
}
delete packet; delete packet;
} }
if (session) session->FlushData (); if (session) session->FlushData ();

View File

@@ -15,9 +15,8 @@ namespace transport
if (msg->len + fragmentSize > msg->maxLen) if (msg->len + fragmentSize > msg->maxLen)
{ {
LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough"); LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough");
I2NPMessage * newMsg = NewI2NPMessage (); auto newMsg = ToSharedI2NPMessage(NewI2NPMessage ());
*newMsg = *msg; *newMsg = *msg;
DeleteI2NPMessage (msg);
msg = newMsg; msg = newMsg;
} }
memcpy (msg->buf + msg->len, fragment, fragmentSize); memcpy (msg->buf + msg->len, fragment, fragmentSize);
@@ -174,7 +173,7 @@ namespace transport
if (it == m_IncompleteMessages.end ()) if (it == m_IncompleteMessages.end ())
{ {
// create new message // create new message
auto msg = NewI2NPShortMessage (); auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
msg->len -= I2NP_SHORT_HEADER_SIZE; msg->len -= I2NP_SHORT_HEADER_SIZE;
it = m_IncompleteMessages.insert (std::make_pair (msgID, it = m_IncompleteMessages.insert (std::make_pair (msgID,
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first; std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
@@ -244,10 +243,7 @@ namespace transport
m_Handler.PutNextMessage (msg); m_Handler.PutNextMessage (msg);
} }
else else
{
LogPrint (eLogWarning, "SSU message ", msgID, " already received"); LogPrint (eLogWarning, "SSU message ", msgID, " already received");
i2p::DeleteI2NPMessage (msg);
}
} }
else else
{ {
@@ -259,7 +255,6 @@ namespace transport
} }
else else
LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ()); LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ());
DeleteI2NPMessage (msg);
} }
} }
else else
@@ -294,13 +289,12 @@ namespace transport
ProcessFragments (buf); ProcessFragments (buf);
} }
void SSUData::Send (i2p::I2NPMessage * msg) void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
uint32_t msgID = msg->ToSSU (); uint32_t msgID = msg->ToSSU ();
if (m_SentMessages.count (msgID) > 0) if (m_SentMessages.count (msgID) > 0)
{ {
LogPrint (eLogWarning, "SSU message ", msgID, " already sent"); LogPrint (eLogWarning, "SSU message ", msgID, " already sent");
DeleteI2NPMessage (msg);
return; return;
} }
if (m_SentMessages.empty ()) // schedule resend at first message only if (m_SentMessages.empty ()) // schedule resend at first message only
@@ -368,7 +362,6 @@ namespace transport
len = 0; len = 0;
fragmentNum++; fragmentNum++;
} }
DeleteI2NPMessage (msg);
} }
void SSUData::SendMsgAck (uint32_t msgID) void SSUData::SendMsgAck (uint32_t msgID)

View File

@@ -59,13 +59,12 @@ namespace transport
struct IncompleteMessage struct IncompleteMessage
{ {
I2NPMessage * msg; std::shared_ptr<I2NPMessage> msg;
int nextFragmentNum; int nextFragmentNum;
uint32_t lastFragmentInsertTime; // in seconds uint32_t lastFragmentInsertTime; // in seconds
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments; std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {};
~IncompleteMessage () { if (msg) DeleteI2NPMessage (msg); };
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
}; };
@@ -89,7 +88,7 @@ namespace transport
void ProcessMessage (uint8_t * buf, size_t len); void ProcessMessage (uint8_t * buf, size_t len);
void FlushReceivedMessage (); void FlushReceivedMessage ();
void Send (i2p::I2NPMessage * msg); void Send (std::shared_ptr<i2p::I2NPMessage> msg);
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent); void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);

View File

@@ -783,7 +783,7 @@ namespace transport
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
} }
m_Data.Start (); m_Data.Start ();
m_Data.Send (CreateDatabaseStoreMsg ()); m_Data.Send (ToSharedI2NPMessage(CreateDatabaseStoreMsg ()));
transports.PeerConnected (shared_from_this ()); transports.PeerConnected (shared_from_this ());
if (m_PeerTest && (m_RemoteRouter && m_RemoteRouter->IsPeerTesting ())) if (m_PeerTest && (m_RemoteRouter && m_RemoteRouter->IsPeerTesting ()))
SendPeerTest (); SendPeerTest ();
@@ -832,39 +832,18 @@ namespace transport
} }
} }
void SSUSession::SendI2NPMessage (I2NPMessage * msg) void SSUSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{
GetService ().post (std::bind (&SSUSession::PostI2NPMessage, shared_from_this (), msg));
}
void SSUSession::PostI2NPMessage (I2NPMessage * msg)
{
if (msg)
{
if (m_State == eSessionStateEstablished)
m_Data.Send (msg);
else
DeleteI2NPMessage (msg);
}
}
void SSUSession::SendI2NPMessages (const std::vector<I2NPMessage *>& msgs)
{ {
GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs)); GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs));
} }
void SSUSession::PostI2NPMessages (std::vector<I2NPMessage *> msgs) void SSUSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
{ {
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
{ {
for (auto it: msgs) for (auto it: msgs)
if (it) m_Data.Send (it); if (it) m_Data.Send (it);
} }
else
{
for (auto it: msgs)
DeleteI2NPMessage (it);
}
} }
void SSUSession::ProcessData (uint8_t * buf, size_t len) void SSUSession::ProcessData (uint8_t * buf, size_t len)

View File

@@ -76,8 +76,7 @@ namespace transport
void Done (); void Done ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); }; bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
void SendI2NPMessage (I2NPMessage * msg); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void SendI2NPMessages (const std::vector<I2NPMessage *>& msgs);
void SendPeerTest (); // Alice void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; }; SessionState GetState () const { return m_State; };
@@ -95,8 +94,7 @@ namespace transport
boost::asio::io_service& GetService (); boost::asio::io_service& GetService ();
void CreateAESandMacKey (const uint8_t * pubKey); void CreateAESandMacKey (const uint8_t * pubKey);
void PostI2NPMessage (I2NPMessage * msg); void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
void PostI2NPMessages (std::vector<I2NPMessage *> msgs);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest (); void SendSessionRequest ();

121
Signature.cpp Normal file
View File

@@ -0,0 +1,121 @@
#include <memory>
#include <cryptopp/integer.h>
#include <cryptopp/eccrypto.h>
#include "Log.h"
#include "Signature.h"
namespace i2p
{
namespace crypto
{
class Ed25519
{
public:
Ed25519 ()
{
q = CryptoPP::Integer::Power2 (255) - CryptoPP::Integer (19); // 2^255-19
l = CryptoPP::Integer::Power2 (252) + CryptoPP::Integer ("27742317777372353535851937790883648493");
// 2^252 + 27742317777372353535851937790883648493
d = CryptoPP::Integer (-121665) * CryptoPP::Integer (121666).InverseMod (q); // -121665/121666
I = a_exp_b_mod_c (CryptoPP::Integer::Two (), (q - CryptoPP::Integer::One ()).DividedBy (4), q);
B = DecodePoint (CryptoPP::Integer (4)*CryptoPP::Integer (5).InverseMod (q));
}
CryptoPP::ECP::Point DecodePublicKey (const uint8_t * key) const
{
return DecodePoint (CryptoPP::Integer (key, 32));
}
CryptoPP::ECP::Point GeneratePublicKey (const uint8_t * privateKey) const
{
return Mul (B, CryptoPP::Integer (privateKey, 32));
}
private:
CryptoPP::ECP::Point Sum (const CryptoPP::ECP::Point& p1, const CryptoPP::ECP::Point& p2) const
{
CryptoPP::Integer m = d*p1.x*p2.x*p1.y*p2.y,
x = a_times_b_mod_c (p1.x*p2.y + p2.x*p1.y, (CryptoPP::Integer::One() + m).InverseMod (q), q),
y = a_times_b_mod_c (p1.y*p2.y + p1.x*p2.x, (CryptoPP::Integer::One() - m).InverseMod (q), q);
return CryptoPP::ECP::Point {x, y};
}
CryptoPP::ECP::Point Mul (const CryptoPP::ECP::Point& p, const CryptoPP::Integer& e) const
{
CryptoPP::ECP::Point res {0, 1};
if (!e.IsZero ())
{
auto bitCount = e.BitCount ();
for (int i = bitCount - 1; i >= 0; i--)
{
res = Sum (res, res);
if (e.GetBit (i)) res = Sum (res, p);
}
}
return res;
}
bool IsOnCurve (const CryptoPP::ECP::Point& p) const
{
auto x2 = p.x.Squared(), y2 = p.y.Squared ();
return (y2 - x2 - CryptoPP::Integer::One() - d*x2*y2).Modulo (q).IsZero ();
}
CryptoPP::Integer RecoverX (const CryptoPP::Integer& y) const
{
auto y2 = y.Squared ();
auto xx = (y2 - CryptoPP::Integer::One())*(d*y2 + CryptoPP::Integer::One()).InverseMod (q);
auto x = a_exp_b_mod_c (xx, (q + CryptoPP::Integer (3)).DividedBy (8), q);
if (!(x.Squared () - xx).Modulo (q).IsZero ())
x = a_times_b_mod_c (x, I, q);
if (x.IsOdd ()) x = q - x;
return x;
}
CryptoPP::ECP::Point DecodePoint (const CryptoPP::Integer& y) const
{
auto x = RecoverX (y);
CryptoPP::ECP::Point p {x, y};
if (!IsOnCurve (p))
{
LogPrint (eLogError, "Decoded point is not on 25519");
return CryptoPP::ECP::Point {0, 1};
}
return p;
}
private:
CryptoPP::Integer q, l, d, I;
CryptoPP::ECP::Point B; // base point
};
static std::unique_ptr<Ed25519> g_Ed25519;
std::unique_ptr<Ed25519>& GetEd25519 ()
{
if (!g_Ed25519)
g_Ed25519.reset (new Ed25519 ());
return g_Ed25519;
}
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey):
m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey))
{
}
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
return true; // TODO:
}
void EDDSA25519Signer::Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const
{
// TODO
}
}
}

View File

@@ -410,6 +410,34 @@ namespace crypto
{ {
} }
}; };
// EdDSA
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
const size_t EDDSA25519_SIGNATURE_LENGTH = 64;
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
class EDDSA25519Verifier: public Verifier
{
public:
EDDSA25519Verifier (const uint8_t * signingKey);
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; };
private:
CryptoPP::ECP::Point m_PublicKey;
};
class EDDSA25519Signer: public Signer
{
public:
EDDSA25519Signer (const uint8_t * signingPrivateKey) {};
void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const;
};
} }
} }

View File

@@ -22,7 +22,7 @@ namespace stream
{ {
m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
m_RemoteIdentity = remote->GetIdentity (); m_RemoteIdentity = remote->GetIdentity ();
UpdateCurrentRemoteLease (); m_CurrentRemoteLease.endDate = 0;
} }
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local): Stream::Stream (boost::asio::io_service& service, StreamingDestination& local):
@@ -61,6 +61,12 @@ namespace stream
m_AckSendTimer.cancel (); m_AckSendTimer.cancel ();
m_ReceiveTimer.cancel (); m_ReceiveTimer.cancel ();
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
if (m_SendHandler)
{
auto handler = m_SendHandler;
m_SendHandler = nullptr;
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted));
}
} }
void Stream::HandleNextPacket (Packet * packet) void Stream::HandleNextPacket (Packet * packet)
@@ -217,9 +223,9 @@ namespace stream
m_LastReceivedSequenceNumber = receivedSeqn; m_LastReceivedSequenceNumber = receivedSeqn;
if (flags & PACKET_FLAG_CLOSE) if (flags & (PACKET_FLAG_CLOSE | PACKET_FLAG_RESET))
{ {
LogPrint (eLogInfo, "Closed"); LogPrint (eLogInfo, (flags & PACKET_FLAG_RESET) ? "Reset" : "Closed");
m_Status = eStreamStatusReset; m_Status = eStreamStatusReset;
Close (); Close ();
} }
@@ -299,6 +305,15 @@ namespace stream
return len; return len;
} }
void Stream::AsyncSend (const uint8_t * buf, size_t len, SendHandler handler)
{
if (m_SendHandler)
handler (boost::asio::error::make_error_code (boost::asio::error::in_progress));
else
m_SendHandler = handler;
Send (buf, len);
}
void Stream::SendBuffer () void Stream::SendBuffer ()
{ {
int numMsgs = m_WindowSize - m_SentPackets.size (); int numMsgs = m_WindowSize - m_SentPackets.size ();
@@ -367,6 +382,11 @@ namespace stream
packets.push_back (p); packets.push_back (p);
numMsgs--; numMsgs--;
} }
if (m_SendBuffer.eof () && m_SendHandler)
{
m_SendHandler (boost::system::error_code ());
m_SendHandler = nullptr;
}
} }
if (packets.size () > 0) if (packets.size () > 0)
{ {
@@ -467,7 +487,7 @@ namespace stream
LogPrint (eLogInfo, "Trying to send stream data before closing"); LogPrint (eLogInfo, "Trying to send stream data before closing");
break; break;
case eStreamStatusReset: case eStreamStatusReset:
SendClose (); SendClose ();
Terminate (); Terminate ();
m_LocalDestination.DeleteStream (shared_from_this ()); m_LocalDestination.DeleteStream (shared_from_this ());
break; break;
@@ -577,7 +597,7 @@ namespace stream
} }
} }
if (!m_CurrentOutboundTunnel || !m_CurrentOutboundTunnel->IsEstablished ()) if (!m_CurrentOutboundTunnel || !m_CurrentOutboundTunnel->IsEstablished ())
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNextOutboundTunnel (); m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
if (!m_CurrentOutboundTunnel) if (!m_CurrentOutboundTunnel)
{ {
LogPrint (eLogError, "No outbound tunnels in the pool"); LogPrint (eLogError, "No outbound tunnels in the pool");
@@ -586,7 +606,7 @@ namespace stream
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000) if (ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000)
UpdateCurrentRemoteLease (); UpdateCurrentRemoteLease (true);
if (ts < m_CurrentRemoteLease.endDate) if (ts < m_CurrentRemoteLease.endDate)
{ {
std::vector<i2p::tunnel::TunnelMessageBlock> msgs; std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
@@ -645,6 +665,7 @@ namespace stream
if (packets.size () > 0) if (packets.size () > 0)
{ {
m_NumResendAttempts++; m_NumResendAttempts++;
m_RTO *= 2;
switch (m_NumResendAttempts) switch (m_NumResendAttempts)
{ {
case 1: // congesion avoidance case 1: // congesion avoidance
@@ -652,9 +673,10 @@ namespace stream
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
break; break;
case 2: case 2:
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time
// no break here
case 4: case 4:
UpdateCurrentRemoteLease (); // pick another lease UpdateCurrentRemoteLease (); // pick another lease
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change
LogPrint (eLogWarning, "Another remote lease has been selected for stream"); LogPrint (eLogWarning, "Another remote lease has been selected for stream");
break; break;
case 3: case 3:
@@ -687,7 +709,7 @@ namespace stream
} }
} }
void Stream::UpdateCurrentRemoteLease () void Stream::UpdateCurrentRemoteLease (bool expired)
{ {
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
{ {
@@ -702,16 +724,31 @@ namespace stream
auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false); // try without threshold first auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false); // try without threshold first
if (leases.empty ()) if (leases.empty ())
{ {
expired = false;
m_LocalDestination.GetOwner ().RequestDestination (m_RemoteIdentity.GetIdentHash ()); // time to re-request m_LocalDestination.GetOwner ().RequestDestination (m_RemoteIdentity.GetIdentHash ()); // time to re-request
leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold
} }
if (!leases.empty ()) if (!leases.empty ())
{ {
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); bool updated = false;
if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID) if (expired)
// make sure we don't select previous {
i = (i + 1) % leases.size (); // if so, pick next for (auto it: leases)
m_CurrentRemoteLease = leases[i]; if ((it.tunnelGateway == m_CurrentRemoteLease.tunnelGateway) && (it.tunnelID != m_CurrentRemoteLease.tunnelID))
{
m_CurrentRemoteLease = it;
updated = true;
break;
}
}
if (!updated)
{
uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1);
if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID)
// make sure we don't select previous
i = (i + 1) % leases.size (); // if so, pick next
m_CurrentRemoteLease = leases[i];
}
} }
else else
{ {
@@ -724,9 +761,9 @@ namespace stream
m_CurrentRemoteLease.endDate = 0; m_CurrentRemoteLease.endDate = 0;
} }
I2NPMessage * Stream::CreateDataMessage (const uint8_t * payload, size_t len) std::shared_ptr<I2NPMessage> Stream::CreateDataMessage (const uint8_t * payload, size_t len)
{ {
I2NPMessage * msg = NewI2NPShortMessage (); auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
CryptoPP::Gzip compressor; CryptoPP::Gzip compressor;
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL); compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL);
@@ -743,7 +780,7 @@ namespace stream
htobe16buf (buf + 6, m_Port); // destination port htobe16buf (buf + 6, m_Port); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
msg->len += size + 4; msg->len += size + 4;
FillI2NPMessageHeader (msg, eI2NPData); msg->FillI2NPMessageHeader (eI2NPData);
return msg; return msg;
} }

View File

@@ -85,7 +85,7 @@ namespace stream
enum StreamStatus enum StreamStatus
{ {
eStreamStatusNew, eStreamStatusNew = 0,
eStreamStatusOpen, eStreamStatusOpen,
eStreamStatusReset, eStreamStatusReset,
eStreamStatusClosing, eStreamStatusClosing,
@@ -97,6 +97,8 @@ namespace stream
{ {
public: public:
typedef std::function<void (const boost::system::error_code& ecode)> SendHandler;
Stream (boost::asio::io_service& service, StreamingDestination& local, Stream (boost::asio::io_service& service, StreamingDestination& local,
std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
@@ -106,12 +108,14 @@ namespace stream
uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; };
std::shared_ptr<const i2p::data::LeaseSet> GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; std::shared_ptr<const i2p::data::LeaseSet> GetRemoteLeaseSet () const { return m_RemoteLeaseSet; };
const i2p::data::IdentityEx& GetRemoteIdentity () const { return m_RemoteIdentity; }; const i2p::data::IdentityEx& GetRemoteIdentity () const { return m_RemoteIdentity; };
bool IsOpen () const { return m_Status == eStreamStatusOpen; }; bool IsOpen () const { return m_Status == eStreamStatusOpen; };
bool IsEstablished () const { return m_SendStreamID; }; bool IsEstablished () const { return m_SendStreamID; };
StreamStatus GetStatus () const { return m_Status; };
StreamingDestination& GetLocalDestination () { return m_LocalDestination; }; StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
size_t Send (const uint8_t * buf, size_t len); size_t Send (const uint8_t * buf, size_t len);
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
@@ -143,7 +147,7 @@ namespace stream
void ProcessAck (Packet * packet); void ProcessAck (Packet * packet);
size_t ConcatenatePackets (uint8_t * buf, size_t len); size_t ConcatenatePackets (uint8_t * buf, size_t len);
void UpdateCurrentRemoteLease (); void UpdateCurrentRemoteLease (bool expired = false);
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler); void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler);
@@ -152,7 +156,7 @@ namespace stream
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);
void HandleAckSendTimer (const boost::system::error_code& ecode); void HandleAckSendTimer (const boost::system::error_code& ecode);
I2NPMessage * CreateDataMessage (const uint8_t * payload, size_t len); std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len);
private: private:
@@ -179,6 +183,7 @@ namespace stream
int m_WindowSize, m_RTT, m_RTO; int m_WindowSize, m_RTT, m_RTO;
uint64_t m_LastWindowSizeIncreaseTime; uint64_t m_LastWindowSizeIncreaseTime;
int m_NumResendAttempts; int m_NumResendAttempts;
SendHandler m_SendHandler;
}; };
class StreamingDestination class StreamingDestination
@@ -228,20 +233,18 @@ namespace stream
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout) void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout)
{ {
if (!m_ReceiveQueue.empty ()) auto s = shared_from_this();
m_Service.post ([=](void)
{ {
auto s = shared_from_this(); if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset)
m_Service.post ([=](void) { s->HandleReceiveTimer ( s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler);
boost::asio::error::make_error_code (boost::asio::error::operation_aborted), else
buffer, handler); }); {
} s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(timeout));
else s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ { s->HandleReceiveTimer (ecode, buffer, handler); });
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)
{ s->HandleReceiveTimer (ecode, buffer, handler); });
}
} }
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>

View File

@@ -20,50 +20,49 @@ namespace tunnel
m_Encryption.SetKeys (layerKey, ivKey); m_Encryption.SetKeys (layerKey, ivKey);
} }
void TransitTunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg) void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{ {
m_Encryption.Encrypt (tunnelMsg->GetPayload () + 4); m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
} }
TransitTunnelParticipant::~TransitTunnelParticipant () TransitTunnelParticipant::~TransitTunnelParticipant ()
{ {
for (auto it: m_TunnelDataMsgs)
i2p::DeleteI2NPMessage (it);
} }
void TransitTunnelParticipant::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
EncryptTunnelMsg (tunnelMsg); auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg);
m_NumTransmittedBytes += tunnelMsg->GetLength (); m_NumTransmittedBytes += tunnelMsg->GetLength ();
htobe32buf (tunnelMsg->GetPayload (), GetNextTunnelID ()); htobe32buf (newMsg->GetPayload (), GetNextTunnelID ());
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
m_TunnelDataMsgs.push_back (tunnelMsg); m_TunnelDataMsgs.push_back (newMsg);
} }
void TransitTunnelParticipant::FlushTunnelDataMsgs () void TransitTunnelParticipant::FlushTunnelDataMsgs ()
{ {
if (!m_TunnelDataMsgs.empty ()) if (!m_TunnelDataMsgs.empty ())
{ {
LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", m_TunnelDataMsgs.size ()); auto num = m_TunnelDataMsgs.size ();
if (num > 1)
LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", num);
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
m_TunnelDataMsgs.clear (); m_TunnelDataMsgs.clear ();
} }
} }
void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
LogPrint (eLogError, "We are not a gateway for transit tunnel ", m_TunnelID); LogPrint (eLogError, "We are not a gateway for transit tunnel ", m_TunnelID);
i2p::DeleteI2NPMessage (msg);
} }
void TransitTunnel::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
LogPrint (eLogError, "Incoming tunnel message is not supported ", m_TunnelID); LogPrint (eLogError, "Incoming tunnel message is not supported ", m_TunnelID);
DeleteI2NPMessage (tunnelMsg);
} }
void TransitTunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
TunnelMessageBlock block; TunnelMessageBlock block;
block.deliveryType = eDeliveryTypeLocal; block.deliveryType = eDeliveryTypeLocal;
@@ -78,12 +77,13 @@ namespace tunnel
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
} }
void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
EncryptTunnelMsg (tunnelMsg); auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg);
LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ()); LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ());
m_Endpoint.HandleDecryptedTunnelDataMsg (tunnelMsg); m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
} }
TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID, TransitTunnel * CreateTransitTunnel (uint32_t receiveTunnelID,

View File

@@ -4,6 +4,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <vector> #include <vector>
#include <mutex> #include <mutex>
#include <memory>
#include "aes.h" #include "aes.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TunnelEndpoint.h" #include "TunnelEndpoint.h"
@@ -27,9 +28,9 @@ namespace tunnel
uint32_t GetTunnelID () const { return m_TunnelID; }; uint32_t GetTunnelID () const { return m_TunnelID; };
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (i2p::I2NPMessage * msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
void EncryptTunnelMsg (I2NPMessage * tunnelMsg); void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
uint32_t GetNextTunnelID () const { return m_NextTunnelID; }; uint32_t GetNextTunnelID () const { return m_NextTunnelID; };
const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; }; const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; };
@@ -53,13 +54,13 @@ namespace tunnel
~TransitTunnelParticipant (); ~TransitTunnelParticipant ();
size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
void FlushTunnelDataMsgs (); void FlushTunnelDataMsgs ();
private: private:
size_t m_NumTransmittedBytes; size_t m_NumTransmittedBytes;
std::vector<i2p::I2NPMessage *> m_TunnelDataMsgs; std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
}; };
class TransitTunnelGateway: public TransitTunnel class TransitTunnelGateway: public TransitTunnel
@@ -72,7 +73,7 @@ namespace tunnel
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {}; layerKey, ivKey), m_Gateway(this) {};
void SendTunnelDataMsg (i2p::I2NPMessage * msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void FlushTunnelDataMsgs (); void FlushTunnelDataMsgs ();
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
@@ -92,7 +93,7 @@ namespace tunnel
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
m_Endpoint (false) {}; // transit endpoint is always outbound m_Endpoint (false) {}; // transit endpoint is always outbound
void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); } size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
private: private:

View File

@@ -71,8 +71,7 @@ namespace transport
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
virtual void SendI2NPMessage (I2NPMessage * msg) = 0; virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
virtual void SendI2NPMessages (const std::vector<I2NPMessage *>& msgs) = 0;
protected: protected:

View File

@@ -109,6 +109,10 @@ namespace transport
void Transports::Start () void Transports::Start ()
{ {
#ifdef USE_UPNP
m_UPnP.Start ();
LogPrint(eLogInfo, "UPnP started");
#endif
m_DHKeysPairSupplier.Start (); m_DHKeysPairSupplier.Start ();
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this)); m_Thread = new std::thread (std::bind (&Transports::Run, this));
@@ -141,6 +145,10 @@ namespace transport
void Transports::Stop () void Transports::Stop ()
{ {
#ifdef USE_UPNP
m_UPnP.Stop ();
LogPrint(eLogInfo, "UPnP stopped");
#endif
m_PeerCleanupTimer.cancel (); m_PeerCleanupTimer.cancel ();
m_Peers.clear (); m_Peers.clear ();
if (m_SSUServer) if (m_SSUServer)
@@ -205,44 +213,17 @@ namespace transport
return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT; return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT;
} }
void Transports::SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg) void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
{ {
m_Service.post (std::bind (&Transports::PostMessage, this, ident, msg)); SendMessages (ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > {msg });
} }
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<i2p::I2NPMessage *>& msgs) void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
{ {
m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs)); m_Service.post (std::bind (&Transports::PostMessages, this, ident, msgs));
} }
void Transports::PostMessage (i2p::data::IdentHash ident, i2p::I2NPMessage * msg)
{
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
{
// we send it to ourself
i2p::HandleI2NPMessage (msg);
return;
}
auto it = m_Peers.find (ident); void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs)
if (it == m_Peers.end ())
{
auto r = netdb.FindRouter (ident);
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, nullptr,
i2p::util::GetSecondsSinceEpoch () })).first;
if (!ConnectToPeer (ident, it->second))
{
DeleteI2NPMessage (msg);
return;
}
}
if (it->second.session)
it->second.session->SendI2NPMessage (msg);
else
it->second.delayedMessages.push_back (msg);
}
void Transports::PostMessages (i2p::data::IdentHash ident, std::vector<i2p::I2NPMessage *> msgs)
{ {
if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) if (ident == i2p::context.GetRouterInfo ().GetIdentHash ())
{ {
@@ -254,18 +235,22 @@ namespace transport
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it == m_Peers.end ()) if (it == m_Peers.end ())
{ {
auto r = netdb.FindRouter (ident); bool connected = false;
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, nullptr, try
i2p::util::GetSecondsSinceEpoch () })).first;
if (!ConnectToPeer (ident, it->second))
{ {
for (auto it1: msgs) auto r = netdb.FindRouter (ident);
DeleteI2NPMessage (it1); it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
return; i2p::util::GetSecondsSinceEpoch () })).first;
} connected = ConnectToPeer (ident, it->second);
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Transports::PostMessages ", ex.what ());
}
if (!connected) return;
} }
if (it->second.session) if (!it->second.sessions.empty ())
it->second.session->SendI2NPMessages (msgs); it->second.sessions.front ()->SendI2NPMessages (msgs);
else else
{ {
for (auto it1: msgs) for (auto it1: msgs)
@@ -319,7 +304,7 @@ namespace transport
} }
} }
LogPrint (eLogError, "No NTCP and SSU addresses available"); LogPrint (eLogError, "No NTCP and SSU addresses available");
if (peer.session) peer.session->Done (); peer.Done ();
m_Peers.erase (ident); m_Peers.erase (ident);
return false; return false;
} }
@@ -446,20 +431,12 @@ namespace transport
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it != m_Peers.end ()) if (it != m_Peers.end ())
{ {
if (!it->second.session) it->second.sessions.push_back (session);
{ session->SendI2NPMessages (it->second.delayedMessages);
it->second.session = session; it->second.delayedMessages.clear ();
session->SendI2NPMessages (it->second.delayedMessages);
it->second.delayedMessages.clear ();
}
else
{
LogPrint (eLogError, "Session for ", ident.ToBase64 ().substr (0, 4), " already exists");
session->Done ();
}
} }
else // incoming connection else // incoming connection
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, session, i2p::util::GetSecondsSinceEpoch () })); m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch () }));
}); });
} }
@@ -469,12 +446,16 @@ namespace transport
{ {
auto ident = session->GetRemoteIdentity ().GetIdentHash (); auto ident = session->GetRemoteIdentity ().GetIdentHash ();
auto it = m_Peers.find (ident); auto it = m_Peers.find (ident);
if (it != m_Peers.end () && (!it->second.session || it->second.session == session)) if (it != m_Peers.end ())
{ {
if (it->second.delayedMessages.size () > 0) it->second.sessions.remove (session);
ConnectToPeer (ident, it->second); if (it->second.sessions.empty ()) // TODO: why?
else {
m_Peers.erase (it); if (it->second.delayedMessages.size () > 0)
ConnectToPeer (ident, it->second);
else
m_Peers.erase (it);
}
} }
}); });
} }
@@ -492,7 +473,7 @@ namespace transport
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_Peers.begin (); it != m_Peers.end (); ) for (auto it = m_Peers.begin (); it != m_Peers.end (); )
{ {
if (!it->second.session && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT) if (it->second.sessions.empty () && ts > it->second.creationTime + SESSION_CREATION_TIMEOUT)
{ {
LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds"); LogPrint (eLogError, "Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
it = m_Peers.erase (it); it = m_Peers.erase (it);
@@ -507,6 +488,14 @@ namespace transport
m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1)); m_PeerCleanupTimer.async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
} }
} }
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
{
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
auto it = m_Peers.begin ();
std::advance (it, rnd.GenerateWord32 (0, m_Peers.size () - 1));
return it != m_Peers.end () ? it->second.router : nullptr;
}
} }
} }

View File

@@ -20,6 +20,10 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Identity.h" #include "Identity.h"
#ifdef USE_UPNP
#include "UPnP.h"
#endif
namespace i2p namespace i2p
{ {
namespace transport namespace transport
@@ -56,14 +60,14 @@ namespace transport
{ {
int numAttempts; int numAttempts;
std::shared_ptr<const i2p::data::RouterInfo> router; std::shared_ptr<const i2p::data::RouterInfo> router;
std::shared_ptr<TransportSession> session; std::list<std::shared_ptr<TransportSession> > sessions;
uint64_t creationTime; uint64_t creationTime;
std::vector<i2p::I2NPMessage *> delayedMessages; std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
~Peer () void Done ()
{ {
for (auto it :delayedMessages) for (auto it: sessions)
i2p::DeleteI2NPMessage (it); it->Done ();
} }
}; };
@@ -83,8 +87,8 @@ namespace transport
i2p::transport::DHKeysPair * GetNextDHKeysPair (); i2p::transport::DHKeysPair * GetNextDHKeysPair ();
void ReuseDHKeysPair (DHKeysPair * pair); void ReuseDHKeysPair (DHKeysPair * pair);
void SendMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<i2p::I2NPMessage *>& msgs); void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router); void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
void PeerConnected (std::shared_ptr<TransportSession> session); void PeerConnected (std::shared_ptr<TransportSession> session);
@@ -98,14 +102,15 @@ namespace transport
uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second uint32_t GetInBandwidth () const { return m_InBandwidth; }; // bytes per second
uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; // bytes per second
bool IsBandwidthExceeded () const; bool IsBandwidthExceeded () const;
size_t GetNumPeers () const { return m_Peers.size (); };
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
private: private:
void Run (); void Run ();
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident); void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident); void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
void PostMessage (i2p::data::IdentHash ident, i2p::I2NPMessage * msg); void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
void PostMessages (i2p::data::IdentHash ident, std::vector<i2p::I2NPMessage *> msgs);
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router); void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer); bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
void HandlePeerCleanupTimer (const boost::system::error_code& ecode); void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
@@ -136,6 +141,10 @@ namespace transport
uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes;
uint64_t m_LastBandwidthUpdateTime; uint64_t m_LastBandwidthUpdateTime;
#ifdef USE_UPNP
UPnP m_UPnP;
#endif
public: public:
// for HTTP only // for HTTP only

View File

@@ -17,14 +17,13 @@ namespace i2p
namespace tunnel namespace tunnel
{ {
Tunnel::Tunnel (TunnelConfig * config): Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending) m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
{ {
} }
Tunnel::~Tunnel () Tunnel::~Tunnel ()
{ {
delete m_Config;
} }
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel) void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
@@ -32,7 +31,7 @@ namespace tunnel
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
auto numHops = m_Config->GetNumHops (); auto numHops = m_Config->GetNumHops ();
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops; int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
I2NPMessage * msg = NewI2NPShortMessage (); auto msg = NewI2NPShortMessage ();
*msg->GetPayload () = numRecords; *msg->GetPayload () = numRecords;
msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1; msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1;
@@ -78,13 +77,13 @@ namespace tunnel
} }
hop = hop->prev; hop = hop->prev;
} }
FillI2NPMessageHeader (msg, eI2NPVariableTunnelBuild); msg->FillI2NPMessageHeader (eI2NPVariableTunnelBuild);
// send message // send message
if (outboundTunnel) if (outboundTunnel)
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, ToSharedI2NPMessage (msg));
else else
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg); i2p::transport::transports.SendMessage (GetNextIdentHash (), ToSharedI2NPMessage (msg));
} }
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
@@ -141,32 +140,34 @@ namespace tunnel
return established; return established;
} }
void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg) void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{ {
uint8_t * payload = tunnelMsg->GetPayload () + 4; const uint8_t * inPayload = in->GetPayload () + 4;
uint8_t * outPayload = out->GetPayload () + 4;
TunnelHopConfig * hop = m_Config->GetLastHop (); TunnelHopConfig * hop = m_Config->GetLastHop ();
while (hop) while (hop)
{ {
hop->decryption.Decrypt (payload); hop->decryption.Decrypt (inPayload, outPayload);
hop = hop->prev; hop = hop->prev;
inPayload = outPayload;
} }
} }
void Tunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) void Tunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
LogPrint (eLogInfo, "Can't send I2NP messages without delivery instructions"); LogPrint (eLogInfo, "Can't send I2NP messages without delivery instructions");
DeleteI2NPMessage (msg);
} }
void InboundTunnel::HandleTunnelDataMsg (I2NPMessage * msg) void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg)
{ {
if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive
msg->from = shared_from_this (); auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (msg); EncryptTunnelMsg (msg, newMsg);
m_Endpoint.HandleDecryptedTunnelDataMsg (msg); newMsg->from = shared_from_this ();
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
} }
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
{ {
TunnelMessageBlock block; TunnelMessageBlock block;
if (gwHash) if (gwHash)
@@ -196,10 +197,9 @@ namespace tunnel
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
} }
void OutboundTunnel::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) void OutboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
LogPrint (eLogError, "Incoming message for outbound tunnel ", GetTunnelID ()); LogPrint (eLogError, "Incoming message for outbound tunnel ", GetTunnelID ());
DeleteI2NPMessage (tunnelMsg);
} }
Tunnels tunnels; Tunnels tunnels;
@@ -287,9 +287,9 @@ namespace tunnel
return tunnel; return tunnel;
} }
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops) std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
{ {
auto pool = std::make_shared<TunnelPool> (localDestination, numInboundHops, numOutboundHops); auto pool = std::make_shared<TunnelPool> (localDestination, numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
std::unique_lock<std::mutex> l(m_PoolsMutex); std::unique_lock<std::mutex> l(m_PoolsMutex);
m_Pools.push_back (pool); m_Pools.push_back (pool);
return pool; return pool;
@@ -353,7 +353,7 @@ namespace tunnel
{ {
try try
{ {
I2NPMessage * msg = m_Queue.GetNextWithTimeout (1000); // 1 sec auto msg = m_Queue.GetNextWithTimeout (1000); // 1 sec
if (msg) if (msg)
{ {
uint32_t prevTunnelID = 0, tunnelID = 0; uint32_t prevTunnelID = 0, tunnelID = 0;
@@ -384,27 +384,18 @@ namespace tunnel
else // tunnel gateway assumed else // tunnel gateway assumed
HandleTunnelGatewayMsg (tunnel, msg); HandleTunnelGatewayMsg (tunnel, msg);
} }
else else
{
LogPrint (eLogWarning, "Tunnel ", tunnelID, " not found"); LogPrint (eLogWarning, "Tunnel ", tunnelID, " not found");
DeleteI2NPMessage (msg);
}
break; break;
} }
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
{
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
DeleteI2NPMessage (msg); break;
break;
}
default: default:
{
LogPrint (eLogError, "Unexpected messsage type ", (int)typeID); LogPrint (eLogError, "Unexpected messsage type ", (int)typeID);
DeleteI2NPMessage (msg);
}
} }
msg = m_Queue.Get (); msg = m_Queue.Get ();
@@ -433,12 +424,11 @@ namespace tunnel
} }
} }
void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, I2NPMessage * msg) void Tunnels::HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg)
{ {
if (!tunnel) if (!tunnel)
{ {
LogPrint (eLogError, "Missing tunnel for TunnelGateway"); LogPrint (eLogError, "Missing tunnel for TunnelGateway");
i2p::DeleteI2NPMessage (msg);
return; return;
} }
const uint8_t * payload = msg->GetPayload (); const uint8_t * payload = msg->GetPayload ();
@@ -450,13 +440,9 @@ namespace tunnel
LogPrint (eLogDebug, "TunnelGateway of ", (int)len, " bytes for tunnel ", tunnel->GetTunnelID (), ". Msg type ", (int)typeID); LogPrint (eLogDebug, "TunnelGateway of ", (int)len, " bytes for tunnel ", tunnel->GetTunnelID (), ". Msg type ", (int)typeID);
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply) if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply)
{
// transit DatabaseStore my contain new/updated RI // transit DatabaseStore my contain new/updated RI
// or DatabaseSearchReply with new routers // or DatabaseSearchReply with new routers
auto ds = NewI2NPMessage (); i2p::data::netdb.PostI2NPMsg (msg);
*ds = *msg;
i2p::data::netdb.PostI2NPMsg (ds);
}
tunnel->SendTunnelDataMsg (msg); tunnel->SendTunnelDataMsg (msg);
} }
@@ -535,17 +521,25 @@ namespace tunnel
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{ {
LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired"); LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired");
{ auto pool = tunnel->GetTunnelPool ();
auto pool = tunnel->GetTunnelPool (); if (pool)
if (pool) pool->TunnelExpired (tunnel);
pool->TunnelExpired (tunnel);
}
it = m_OutboundTunnels.erase (it); it = m_OutboundTunnels.erase (it);
} }
else else
{ {
if (tunnel->IsEstablished () && ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (tunnel->IsEstablished ())
tunnel->SetState (eTunnelStateExpiring); {
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->RecreateOutboundTunnel (tunnel);
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
}
it++; it++;
} }
} }
@@ -555,14 +549,13 @@ namespace tunnel
{ {
// trying to create one more oubound tunnel // trying to create one more oubound tunnel
auto inboundTunnel = GetNextInboundTunnel (); auto inboundTunnel = GetNextInboundTunnel ();
if (!inboundTunnel) return; auto router = i2p::data::netdb.GetRandomRouter ();
if (!inboundTunnel || !router) return;
LogPrint ("Creating one hop outbound tunnel..."); LogPrint ("Creating one hop outbound tunnel...");
CreateTunnel<OutboundTunnel> ( CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > { router },
{ inboundTunnel->GetTunnelConfig ())
i2p::data::netdb.GetRandomRouter () );
},
inboundTunnel->GetTunnelConfig ()));
} }
} }
@@ -576,17 +569,26 @@ namespace tunnel
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{ {
LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired"); LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired");
{ auto pool = tunnel->GetTunnelPool ();
auto pool = tunnel->GetTunnelPool (); if (pool)
if (pool) pool->TunnelExpired (tunnel);
pool->TunnelExpired (tunnel);
}
it = m_InboundTunnels.erase (it); it = m_InboundTunnels.erase (it);
} }
else else
{ {
if (tunnel->IsEstablished () && ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (tunnel->IsEstablished ())
tunnel->SetState (eTunnelStateExpiring); {
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
tunnel->SetIsRecreated ();
auto pool = tunnel->GetTunnelPool ();
if (pool)
pool->RecreateInboundTunnel (tunnel);
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
}
it++; it++;
} }
} }
@@ -597,19 +599,18 @@ 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); // 2-hop exploratory m_ExploratoryPool = CreateTunnelPool (&i2p::context, 2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
return; return;
} }
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5) if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5)
{ {
// trying to create one more inbound tunnel // trying to create one more inbound tunnel
auto router = i2p::data::netdb.GetRandomRouter ();
LogPrint ("Creating one hop inbound tunnel..."); LogPrint ("Creating one hop inbound tunnel...");
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > { router })
{ );
i2p::data::netdb.GetRandomRouter ()
}));
} }
} }
@@ -647,18 +648,18 @@ namespace tunnel
} }
} }
void Tunnels::PostTunnelData (I2NPMessage * msg) void Tunnels::PostTunnelData (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) m_Queue.Put (msg); if (msg) m_Queue.Put (msg);
} }
void Tunnels::PostTunnelData (const std::vector<I2NPMessage *>& msgs) void Tunnels::PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{ {
m_Queue.Put (msgs); m_Queue.Put (msgs);
} }
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> Tunnels::CreateTunnel (TunnelConfig * config, std::shared_ptr<OutboundTunnel> outboundTunnel) std::shared_ptr<TTunnel> Tunnels::CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
auto newTunnel = std::make_shared<TTunnel> (config); auto newTunnel = std::make_shared<TTunnel> (config);
uint32_t replyMsgID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); uint32_t replyMsgID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 ();
@@ -709,7 +710,7 @@ namespace tunnel
void Tunnels::CreateZeroHopsInboundTunnel () void Tunnels::CreateZeroHopsInboundTunnel ()
{ {
CreateTunnel<InboundTunnel> ( CreateTunnel<InboundTunnel> (
new TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >
{ {
i2p::context.GetSharedRouterInfo () i2p::context.GetSharedRouterInfo ()
})); }));

View File

@@ -24,6 +24,7 @@ namespace tunnel
{ {
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds
const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message
@@ -44,16 +45,18 @@ namespace tunnel
{ {
public: public:
Tunnel (TunnelConfig * config); Tunnel (std::shared_ptr<const TunnelConfig> config);
~Tunnel (); ~Tunnel ();
void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
TunnelConfig * GetTunnelConfig () const { return m_Config; } std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; }
TunnelState GetState () const { return m_State; }; TunnelState GetState () const { return m_State; };
void SetState (TunnelState state) { m_State = state; }; void SetState (TunnelState state) { m_State = state; };
bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
bool IsFailed () const { return m_State == eTunnelStateFailed; }; bool IsFailed () const { return m_State == eTunnelStateFailed; };
bool IsRecreated () const { return m_IsRecreated; };
void SetIsRecreated () { m_IsRecreated = true; };
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; }; std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; }; void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
@@ -61,32 +64,33 @@ namespace tunnel
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (i2p::I2NPMessage * msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void EncryptTunnelMsg (I2NPMessage * tunnelMsg); void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; }; uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; };
const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); }; const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); };
private: private:
TunnelConfig * m_Config; std::shared_ptr<const TunnelConfig> m_Config;
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
TunnelState m_State; TunnelState m_State;
bool m_IsRecreated;
}; };
class OutboundTunnel: public Tunnel class OutboundTunnel: public Tunnel
{ {
public: public:
OutboundTunnel (TunnelConfig * config): Tunnel (config), m_Gateway (this) {}; OutboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Gateway (this) {};
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
std::shared_ptr<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 (); };
// implements TunnelBase // implements TunnelBase
void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
uint32_t GetTunnelID () const { return GetNextTunnelID (); }; uint32_t GetTunnelID () const { return GetNextTunnelID (); };
private: private:
@@ -99,8 +103,8 @@ namespace tunnel
{ {
public: public:
InboundTunnel (TunnelConfig * config): Tunnel (config), m_Endpoint (true) {}; InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
void HandleTunnelDataMsg (I2NPMessage * msg); void HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg);
size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
// implements TunnelBase // implements TunnelBase
@@ -131,13 +135,13 @@ namespace tunnel
void AddTransitTunnel (TransitTunnel * tunnel); void AddTransitTunnel (TransitTunnel * tunnel);
void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel); void AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel);
void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel); void AddInboundTunnel (std::shared_ptr<InboundTunnel> newTunnel);
void PostTunnelData (I2NPMessage * msg); void PostTunnelData (std::shared_ptr<I2NPMessage> msg);
void PostTunnelData (const std::vector<I2NPMessage *>& msgs); void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (TunnelConfig * config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops); std::shared_ptr<TunnelPool> CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool); void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
void StopTunnelPool (std::shared_ptr<TunnelPool> pool); void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
@@ -146,7 +150,7 @@ namespace tunnel
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels); std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
void HandleTunnelGatewayMsg (TunnelBase * tunnel, I2NPMessage * msg); void HandleTunnelGatewayMsg (TunnelBase * tunnel, std::shared_ptr<I2NPMessage> msg);
void Run (); void Run ();
void ManageTunnels (); void ManageTunnels ();
@@ -173,7 +177,7 @@ namespace tunnel
std::mutex m_PoolsMutex; std::mutex m_PoolsMutex;
std::list<std::shared_ptr<TunnelPool>> m_Pools; std::list<std::shared_ptr<TunnelPool>> m_Pools;
std::shared_ptr<TunnelPool> m_ExploratoryPool; std::shared_ptr<TunnelPool> m_ExploratoryPool;
i2p::util::Queue<I2NPMessage> m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
// some stats // some stats
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;

View File

@@ -26,7 +26,7 @@ namespace tunnel
TunnelDeliveryType deliveryType; TunnelDeliveryType deliveryType;
i2p::data::IdentHash hash; i2p::data::IdentHash hash;
uint32_t tunnelID; uint32_t tunnelID;
I2NPMessage * data; std::shared_ptr<I2NPMessage> data;
}; };
class TunnelBase class TunnelBase
@@ -37,10 +37,10 @@ namespace tunnel
TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
virtual ~TunnelBase () {}; virtual ~TunnelBase () {};
virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) = 0; virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0;
virtual void SendTunnelDataMsg (i2p::I2NPMessage * msg) = 0; virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0;
virtual void FlushTunnelDataMsgs () {}; virtual void FlushTunnelDataMsgs () {};
virtual void EncryptTunnelMsg (I2NPMessage * tunnelMsg) = 0; virtual void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) = 0;
virtual uint32_t GetNextTunnelID () const = 0; virtual uint32_t GetNextTunnelID () const = 0;
virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0; virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0;
virtual uint32_t GetTunnelID () const = 0; // as known at our side virtual uint32_t GetTunnelID () const = 0; // as known at our side

View File

@@ -84,7 +84,7 @@ namespace tunnel
} }
} }
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID) void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID) const
{ {
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID); htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
@@ -107,13 +107,13 @@ namespace tunnel
} }
}; };
class TunnelConfig class TunnelConfig: public std::enable_shared_from_this<TunnelConfig>
{ {
public: public:
TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers, TunnelConfig (std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers,
const TunnelConfig * replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound std::shared_ptr<const TunnelConfig> replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound
{ {
TunnelHopConfig * prev = nullptr; TunnelHopConfig * prev = nullptr;
for (auto it: peers) for (auto it: peers)
@@ -170,10 +170,24 @@ namespace tunnel
return num; return num;
} }
bool IsInbound () const { return m_FirstHop->isGateway; }
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > GetPeers () const
{
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers;
TunnelHopConfig * hop = m_FirstHop;
while (hop)
{
peers.push_back (hop->router);
hop = hop->next;
}
return peers;
}
void Print (std::stringstream& s) const void Print (std::stringstream& s) const
{ {
TunnelHopConfig * hop = m_FirstHop; TunnelHopConfig * hop = m_FirstHop;
if (!m_FirstHop->isGateway) if (!IsInbound ()) // outbound
s << "me"; s << "me";
s << "-->" << m_FirstHop->tunnelID; s << "-->" << m_FirstHop->tunnelID;
while (hop) while (hop)
@@ -189,44 +203,17 @@ namespace tunnel
s << ":me"; s << ":me";
} }
TunnelConfig * Invert () const std::shared_ptr<TunnelConfig> Invert () const
{ {
TunnelConfig * newConfig = new TunnelConfig (); auto peers = GetPeers ();
TunnelHopConfig * hop = m_FirstHop, * nextNewHop = nullptr; std::reverse (peers.begin (), peers.end ());
while (hop) // we use ourself as reply tunnel for outbound tunnel
{ return IsInbound () ? std::make_shared<TunnelConfig>(peers, shared_from_this ()) : std::make_shared<TunnelConfig>(peers);
TunnelHopConfig * newHop = new TunnelHopConfig (hop->router);
if (nextNewHop)
newHop->SetNext (nextNewHop);
nextNewHop = newHop;
newHop->isEndpoint = hop->isGateway;
newHop->isGateway = hop->isEndpoint;
if (!hop->prev) // first hop
{
newConfig->m_LastHop = newHop;
if (hop->isGateway) // inbound tunnel
newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel
else
newHop->SetNextRouter (i2p::context.GetSharedRouterInfo ());
}
if (!hop->next) newConfig->m_FirstHop = newHop; // last hop
hop = hop->next;
}
return newConfig;
} }
TunnelConfig * Clone (const TunnelConfig * replyTunnelConfig = nullptr) const std::shared_ptr<TunnelConfig> Clone (std::shared_ptr<const TunnelConfig> replyTunnelConfig = nullptr) const
{ {
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > peers; return std::make_shared<TunnelConfig> (GetPeers (), replyTunnelConfig);
TunnelHopConfig * hop = m_FirstHop;
while (hop)
{
peers.push_back (hop->router);
hop = hop->next;
}
return new TunnelConfig (peers, replyTunnelConfig);
} }
private: private:

View File

@@ -13,13 +13,9 @@ namespace tunnel
{ {
TunnelEndpoint::~TunnelEndpoint () TunnelEndpoint::~TunnelEndpoint ()
{ {
for (auto it: m_IncompleteMessages)
i2p::DeleteI2NPMessage (it.second.data);
for (auto it: m_OutOfSequenceFragments)
i2p::DeleteI2NPMessage (it.second.data);
} }
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (I2NPMessage * msg) void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg)
{ {
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE; m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
@@ -35,7 +31,6 @@ namespace tunnel
if (memcmp (hash, decrypted, 4)) if (memcmp (hash, decrypted, 4))
{ {
LogPrint (eLogError, "TunnelMessage: checksum verification failed"); LogPrint (eLogError, "TunnelMessage: checksum verification failed");
i2p::DeleteI2NPMessage (msg);
return; return;
} }
// process fragments // process fragments
@@ -97,7 +92,7 @@ namespace tunnel
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
{ {
// this is not last message. we have to copy it // this is not last message. we have to copy it
m.data = NewI2NPShortMessage (); m.data = ToSharedI2NPMessage (NewI2NPShortMessage ());
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE; m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
*(m.data) = *msg; *(m.data) = *msg;
@@ -118,10 +113,7 @@ namespace tunnel
if (ret.second) if (ret.second)
HandleOutOfSequenceFragment (msgID, ret.first->second); HandleOutOfSequenceFragment (msgID, ret.first->second);
else else
{
LogPrint (eLogError, "Incomplete message ", msgID, "already exists"); LogPrint (eLogError, "Incomplete message ", msgID, "already exists");
DeleteI2NPMessage (m.data);
}
} }
else else
{ {
@@ -130,20 +122,14 @@ namespace tunnel
} }
} }
else else
{
LogPrint (eLogError, "Message is fragmented, but msgID is not presented"); LogPrint (eLogError, "Message is fragmented, but msgID is not presented");
DeleteI2NPMessage (m.data);
}
} }
fragment += size; fragment += size;
} }
} }
else else
{
LogPrint (eLogError, "TunnelMessage: zero not found"); LogPrint (eLogError, "TunnelMessage: zero not found");
i2p::DeleteI2NPMessage (msg);
}
} }
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m) void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m)
@@ -161,9 +147,8 @@ namespace tunnel
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
I2NPMessage * newMsg = NewI2NPMessage (); auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
*newMsg = *(msg.data); *newMsg = *(msg.data);
DeleteI2NPMessage (msg.data);
msg.data = newMsg; msg.data = newMsg;
} }
memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment
@@ -183,10 +168,8 @@ namespace tunnel
else else
{ {
LogPrint (eLogError, "Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped"); LogPrint (eLogError, "Fragment ", m.nextFragmentNum, " of message ", msgID, "exceeds max I2NP message size. Message dropped");
i2p::DeleteI2NPMessage (msg.data);
m_IncompleteMessages.erase (it); m_IncompleteMessages.erase (it);
} }
i2p::DeleteI2NPMessage (m.data);
} }
else else
{ {
@@ -201,13 +184,11 @@ namespace tunnel
} }
} }
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, I2NPMessage * data) void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data)
{ {
auto it = m_OutOfSequenceFragments.find (msgID); auto it = m_OutOfSequenceFragments.find (msgID);
if (it == m_OutOfSequenceFragments.end ()) if (it == m_OutOfSequenceFragments.end ())
m_OutOfSequenceFragments.insert (std::pair<uint32_t, Fragment> (msgID, {fragmentNum, isLastFragment, data})); m_OutOfSequenceFragments.insert (std::pair<uint32_t, Fragment> (msgID, {fragmentNum, isLastFragment, data}));
else
i2p::DeleteI2NPMessage (data);
} }
void TunnelEndpoint::HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg) void TunnelEndpoint::HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg)
@@ -222,9 +203,8 @@ namespace tunnel
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
I2NPMessage * newMsg = NewI2NPMessage (); auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
*newMsg = *(msg.data); *newMsg = *(msg.data);
DeleteI2NPMessage (msg.data);
msg.data = newMsg; msg.data = newMsg;
} }
memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment
@@ -237,7 +217,6 @@ namespace tunnel
} }
else else
msg.nextFragmentNum++; msg.nextFragmentNum++;
i2p::DeleteI2NPMessage (it->second.data);
m_OutOfSequenceFragments.erase (it); m_OutOfSequenceFragments.erase (it);
} }
} }
@@ -262,28 +241,18 @@ namespace tunnel
// to somebody else // to somebody else
if (!m_IsInbound) // outbound transit tunnel if (!m_IsInbound) // outbound transit tunnel
{ {
auto typeID = msg.data->GetTypeID (); /* auto typeID = msg.data->GetTypeID ();
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply ) if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply )
{
// catch RI or reply with new list of routers // catch RI or reply with new list of routers
auto ds = NewI2NPShortMessage (); i2p::data::netdb.PostI2NPMsg (msg.data);*/
*ds = *(msg.data);
i2p::data::netdb.PostI2NPMsg (ds);
}
i2p::transport::transports.SendMessage (msg.hash, msg.data); i2p::transport::transports.SendMessage (msg.hash, msg.data);
} }
else // we shouldn't send this message. possible leakage else // we shouldn't send this message. possible leakage
{
LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped"); LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped");
i2p::DeleteI2NPMessage (msg.data);
}
} }
break; break;
default: default:
{
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
i2p::DeleteI2NPMessage (msg.data);
}
}; };
} }
} }

View File

@@ -22,7 +22,7 @@ namespace tunnel
{ {
uint8_t fragmentNum; uint8_t fragmentNum;
bool isLastFragment; bool isLastFragment;
I2NPMessage * data; std::shared_ptr<I2NPMessage> data;
}; };
public: public:
@@ -31,14 +31,14 @@ namespace tunnel
~TunnelEndpoint (); ~TunnelEndpoint ();
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void HandleDecryptedTunnelDataMsg (I2NPMessage * msg); void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg);
private: private:
void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m); void HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m);
void HandleNextMessage (const TunnelMessageBlock& msg); void HandleNextMessage (const TunnelMessageBlock& msg);
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, I2NPMessage * data); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data);
void HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); void HandleOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg);
private: private:

View File

@@ -10,10 +10,16 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelGatewayBuffer::TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID),
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0)
{
context.GetRandomNumberGenerator ().GenerateBlock (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE);
for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++)
if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1;
}
TunnelGatewayBuffer::~TunnelGatewayBuffer () TunnelGatewayBuffer::~TunnelGatewayBuffer ()
{ {
for (auto it: m_TunnelDataMsgs)
DeleteI2NPMessage (it);
} }
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
@@ -42,7 +48,7 @@ namespace tunnel
di[0] = block.deliveryType << 5; // set delivery type di[0] = block.deliveryType << 5; // set delivery type
// create fragments // create fragments
I2NPMessage * msg = block.data; std::shared_ptr<I2NPMessage> msg = block.data;
auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length auto fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
if (fullMsgLen <= m_RemainingSize) if (fullMsgLen <= m_RemainingSize)
{ {
@@ -55,7 +61,6 @@ namespace tunnel
m_RemainingSize -= diLen + msg->GetLength (); m_RemainingSize -= diLen + msg->GetLength ();
if (!m_RemainingSize) if (!m_RemainingSize)
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();
DeleteI2NPMessage (msg);
} }
else else
{ {
@@ -119,7 +124,6 @@ namespace tunnel
size += s; size += s;
fragmentNumber++; fragmentNumber++;
} }
DeleteI2NPMessage (msg);
} }
else else
{ {
@@ -138,7 +142,7 @@ namespace tunnel
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage () void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
{ {
m_CurrentTunnelDataMsg = NewI2NPShortMessage (); m_CurrentTunnelDataMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
m_CurrentTunnelDataMsg->Align (12); m_CurrentTunnelDataMsg->Align (12);
// we reserve space for padding // we reserve space for padding
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE; m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;
@@ -164,13 +168,17 @@ namespace tunnel
payload[-1] = 0; // zero payload[-1] = 0; // zero
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1 ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
if (paddingSize > 0) if (paddingSize > 0)
memset (buf + 24, 1, paddingSize); // padding TODO: fill with random data {
// non-zero padding
auto randomOffset = rnd.GenerateWord32 (0, TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize);
memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize);
}
// we can't fill message header yet because encryption is required // we can't fill message header yet because encryption is required
m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg); m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg);
m_CurrentTunnelDataMsg = nullptr; m_CurrentTunnelDataMsg = nullptr;
} }
void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block) void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block)
{ {
if (block.data) if (block.data)
@@ -192,8 +200,8 @@ namespace tunnel
auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs (); auto tunnelMsgs = m_Buffer.GetTunnelDataMsgs ();
for (auto tunnelMsg : tunnelMsgs) for (auto tunnelMsg : tunnelMsgs)
{ {
m_Tunnel->EncryptTunnelMsg (tunnelMsg); m_Tunnel->EncryptTunnelMsg (tunnelMsg, tunnelMsg);
FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData);
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
} }
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), tunnelMsgs); i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), tunnelMsgs);

View File

@@ -3,6 +3,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <vector> #include <vector>
#include <memory>
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TunnelBase.h" #include "TunnelBase.h"
@@ -13,11 +14,10 @@ namespace tunnel
class TunnelGatewayBuffer class TunnelGatewayBuffer
{ {
public: public:
TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), TunnelGatewayBuffer (uint32_t tunnelID);
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {};
~TunnelGatewayBuffer (); ~TunnelGatewayBuffer ();
void PutI2NPMsg (const TunnelMessageBlock& block); void PutI2NPMsg (const TunnelMessageBlock& block);
const std::vector<I2NPMessage *>& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; }; const std::vector<std::shared_ptr<I2NPMessage> >& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; };
void ClearTunnelDataMsgs (); void ClearTunnelDataMsgs ();
void CompleteCurrentTunnelDataMessage (); void CompleteCurrentTunnelDataMessage ();
@@ -28,16 +28,17 @@ namespace tunnel
private: private:
uint32_t m_TunnelID; uint32_t m_TunnelID;
std::vector<I2NPMessage *> m_TunnelDataMsgs; std::vector<std::shared_ptr<I2NPMessage> > m_TunnelDataMsgs;
I2NPMessage * m_CurrentTunnelDataMsg; std::shared_ptr<I2NPMessage> m_CurrentTunnelDataMsg;
size_t m_RemainingSize; size_t m_RemainingSize;
uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE];
}; };
class TunnelGateway class TunnelGateway
{ {
public: public:
TunnelGateway (TunnelBase * tunnel): TunnelGateway (TunnelBase * tunnel):
m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {};
void SendTunnelDataMsg (const TunnelMessageBlock& block); void SendTunnelDataMsg (const TunnelMessageBlock& block);
void PutTunnelDataMsg (const TunnelMessageBlock& block); void PutTunnelDataMsg (const TunnelMessageBlock& block);

View File

@@ -1,18 +1,20 @@
#include <algorithm>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "CryptoConst.h" #include "CryptoConst.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "NetDb.h" #include "NetDb.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Garlic.h" #include "Garlic.h"
#include "Transports.h"
#include "TunnelPool.h" #include "TunnelPool.h"
namespace i2p namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numTunnels): TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_NumTunnels (numTunnels), m_IsActive (true) m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true)
{ {
} }
@@ -21,6 +23,27 @@ namespace tunnel
DetachTunnels (); DetachTunnels ();
} }
void TunnelPool::SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers)
{
m_ExplicitPeers = explicitPeers;
if (m_ExplicitPeers)
{
int size = m_ExplicitPeers->size ();
if (m_NumInboundHops > size)
{
m_NumInboundHops = size;
LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
}
if (m_NumOutboundHops > size)
{
m_NumOutboundHops = size;
LogPrint (eLogInfo, "Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
}
m_NumInboundTunnels = 1;
m_NumOutboundTunnels = 1;
}
}
void TunnelPool::DetachTunnels () void TunnelPool::DetachTunnels ()
{ {
{ {
@@ -56,7 +79,6 @@ namespace tunnel
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
for (auto it: m_Tests) for (auto it: m_Tests)
if (it.second.second == expiredTunnel) it.second.second = nullptr; if (it.second.second == expiredTunnel) it.second.second = nullptr;
RecreateInboundTunnel (expiredTunnel);
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
m_InboundTunnels.erase (expiredTunnel); m_InboundTunnels.erase (expiredTunnel);
@@ -66,8 +88,11 @@ namespace tunnel
void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel) void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel)
{ {
if (!m_IsActive) return; if (!m_IsActive) return;
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); {
m_OutboundTunnels.insert (createdTunnel); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
m_OutboundTunnels.insert (createdTunnel);
}
//CreatePairedInboundTunnel (createdTunnel);
} }
void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel) void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel)
@@ -77,7 +102,6 @@ namespace tunnel
expiredTunnel->SetTunnelPool (nullptr); expiredTunnel->SetTunnelPool (nullptr);
for (auto it: m_Tests) for (auto it: m_Tests)
if (it.second.first == expiredTunnel) it.second.first = nullptr; if (it.second.first == expiredTunnel) it.second.first = nullptr;
RecreateOutboundTunnel (expiredTunnel);
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
m_OutboundTunnels.erase (expiredTunnel); m_OutboundTunnels.erase (expiredTunnel);
@@ -133,6 +157,26 @@ namespace tunnel
return tunnel; return tunnel;
} }
std::shared_ptr<OutboundTunnel> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const
{
if (old && old->IsEstablished ()) return old;
std::shared_ptr<OutboundTunnel> tunnel;
if (old)
{
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
for (auto it: m_OutboundTunnels)
if (it->IsEstablished () && old->GetEndpointRouter ()->GetIdentHash () == it->GetEndpointRouter ()->GetIdentHash ())
{
tunnel = it;
break;
}
}
if (!tunnel)
tunnel = GetNextOutboundTunnel ();
return tunnel;
}
void TunnelPool::CreateTunnels () void TunnelPool::CreateTunnels ()
{ {
int num = 0; int num = 0;
@@ -141,7 +185,7 @@ namespace tunnel
for (auto it : m_InboundTunnels) for (auto it : m_InboundTunnels)
if (it->IsEstablished ()) num++; if (it->IsEstablished ()) num++;
} }
for (int i = num; i < m_NumTunnels; i++) for (int i = num; i < m_NumInboundTunnels; i++)
CreateInboundTunnel (); CreateInboundTunnel ();
num = 0; num = 0;
@@ -150,7 +194,7 @@ namespace tunnel
for (auto it : m_OutboundTunnels) for (auto it : m_OutboundTunnels)
if (it->IsEstablished ()) num++; if (it->IsEstablished ()) num++;
} }
for (int i = num; i < m_NumTunnels; i++) for (int i = num; i < m_NumOutboundTunnels; i++)
CreateOutboundTunnel (); CreateOutboundTunnel ();
} }
@@ -216,18 +260,15 @@ namespace tunnel
} }
} }
void TunnelPool::ProcessGarlicMessage (I2NPMessage * msg) void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (m_LocalDestination) if (m_LocalDestination)
m_LocalDestination->ProcessGarlicMessage (msg); m_LocalDestination->ProcessGarlicMessage (msg);
else else
{
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped"); LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
DeleteI2NPMessage (msg);
}
} }
void TunnelPool::ProcessDeliveryStatus (I2NPMessage * msg) void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
{ {
const uint8_t * buf = msg->GetPayload (); const uint8_t * buf = msg->GetPayload ();
uint32_t msgID = bufbe32toh (buf); uint32_t msgID = bufbe32toh (buf);
@@ -244,17 +285,13 @@ namespace tunnel
it->second.second->SetState (eTunnelStateEstablished); it->second.second->SetState (eTunnelStateEstablished);
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds"); LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
m_Tests.erase (it); m_Tests.erase (it);
DeleteI2NPMessage (msg);
} }
else else
{ {
if (m_LocalDestination) if (m_LocalDestination)
m_LocalDestination->ProcessDeliveryStatusMessage (msg); m_LocalDestination->ProcessDeliveryStatusMessage (msg);
else else
{
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped"); LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
DeleteI2NPMessage (msg);
}
} }
} }
@@ -263,46 +300,81 @@ namespace tunnel
bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop): auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop); i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
if (!isExploratory && hop && hop->GetProfile ()->IsBad ())
{ if (!hop || hop->GetProfile ()->IsBad ())
LogPrint (eLogInfo, "Selected peer for tunnel has bad profile. Selecting another");
hop = i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
}
if (!hop)
hop = i2p::data::netdb.GetRandomRouter (); hop = i2p::data::netdb.GetRandomRouter ();
return hop; return hop;
} }
bool TunnelPool::SelectPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound)
{
if (m_ExplicitPeers) return SelectExplicitPeers (hops, isInbound);
auto prevHop = i2p::context.GetSharedRouterInfo ();
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
if (i2p::transport::transports.GetNumPeers () > 25)
{
auto r = i2p::transport::transports.GetRandomPeer ();
if (r && !r->GetProfile ()->IsBad ())
{
prevHop = r;
hops.push_back (r);
numHops--;
}
}
for (int i = 0; i < numHops; i++)
{
auto hop = SelectNextHop (prevHop);
if (!hop)
{
LogPrint (eLogError, "Can't select next hop");
return false;
}
prevHop = hop;
hops.push_back (hop);
}
return true;
}
bool TunnelPool::SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound)
{
int size = m_ExplicitPeers->size ();
std::vector<int> peerIndicies;
for (int i = 0; i < size; i++) peerIndicies.push_back(i);
std::random_shuffle (peerIndicies.begin(), peerIndicies.end());
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
for (int i = 0; i < numHops; i++)
{
auto& ident = (*m_ExplicitPeers)[peerIndicies[i]];
auto r = i2p::data::netdb.FindRouter (ident);
if (r)
hops.push_back (r);
else
{
LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ());
i2p::data::netdb.RequestDestination (ident);
return false;
}
}
return true;
}
void TunnelPool::CreateInboundTunnel () void TunnelPool::CreateInboundTunnel ()
{ {
auto outboundTunnel = GetNextOutboundTunnel (); auto outboundTunnel = GetNextOutboundTunnel ();
if (!outboundTunnel) if (!outboundTunnel)
outboundTunnel = tunnels.GetNextOutboundTunnel (); outboundTunnel = tunnels.GetNextOutboundTunnel ();
LogPrint ("Creating destination inbound tunnel..."); LogPrint ("Creating destination inbound tunnel...");
auto prevHop = i2p::context.GetSharedRouterInfo ();
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
int numHops = m_NumInboundHops; if (SelectPeers (hops, true))
if (outboundTunnel)
{
// last hop
auto hop = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router;
if (hop->GetIdentHash () != i2p::context.GetIdentHash ()) // outbound shouldn't be zero-hop tunnel
{
prevHop = hop;
hops.push_back (prevHop);
numHops--;
}
}
for (int i = 0; i < numHops; i++)
{ {
auto hop = SelectNextHop (prevHop); std::reverse (hops.begin (), hops.end ());
prevHop = hop; auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig> (hops), outboundTunnel);
hops.push_back (hop); tunnel->SetTunnelPool (shared_from_this ());
} }
std::reverse (hops.begin (), hops.end ()); else
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (new TunnelConfig (hops), outboundTunnel); LogPrint (eLogError, "Can't create inbound tunnel. No peers available");
tunnel->SetTunnelPool (shared_from_this ());
} }
void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel) void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel)
@@ -323,22 +395,18 @@ namespace tunnel
if (inboundTunnel) if (inboundTunnel)
{ {
LogPrint ("Creating destination outbound tunnel..."); LogPrint ("Creating destination outbound tunnel...");
auto prevHop = i2p::context.GetSharedRouterInfo ();
std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops; std::vector<std::shared_ptr<const i2p::data::RouterInfo> > hops;
for (int i = 0; i < m_NumOutboundHops; i++) if (SelectPeers (hops, false))
{ {
auto hop = SelectNextHop (prevHop); auto tunnel = tunnels.CreateTunnel<OutboundTunnel> (
prevHop = hop; std::make_shared<TunnelConfig> (hops, inboundTunnel->GetTunnelConfig ()));
hops.push_back (hop); tunnel->SetTunnelPool (shared_from_this ());
} }
else
auto tunnel = tunnels.CreateTunnel<OutboundTunnel> ( LogPrint (eLogError, "Can't create outbound tunnel. No peers available");
new TunnelConfig (hops, inboundTunnel->GetTunnelConfig ()));
tunnel->SetTunnelPool (shared_from_this ());
} }
else else
LogPrint ("Can't create outbound tunnel. No inbound tunnels found"); LogPrint (eLogError, "Can't create outbound tunnel. No inbound tunnels found");
} }
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel) void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
@@ -355,6 +423,13 @@ namespace tunnel
} }
else else
LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found"); LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found");
} }
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
{
LogPrint (eLogInfo, "Creating paired inbound tunnel...");
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (outboundTunnel->GetTunnelConfig ()->Invert (), outboundTunnel);
tunnel->SetTunnelPool (shared_from_this ());
}
} }
} }

View File

@@ -27,24 +27,28 @@ namespace tunnel
{ {
public: public:
TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numTunnels = 5); TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
~TunnelPool (); ~TunnelPool ();
i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; }; i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; };
void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; }; void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; };
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
void CreateTunnels (); void CreateTunnels ();
void TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel); void TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel);
void TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel); void TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel);
void TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel); void TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel);
void TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel); void TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel);
void RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel);
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const; std::vector<std::shared_ptr<InboundTunnel> > GetInboundTunnels (int num) const;
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const; std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded = nullptr) const;
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const; std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
void TestTunnels (); void TestTunnels ();
void ProcessGarlicMessage (I2NPMessage * msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatus (I2NPMessage * msg); void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
bool IsActive () const { return m_IsActive; }; bool IsActive () const { return m_IsActive; };
void SetActive (bool isActive) { m_IsActive = isActive; }; void SetActive (bool isActive) { m_IsActive = isActive; };
@@ -54,16 +58,18 @@ namespace tunnel
void CreateInboundTunnel (); void CreateInboundTunnel ();
void CreateOutboundTunnel (); void CreateOutboundTunnel ();
void RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel); void CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel);
void RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel);
template<class TTunnels> template<class TTunnels>
typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const; typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const;
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const; std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
bool SelectPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound);
bool SelectExplicitPeers (std::vector<std::shared_ptr<const i2p::data::RouterInfo> >& hops, bool isInbound);
private: private:
i2p::garlic::GarlicDestination * m_LocalDestination; i2p::garlic::GarlicDestination * m_LocalDestination;
int m_NumInboundHops, m_NumOutboundHops, m_NumTunnels; int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
mutable std::mutex m_InboundTunnelsMutex; mutable std::mutex m_InboundTunnelsMutex;
std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first std::set<std::shared_ptr<InboundTunnel>, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
mutable std::mutex m_OutboundTunnelsMutex; mutable std::mutex m_OutboundTunnelsMutex;

171
UPnP.cpp
View File

@@ -2,15 +2,19 @@
#include <string> #include <string>
#include <thread> #include <thread>
#ifdef _WIN32
#include <windows.h>
#endif
#include <boost/thread/thread.hpp> #include <boost/thread/thread.hpp>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#ifdef _WIN32
#include <windows.h>
#define dlsym GetProcAddress
#else
#include <dlfcn.h>
#endif
#include "Log.h" #include "Log.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "UPnP.h" #include "UPnP.h"
#include "NetDb.h" #include "NetDb.h"
@@ -18,31 +22,41 @@
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h> #include <miniupnpc/upnpcommands.h>
#include <dlfcn.h>
// These are per-process and are safe to reuse for all threads
#ifndef UPNPDISCOVER_SUCCESS #ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */ /* miniupnpc 1.5 */
typedef UPNPDev* (*upnp_upnpDiscoverFunc) (int, const char *, const char *, int); UPNPDev* (*upnpDiscoverFunc) (int, const char *, const char *, int);
typedef int (*upnp_UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *, int (*UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *,
const char *, const char *, const char *, const char *); const char *, const char *, const char *, const char *);
#else #else
/* miniupnpc 1.6 */ /* miniupnpc 1.6 */
typedef UPNPDev* (*upnp_upnpDiscoverFunc) (int, const char *, const char *, int, int, int *); UPNPDev* (*upnpDiscoverFunc) (int, const char *, const char *, int, int, int *);
typedef int (*upnp_UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *, int (*UPNP_AddPortMappingFunc) (const char *, const char *, const char *, const char *,
const char *, const char *, const char *, const char *, const char *); const char *, const char *, const char *, const char *, const char *);
#endif #endif
typedef int (*upnp_UPNP_GetValidIGDFunc) (struct UPNPDev *, struct UPNPUrls *, struct IGDdatas *, char *, int); int (*UPNP_GetValidIGDFunc) (struct UPNPDev *, struct UPNPUrls *, struct IGDdatas *, char *, int);
typedef int (*upnp_UPNP_GetExternalIPAddressFunc) (const char *, const char *, char *); int (*UPNP_GetExternalIPAddressFunc) (const char *, const char *, char *);
typedef int (*upnp_UPNP_DeletePortMappingFunc) (const char *, const char *, const char *, const char *, const char *); int (*UPNP_DeletePortMappingFunc) (const char *, const char *, const char *, const char *, const char *);
typedef void (*upnp_freeUPNPDevlistFunc) (struct UPNPDev *); void (*freeUPNPDevlistFunc) (struct UPNPDev *);
typedef void (*upnp_FreeUPNPUrlsFunc) (struct UPNPUrls *); void (*FreeUPNPUrlsFunc) (struct UPNPUrls *);
// Nice approach http://stackoverflow.com/a/21517513/673826
template<class M, typename F>
F GetKnownProcAddressImpl(M hmod, const char *name, F) {
auto proc = reinterpret_cast<F>(dlsym(hmod, name));
if (!proc) {
LogPrint("Error resolving ", name, " from UPNP library. This often happens if there is version mismatch!");
}
return proc;
}
#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func);
namespace i2p namespace i2p
{ {
namespace UPnP namespace transport
{ {
UPnP upnpc;
UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false) UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false)
{ {
} }
@@ -59,6 +73,33 @@ namespace UPnP
void UPnP::Start() void UPnP::Start()
{ {
if (!m_IsModuleLoaded) {
#ifdef MAC_OSX
m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY);
#elif _WIN32
m_Module = LoadLibrary ("miniupnpc.dll"); // official prebuilt binary, e.g., in upnpc-exe-win32-20140422.zip
#else
m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY);
#endif
if (m_Module == NULL)
{
LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!");
return;
}
else
{
upnpDiscoverFunc = GetKnownProcAddress (m_Module, upnpDiscover);
UPNP_GetValidIGDFunc = GetKnownProcAddress (m_Module, UPNP_GetValidIGD);
UPNP_GetExternalIPAddressFunc = GetKnownProcAddress (m_Module, UPNP_GetExternalIPAddress);
UPNP_AddPortMappingFunc = GetKnownProcAddress (m_Module, UPNP_AddPortMapping);
UPNP_DeletePortMappingFunc = GetKnownProcAddress (m_Module, UPNP_DeletePortMapping);
freeUPNPDevlistFunc = GetKnownProcAddress (m_Module, freeUPNPDevlist);
FreeUPNPUrlsFunc = GetKnownProcAddress (m_Module, FreeUPNPUrls);
if (upnpDiscoverFunc && UPNP_GetValidIGDFunc && UPNP_GetExternalIPAddressFunc && UPNP_AddPortMappingFunc &&
UPNP_DeletePortMappingFunc && freeUPNPDevlistFunc && FreeUPNPUrlsFunc)
m_IsModuleLoaded = true;
}
}
m_Thread = new std::thread (std::bind (&UPnP::Run, this)); m_Thread = new std::thread (std::bind (&UPnP::Run, this));
} }
@@ -68,46 +109,18 @@ namespace UPnP
void UPnP::Run () void UPnP::Run ()
{ {
#ifdef MAC_OSX
m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY);
#elif _WIN32
m_Module = LoadLibrary ("libminiupnpc.dll");
if (m_Module == NULL)
{
LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!");
return;
}
else
{
m_IsModuleLoaded = true;
}
#else
m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY);
#endif
#ifndef _WIN32
if (!m_Module)
{
LogPrint ("no UPnP module available (", dlerror (), ")");
return;
}
else
{
m_IsModuleLoaded = true;
}
#endif
for (auto& address : context.GetRouterInfo ().GetAddresses ()) for (auto& address : context.GetRouterInfo ().GetAddresses ())
{ {
if (!address.host.is_v6 ()) if (!address.host.is_v6 ())
{ {
m_Port = std::to_string (util::config::GetArg ("-port", address.port));
Discover (); Discover ();
if (address.transportStyle == data::RouterInfo::eTransportSSU ) if (address.transportStyle == data::RouterInfo::eTransportSSU )
{ {
TryPortMapping (I2P_UPNP_UDP); TryPortMapping (I2P_UPNP_UDP, address.port);
} }
else if (address.transportStyle == data::RouterInfo::eTransportNTCP ) else if (address.transportStyle == data::RouterInfo::eTransportNTCP )
{ {
TryPortMapping (I2P_UPNP_TCP); TryPortMapping (I2P_UPNP_TCP, address.port);
} }
} }
} }
@@ -115,18 +128,6 @@ namespace UPnP
void UPnP::Discover () void UPnP::Discover ()
{ {
const char *error;
#ifdef _WIN32
upnp_upnpDiscoverFunc upnpDiscoverFunc = (upnp_upnpDiscoverFunc) GetProcAddress (m_Module, "upnpDiscover");
#else
upnp_upnpDiscoverFunc upnpDiscoverFunc = (upnp_upnpDiscoverFunc) dlsym (m_Module, "upnpDiscover");
// reinterpret_cast<upnp_upnpDiscoverFunc> (dlsym(...));
if ( (error = dlerror ()))
{
LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!");
return;
}
#endif // _WIN32
#ifndef UPNPDISCOVER_SUCCESS #ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */ /* miniupnpc 1.5 */
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0); m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0);
@@ -137,15 +138,9 @@ namespace UPnP
#endif #endif
int r; int r;
#ifdef _WIN32 r = UPNP_GetValidIGDFunc (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
upnp_UPNP_GetValidIGDFunc UPNP_GetValidIGDFunc = (upnp_UPNP_GetValidIGDFunc) GetProcAddress (m_Module, "UPNP_GetValidIGD");
#else
upnp_UPNP_GetValidIGDFunc UPNP_GetValidIGDFunc = (upnp_UPNP_GetValidIGDFunc) dlsym (m_Module, "UPNP_GetValidIGD");
#endif
r = (*UPNP_GetValidIGDFunc) (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
if (r == 1) if (r == 1)
{ {
upnp_UPNP_GetExternalIPAddressFunc UPNP_GetExternalIPAddressFunc = (upnp_UPNP_GetExternalIPAddressFunc) dlsym (m_Module, "UPNP_GetExternalIPAddress");
r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS) if(r != UPNPCOMMAND_SUCCESS)
{ {
@@ -169,9 +164,9 @@ namespace UPnP
} }
} }
void UPnP::TryPortMapping (int type) void UPnP::TryPortMapping (int type, int port)
{ {
std::string strType; std::string strType, strPort (std::to_string (port));
switch (type) switch (type)
{ {
case I2P_UPNP_TCP: case I2P_UPNP_TCP:
@@ -185,42 +180,39 @@ namespace UPnP
std::string strDesc = "I2Pd"; std::string strDesc = "I2Pd";
try { try {
for (;;) { for (;;) {
#ifdef _WIN32
upnp_UPNP_AddPortMappingFunc UPNP_AddPortMappingFunc = (upnp_UPNP_AddPortMappingFunc) GetProcAddress (m_Module, "UPNP_AddPortMapping");
#else
upnp_UPNP_AddPortMappingFunc UPNP_AddPortMappingFunc = (upnp_UPNP_AddPortMappingFunc) dlsym (m_Module, "UPNP_AddPortMapping");
#endif
#ifndef UPNPDISCOVER_SUCCESS #ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */ /* miniupnpc 1.5 */
r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_Port.c_str (), m_Port.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0); r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0);
#else #else
/* miniupnpc 1.6 */ /* miniupnpc 1.6 */
r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_Port.c_str (), m_Port.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
#endif #endif
if (r!=UPNPCOMMAND_SUCCESS) if (r!=UPNPCOMMAND_SUCCESS)
{ {
LogPrint ("AddPortMapping (", m_Port.c_str () ,", ", m_Port.c_str () ,", ", m_NetworkAddr, ") failed with code ", r); LogPrint ("AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
return; return;
} }
else else
{ {
LogPrint ("UPnP Port Mapping successful. (", m_NetworkAddr ,":", m_Port.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", m_Port.c_str() ,")"); LogPrint ("UPnP Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")");
return; return;
} }
sleep(20*60); std::this_thread::sleep_for(std::chrono::minutes(20)); // c++11
//boost::this_thread::sleep_for(); // pre c++11
//sleep(20*60); // non-portable
} }
} }
catch (boost::thread_interrupted) catch (boost::thread_interrupted)
{ {
CloseMapping(type); CloseMapping(type, port);
Close(); Close();
throw; throw;
} }
} }
void UPnP::CloseMapping (int type) void UPnP::CloseMapping (int type, int port)
{ {
std::string strType; std::string strType, strPort (std::to_string (port));
switch (type) switch (type)
{ {
case I2P_UPNP_TCP: case I2P_UPNP_TCP:
@@ -231,29 +223,14 @@ namespace UPnP
strType = "UDP"; strType = "UDP";
} }
int r = 0; int r = 0;
#ifdef _WIN32 r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
upnp_UPNP_DeletePortMappingFunc UPNP_DeletePortMappingFunc = (upnp_UPNP_DeletePortMappingFunc) GetProcAddress (m_Module, "UPNP_DeletePortMapping");
#else
upnp_UPNP_DeletePortMappingFunc UPNP_DeletePortMappingFunc = (upnp_UPNP_DeletePortMappingFunc) dlsym (m_Module, "UPNP_DeletePortMapping");
#endif
r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_Port.c_str (), strType.c_str (), 0);
LogPrint ("UPNP_DeletePortMapping() returned : ", r, "\n"); LogPrint ("UPNP_DeletePortMapping() returned : ", r, "\n");
} }
void UPnP::Close () void UPnP::Close ()
{ {
#ifdef _WIN32
upnp_freeUPNPDevlistFunc freeUPNPDevlistFunc = (upnp_freeUPNPDevlistFunc) GetProcAddress (m_Module, "freeUPNPDevlist");
#else
upnp_freeUPNPDevlistFunc freeUPNPDevlistFunc = (upnp_freeUPNPDevlistFunc) dlsym (m_Module, "freeUPNPDevlist");
#endif
freeUPNPDevlistFunc (m_Devlist); freeUPNPDevlistFunc (m_Devlist);
m_Devlist = 0; m_Devlist = 0;
#ifdef _WIN32
upnp_FreeUPNPUrlsFunc FreeUPNPUrlsFunc = (upnp_FreeUPNPUrlsFunc) GetProcAddress (m_Module, "FreeUPNPUrlsFunc");
#else
upnp_FreeUPNPUrlsFunc FreeUPNPUrlsFunc = (upnp_FreeUPNPUrlsFunc) dlsym (m_Module, "FreeUPNPUrlsFunc");
#endif
FreeUPNPUrlsFunc (&m_upnpUrls); FreeUPNPUrlsFunc (&m_upnpUrls);
#ifndef _WIN32 #ifndef _WIN32
dlclose (m_Module); dlclose (m_Module);

10
UPnP.h
View File

@@ -19,7 +19,7 @@
namespace i2p namespace i2p
{ {
namespace UPnP namespace transport
{ {
class UPnP class UPnP
{ {
@@ -33,8 +33,8 @@ namespace UPnP
void Stop (); void Stop ();
void Discover (); void Discover ();
void TryPortMapping (int type); void TryPortMapping (int type, int port);
void CloseMapping (int type); void CloseMapping (int type, int port);
private: private:
void Run (); void Run ();
@@ -49,14 +49,12 @@ namespace UPnP
char m_NetworkAddr[64]; char m_NetworkAddr[64];
char m_externalIPAddress[40]; char m_externalIPAddress[40];
bool m_IsModuleLoaded; bool m_IsModuleLoaded;
std::string m_Port = std::to_string (util::config::GetArg ("-port", 17070));
#ifndef _WIN32 #ifndef _WIN32
void *m_Module; void *m_Module;
#else #else
HINSTANCE *m_Module; HINSTANCE m_Module;
#endif #endif
}; };
extern UPnP upnpc;
} }
} }

View File

@@ -3,8 +3,8 @@ Building i2pd for Windows
Requirements for building: Requirements for building:
* Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4 RC) * Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4)
* Boost (tested with 1.56 and 1.57) * Boost (tested with 1.56, 1.57, and 1.58)
* Crypto++ (tested with 5.6.2) * Crypto++ (tested with 5.6.2)
@@ -31,7 +31,7 @@ After Boost is compiled, set the environment variable `BOOST` to the directory
Boost was installed to. If you followed the instructions outlined here, you Boost was installed to. If you followed the instructions outlined here, you
should set it to `C:\Boost`. Additionally, set the BOOSTVER variable to the should set it to `C:\Boost`. Additionally, set the BOOSTVER variable to the
version of Boost that you're using, but instead of a '.' use a '_'. For version of Boost that you're using, but instead of a '.' use a '_'. For
example, I have `BOOSTVER` set to `1_57`. example, I have `BOOSTVER` set to `1_58`.
Building Crypto++ Building Crypto++
----------------- -----------------

View File

@@ -37,11 +37,13 @@
<ClCompile Include="..\LeaseSet.cpp" /> <ClCompile Include="..\LeaseSet.cpp" />
<ClCompile Include="..\Log.cpp" /> <ClCompile Include="..\Log.cpp" />
<ClCompile Include="..\NetDb.cpp" /> <ClCompile Include="..\NetDb.cpp" />
<ClCompile Include="..\NetDbRequests.cpp" />
<ClCompile Include="..\NTCPSession.cpp" /> <ClCompile Include="..\NTCPSession.cpp" />
<ClCompile Include="..\Profiling.cpp" /> <ClCompile Include="..\Profiling.cpp" />
<ClCompile Include="..\Reseed.cpp" /> <ClCompile Include="..\Reseed.cpp" />
<ClCompile Include="..\RouterContext.cpp" /> <ClCompile Include="..\RouterContext.cpp" />
<ClCompile Include="..\RouterInfo.cpp" /> <ClCompile Include="..\RouterInfo.cpp" />
<ClCompile Include="..\Signature.cpp" />
<ClCompile Include="..\SAM.cpp" /> <ClCompile Include="..\SAM.cpp" />
<ClCompile Include="..\SSU.cpp" /> <ClCompile Include="..\SSU.cpp" />
<ClCompile Include="..\SSUData.cpp" /> <ClCompile Include="..\SSUData.cpp" />
@@ -80,6 +82,7 @@
<ClInclude Include="..\LeaseSet.h" /> <ClInclude Include="..\LeaseSet.h" />
<ClInclude Include="..\LittleBigEndian.h" /> <ClInclude Include="..\LittleBigEndian.h" />
<ClInclude Include="..\Log.h" /> <ClInclude Include="..\Log.h" />
<ClInclude Include="..\NetDbRequests.h" />
<ClInclude Include="..\NetDb.h" /> <ClInclude Include="..\NetDb.h" />
<ClInclude Include="..\NTCPSession.h" /> <ClInclude Include="..\NTCPSession.h" />
<ClInclude Include="..\Queue.h" /> <ClInclude Include="..\Queue.h" />

46
aes.cpp
View File

@@ -280,74 +280,76 @@ namespace crypto
#endif #endif
} }
void TunnelEncryption::Encrypt (uint8_t * payload) void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{ {
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
// encrypt IV // encrypt IV
"movups (%[payload]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
// double IV encryption // double IV encryption
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[out]) \n"
// encrypt data, IV is xmm1 // encrypt data, IV is xmm1
"1: \n" "1: \n"
"add $16, %[payload] \n" "add $16, %[in] \n"
"movups (%[payload]), %%xmm0 \n" "add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched_l) EncryptAES256(sched_l)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[out]) \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \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 [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "cc", "memory" : "%xmm0", "%xmm1", "cc", "memory"
); );
#else #else
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerEncryption.SetIV (payload); m_LayerEncryption.SetIV (out);
m_LayerEncryption.Encrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
#endif #endif
} }
void TunnelDecryption::Decrypt (uint8_t * payload) void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{ {
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
// decrypt IV // decrypt IV
"movups (%[payload]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
// double IV encryption // double IV encryption
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[out]) \n"
// decrypt data, IV is xmm1 // decrypt data, IV is xmm1
"1: \n" "1: \n"
"add $16, %[payload] \n" "add $16, %[in] \n"
"movups (%[payload]), %%xmm0 \n" "add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched_l) DecryptAES256(sched_l)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[payload]) \n" "movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n" "movaps %%xmm2, %%xmm1 \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \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 [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory" : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
); );
#else #else
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerDecryption.SetIV (payload); m_LayerDecryption.SetIV (out);
m_LayerDecryption.Decrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
#endif #endif
} }
} }

4
aes.h
View File

@@ -185,7 +185,7 @@ namespace crypto
m_IVEncryption.SetKey (ivKey); m_IVEncryption.SetKey (ivKey);
} }
void Encrypt (uint8_t * payload); // 1024 bytes (16 IV + 1008 data) void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
private: private:
@@ -207,7 +207,7 @@ namespace crypto
m_IVDecryption.SetKey (ivKey); m_IVDecryption.SetKey (ivKey);
} }
void Decrypt (uint8_t * payload); // 1024 bytes (16 IV + 1008 data) void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
private: private:

View File

@@ -24,6 +24,7 @@ Required "-dev" packages:
* libboost-program-options-dev * libboost-program-options-dev
* libboost-regex-dev * libboost-regex-dev
* libboost-system-dev * libboost-system-dev
* libboost-date-time-dev
* libcrypto++-dev * libcrypto++-dev
FreeBSD FreeBSD

View File

@@ -1,4 +1,4 @@
cmake_minimum_required ( VERSION 2.8.5 ) cmake_minimum_required ( VERSION 2.8.12 )
project ( "i2pd" ) project ( "i2pd" )
# configurale options # configurale options
@@ -7,6 +7,8 @@ option(WITH_HARDENING "Use hardening compiler flags" OFF)
option(WITH_LIBRARY "Build library" ON) option(WITH_LIBRARY "Build library" ON)
option(WITH_BINARY "Build binary" ON) option(WITH_BINARY "Build binary" ON)
option(WITH_STATIC "Static build" OFF) option(WITH_STATIC "Static build" OFF)
option(WITH_UPNP "Include support for UPnP client" OFF)
option(WITH_PCH "Use precompiled header" OFF)
# paths # paths
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
@@ -21,6 +23,7 @@ set (COMMON_SRC
"${CMAKE_SOURCE_DIR}/LeaseSet.cpp" "${CMAKE_SOURCE_DIR}/LeaseSet.cpp"
"${CMAKE_SOURCE_DIR}/Log.cpp" "${CMAKE_SOURCE_DIR}/Log.cpp"
"${CMAKE_SOURCE_DIR}/NTCPSession.cpp" "${CMAKE_SOURCE_DIR}/NTCPSession.cpp"
"${CMAKE_SOURCE_DIR}/NetDbRequests.cpp"
"${CMAKE_SOURCE_DIR}/NetDb.cpp" "${CMAKE_SOURCE_DIR}/NetDb.cpp"
"${CMAKE_SOURCE_DIR}/Profiling.cpp" "${CMAKE_SOURCE_DIR}/Profiling.cpp"
"${CMAKE_SOURCE_DIR}/Reseed.cpp" "${CMAKE_SOURCE_DIR}/Reseed.cpp"
@@ -40,9 +43,17 @@ set (COMMON_SRC
"${CMAKE_SOURCE_DIR}/aes.cpp" "${CMAKE_SOURCE_DIR}/aes.cpp"
"${CMAKE_SOURCE_DIR}/base64.cpp" "${CMAKE_SOURCE_DIR}/base64.cpp"
"${CMAKE_SOURCE_DIR}/util.cpp" "${CMAKE_SOURCE_DIR}/util.cpp"
"${CMAKE_SOURCE_DIR}/Datagram.cpp" "${CMAKE_SOURCE_DIR}/Datagram.cpp"
"${CMAKE_SOURCE_DIR}/Signature.cpp"
"${CMAKE_SOURCE_DIR}/UPnP.cpp"
) )
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
list (APPEND COMMON_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
endif ()
add_library(common ${COMMON_SRC})
set (DAEMON_SRC set (DAEMON_SRC
"${CMAKE_SOURCE_DIR}/BOB.cpp" "${CMAKE_SOURCE_DIR}/BOB.cpp"
"${CMAKE_SOURCE_DIR}/ClientContext.cpp" "${CMAKE_SOURCE_DIR}/ClientContext.cpp"
@@ -54,10 +65,16 @@ set (DAEMON_SRC
"${CMAKE_SOURCE_DIR}/I2PTunnel.cpp" "${CMAKE_SOURCE_DIR}/I2PTunnel.cpp"
"${CMAKE_SOURCE_DIR}/SAM.cpp" "${CMAKE_SOURCE_DIR}/SAM.cpp"
"${CMAKE_SOURCE_DIR}/SOCKS.cpp" "${CMAKE_SOURCE_DIR}/SOCKS.cpp"
"${CMAKE_SOURCE_DIR}/UPnP.cpp"
"${CMAKE_SOURCE_DIR}/i2p.cpp" "${CMAKE_SOURCE_DIR}/i2p.cpp"
) )
if (WITH_UPNP)
add_definitions(-DUSE_UPNP)
if (NOT MSVC)
set(DL_LIB ${CMAKE_DL_LIBS})
endif ()
endif ()
set (LIBRARY_SRC set (LIBRARY_SRC
"${CMAKE_SOURCE_DIR}/api.cpp" "${CMAKE_SOURCE_DIR}/api.cpp"
) )
@@ -69,14 +86,19 @@ source_group ("Header Files" FILES ${HEADERS})
source_group ("Source Files" FILES ${COMMON_SRC} ${DAEMON_SRC} ${LIBRARY_SRC}) 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 (NOT CMAKE_BUILD_TYPE)
add_definitions( "-pedantic" )
else ()
set(CMAKE_BUILD_TYPE Debug) set(CMAKE_BUILD_TYPE Debug)
endif () endif ()
# compiler flags customization (by vendor) # compiler flags customization (by vendor)
add_definitions ( "-Wall -Wextra -fPIC" ) if (NOT MSVC)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic" )
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
# Multiple definitions of __stack_chk_fail (libssp & libc)
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections" )
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above
endif ()
# check for c++11 support # check for c++11 support
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@@ -86,7 +108,7 @@ if (CXX11_SUPPORTED)
add_definitions( "-std=c++11" ) add_definitions( "-std=c++11" )
elseif (CXX0X_SUPPORTED) # gcc 4.6 elseif (CXX0X_SUPPORTED) # gcc 4.6
add_definitions( "-std=c++0x" ) add_definitions( "-std=c++0x" )
else () elseif (NOT MSVC)
message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?") message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?")
endif () endif ()
@@ -113,6 +135,7 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32Service.cpp")
endif () endif ()
if (WITH_AESNI) if (WITH_AESNI)
@@ -120,9 +143,71 @@ if (WITH_AESNI)
endif() endif()
# libraries # libraries
# TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826
# use imported Threads::Threads instead
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package ( Threads REQUIRED ) find_package ( Threads REQUIRED )
if(THREADS_HAVE_PTHREAD_ARG) # compile time flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
find_package ( Boost COMPONENTS system filesystem regex program_options REQUIRED ) if (WITH_STATIC)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
if (WIN32)
# http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
# Note that you might need to rebuild Crypto++
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif(${flag_var} MATCHES "/MD")
endforeach(flag_var)
else ()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif ()
set(BUILD_SHARED_LIBS OFF)
if (${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" )
# set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive" )
set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,-u,pthread_create,-u,pthread_once,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_join,-u,pthread_equal,-u,pthread_detach,-u,pthread_cond_wait,-u,pthread_cond_signal,-u,pthread_cond_destroy,-u,pthread_cond_broadcast,-u,pthread_cancel" )
endif ()
else()
if (NOT WIN32)
# TODO: Consider separate compilation for COMMON_SRC for library.
# No need in -fPIC overhead for binary if not interested in library
# HINT: revert c266cff CMakeLists.txt: compilation speed up
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" )
endif ()
add_definitions(-DBOOST_ALL_DYN_LINK)
endif ()
if (WITH_PCH)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_library(stdafx STATIC "${CMAKE_SOURCE_DIR}/stdafx.cpp")
if(MSVC)
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm135)
add_custom_command(TARGET stdafx POST_BUILD
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb common.dir\\$<CONFIG>\\
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pd-bin.dir\\$<CONFIG>\\
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pd.dir\\$<CONFIG>\\
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
target_compile_options(common PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
string(TOUPPER ${CMAKE_BUILD_TYPE} BTU)
get_directory_property(DEFS DEFINITIONS)
string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}")
add_custom_command(TARGET stdafx PRE_BUILD
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h
)
target_compile_options(common PRIVATE -include stdafx.h)
endif()
target_link_libraries(common stdafx)
endif()
find_package ( Boost COMPONENTS system filesystem regex program_options date_time thread chrono REQUIRED )
if(NOT DEFINED Boost_INCLUDE_DIRS) if(NOT DEFINED Boost_INCLUDE_DIRS)
message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!") message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!")
endif() endif()
@@ -132,8 +217,13 @@ if(NOT DEFINED CRYPTO++_INCLUDE_DIR)
message(SEND_ERROR "Could not find Crypto++. Please download and install it first!") message(SEND_ERROR "Could not find Crypto++. Please download and install it first!")
endif() endif()
find_package ( MiniUPnPc )
if (NOT ${MINIUPNPC_FOUND})
set(WITH_UPNP OFF)
endif()
# load includes # load includes
include_directories( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR} "${CMAKE_SOURCE_DIR}/..") include_directories( ${Boost_INCLUDE_DIRS} ${CRYPTO++_INCLUDE_DIR} )
# show summary # show summary
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
@@ -148,30 +238,62 @@ message(STATUS " HARDENING : ${WITH_HARDENING}")
message(STATUS " LIBRARY : ${WITH_LIBRARY}") message(STATUS " LIBRARY : ${WITH_LIBRARY}")
message(STATUS " BINARY : ${WITH_BINARY}") message(STATUS " BINARY : ${WITH_BINARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}") message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS " UPnP : ${WITH_UPNP}")
message(STATUS " PCH : ${WITH_PCH}")
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
#Handle paths nicely #Handle paths nicely
include(GNUInstallDirs) include(GNUInstallDirs)
if (WITH_BINARY) if (WITH_BINARY)
add_executable ( "${PROJECT_NAME}-bin" ${COMMON_SRC} ${DAEMON_SRC}) add_executable ( "${PROJECT_NAME}-bin" ${DAEMON_SRC} )
if(NOT MSVC) # FIXME: incremental linker file name (.ilk) collision for dll & exe
set_target_properties("${PROJECT_NAME}-bin" PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") set_target_properties("${PROJECT_NAME}-bin" PROPERTIES OUTPUT_NAME "${PROJECT_NAME}")
if (WITH_STATIC)
set_target_properties("${PROJECT_NAME}-bin" PROPERTIES LINK_FLAGS "-static" )
endif ()
endif()
if (WITH_PCH)
if (MSVC)
target_compile_options("${PROJECT_NAME}-bin" PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
target_compile_options("${PROJECT_NAME}-bin" PRIVATE -include stdafx.h)
endif()
endif()
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}-bin" PROPERTIES LINK_FLAGS "-z relro -z now" ) set_target_properties("${PROJECT_NAME}-bin" PROPERTIES LINK_FLAGS "-z relro -z now" )
endif () endif ()
if (WITH_STATIC) # FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04
set(BUILD_SHARED_LIBS OFF) list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
set_target_properties("${PROJECT_NAME}-bin" PROPERTIES LINK_FLAGS "-static" ) if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")
endif () list(REMOVE_AT Boost_LIBRARIES -1)
endif()
target_link_libraries( "${PROJECT_NAME}-bin" ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) target_link_libraries( "${PROJECT_NAME}-bin" common ${DL_LIB} ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} )
install(TARGETS "${PROJECT_NAME}-bin" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(TARGETS "${PROJECT_NAME}-bin" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
if (MSVC)
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}-bin> DESTINATION "bin" CONFIGURATIONS DEBUG)
endif ()
endif () endif ()
if (WITH_LIBRARY) if (WITH_LIBRARY)
add_library(${PROJECT_NAME} SHARED ${COMMON_SRC} ${LIBRARY_SRC}) if (MSVC)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) # FIXME: DLL would not have any symbols unless we use __declspec(dllexport) through out the code
add_library(${PROJECT_NAME} STATIC ${LIBRARY_SRC})
else ()
add_library(${PROJECT_NAME} ${LIBRARY_SRC})
target_link_libraries( ${PROJECT_NAME} common ${Boost_LIBRARIES} ${CRYPTO++_LIBRARIES})
endif ()
if (WITH_PCH)
if (MSVC)
add_dependencies(${PROJECT_NAME} stdafx)
target_compile_options(${PROJECT_NAME} PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
target_compile_options(${PROJECT_NAME} PRIVATE -include stdafx.h)
endif()
endif()
install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif () endif ()

View File

@@ -116,7 +116,7 @@ am_i2p_OBJECTS = AddressBook.$(OBJEXT) CryptoConst.$(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) BOB.$(OBJEXT) \ Datagram.$(OBJEXT) SSUSession.$(OBJEXT) BOB.$(OBJEXT) \
I2PControl.$(OBJEXT) Profiling.$(OBJEXT) I2PControl.$(OBJEXT) Profiling.$(OBJEXT) Signature.$(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@)
@@ -328,7 +328,8 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.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 BOB.cpp \ ClientContext.cpp DataFram.cpp SSUSession.cpp BOB.cpp \
I2PControl.cpp Profiling.cpp \ I2PControl.cpp Profiling.cpp Signature.cpp \
NetDbRequests.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 \
@@ -341,7 +342,7 @@ i2p_SOURCES = AddressBook.cpp CryptoConst.cpp Daemon.cpp \
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 BOB.h \ TransportSession.h Datagram.h SSUSession.h BOB.h \
I2PControl.h Profiling.h I2PControl.h Profiling.h NetDbRequests.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@ \
@@ -493,6 +494,9 @@ distclean-compile:
@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@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Profiling.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Signature.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetDbRequests.Po@am__quote@
.cpp.o: .cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<

View File

@@ -4,14 +4,14 @@ if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND TRUE) set(CRYPTO++_FOUND TRUE)
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES) else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
find_path(CRYPTO++_INCLUDE_DIR cryptlib.h find_path(CRYPTO++_INCLUDE_DIR cryptopp/cryptlib.h
/usr/include/crypto++ /usr/include
/usr/include/cryptopp /usr/local/include
/usr/local/include/crypto++
/usr/local/include/cryptopp
/opt/local/include/crypto++
/opt/local/include/cryptopp
$ENV{SystemDrive}/Crypto++/include $ENV{SystemDrive}/Crypto++/include
$ENV{CRYPTOPP}
$ENV{CRYPTOPP}/..
$ENV{CRYPTOPP}/include
${PROJECT_SOURCE_DIR}/../..
) )
find_library(CRYPTO++_LIBRARIES NAMES cryptopp find_library(CRYPTO++_LIBRARIES NAMES cryptopp
@@ -20,8 +20,34 @@ else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
/usr/local/lib /usr/local/lib
/opt/local/lib /opt/local/lib
$ENV{SystemDrive}/Crypto++/lib $ENV{SystemDrive}/Crypto++/lib
$ENV{CRYPTOPP}/lib
) )
if(MSVC AND NOT CRYPTO++_LIBRARIES) # Give a chance for MSVC multiconfig
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(PLATFORM x64)
else()
set(PLATFORM Win32)
endif()
find_library(CRYPTO++_LIBRARIES_RELEASE NAMES cryptlib cryptopp
HINTS
${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Release
PATHS
$ENV{CRYPTOPP}/Win32/Output/Release
)
find_library(CRYPTO++_LIBRARIES_DEBUG NAMES cryptlib cryptopp
HINTS
${PROJECT_SOURCE_DIR}/../../cryptopp/${PLATFORM}/Output/Debug
PATHS
$ENV{CRYPTOPP}/Win32/Output/Debug
)
set(CRYPTO++_LIBRARIES
debug ${CRYPTO++_LIBRARIES_DEBUG}
optimized ${CRYPTO++_LIBRARIES_RELEASE}
CACHE PATH "Path to Crypto++ library" FORCE
)
endif()
if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES) if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
set(CRYPTO++_FOUND TRUE) set(CRYPTO++_FOUND TRUE)
message(STATUS "Found Crypto++: ${CRYPTO++_INCLUDE_DIR}, ${CRYPTO++_LIBRARIES}") message(STATUS "Found Crypto++: ${CRYPTO++_INCLUDE_DIR}, ${CRYPTO++_LIBRARIES}")

View File

@@ -0,0 +1,25 @@
# - Find MINIUPNPC
if(MINIUPNPC_INCLUDE_DIR)
set(MINIUPNPC_FOUND TRUE)
else()
find_path(MINIUPNPC_INCLUDE_DIR miniupnpc.h
/usr/include/miniupnpc
/usr/local/include/miniupnpc
/opt/local/include/miniupnpc
$ENV{SystemDrive}/miniupnpc
${PROJECT_SOURCE_DIR}/../../miniupnpc
)
if(MINIUPNPC_INCLUDE_DIR)
set(MINIUPNPC_FOUND TRUE)
message(STATUS "Found MiniUPnP headers: ${MINIUPNPC_INCLUDE_DIR}")
else()
set(MINIUPNPC_FOUND FALSE)
message(STATUS "MiniUPnP not found.")
endif()
mark_as_advanced(MINIUPNPC_INCLUDE_DIR)
endif()

View File

@@ -1,23 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID2zCCApOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBCMR8wHQYDVQQDExZpMnAt
bmV0ZGIuaW5ub3ZhdGlvLm5vMRIwEAYDVQQKEwlJbm5vdmF0aW8xCzAJBgNVBAYT
Ak5PMCIYDzIwMTQwMTIxMDUzMzMxWhgPMjAyNDAxMTkwNTMzMzFaMEIxHzAdBgNV
BAMTFmkycC1uZXRkYi5pbm5vdmF0aW8ubm8xEjAQBgNVBAoTCUlubm92YXRpbzEL
MAkGA1UEBhMCTk8wggFSMA0GCSqGSIb3DQEBAQUAA4IBPwAwggE6AoIBMQC9WVet
EFeKAHmwgTUxJ/bRI4Gtjke3uj897eeZ15Y0SiqdHzypsEIWtXqx4G3W801xZzhv
UiAculvwRY4kpv3DnQE4sNTzbkAlvC6z4+CpFM2mhZ7o+YmozrIsNmQNCsvlxqJV
AD1mzqTFl/OB7LVtLmpSSd36IQFGmsh24XXa4pVH33e+NCZIGsdVwGsa4GoRuC9a
s/DiLI+x6zYRoY9cfOF2DuuOfKNMjSl65QUe4uHZCsRTb1q08NnPIidEFHr94kZH
Hph+MQs6MUVK1eT4yYt084S3cEWmWBQZVyAvWQ9q8EW+MoniOM7bBG2Bn9wu2F5x
kAKWTYfKSStW5CKSox9VSoopiUAtEIqhwgFGTISqhQyfOfyY97X2M47wvyWsl6dE
NxTgdvLD/o24rejBAgMBAAGjeDB2MAwGA1UdEwEB/wQCMAAwIQYDVR0RBBowGIIW
aTJwLW5ldGRiLmlubm92YXRpby5ubzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNV
HQ8BAf8EBQMDByAAMB0GA1UdDgQWBBTaTuBpTAinNiT9PfKNRdIn3HrwxTANBgkq
hkiG9w0BAQsFAAOCATEAsYtojwAHiFwUqvCMIMJa5YN0Ms/QpjqZiENuGBpxvmVF
WVImX4s8K/qoBAKED8uKcRbMQd0FeDea7kMisJt5cblDzYuSv6wfeLXYkaT8/9H2
X1pXhO/eghJ2U42RTgBkaW3mCI8ohk/GehU4tEXnbWRPHt6XDoSYDJdf2X8BPcgB
ZE10owLCw9c80QTuU+LCvbt8/F2USyNplUrogJGThzxrxZvxjGq6EcDj0iA0RRoG
5CUNrCB+JgFc+4bagI3E5B0skk/wn3Nl7mM8/Nf8b1QENmc8eYBZx2InA9769DHL
tNxzvE+OeMNlKy4M9WvLieIh6KmpYhHBG8ubJT8X+bZpJkh4rH6RzVYiXeCpX2iL
eoeSriGO0+8CJTBRbd5cXYd/COT0iAomMTelhcGVTA==
-----END CERTIFICATE-----

View File

@@ -1,25 +1,25 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIESzCCAzOgAwIBAgIJALGqvElYEEqyMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD MIIESzCCAzOgAwIBAgIJAKII1waVnWddMA0GCSqGSIb3DQEBCwUAMIG7MQswCQYD
VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll VQQGEwJERTEaMBgGA1UECAwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWll
Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG Yjlvb3BvLm1vb28uY29tMRowGAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgG
A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u A1UECwwRaWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28u
Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDA0MTMx Y29tMSAwHgYJKoZIhvcNAQkBFhFpZWI5b29wby5tb29vLmNvbTAeFw0xNDExMjIx
NDI3MThaFw0zNDA0MDgxNDI3MThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR MzQzNThaFw0yMDA1MTQxMzQzNThaMIG7MQswCQYDVQQGEwJERTEaMBgGA1UECAwR
aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow aWViOW9vcG8ubW9vby5jb20xGjAYBgNVBAcMEWllYjlvb3BvLm1vb28uY29tMRow
GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v GAYDVQQKDBFpZWI5b29wby5tb29vLmNvbTEaMBgGA1UECwwRaWViOW9vcG8ubW9v
by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB by5jb20xGjAYBgNVBAMMEWllYjlvb3BvLm1vb28uY29tMSAwHgYJKoZIhvcNAQkB
FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC FhFpZWI5b29wby5tb29vLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAN1CusoQ3OxJFTytbVMe7LPY8lnR7GIIQt5eCs0XTLl3ECclET1KLRo1c8Mv ggEBAMhcnkSifOMw5bd66UlvYVsc42H22Nuy64qhtJHtggofrwBooF38kRCBVFL8
vj5AwDRvL3Kw/oeDS+QvSRhgxG3lJ8i0soWDC/1LIX1NS/ZXG7hbycZ7YqAovCxU 9Xjzr0xsSshvO6p7E+CEUtA8v55l5vNbUTAvGP9WmzeZyZuCFg9Heo3orNMbIK7m
958WPjUios73sAWUJrI8BbWFTYPWBB5lbyTaCooxtf6k7yB+CSwZnstEP/lbPNkf ppwKhwh6tFEIEpUTz/+xF5NRt0+CqcS4aNHuH3JPwNugfTBuSa86GeSaqL7K4eEZ
Iupj+9B18ba21D2kQqZXyQRLX02d/rXq963BSkPX14Dxa7abw4lgDltvh2CzcoQH bZXqQ16Onvi0yyMqRJDp/ijRFxr2eKGPWb55kuRSET9PxVhlgRKULZkr39Dh9q1c
VbQh3eGfPIIQGfvAAVEGsoy9fFt+xOUxp3KO7Y1VMKzegWqa2vBtWK+2nhpHfswq wb9lAMLMRZIzPVnyvC9jWkIqSDl5bkAAto0n1Jkw92rRp6EVKgSLA/4vl9wTb6xf
eaE1qeVh12cG5kaVNP0o0hOUxkECAwEAAaNQME4wHQYDVR0OBBYEFIQ5U4EKfr0t WfT5cs7pykAE0WXBr9TqpS3okncCAwEAAaNQME4wHQYDVR0OBBYEFGeEOHhWiKwZ
4L+RFe/RBFcDVoijMB8GA1UdIwQYMBaAFIQ5U4EKfr0t4L+RFe/RBFcDVoijMAwG TGbc7uuK3DD7YjYZMB8GA1UdIwQYMBaAFGeEOHhWiKwZTGbc7uuK3DD7YjYZMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGlNHzxF9tbS/Xr8jGpSdRLm A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAAzRA/0OpJtCO4kQkTn/hux9
oIIoTr7+dIfFIy2TMAow0+gx1qEtWASUYIwbCP5mdMfhUjL8POfSwtTvgjw3LMoM dRi9T6B54Xav5jG53iAPLTeMxsaLkvweh2pZ3kvEUrQhvW0JF8QBrHTsgxzb4Wd6
2zsGBvgGWs6VJbMPAgkgfsyjdJTM/IOiJtze6degn2bdZvAr1XiInLGMRMko7WyE FNDHSgJbZv3uCjFtWeuUh+GTG1k9uwgNIEnx7J9Vp0JCi4ezi/HMNI7c+LjinM9f
QQ1WJPcTUt8rNYVaCkq3CYioIlkb/C6M6ObHGSia0kwoZa6grD3CNUCa/c/dlFKO hrAzclkeRPLYg645DkxckLyDUbrc9v1qWFoTpezXSBPO7n3Wk4sCytdoA1FkTdXh
E06qN72fsYihp0ghHkBaCxb+YfYpIAPIpfuuTSGkVYyjpY0a8EQ1JlzbJctQkX5r RF4BWCl/3uOxcrn0TqoC9vCh8RcxnllOiOO5j4+PQ1Z6NkQ/5oRCK/jjaWc3Lr6/
sd9jfHsrZriAGCzdsL/diG8bUi9Yex/G0ip8GGEuHs5e2bJ6+7O/mPlL6SL/0tI= FicOZJe29BVnrPGynqe0Ky1o+kTdXFflKowfr7g8dwn8k9YavjtGbl1ZSHeuMF8=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

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

@@ -1,33 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFqTCCA5GgAwIBAgIJAPsJOCng4aEOMA0GCSqGSIb3DQEBBQUAMGsxCzAJBgNV
BAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ4wDAYDVQQHDAVKYXBhbjEMMAoGA1UECgwD
STJQMRMwEQYDVQQLDApJMlAgUmVzZWVkMRowGAYDVQQDDBFqcC5yZXNlZWQuaTJw
Mi5ubzAeFw0xNDA2MjgyMDQ3MThaFw0yNDA2MjUyMDQ3MThaMGsxCzAJBgNVBAYT
Ak5PMQ0wCwYDVQQIDARPc2xvMQ4wDAYDVQQHDAVKYXBhbjEMMAoGA1UECgwDSTJQ
MRMwEQYDVQQLDApJMlAgUmVzZWVkMRowGAYDVQQDDBFqcC5yZXNlZWQuaTJwMi5u
bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALlZBIbb4MHqLPpUy298
PG5z7RFo4bO7CxW2LO8DgE93KNbdkZuYpt6KcAW/gkDfKCiXTxDjyqmzZeBeIbcS
ea96jFc/pTknkiiSm9NX4ATcyRwvKXn6DR/iOiofP3G/sEkxgIdv3BgEYsF5jPQY
KefG0Jvl612cIX+1jC3lRRePYPUZnWxIuokXglLApeyhNzTK/KHIsLzR+56ScltM
pwGlroTky5ekPx4ZnJCxI+qFXWcgqdoNixPUkOtceYm7u5gd1D+mQDuCB5zfB+Pw
Iy9BTARot9M3fMrcRRVfEIGWwN1+bRnZvr0A/sqYMUqGPiUVOMi/mzyqZVQ14CGy
0idRhUKdOb/HNSmcep0Jwp0cP+VD/nCNU4JLptTLdErpTJrmDn+zkuQPPSMTzTWg
Fh3ktRsJ5zKfrnrBGxeKbciZgRkVHyWpv3+0AgbD8C3HvDj4qpkIO6D2gf+TREyM
frDXN6luqkThQcUFv+huMaL3Iul2doYqw5YPAdel6/cCD12n/FoEj5UJ47O/77DA
ITYfKCFRKDh/Ew7Ih3bH66uNaUUp+a0Sd6fNXLmWWr7gcn5B5CvrXhjPPror+Xyz
EZVByPTTfU1BkMQuxv20GG65M9g9wtXrD79N8di2wOfr4EG5i6L9ZvNTThwgWGGd
9f745WCnPL/ulLT9Glnlfk01AgMBAAGjUDBOMB0GA1UdDgQWBBR5Ed38JID7+JwB
hpOLi1Xt1ORyoTAfBgNVHSMEGDAWgBR5Ed38JID7+JwBhpOLi1Xt1ORyoTAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4ICAQBRT/ourx4xT0n/qHF1vy8Ii02v
Hg5lHmzmiVn/3/S4q+t4HrOF6MSjjvVzVNk6JIIYb3+hwGUO31OLNZX60JfSMW+C
ffPiaNDLm/xE4yt4B/QZZDs0kv0RMjGau6k2XJPGvxVNl6LhM6LLvzMEtOGzBr0J
Ai4ZU+WqHk3nnXYHbg7C7Iuu8CT8tBpkaeW/VEN82dcLEulHFxA5Ia6HlwqrgvIW
w77oaOhOh5LKkdS8uHx4OUP8Mv25H2cMBblUdubbeqREyOGRGTkVXfRekD8K95ol
PfT9PhnhUXKRaSwy0nRqvRMiwk/CyIJTbMMflDET1P785diSvtJP0fOhkev9Uprz
FvLsPUTvANUz+vd2KJiLuGbR/d/LaJm18vdWx13vKVO60TBnyFQDS4RZbeuNp73v
x5fPTmiiPZYZj13m2xyes7SXJqhVbms0F39soThpuYrjCaHXyFgqah27+9Ivmbhu
EefPgLmkOx3v0kSfXdJYdji/mrKxERmqT1L34U6M32tCoSbjO7lakAV2opisbHEw
EehCuI83cGp/m3z8yjMoWV8Z4VoB+qMzxzgrXc5C2lxYAT4JggAV2SGcY9MszETI
/S7y5UypV4rutyJvHFrlJZKtp2B7Xi8N8n2NG1WGppYh9UShbFhDaVIMQpjZokAg
MHk7ixe0rSbnHcNF8g==
-----END CERTIFICATE-----

View File

@@ -1,18 +1,23 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC0DCCAjmgAwIBAgIJANdBFbakbhhOMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD MIID1TCCAr2gAwIBAgIJAOd9wIt+w/I5MA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD
VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD
STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq
hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTIxMDIzMDExMjIyWhcNMTkx hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTQxMjA2MjM1OTM1WhcNMjAw
MDIyMDExMjIyWjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV NTI4MjM1OTM1WjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV
BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u
ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIGf ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIB
MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCDvmjTpff6/XpiNuqoa9ZEKMlyq1o IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtRtAALMImh0G0X+AtMpJNBa
kas9fHwnZax/0QTM3xusSQQ9DzeVMSx1ueYxhTZ6VLmE1mTr0aIndzugxGK/g85H HduNkg5t+0juitKRboXXAp5k7yN9qnimlBxlAicNb+QubcDuL+WV91NKz43dd6Xp
Y+cUl3nw7+5gLPMCUrKAXqQokE3mYxSNY3AUeend7nmHvm9iciw4+Sa2+6ROvQQy SAewqMFRPUAki8uYzoh+hQEfzyd3NmadUKquYZsYwomhHnraOmLZLbxD6ED3FEwl
kD31CEN6/I04rwIDAQABo1AwTjAdBgNVHQ4EFgQUV83dJhEcLbfJ+uh+MDYNPdah hGBJwYnhyMZUCgB5+DEEHg8RdLz+H0bMrwz3e7/0lMtH6lM1lIHz0KBULWLp7Om0
RoQwHwYDVR0jBBgwFoAUV83dJhEcLbfJ+uh+MDYNPdahRoQwDAYDVR0TBAUwAwEB sk3rmmhPUIXqfoY8X3vClI74o0KcslMVaF4rt3lAHdoi3lwA6Qbdqq9nC9rPWHUS
/zANBgkqhkiG9w0BAQUFAAOBgQBQQlJym7mUMUM2ryKu20z2PSUzFyq5U4rWHeo3 USQQ/MKsNfDTGsHkbW2l0VgNvJkw92DwHTXSJrsEqgkdV/B1hHxCKgL44c/CbwID
elbNaTsFBwi+Ot/Lg/A5I4V8gywH1fBTG5bYKDUYvWohz1qIg66G57B1zT1zK9yh AQABo1AwTjAdBgNVHQ4EFgQUCkebDZE05yKMbXORa6gO+aLdCscwHwYDVR0jBBgw
Byz9go44M3y1/kXXSsJlY9llG9DDicr1y6LfldwZJ5zFAd3iiB8D8UadP5YLqb7v FoAUCkebDZE05yKMbXORa6gO+aLdCscwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
wb1F1g== AQsFAAOCAQEAfHO0g5M//X5xDIuXGCeqQMUrF3r1N45a+0kqo2b/rd9USueNGrJl
KE7MfDgShy2d4strZ1m0M4StW0RlUUZ4V4FYwzcknF6VXbOQK3BTrAeOwuxsrHoT
abrMZ36ABYur5WakOYtPyQ5oXFUAIpGBe9LH7q3XLegSOfftvc2xdJ+VK0n4MEfY
GfaRGMNW/pxGYLWvao3soOJMtp6cQ5KIYGuX92DMon/UgPBqEygeUj7aIqjhRss0
b0dUZQyHccAG+e5NeTF2ifHCEh2rZY18VGxPL7KLrCQigu5lif1TTv5CDO5rKrHl
TuTOsnooMxUH4ThIVI9cxXk6bzRMehLghA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@@ -1,23 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID1TCCAr2gAwIBAgIJAOd9wIt+w/I5MA0GCSqGSIb3DQEBCwUAMIGAMQswCQYD
VQQGEwJOTzENMAsGA1UECAwET3NsbzENMAsGA1UEBwwET3NsbzEMMAoGA1UECgwD
STJQMQwwCgYDVQQLDANJMlAxFjAUBgNVBAMMDW5ldGRiLmkycDIubm8xHzAdBgkq
hkiG9w0BCQEWEG1lZWhAaTJwbWFpbC5vcmcwHhcNMTQxMjA2MjM1OTM1WhcNMjAw
NTI4MjM1OTM1WjCBgDELMAkGA1UEBhMCTk8xDTALBgNVBAgMBE9zbG8xDTALBgNV
BAcMBE9zbG8xDDAKBgNVBAoMA0kyUDEMMAoGA1UECwwDSTJQMRYwFAYDVQQDDA1u
ZXRkYi5pMnAyLm5vMR8wHQYJKoZIhvcNAQkBFhBtZWVoQGkycG1haWwub3JnMIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmtRtAALMImh0G0X+AtMpJNBa
HduNkg5t+0juitKRboXXAp5k7yN9qnimlBxlAicNb+QubcDuL+WV91NKz43dd6Xp
SAewqMFRPUAki8uYzoh+hQEfzyd3NmadUKquYZsYwomhHnraOmLZLbxD6ED3FEwl
hGBJwYnhyMZUCgB5+DEEHg8RdLz+H0bMrwz3e7/0lMtH6lM1lIHz0KBULWLp7Om0
sk3rmmhPUIXqfoY8X3vClI74o0KcslMVaF4rt3lAHdoi3lwA6Qbdqq9nC9rPWHUS
USQQ/MKsNfDTGsHkbW2l0VgNvJkw92DwHTXSJrsEqgkdV/B1hHxCKgL44c/CbwID
AQABo1AwTjAdBgNVHQ4EFgQUCkebDZE05yKMbXORa6gO+aLdCscwHwYDVR0jBBgw
FoAUCkebDZE05yKMbXORa6gO+aLdCscwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B
AQsFAAOCAQEAfHO0g5M//X5xDIuXGCeqQMUrF3r1N45a+0kqo2b/rd9USueNGrJl
KE7MfDgShy2d4strZ1m0M4StW0RlUUZ4V4FYwzcknF6VXbOQK3BTrAeOwuxsrHoT
abrMZ36ABYur5WakOYtPyQ5oXFUAIpGBe9LH7q3XLegSOfftvc2xdJ+VK0n4MEfY
GfaRGMNW/pxGYLWvao3soOJMtp6cQ5KIYGuX92DMon/UgPBqEygeUj7aIqjhRss0
b0dUZQyHccAG+e5NeTF2ifHCEh2rZY18VGxPL7KLrCQigu5lif1TTv5CDO5rKrHl
TuTOsnooMxUH4ThIVI9cxXk6bzRMehLghA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFszCCA52gAwIBAgIRALWZzF745GPT8GVUcZ0RMg0wCwYJKoZIhvcNAQELMG0x
CzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAK
BgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMRYwFAYDVQQDEw1u
ZXRkYi5yb3dzLmlvMB4XDTE0MTIyMDE2NDIwNVoXDTE2MTIxOTE2NDIwNVowbTEL
MAkGA1UEBhMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoG
A1UECxMDSTJQMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxFjAUBgNVBAMTDW5l
dGRiLnJvd3MuaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCTZyJF
Im9pnc7OO5DfQy4SuotUztO5BJX7xniTqD4fKLQQXzZFeT4XHrkDste8TsTzUfxt
CWDEBH3af5cpnwWMT28rlRw2DlPr+LnAgt7VjFXdhFZr1N5VfNlTI1K3OiZ/DRlB
92CoTypyx4ebNfLtZfh+TPLOdg5UqROpHIrybsUj2IaG3IpGHJK8FuH79b/X5oVI
FlDZJs5QsJEARzq2QMJd6fnNqkCBSSjNpeL7TtDar9EKa6+O7s351kH8MVFNSogB
F0Hqu8LYaRC1L1JCz5lsOYKepp3MMIOdDOhy+FTd8NuNZXYkUTdTNI4dB6w4Z6o+
xlnHEPpezIAAlPXLiupvlEi0om69/TMS+pLDBLAOlCZ2YaXS18UrSbmYYlekg40J
nEeALt8ZdsU/is7Q6SJZ3UltFIPCuMD+ixvaIvakkhNiqEWPxdg0XxAK1ZJYFup+
2aVtPLQIzWePkG/VbdA5cxQKNtRwOgvCoKIE29nUbxuq2PCmMhLAfXHeieSzP5c7
Q8A23qX94hwCIePj1YA9uNtStjECfVS1wjyXV4M1tTFUdSJv4aVtFjtya7PY+6SG
Srz11SqBWSqyJ/C14Su0QY/HquglzMRnkJ49Scwb+79hl7kPslO1iIgPLE5S2fIW
ZwJ/4AgGb6BZT8XPEYYANEA5y7KGanYNo8KdYwIDAQABo1IwUDAOBgNVHQ8BAf8E
BAMCAKQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAYBgNV
HREEETAPgg1uZXRkYi5yb3dzLmlvMAsGCSqGSIb3DQEBCwOCAgEAMjQSHPR/p9If
mJA1y489D1NB2CxfwO+CgAIs9HA7OsdneQBZTldMgBHoQGifkpD1uSl8DHoZqnJ8
wo5YWcT1rYkP+V1jGfZj92VvfQL0/R4G4hWdQwYY0CcXN8ixS36UDQVSFKb4zvNG
j9iIN57WToEmxp5noHguKrpViwhXCMCpAXr3ZIv/Fd+QACNEXuvdZgbtwfOTPLKh
ZlkUPgVHiQopeQnZhZCT3aLZ5lndrUtWlQYiGN/OolVyRie+ysuxjRR4L5brt4Rz
hrwFBswbQZlgxJ3Nod9/wEdEJWP4+X69ggzOkBB+PgpOFpuDlJxNTcPA/WFIlsm0
CzCv/o8Vg+MMWFPMwEZrk6UQXXACr1AEF+MUnZq3o5JaLvHoUcikewbZPcTCNvDp
nqT1RN9vq/MGdlRfPJkF028IXPz7T9DXXPXhJvv+FAfnOkREeUYpzBIftyYf92ol
l63z0FooVUTKWYPvFFgl5ShNnINTMVXPCZp8j7myLGSLOAFFwiaL1OtvftgxXfzC
B7Qj42SNhFUrHmO9fH3H2ptm/iW/Xe5eqgeb6MVGQ/eQJpdp0AvpDa50/AYNt1Iq
CcMKmBgzUezrIN24XXW/LZwazlc7I8e5RzgbEgXEDBZu21TApTKlmOqEYle8294W
fWThMdwk1kTrWxLooiVrS5A1hXqADqE=
-----END CERTIFICATE-----

View File

@@ -1,9 +1,10 @@
COMMON_SRC = \ COMMON_SRC = \
CryptoConst.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ CryptoConst.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \
Log.cpp NTCPSession.cpp NetDb.cpp Profiling.cpp Reseed.cpp RouterContext.cpp \ Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \
RouterInfo.cpp SSU.cpp SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp \ Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \
TransitTunnel.cpp Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
TunnelGateway.cpp Destination.cpp UPnP.cpp util.cpp aes.cpp base64.cpp Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
Destination.cpp UPnP.cpp util.cpp aes.cpp base64.cpp
ifeq ($(UNAME),Darwin) ifeq ($(UNAME),Darwin)

1
stdafx.cpp Normal file
View File

@@ -0,0 +1 @@
#include "stdafx.h"

67
stdafx.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef STDAFX_H__
#define STDAFX_H__
#include <inttypes.h>
#include <stdlib.h>
#include <cassert>
#include <time.h>
#include <stdio.h>
#include <string.h> // TODO: replace with cstring and std::<old func> through out
#include <string>
#include <cstring>
#include <iostream>
#include <sstream>
#include <fstream>
#include <functional>
#include <algorithm>
#include <atomic>
#include <utility>
#include <cctype>
#include <condition_variable>
#include <chrono>
#include <set>
#include <map>
#include <memory>
#include <queue>
#include <vector>
#include <thread>
#include <mutex>
#include <boost/asio.hpp>
#include <boost/regex.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread/thread.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/algorithm/string.hpp>
#include <cryptopp/aes.h>
#include <cryptopp/adler32.h>
#include <cryptopp/asn.h>
#include <cryptopp/base64.h>
#include <cryptopp/crc.h>
#include <cryptopp/dh.h>
#include <cryptopp/dsa.h>
#include <cryptopp/eccrypto.h>
#include <cryptopp/gzip.h>
#include <cryptopp/hmac.h>
#include <cryptopp/integer.h>
#include <cryptopp/modes.h>
#include <cryptopp/osrng.h>
#include <cryptopp/sha.h>
#include <cryptopp/zinflate.h>
#endif

View File

@@ -2,7 +2,7 @@
#define _VERSION_H_ #define _VERSION_H_
#define CODENAME "Purple" #define CODENAME "Purple"
#define VERSION "0.9.0" #define VERSION "0.10.0"
#define I2P_VERSION "0.9.18" #define I2P_VERSION "0.9.20"
#endif #endif