mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
221 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cae9ccfda1 | ||
|
|
248ae7d4d5 | ||
|
|
7f08bbe938 | ||
|
|
81b2f2114d | ||
|
|
5eee430be3 | ||
|
|
870e84a700 | ||
|
|
8d4fae24ea | ||
|
|
7a84daf3f7 | ||
|
|
7968279bc2 | ||
|
|
258be40285 | ||
|
|
b2ae30eba1 | ||
|
|
daaba1dbc0 | ||
|
|
a3c6ed4dd2 | ||
|
|
e4255ed712 | ||
|
|
5d510f1cf4 | ||
|
|
1819bd910a | ||
|
|
43eecdbb3f | ||
|
|
108c1bcac4 | ||
|
|
4b7e5864d4 | ||
|
|
fb1d2abbfa | ||
|
|
0c290e65ef | ||
|
|
5487fad2ce | ||
|
|
d41f930f69 | ||
|
|
595b2619fd | ||
|
|
26d305d866 | ||
|
|
c9d95ff161 | ||
|
|
9cc592b564 | ||
|
|
ff48422ec0 | ||
|
|
a26c5f85c3 | ||
|
|
727436e1cf | ||
|
|
d1c57a1872 | ||
|
|
b7c021af8c | ||
|
|
7149b509d7 | ||
|
|
45e7111dda | ||
|
|
9fc69db9eb | ||
|
|
2ba314d9d9 | ||
|
|
f35660c8e2 | ||
|
|
68b1fe8631 | ||
|
|
4242c86d40 | ||
|
|
ef4dc3cbc9 | ||
|
|
8daa7561fa | ||
|
|
2cc3dfc2ce | ||
|
|
459800568a | ||
|
|
3a35b84b03 | ||
|
|
79cfa52bf9 | ||
|
|
a0e8fe5848 | ||
|
|
2dae5bccb2 | ||
|
|
8e867ab0c0 | ||
|
|
1b2c88fe38 | ||
|
|
f3bee5ff3f | ||
|
|
196d7e8f72 | ||
|
|
16596c18fb | ||
|
|
7ea3a87bfc | ||
|
|
a57905b6cd | ||
|
|
f9c592ca22 | ||
|
|
aecac0ef85 | ||
|
|
ca315c51a0 | ||
|
|
45c8858140 | ||
|
|
06e45bff24 | ||
|
|
2635a658d0 | ||
|
|
f48a98f691 | ||
|
|
3badda95c1 | ||
|
|
364ccc05d5 | ||
|
|
d09fedf208 | ||
|
|
7936f8730f | ||
|
|
6c0dfc4356 | ||
|
|
d9af8c31a2 | ||
|
|
ca375314f0 | ||
|
|
5266d4d79c | ||
|
|
1cb0826de0 | ||
|
|
89e3178ea3 | ||
|
|
3b5d9d6cee | ||
|
|
ce4ed19029 | ||
|
|
01a502339c | ||
|
|
642d0e6f74 | ||
|
|
d9e659deb0 | ||
|
|
830fe7f9b8 | ||
|
|
3e8c247c05 | ||
|
|
16880074fa | ||
|
|
19c74ce9fa | ||
|
|
56ef0dad9c | ||
|
|
8d99808821 | ||
|
|
1cb08fdecc | ||
|
|
e8952d7e02 | ||
|
|
18fad9c9d9 | ||
|
|
89a0a94f3e | ||
|
|
0859cf30f8 | ||
|
|
a0fe02a560 | ||
|
|
3156f7dacd | ||
|
|
c3958bf042 | ||
|
|
facc5f8aa7 | ||
|
|
8170257c26 | ||
|
|
489e37b2a1 | ||
|
|
4899e0d2d5 | ||
|
|
762f9c4b23 | ||
|
|
6d3dac0ec1 | ||
|
|
f684815272 | ||
|
|
8e04218c95 | ||
|
|
23cb45454b | ||
|
|
7fc9a161b1 | ||
|
|
95a5473051 | ||
|
|
66ceb573dc | ||
|
|
5f8223ebb5 | ||
|
|
51146d4152 | ||
|
|
3334281949 | ||
|
|
8e85d9ac00 | ||
|
|
e1c69a6250 | ||
|
|
edd9a18257 | ||
|
|
65f993677f | ||
|
|
bc775140bb | ||
|
|
4b2bd6e18f | ||
|
|
c36a810bcb | ||
|
|
a994bbc36b | ||
|
|
c3238f4d0b | ||
|
|
632d26e398 | ||
|
|
214cc8b810 | ||
|
|
8f218141f4 | ||
|
|
3676304751 | ||
|
|
c605fd57aa | ||
|
|
4599f6919c | ||
|
|
8ad20c0db3 | ||
|
|
638a69e5f0 | ||
|
|
9fa6b1ebe1 | ||
|
|
5930e2d221 | ||
|
|
fdd96975fb | ||
|
|
de6dd77046 | ||
|
|
1b6ad8413e | ||
|
|
6096d572f3 | ||
|
|
badcd64b62 | ||
|
|
a7b8b52dbd | ||
|
|
d89f0f51df | ||
|
|
be358f3f2e | ||
|
|
f122da1485 | ||
|
|
0dda4728b6 | ||
|
|
45fd95e02b | ||
|
|
91aa2d7f6f | ||
|
|
a96b7d2a80 | ||
|
|
8f9cea54c5 | ||
|
|
045558bede | ||
|
|
58124ebaab | ||
|
|
0c87dd5624 | ||
|
|
b87f986a49 | ||
|
|
c6a6035bb9 | ||
|
|
1ef12f0645 | ||
|
|
ef3ec33ba3 | ||
|
|
c82ef1ee8f | ||
|
|
23b8a60242 | ||
|
|
ac9511165e | ||
|
|
9d70851eb9 | ||
|
|
759dfb28ce | ||
|
|
ff356b1f21 | ||
|
|
b2a6c1bc68 | ||
|
|
76549d0a4a | ||
|
|
e5c72cae83 | ||
|
|
bf47df46c9 | ||
|
|
0ef42870e5 | ||
|
|
da8a6a4c2b | ||
|
|
988007a8c9 | ||
|
|
710439e83c | ||
|
|
80a0a3d4fb | ||
|
|
43299aea10 | ||
|
|
f5aea766a7 | ||
|
|
c5308e3f2f | ||
|
|
2b8e662f81 | ||
|
|
0a6d849435 | ||
|
|
a0106fe5d8 | ||
|
|
cee1b8a64a | ||
|
|
4e2ba71d59 | ||
|
|
fb2bdfb9ee | ||
|
|
72785f6740 | ||
|
|
a94a05fac9 | ||
|
|
430368de97 | ||
|
|
7bfb499549 | ||
|
|
9bc477e1b6 | ||
|
|
f84ac18472 | ||
|
|
cd515a2e54 | ||
|
|
c73c8fdc47 | ||
|
|
e755a32b23 | ||
|
|
d4d1768575 | ||
|
|
0a5745c559 | ||
|
|
b24959205b | ||
|
|
d69f297c05 | ||
|
|
3c8e331809 | ||
|
|
d169471e8c | ||
|
|
56453f6b5c | ||
|
|
dac2e8c79e | ||
|
|
ccc96bc610 | ||
|
|
654371cb6a | ||
|
|
1af8d873bb | ||
|
|
b7a0e23309 | ||
|
|
4a0f868941 | ||
|
|
448073cdd6 | ||
|
|
ad79ec7b1f | ||
|
|
e194854c6d | ||
|
|
d01d033209 | ||
|
|
06c4aca490 | ||
|
|
885d57138a | ||
|
|
9e2a770a26 | ||
|
|
942b699bb9 | ||
|
|
c9d03a8094 | ||
|
|
d015538bb4 | ||
|
|
90d6c5c5bb | ||
|
|
387ce4b6fa | ||
|
|
7943b13891 | ||
|
|
50a7cd19b4 | ||
|
|
53e9335bb0 | ||
|
|
e5cb70972e | ||
|
|
0d84871037 | ||
|
|
1d37745c0c | ||
|
|
ad9ade7849 | ||
|
|
c1e2ee32b4 | ||
|
|
1588d2734c | ||
|
|
50dda4263f | ||
|
|
a8f2239495 | ||
|
|
c42636b0ee | ||
|
|
54b2c8bd7e | ||
|
|
d01a21a867 | ||
|
|
5d43052c05 | ||
|
|
4109ab1590 | ||
|
|
f6eabd695b | ||
|
|
24d9dacfd9 |
@@ -34,8 +34,15 @@ namespace client
|
||||
|
||||
private:
|
||||
|
||||
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / "addressbook"; };
|
||||
|
||||
boost::filesystem::path GetPath () const
|
||||
{
|
||||
return i2p::util::filesystem::GetDefaultDataDir() / "addressbook";
|
||||
}
|
||||
boost::filesystem::path GetAddressPath (const i2p::data::IdentHash& ident) const
|
||||
{
|
||||
auto b32 = ident.ToBase32();
|
||||
return GetPath () / (std::string ("b") + b32[0]) / (b32 + ".b32");
|
||||
}
|
||||
};
|
||||
|
||||
AddressBookFilesystemStorage::AddressBookFilesystemStorage ()
|
||||
@@ -47,12 +54,28 @@ namespace client
|
||||
if (!boost::filesystem::create_directory (path))
|
||||
LogPrint (eLogError, "Failed to create addressbook directory");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
|
||||
{
|
||||
auto filename = GetPath () / (ident.ToBase32() + ".b32");
|
||||
std::ifstream f(filename.c_str (), std::ifstream::binary);
|
||||
auto filename = GetAddressPath (ident);
|
||||
if (!boost::filesystem::exists (filename))
|
||||
{
|
||||
boost::filesystem::create_directory (filename.parent_path ());
|
||||
// try to find in main folder
|
||||
auto filename1 = GetPath () / (ident.ToBase32 () + ".b32");
|
||||
if (!boost::filesystem::exists (filename1))
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::rename (filename1, filename, ec);
|
||||
if (ec)
|
||||
LogPrint (eLogError, "Couldn't move file ", ec.message ());
|
||||
}
|
||||
else
|
||||
return nullptr; // address doesn't exist
|
||||
}
|
||||
std::ifstream f(filename.string (), std::ifstream::binary);
|
||||
if (f.is_open ())
|
||||
{
|
||||
f.seekg (0,std::ios::end);
|
||||
@@ -75,8 +98,14 @@ namespace client
|
||||
|
||||
void AddressBookFilesystemStorage::AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
||||
{
|
||||
auto filename = GetPath () / (address->GetIdentHash ().ToBase32() + ".b32");
|
||||
std::ofstream f (filename.c_str (), std::ofstream::binary | std::ofstream::out);
|
||||
auto filename = GetAddressPath (address->GetIdentHash ());
|
||||
std::ofstream f (filename.string (), std::ofstream::binary | std::ofstream::out);
|
||||
if (!f.is_open ())
|
||||
{
|
||||
// create subdirectory
|
||||
if (boost::filesystem::create_directory (filename.parent_path ()))
|
||||
f.open (filename.string (), std::ofstream::binary | std::ofstream::out); // and try to open again
|
||||
}
|
||||
if (f.is_open ())
|
||||
{
|
||||
size_t len = address->GetFullLen ();
|
||||
@@ -91,7 +120,7 @@ namespace client
|
||||
|
||||
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto filename = GetPath () / (ident.ToBase32() + ".b32");
|
||||
auto filename = GetAddressPath (ident);
|
||||
if (boost::filesystem::exists (filename))
|
||||
boost::filesystem::remove (filename);
|
||||
}
|
||||
@@ -100,7 +129,7 @@ namespace client
|
||||
{
|
||||
int num = 0;
|
||||
auto filename = GetPath () / "addresses.csv";
|
||||
std::ifstream f (filename.c_str (), std::ofstream::in); // in text mode
|
||||
std::ifstream f (filename.string (), std::ofstream::in); // in text mode
|
||||
if (f.is_open ())
|
||||
{
|
||||
addresses.clear ();
|
||||
@@ -123,10 +152,10 @@ namespace client
|
||||
num++;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, num, " addresses loaded");
|
||||
LogPrint (eLogInfo, "Addressbook: ", num, " addresses loaded");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, filename, " not found");
|
||||
LogPrint (eLogWarning, "Addressbook: ", filename, " not found");
|
||||
return num;
|
||||
}
|
||||
|
||||
@@ -134,7 +163,7 @@ namespace client
|
||||
{
|
||||
int num = 0;
|
||||
auto filename = GetPath () / "addresses.csv";
|
||||
std::ofstream f (filename.c_str (), std::ofstream::out); // in text mode
|
||||
std::ofstream f (filename.string (), std::ofstream::out); // in text mode
|
||||
if (f.is_open ())
|
||||
{
|
||||
for (auto it: addresses)
|
||||
@@ -142,7 +171,7 @@ namespace client
|
||||
f << it.first << "," << it.second.ToBase32 () << std::endl;
|
||||
num++;
|
||||
}
|
||||
LogPrint (eLogInfo, num, " addresses saved");
|
||||
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't open file ", filename);
|
||||
@@ -261,7 +290,7 @@ namespace client
|
||||
m_Storage = CreateStorage ();
|
||||
m_Storage->AddAddress (ident);
|
||||
m_Addresses[address] = ident->GetIdentHash ();
|
||||
LogPrint (address,"->", ToAddress(ident->GetIdentHash ()), " added");
|
||||
LogPrint (eLogInfo, "Addressbook: ", address,"->", ToAddress(ident->GetIdentHash ()), " added");
|
||||
}
|
||||
|
||||
void AddressBook::InsertAddress (std::shared_ptr<const i2p::data::IdentityEx> address)
|
||||
@@ -447,7 +476,7 @@ namespace client
|
||||
void AddressBookSubscription::Request ()
|
||||
{
|
||||
// must be run in separate thread
|
||||
LogPrint (eLogInfo, "Downloading hosts from ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
||||
LogPrint (eLogInfo, "Downloading hosts database from ", m_Link, " ETag: ", m_Etag, " Last-Modified: ", m_LastModified);
|
||||
bool success = false;
|
||||
i2p::util::http::url u (m_Link);
|
||||
i2p::data::IdentHash ident;
|
||||
@@ -466,7 +495,10 @@ namespace client
|
||||
newDataReceived.notify_all ();
|
||||
});
|
||||
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 LeaseSet request timeout expired");
|
||||
i2p::client::context.GetSharedLocalDestination ()->CancelDestinationRequest (ident);
|
||||
}
|
||||
}
|
||||
if (leaseSet)
|
||||
{
|
||||
@@ -559,7 +591,10 @@ namespace client
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't resolve ", u.host_);
|
||||
LogPrint (eLogInfo, "Download complete ", success ? "Success" : "Failed");
|
||||
|
||||
if (!success)
|
||||
LogPrint (eLogError, "Addressbook download failed");
|
||||
|
||||
m_Book.DownloadComplete (success);
|
||||
}
|
||||
}
|
||||
|
||||
30
BOB.cpp
30
BOB.cpp
@@ -61,7 +61,7 @@ namespace client
|
||||
std::shared_ptr<AddressReceiver> receiver)
|
||||
{
|
||||
if (ecode)
|
||||
LogPrint ("BOB inbound tunnel read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "BOB: inbound tunnel read error: ", ecode.message ());
|
||||
else
|
||||
{
|
||||
receiver->bufferOffset += bytes_transferred;
|
||||
@@ -76,7 +76,7 @@ namespace client
|
||||
i2p::data::IdentHash ident;
|
||||
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
|
||||
{
|
||||
LogPrint (eLogError, "BOB address ", receiver->buffer, " not found");
|
||||
LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found");
|
||||
return;
|
||||
}
|
||||
auto leaseSet = GetLocalDestination ()->FindLeaseSet (ident);
|
||||
@@ -92,7 +92,7 @@ namespace client
|
||||
if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE)
|
||||
ReceiveAddress (receiver);
|
||||
else
|
||||
LogPrint ("BOB missing inbound address ");
|
||||
LogPrint (eLogError, "BOB: missing inbound address");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,12 +102,12 @@ namespace client
|
||||
if (leaseSet)
|
||||
CreateConnection (receiver, leaseSet);
|
||||
else
|
||||
LogPrint ("LeaseSet for BOB inbound destination not found");
|
||||
LogPrint (eLogError, "BOB: LeaseSet for inbound destination not found");
|
||||
}
|
||||
|
||||
void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
|
||||
{
|
||||
LogPrint ("New BOB inbound connection");
|
||||
LogPrint (eLogDebug, "BOB: New inbound connection");
|
||||
auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet);
|
||||
AddHandler (connection);
|
||||
connection->I2PConnect (receiver->data, receiver->dataLen);
|
||||
@@ -135,7 +135,7 @@ namespace client
|
||||
if (localDestination)
|
||||
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
else
|
||||
LogPrint ("Local destination not set for server tunnel");
|
||||
LogPrint (eLogError, "BOB: Local destination not set for server tunnel");
|
||||
}
|
||||
|
||||
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
@@ -229,7 +229,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("BOB command channel read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "BOB: command channel read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -256,7 +256,7 @@ namespace client
|
||||
(this->*(it->second))(operand, eol - operand);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "BOB unknown command ", m_ReceiveBuffer);
|
||||
LogPrint (eLogError, "BOB: unknown command ", m_ReceiveBuffer);
|
||||
SendReplyError ("unknown command");
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@ namespace client
|
||||
m_ReceiveBufferOffset = size;
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Malformed input of the BOB command channel");
|
||||
LogPrint (eLogError, "BOB: Malformed input of the command channel");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
@@ -288,7 +288,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("BOB command channel send error: ", ecode.message ());
|
||||
LogPrint (eLogError, "BOB: command channel send error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -524,9 +524,9 @@ namespace client
|
||||
SendReplyError ("malformed");
|
||||
}
|
||||
|
||||
BOBCommandChannel::BOBCommandChannel (int port):
|
||||
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
|
||||
m_IsRunning (false), m_Thread (nullptr),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port))
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
|
||||
{
|
||||
// command -> handler
|
||||
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
|
||||
@@ -589,7 +589,7 @@ namespace client
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "BOB: ", ex.what ());
|
||||
LogPrint (eLogError, "BOB: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -632,11 +632,11 @@ namespace client
|
||||
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "New BOB command connection from ", session->GetSocket ().remote_endpoint ());
|
||||
LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ());
|
||||
session->SendVersion ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "BOB accept error: ", ecode.message ());
|
||||
LogPrint (eLogError, "BOB: accept error: ", ecode.message ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
BOB.h
2
BOB.h
@@ -199,7 +199,7 @@ namespace client
|
||||
{
|
||||
public:
|
||||
|
||||
BOBCommandChannel (int port);
|
||||
BOBCommandChannel (const std::string& address, int port);
|
||||
~BOBCommandChannel ();
|
||||
|
||||
void Start ();
|
||||
|
||||
2
Base.cpp
2
Base.cpp
@@ -154,7 +154,7 @@ namespace data
|
||||
if (isFirstTime) iT64Build();
|
||||
n = InCount/4;
|
||||
m = InCount%4;
|
||||
if (!m)
|
||||
if (InCount && !m)
|
||||
outCount = 3*n;
|
||||
else {
|
||||
outCount = 0;
|
||||
|
||||
@@ -41,55 +41,32 @@ namespace client
|
||||
std::string proxyKeys = i2p::util::config::GetArg("-proxykeys", "");
|
||||
if (proxyKeys.length () > 0)
|
||||
localDestination = LoadLocalDestination (proxyKeys, false);
|
||||
m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyport", 4446), localDestination);
|
||||
LogPrint(eLogInfo, "Clients: starting HTTP Proxy");
|
||||
m_HttpProxy = new i2p::proxy::HTTPProxy(i2p::util::config::GetArg("-httpproxyaddress", "127.0.0.1"), i2p::util::config::GetArg("-httpproxyport", 4446), localDestination);
|
||||
m_HttpProxy->Start();
|
||||
LogPrint("HTTP Proxy started");
|
||||
m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyport", 4447), localDestination);
|
||||
LogPrint(eLogInfo, "Clients: starting SOCKS Proxy");
|
||||
m_SocksProxy = new i2p::proxy::SOCKSProxy(i2p::util::config::GetArg("-socksproxyaddress", "127.0.0.1"), i2p::util::config::GetArg("-socksproxyport", 4447), localDestination);
|
||||
m_SocksProxy->Start();
|
||||
LogPrint("SOCKS Proxy Started");
|
||||
|
||||
// I2P tunnels
|
||||
std::string ircDestination = i2p::util::config::GetArg("-ircdest", "");
|
||||
if (ircDestination.length () > 0) // ircdest is presented
|
||||
{
|
||||
localDestination = nullptr;
|
||||
std::string ircKeys = i2p::util::config::GetArg("-irckeys", "");
|
||||
if (ircKeys.length () > 0)
|
||||
localDestination = LoadLocalDestination (ircKeys, false);
|
||||
auto ircPort = i2p::util::config::GetArg("-ircport", 6668);
|
||||
auto ircTunnel = new I2PClientTunnel (ircDestination, ircPort, localDestination);
|
||||
ircTunnel->Start ();
|
||||
m_ClientTunnels.insert (std::make_pair(ircPort, std::unique_ptr<I2PClientTunnel>(ircTunnel)));
|
||||
LogPrint("IRC tunnel started");
|
||||
}
|
||||
std::string eepKeys = i2p::util::config::GetArg("-eepkeys", "");
|
||||
if (eepKeys.length () > 0) // eepkeys file is presented
|
||||
{
|
||||
localDestination = LoadLocalDestination (eepKeys, true);
|
||||
auto serverTunnel = new I2PServerTunnel (i2p::util::config::GetArg("-eephost", "127.0.0.1"),
|
||||
i2p::util::config::GetArg("-eepport", 80), localDestination);
|
||||
serverTunnel->Start ();
|
||||
m_ServerTunnels.insert (std::make_pair(localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel)));
|
||||
LogPrint("Server tunnel started");
|
||||
}
|
||||
ReadTunnels ();
|
||||
|
||||
// SAM
|
||||
int samPort = i2p::util::config::GetArg("-samport", 0);
|
||||
if (samPort)
|
||||
{
|
||||
m_SamBridge = new SAMBridge (samPort);
|
||||
LogPrint(eLogInfo, "Clients: starting SAM bridge");
|
||||
m_SamBridge = new SAMBridge (i2p::util::config::GetArg("-samaddress", "127.0.0.1"), samPort);
|
||||
m_SamBridge->Start ();
|
||||
LogPrint("SAM bridge started");
|
||||
}
|
||||
|
||||
// BOB
|
||||
int bobPort = i2p::util::config::GetArg("-bobport", 0);
|
||||
if (bobPort)
|
||||
{
|
||||
m_BOBCommandChannel = new BOBCommandChannel (bobPort);
|
||||
LogPrint(eLogInfo, "Clients: starting BOB command channel");
|
||||
m_BOBCommandChannel = new BOBCommandChannel (i2p::util::config::GetArg("-bobaddress", "127.0.0.1"), bobPort);
|
||||
m_BOBCommandChannel->Start ();
|
||||
LogPrint("BOB command channel started");
|
||||
}
|
||||
|
||||
m_AddressBook.Start ();
|
||||
@@ -97,40 +74,47 @@ namespace client
|
||||
|
||||
void ClientContext::Stop ()
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping HTTP Proxy");
|
||||
m_HttpProxy->Stop();
|
||||
delete m_HttpProxy;
|
||||
m_HttpProxy = nullptr;
|
||||
LogPrint("HTTP Proxy stopped");
|
||||
|
||||
LogPrint(eLogInfo, "Clients: stopping SOCKS Proxy");
|
||||
m_SocksProxy->Stop();
|
||||
delete m_SocksProxy;
|
||||
m_SocksProxy = nullptr;
|
||||
LogPrint("SOCKS Proxy stopped");
|
||||
|
||||
for (auto& it: m_ClientTunnels)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping I2P client tunnel on port ", it.first);
|
||||
it.second->Stop ();
|
||||
LogPrint("I2P client tunnel on port ", it.first, " stopped");
|
||||
}
|
||||
m_ClientTunnels.clear ();
|
||||
|
||||
for (auto& it: m_ServerTunnels)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping I2P server tunnel");
|
||||
it.second->Stop ();
|
||||
LogPrint("I2P server tunnel stopped");
|
||||
}
|
||||
m_ServerTunnels.clear ();
|
||||
|
||||
if (m_SamBridge)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping SAM bridge");
|
||||
m_SamBridge->Stop ();
|
||||
delete m_SamBridge;
|
||||
m_SamBridge = nullptr;
|
||||
LogPrint("SAM brdige stopped");
|
||||
}
|
||||
|
||||
if (m_BOBCommandChannel)
|
||||
{
|
||||
LogPrint(eLogInfo, "Clients: stopping BOB command channel");
|
||||
m_BOBCommandChannel->Stop ();
|
||||
delete m_BOBCommandChannel;
|
||||
m_BOBCommandChannel = nullptr;
|
||||
LogPrint("BOB command channel stopped");
|
||||
}
|
||||
}
|
||||
|
||||
LogPrint(eLogInfo, "Clients: stopping AddressBook");
|
||||
m_AddressBook.Stop ();
|
||||
for (auto it: m_Destinations)
|
||||
it.second->Stop ();
|
||||
@@ -138,7 +122,8 @@ namespace client
|
||||
m_SharedLocalDestination = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientDestination> ClientContext::LoadLocalDestination (const std::string& filename, bool isPublic)
|
||||
std::shared_ptr<ClientDestination> ClientContext::LoadLocalDestination (const std::string& filename,
|
||||
bool isPublic, i2p::data::SigningKeyType sigType)
|
||||
{
|
||||
i2p::data::PrivateKeys keys;
|
||||
std::string fullPath = i2p::util::filesystem::GetFullPath (filename);
|
||||
@@ -152,12 +137,12 @@ namespace client
|
||||
s.read ((char *)buf, len);
|
||||
keys.FromBuffer (buf, len);
|
||||
delete[] buf;
|
||||
LogPrint ("Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
|
||||
LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Can't open file ", fullPath, " Creating new one");
|
||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType);
|
||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
|
||||
size_t len = keys.GetFullLen ();
|
||||
uint8_t * buf = new uint8_t[len];
|
||||
@@ -165,7 +150,7 @@ namespace client
|
||||
f.write ((char *)buf, len);
|
||||
delete[] buf;
|
||||
|
||||
LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
||||
LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
||||
}
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||
@@ -173,7 +158,7 @@ namespace client
|
||||
auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
|
||||
if (it != m_Destinations.end ())
|
||||
{
|
||||
LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " alreday exists");
|
||||
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " already exists");
|
||||
localDestination = it->second;
|
||||
}
|
||||
else
|
||||
@@ -217,7 +202,7 @@ namespace client
|
||||
auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
|
||||
if (it != m_Destinations.end ())
|
||||
{
|
||||
LogPrint ("Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
||||
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
||||
if (!it->second->IsRunning ())
|
||||
{
|
||||
it->second->Start ();
|
||||
@@ -240,16 +225,18 @@ namespace client
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// should be moved in i2p::utils::fs
|
||||
void ClientContext::ReadTunnels ()
|
||||
{
|
||||
boost::property_tree::ptree pt;
|
||||
std::string pathTunnelsConfigFile = i2p::util::filesystem::GetTunnelsConfigFile().string();
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_ini (i2p::util::filesystem::GetFullPath (TUNNELS_CONFIG_FILENAME), pt);
|
||||
boost::property_tree::read_ini (pathTunnelsConfigFile, pt);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "Can't read ", TUNNELS_CONFIG_FILENAME, ": ", ex.what ());
|
||||
LogPrint (eLogWarning, "Clients: Can't read ", pathTunnelsConfigFile, ": ", ex.what ());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -267,16 +254,18 @@ namespace client
|
||||
int port = section.second.get<int> (I2P_CLIENT_TUNNEL_PORT);
|
||||
// optional params
|
||||
std::string keys = section.second.get (I2P_CLIENT_TUNNEL_KEYS, "");
|
||||
std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1");
|
||||
int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0);
|
||||
i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
|
||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||
if (keys.length () > 0)
|
||||
localDestination = LoadLocalDestination (keys, false);
|
||||
auto clientTunnel = new I2PClientTunnel (dest, port, localDestination, destinationPort);
|
||||
localDestination = LoadLocalDestination (keys, false, sigType);
|
||||
auto clientTunnel = new I2PClientTunnel (dest, address, port, localDestination, destinationPort);
|
||||
if (m_ClientTunnels.insert (std::make_pair (port, std::unique_ptr<I2PClientTunnel>(clientTunnel))).second)
|
||||
clientTunnel->Start ();
|
||||
else
|
||||
LogPrint (eLogError, "I2P client tunnel with port ", port, " already exists");
|
||||
LogPrint (eLogError, "Clients: I2P client tunnel with port ", port, " already exists");
|
||||
numClientTunnels++;
|
||||
}
|
||||
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER || type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
||||
@@ -288,8 +277,9 @@ namespace client
|
||||
// optional params
|
||||
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
||||
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
||||
|
||||
auto localDestination = LoadLocalDestination (keys, true);
|
||||
i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
|
||||
auto localDestination = LoadLocalDestination (keys, true, sigType);
|
||||
I2PServerTunnel * serverTunnel = (type == I2P_TUNNELS_SECTION_TYPE_HTTP) ? new I2PServerTunnelHTTP (host, port, localDestination, inPort) : new I2PServerTunnel (host, port, localDestination, inPort);
|
||||
if (accessList.length () > 0)
|
||||
{
|
||||
@@ -309,20 +299,20 @@ namespace client
|
||||
if (m_ServerTunnels.insert (std::make_pair (localDestination->GetIdentHash (), std::unique_ptr<I2PServerTunnel>(serverTunnel))).second)
|
||||
serverTunnel->Start ();
|
||||
else
|
||||
LogPrint (eLogError, "I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
|
||||
LogPrint (eLogError, "Clients: I2P server tunnel for destination ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), " already exists");
|
||||
numServerTunnels++;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Unknown section type=", type, " of ", name, " in ", TUNNELS_CONFIG_FILENAME);
|
||||
LogPrint (eLogWarning, "Clients: Unknown section type=", type, " of ", name, " in ", pathTunnelsConfigFile);
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Can't read tunnel ", name, " params: ", ex.what ());
|
||||
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, numClientTunnels, " I2P client tunnels created");
|
||||
LogPrint (eLogInfo, numServerTunnels, " I2P server tunnels created");
|
||||
LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created");
|
||||
LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,15 +21,17 @@ namespace client
|
||||
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_ADDRESS[] = "address";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination";
|
||||
const char I2P_CLIENT_TUNNEL_KEYS[] = "keys";
|
||||
const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
||||
const char I2P_SERVER_TUNNEL_KEYS[] = "keys";
|
||||
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
||||
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
||||
const char TUNNELS_CONFIG_FILENAME[] = "tunnels.cfg";
|
||||
|
||||
class ClientContext
|
||||
{
|
||||
@@ -48,7 +50,8 @@ namespace client
|
||||
const std::map<std::string, std::string> * params = nullptr);
|
||||
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||
std::shared_ptr<ClientDestination> LoadLocalDestination (const std::string& filename, bool isPublic);
|
||||
std::shared_ptr<ClientDestination> LoadLocalDestination (const std::string& filename, bool isPublic,
|
||||
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256);
|
||||
|
||||
AddressBook& GetAddressBook () { return m_AddressBook; };
|
||||
const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
|
||||
|
||||
103
Crypto.cpp
103
Crypto.cpp
@@ -1,11 +1,16 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "TunnelBase.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include "Log.h"
|
||||
//#include "TunnelBase.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace i2p
|
||||
@@ -66,7 +71,44 @@ namespace crypto
|
||||
|
||||
const int rsae_ = 65537;
|
||||
|
||||
const CryptoConstants& GetCryptoConstants ()
|
||||
struct CryptoConstants
|
||||
{
|
||||
// DH/ElGamal
|
||||
BIGNUM * elgp;
|
||||
BIGNUM * elgg;
|
||||
|
||||
// DSA
|
||||
BIGNUM * dsap;
|
||||
BIGNUM * dsaq;
|
||||
BIGNUM * dsag;
|
||||
|
||||
// RSA
|
||||
BIGNUM * rsae;
|
||||
|
||||
CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_,
|
||||
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_)
|
||||
{
|
||||
elgp = BN_new ();
|
||||
BN_bin2bn (elgp_, 256, elgp);
|
||||
elgg = BN_new ();
|
||||
BN_set_word (elgg, elgg_);
|
||||
dsap = BN_new ();
|
||||
BN_bin2bn (dsap_, 128, dsap);
|
||||
dsaq = BN_new ();
|
||||
BN_bin2bn (dsaq_, 20, dsaq);
|
||||
dsag = BN_new ();
|
||||
BN_bin2bn (dsag_, 128, dsag);
|
||||
rsae = BN_new ();
|
||||
BN_set_word (rsae, rsae_);
|
||||
}
|
||||
|
||||
~CryptoConstants ()
|
||||
{
|
||||
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
|
||||
}
|
||||
};
|
||||
|
||||
static const CryptoConstants& GetCryptoConstants ()
|
||||
{
|
||||
static CryptoConstants cryptoConstants (elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_);
|
||||
return cryptoConstants;
|
||||
@@ -81,6 +123,32 @@ namespace crypto
|
||||
return true;
|
||||
}
|
||||
|
||||
// RSA
|
||||
#define rsae GetCryptoConstants ().rsae
|
||||
const BIGNUM * GetRSAE ()
|
||||
{
|
||||
return rsae;
|
||||
}
|
||||
|
||||
// DSA
|
||||
#define dsap GetCryptoConstants ().dsap
|
||||
#define dsaq GetCryptoConstants ().dsaq
|
||||
#define dsag GetCryptoConstants ().dsag
|
||||
DSA * CreateDSA ()
|
||||
{
|
||||
DSA * dsa = DSA_new ();
|
||||
dsa->p = BN_dup (dsap);
|
||||
dsa->q = BN_dup (dsaq);
|
||||
dsa->g = BN_dup (dsag);
|
||||
dsa->priv_key = NULL;
|
||||
dsa->pub_key = NULL;
|
||||
return dsa;
|
||||
}
|
||||
|
||||
// DH/ElGamal
|
||||
#define elgp GetCryptoConstants ().elgp
|
||||
#define elgg GetCryptoConstants ().elgg
|
||||
|
||||
// DH
|
||||
|
||||
DHKeys::DHKeys (): m_IsUpdated (true)
|
||||
@@ -573,7 +641,7 @@ namespace crypto
|
||||
#else
|
||||
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
||||
m_LayerEncryption.SetIV (out);
|
||||
m_LayerEncryption.Encrypt (in + 16, /*i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE*/1008, out + 16); // data
|
||||
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
||||
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
||||
#endif
|
||||
}
|
||||
@@ -610,10 +678,37 @@ namespace crypto
|
||||
#else
|
||||
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
|
||||
m_LayerDecryption.SetIV (out);
|
||||
m_LayerDecryption.Decrypt (in + 16, /*i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE*/1008, out + 16); // data
|
||||
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
|
||||
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
|
||||
#endif
|
||||
}
|
||||
|
||||
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
||||
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
|
||||
{
|
||||
if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ())
|
||||
{
|
||||
if (mode & CRYPTO_LOCK)
|
||||
m_OpenSSLMutexes[type]->lock ();
|
||||
else
|
||||
m_OpenSSLMutexes[type]->unlock ();
|
||||
}
|
||||
}*/
|
||||
|
||||
void InitCrypto ()
|
||||
{
|
||||
SSL_library_init ();
|
||||
/* auto numLocks = CRYPTO_num_locks();
|
||||
for (int i = 0; i < numLocks; i++)
|
||||
m_OpenSSLMutexes.emplace_back (new std::mutex);
|
||||
CRYPTO_set_locking_callback (OpensslLockingCallback);*/
|
||||
}
|
||||
|
||||
void TerminateCrypto ()
|
||||
{
|
||||
/* CRYPTO_set_locking_callback (nullptr);
|
||||
m_OpenSSLMutexes.clear ();*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
55
Crypto.h
55
Crypto.h
@@ -6,64 +6,20 @@
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include "Base.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
struct CryptoConstants
|
||||
{
|
||||
// DH/ElGamal
|
||||
BIGNUM * elgp;
|
||||
BIGNUM * elgg;
|
||||
|
||||
// DSA
|
||||
BIGNUM * dsap;
|
||||
BIGNUM * dsaq;
|
||||
BIGNUM * dsag;
|
||||
|
||||
// RSA
|
||||
BIGNUM * rsae;
|
||||
|
||||
CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_,
|
||||
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_)
|
||||
{
|
||||
elgp = BN_new ();
|
||||
BN_bin2bn (elgp_, 256, elgp);
|
||||
elgg = BN_new ();
|
||||
BN_set_word (elgg, elgg_);
|
||||
dsap = BN_new ();
|
||||
BN_bin2bn (dsap_, 128, dsap);
|
||||
dsaq = BN_new ();
|
||||
BN_bin2bn (dsaq_, 20, dsaq);
|
||||
dsag = BN_new ();
|
||||
BN_bin2bn (dsag_, 128, dsag);
|
||||
rsae = BN_new ();
|
||||
BN_set_word (rsae, rsae_);
|
||||
}
|
||||
|
||||
~CryptoConstants ()
|
||||
{
|
||||
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
|
||||
}
|
||||
};
|
||||
|
||||
const CryptoConstants& GetCryptoConstants ();
|
||||
|
||||
// DH/ElGamal
|
||||
#define elgp GetCryptoConstants ().elgp
|
||||
#define elgg GetCryptoConstants ().elgg
|
||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
||||
|
||||
// DSA
|
||||
#define dsap GetCryptoConstants ().dsap
|
||||
#define dsaq GetCryptoConstants ().dsaq
|
||||
#define dsag GetCryptoConstants ().dsag
|
||||
DSA * CreateDSA ();
|
||||
|
||||
// RSA
|
||||
#define rsae GetCryptoConstants ().rsae
|
||||
|
||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
||||
const BIGNUM * GetRSAE ();
|
||||
|
||||
// DH
|
||||
class DHKeys
|
||||
@@ -316,6 +272,9 @@ namespace crypto
|
||||
CBCDecryption m_LayerDecryption;
|
||||
#endif
|
||||
};
|
||||
|
||||
void InitCrypto ();
|
||||
void TerminateCrypto ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
74
Daemon.cpp
74
Daemon.cpp
@@ -19,8 +19,7 @@
|
||||
#include "HTTPServer.h"
|
||||
#include "I2PControl.h"
|
||||
#include "ClientContext.h"
|
||||
// ssl.h somehow pulls Windows.h stuff that has to go after asio
|
||||
#include <openssl/ssl.h>
|
||||
#include "Crypto.h"
|
||||
|
||||
#ifdef USE_UPNP
|
||||
#include "UPnP.h"
|
||||
@@ -60,13 +59,12 @@ namespace i2p
|
||||
|
||||
bool Daemon_Singleton::init(int argc, char* argv[])
|
||||
{
|
||||
SSL_library_init ();
|
||||
i2p::crypto::InitCrypto ();
|
||||
i2p::util::config::OptionParser(argc, argv);
|
||||
i2p::context.Init ();
|
||||
|
||||
LogPrint("\n\n\n\ni2pd starting\n");
|
||||
LogPrint("Version ", VERSION);
|
||||
LogPrint("data directory: ", i2p::util::filesystem::GetDataDir().string());
|
||||
LogPrint(eLogInfo, "\n\n\n\ni2pd v", VERSION, " starting\n");
|
||||
LogPrint(eLogDebug, "data directory: ", i2p::util::filesystem::GetDataDir().string());
|
||||
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||
|
||||
isDaemon = i2p::util::config::GetArg("-daemon", 0);
|
||||
@@ -75,24 +73,29 @@ namespace i2p
|
||||
int port = i2p::util::config::GetArg("-port", 0);
|
||||
if (port)
|
||||
i2p::context.UpdatePort (port);
|
||||
const char * host = i2p::util::config::GetCharArg("-host", "");
|
||||
if (host && host[0])
|
||||
std::string host = i2p::util::config::GetArg("-host", "");
|
||||
if (host != "")
|
||||
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
|
||||
|
||||
i2p::context.SetSupportsV6 (i2p::util::config::GetArg("-v6", 0));
|
||||
i2p::context.SetFloodfill (i2p::util::config::GetArg("-floodfill", 0));
|
||||
i2p::context.SetAcceptsTunnels (!i2p::util::config::GetArg("-notransit", 0));
|
||||
bool isFloodfill = i2p::util::config::GetArg("-floodfill", 0);
|
||||
i2p::context.SetFloodfill (isFloodfill);
|
||||
auto bandwidth = i2p::util::config::GetArg("-bandwidth", "");
|
||||
if (bandwidth.length () > 0)
|
||||
{
|
||||
if (bandwidth[0] > 'L')
|
||||
if (bandwidth[0] > 'O')
|
||||
i2p::context.SetExtraBandwidth ();
|
||||
else if (bandwidth[0] > 'L')
|
||||
i2p::context.SetHighBandwidth ();
|
||||
else
|
||||
i2p::context.SetLowBandwidth ();
|
||||
}
|
||||
|
||||
LogPrint("CMD parameters:");
|
||||
else if (isFloodfill)
|
||||
i2p::context.SetExtraBandwidth ();
|
||||
LogPrint(eLogDebug, "Daemon: CMD parameters:");
|
||||
for (int i = 0; i < argc; ++i)
|
||||
LogPrint(i, " ", argv[i]);
|
||||
LogPrint(eLogDebug, i, ": ", argv[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -111,61 +114,68 @@ namespace i2p
|
||||
logfile_path.append("\\i2pd.log");
|
||||
#endif
|
||||
StartLog (logfile_path);
|
||||
}
|
||||
else
|
||||
} else {
|
||||
StartLog (""); // write to stdout
|
||||
}
|
||||
g_Log->SetLogLevel(i2p::util::config::GetArg("-loglevel", "info"));
|
||||
}
|
||||
|
||||
d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070)));
|
||||
LogPrint(eLogInfo, "Daemon: staring HTTP Server");
|
||||
d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpaddress", "127.0.0.1"), i2p::util::config::GetArg("-httpport", 7070)));
|
||||
d.httpServer->Start();
|
||||
LogPrint("HTTP Server started");
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting NetDB");
|
||||
i2p::data::netdb.Start();
|
||||
LogPrint("NetDB started");
|
||||
|
||||
#ifdef USE_UPNP
|
||||
LogPrint(eLogInfo, "Daemon: starting UPnP");
|
||||
d.m_UPnP.Start ();
|
||||
LogPrint(eLogInfo, "UPnP started");
|
||||
#endif
|
||||
LogPrint(eLogInfo, "Daemon: starting Transports");
|
||||
i2p::transport::transports.Start();
|
||||
LogPrint("Transports started");
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting Tunnels");
|
||||
i2p::tunnel::tunnels.Start();
|
||||
LogPrint("Tunnels started");
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting Client");
|
||||
i2p::client::context.Start ();
|
||||
LogPrint("Client started");
|
||||
|
||||
// I2P Control
|
||||
int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0);
|
||||
if (i2pcontrolPort)
|
||||
{
|
||||
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcontrolPort));
|
||||
LogPrint(eLogInfo, "Daemon: starting I2PControl");
|
||||
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2p::util::config::GetArg("-i2pcontroladdress", "127.0.0.1"), i2pcontrolPort));
|
||||
d.m_I2PControlService->Start ();
|
||||
LogPrint("I2PControl started");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::stop()
|
||||
{
|
||||
LogPrint("Shutdown started.");
|
||||
LogPrint(eLogInfo, "Daemon: shutting down");
|
||||
LogPrint(eLogInfo, "Daemon: stopping Client");
|
||||
i2p::client::context.Stop();
|
||||
LogPrint("Client stopped");
|
||||
LogPrint(eLogInfo, "Daemon: stopping Tunnels");
|
||||
i2p::tunnel::tunnels.Stop();
|
||||
LogPrint("Tunnels stopped");
|
||||
#ifdef USE_UPNP
|
||||
LogPrint(eLogInfo, "Daemon: stopping UPnP");
|
||||
d.m_UPnP.Stop ();
|
||||
LogPrint(eLogInfo, "UPnP stopped");
|
||||
#endif
|
||||
LogPrint(eLogInfo, "Daemon: stopping Transports");
|
||||
i2p::transport::transports.Stop();
|
||||
LogPrint("Transports stopped");
|
||||
LogPrint(eLogInfo, "Daemon: stopping NetDB");
|
||||
i2p::data::netdb.Stop();
|
||||
LogPrint("NetDB stopped");
|
||||
LogPrint(eLogInfo, "Daemon: stopping HTTP Server");
|
||||
d.httpServer->Stop();
|
||||
d.httpServer = nullptr;
|
||||
LogPrint("HTTP Server stopped");
|
||||
if (d.m_I2PControlService)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: stopping I2PControl");
|
||||
d.m_I2PControlService->Stop ();
|
||||
d.m_I2PControlService = nullptr;
|
||||
LogPrint("I2PControl stopped");
|
||||
}
|
||||
i2p::crypto::TerminateCrypto ();
|
||||
StopLog ();
|
||||
|
||||
return true;
|
||||
|
||||
2
Daemon.h
2
Daemon.h
@@ -63,7 +63,7 @@ namespace i2p
|
||||
virtual bool stop();
|
||||
private:
|
||||
std::string pidfile;
|
||||
int pidFilehandle;
|
||||
int pidFH;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -17,17 +17,8 @@ void handle_signal(int sig)
|
||||
switch (sig)
|
||||
{
|
||||
case SIGHUP:
|
||||
if (i2p::util::config::GetArg("daemon", 0) == 1)
|
||||
{
|
||||
static bool first=true;
|
||||
if (first)
|
||||
{
|
||||
first=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogPrint("Reloading config.");
|
||||
i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
|
||||
LogPrint(eLogInfo, "Daemon: Got SIGHUP, doing nothing");
|
||||
// TODO:
|
||||
break;
|
||||
case SIGABRT:
|
||||
case SIGTERM:
|
||||
@@ -52,18 +43,25 @@ namespace i2p
|
||||
::exit (EXIT_SUCCESS);
|
||||
|
||||
if (pid < 0) // error
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// child
|
||||
umask(0);
|
||||
umask(S_IWGRP | S_IRWXO); // 0027
|
||||
int sid = setsid();
|
||||
if (sid < 0)
|
||||
{
|
||||
LogPrint("Error, could not create process group.");
|
||||
LogPrint(eLogError, "Daemon: could not create process group.");
|
||||
return false;
|
||||
}
|
||||
std::string d(i2p::util::filesystem::GetDataDir().string ()); // make a copy
|
||||
chdir(d.c_str());
|
||||
if (chdir(d.c_str()) != 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// close stdin/stdout/stderr descriptors
|
||||
::close (0);
|
||||
@@ -75,22 +73,29 @@ namespace i2p
|
||||
}
|
||||
|
||||
// Pidfile
|
||||
pidfile = IsService () ? "/var/run" : i2p::util::filesystem::GetDataDir().string();
|
||||
pidfile.append("/i2pd.pid");
|
||||
pidFilehandle = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
|
||||
if (pidFilehandle == -1)
|
||||
{
|
||||
LogPrint("Error, could not create pid file (", pidfile, ")\nIs an instance already running?");
|
||||
return false;
|
||||
// this code is c-styled and a bit ugly, but we need fd for locking pidfile
|
||||
pidfile = i2p::util::config::GetArg("-pidfile", "");
|
||||
if (pidfile != "") {
|
||||
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
|
||||
if (pidFH < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
char pid[10];
|
||||
sprintf(pid, "%d\n", getpid());
|
||||
ftruncate(pidFH, 0);
|
||||
if (write(pidFH, pid, strlen(pid)) < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (lockf(pidFilehandle, F_TLOCK, 0) == -1)
|
||||
{
|
||||
LogPrint("Error, could not lock pid file (", pidfile, ")\nIs an instance already running?");
|
||||
return false;
|
||||
}
|
||||
char pid[10];
|
||||
sprintf(pid, "%d\n", getpid());
|
||||
write(pidFilehandle, pid, strlen(pid));
|
||||
|
||||
// Signal handler
|
||||
struct sigaction sa;
|
||||
@@ -107,7 +112,6 @@ namespace i2p
|
||||
|
||||
bool DaemonLinux::stop()
|
||||
{
|
||||
close(pidFilehandle);
|
||||
unlink(pidfile.c_str());
|
||||
|
||||
return Daemon_Singleton::stop();
|
||||
|
||||
@@ -49,17 +49,17 @@ namespace i2p
|
||||
|
||||
if (isDaemon == 1)
|
||||
{
|
||||
LogPrint("Service session");
|
||||
LogPrint(eLogDebug, "Daemon: running as service");
|
||||
I2PService service(SERVICE_NAME);
|
||||
if (!I2PService::Run(service))
|
||||
{
|
||||
LogPrint("Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else
|
||||
LogPrint("User session");
|
||||
LogPrint(eLogDebug, "Daemon: running as user");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -80,4 +80,4 @@ namespace i2p
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
16
Datagram.cpp
16
Datagram.cpp
@@ -48,15 +48,13 @@ namespace datagram
|
||||
m_Owner->RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg));
|
||||
}
|
||||
|
||||
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, I2NPMessage * msg)
|
||||
void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> remote, std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (remote)
|
||||
SendMsg (msg, remote);
|
||||
else
|
||||
DeleteI2NPMessage (msg);
|
||||
}
|
||||
|
||||
void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
|
||||
void DatagramDestination::SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote)
|
||||
{
|
||||
auto outboundTunnel = m_Owner->GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||
auto leases = remote->GetNonExpiredLeases ();
|
||||
@@ -64,7 +62,7 @@ namespace datagram
|
||||
{
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
uint32_t i = rand () % leases.size ();
|
||||
auto garlic = m_Owner->WrapMessage (remote, ToSharedI2NPMessage (msg), true);
|
||||
auto garlic = m_Owner->WrapMessage (remote, msg, true);
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
@@ -79,7 +77,6 @@ namespace datagram
|
||||
LogPrint (eLogWarning, "Failed to send datagram. All leases expired");
|
||||
else
|
||||
LogPrint (eLogWarning, "Failed to send datagram. No outbound tunnels");
|
||||
DeleteI2NPMessage (msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,9 +120,9 @@ namespace datagram
|
||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||
}
|
||||
|
||||
I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPMessage ();
|
||||
auto msg = NewI2NPMessage ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
buf += 4; // reserve for length
|
||||
size_t size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
|
||||
@@ -139,10 +136,7 @@ namespace datagram
|
||||
msg->FillI2NPMessageHeader (eI2NPData);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteI2NPMessage (msg);
|
||||
msg = nullptr;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ namespace datagram
|
||||
|
||||
private:
|
||||
|
||||
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, I2NPMessage * msg);
|
||||
void HandleLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
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);
|
||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||
void SendMsg (std::shared_ptr<I2NPMessage> msg, std::shared_ptr<const i2p::data::LeaseSet> remote);
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
134
Destination.cpp
134
Destination.cpp
@@ -19,7 +19,10 @@ namespace client
|
||||
m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0),
|
||||
m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service)
|
||||
{
|
||||
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
if (m_IsPublic)
|
||||
PersistTemporaryKeys ();
|
||||
else
|
||||
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
|
||||
int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
|
||||
int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY;
|
||||
@@ -34,7 +37,7 @@ namespace client
|
||||
if (len > 0)
|
||||
{
|
||||
inboundTunnelLen = len;
|
||||
LogPrint (eLogInfo, "Inbound tunnel length set to ", len);
|
||||
LogPrint (eLogInfo, "Destination: Inbound tunnel length set to ", len);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH);
|
||||
@@ -44,7 +47,7 @@ namespace client
|
||||
if (len > 0)
|
||||
{
|
||||
outboundTunnelLen = len;
|
||||
LogPrint (eLogInfo, "Outbound tunnel length set to ", len);
|
||||
LogPrint (eLogInfo, "Destination: Outbound tunnel length set to ", len);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY);
|
||||
@@ -54,7 +57,7 @@ namespace client
|
||||
if (quantity > 0)
|
||||
{
|
||||
inboundTunnelsQuantity = quantity;
|
||||
LogPrint (eLogInfo, "Inbound tunnels quantity set to ", quantity);
|
||||
LogPrint (eLogInfo, "Destination: Inbound tunnels quantity set to ", quantity);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
|
||||
@@ -64,7 +67,7 @@ namespace client
|
||||
if (quantity > 0)
|
||||
{
|
||||
outboundTunnelsQuantity = quantity;
|
||||
LogPrint (eLogInfo, "Outbound tunnels quantity set to ", quantity);
|
||||
LogPrint (eLogInfo, "Destination: Outbound tunnels quantity set to ", quantity);
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
|
||||
@@ -79,14 +82,14 @@ namespace client
|
||||
ident.FromBase64 (b64);
|
||||
explicitPeers->push_back (ident);
|
||||
}
|
||||
LogPrint (eLogInfo, "Explicit peers set to ", it->second);
|
||||
LogPrint (eLogInfo, "Destination: Explicit peers set to ", it->second);
|
||||
}
|
||||
}
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this, inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inboundTunnelLen, outboundTunnelLen, inboundTunnelsQuantity, outboundTunnelsQuantity);
|
||||
if (explicitPeers)
|
||||
m_Pool->SetExplicitPeers (explicitPeers);
|
||||
if (m_IsPublic)
|
||||
LogPrint (eLogInfo, "Local address ", GetIdentHash().ToBase32 (), " created");
|
||||
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
||||
}
|
||||
|
||||
ClientDestination::~ClientDestination ()
|
||||
@@ -94,7 +97,8 @@ namespace client
|
||||
if (m_IsRunning)
|
||||
Stop ();
|
||||
for (auto it: m_LeaseSetRequests)
|
||||
delete it.second;
|
||||
if (it.second->requestComplete) it.second->requestComplete (nullptr);
|
||||
m_LeaseSetRequests.clear ();
|
||||
if (m_Pool)
|
||||
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
|
||||
if (m_DatagramDestination)
|
||||
@@ -111,7 +115,7 @@ namespace client
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("Destination: ", ex.what ());
|
||||
LogPrint (eLogError, "Destination: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +125,7 @@ namespace client
|
||||
if (!m_IsRunning)
|
||||
{
|
||||
m_IsRunning = true;
|
||||
m_Pool->SetLocalDestination (this);
|
||||
m_Pool->SetLocalDestination (shared_from_this ());
|
||||
m_Pool->SetActive (true);
|
||||
m_Thread = new std::thread (std::bind (&ClientDestination::Run, this));
|
||||
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (shared_from_this ()); // TODO:
|
||||
@@ -174,7 +178,7 @@ namespace client
|
||||
if (it->second->HasNonExpiredLeases ())
|
||||
return it->second;
|
||||
else
|
||||
LogPrint ("All leases of remote LeaseSet expired");
|
||||
LogPrint (eLogWarning, "Destination: All leases of remote LeaseSet expired");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -198,7 +202,7 @@ namespace client
|
||||
|
||||
void ClientDestination::UpdateLeaseSet ()
|
||||
{
|
||||
m_LeaseSet.reset (new i2p::data::LeaseSet (*m_Pool));
|
||||
m_LeaseSet.reset (new i2p::data::LeaseSet (m_Pool));
|
||||
}
|
||||
|
||||
bool ClientDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
|
||||
@@ -255,7 +259,7 @@ namespace client
|
||||
size_t offset = DATABASE_STORE_HEADER_SIZE;
|
||||
if (replyToken)
|
||||
{
|
||||
LogPrint (eLogInfo, "Reply token is ignored for DatabaseStore");
|
||||
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
|
||||
offset += 36;
|
||||
}
|
||||
std::shared_ptr<i2p::data::LeaseSet> leaseSet;
|
||||
@@ -292,14 +296,13 @@ namespace client
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ". Dropped");
|
||||
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
|
||||
|
||||
auto it1 = m_LeaseSetRequests.find (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
if (it1 != m_LeaseSetRequests.end ())
|
||||
{
|
||||
it1->second->requestTimeoutTimer.cancel ();
|
||||
if (it1->second->requestComplete) it1->second->requestComplete (leaseSet);
|
||||
delete it1->second;
|
||||
m_LeaseSetRequests.erase (it1);
|
||||
}
|
||||
}
|
||||
@@ -308,11 +311,11 @@ namespace client
|
||||
{
|
||||
i2p::data::IdentHash key (buf);
|
||||
int num = buf[32]; // num
|
||||
LogPrint ("DatabaseSearchReply for ", key.ToBase64 (), " num=", num);
|
||||
LogPrint (eLogDebug, "Destination: DatabaseSearchReply for ", key.ToBase64 (), " num=", num);
|
||||
auto it = m_LeaseSetRequests.find (key);
|
||||
if (it != m_LeaseSetRequests.end ())
|
||||
{
|
||||
LeaseSetRequest * request = it->second;
|
||||
auto request = it->second;
|
||||
bool found = false;
|
||||
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
|
||||
{
|
||||
@@ -322,30 +325,29 @@ namespace client
|
||||
auto floodfill = i2p::data::netdb.FindRouter (peerHash);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint (eLogInfo, "Requesting ", key.ToBase64 (), " at ", peerHash.ToBase64 ());
|
||||
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", peerHash.ToBase64 ());
|
||||
if (SendLeaseSetRequest (key, floodfill, request))
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "Found new floodfill. Request it");
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); // TODO: recheck this message
|
||||
i2p::data::netdb.RequestDestination (peerHash);
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
LogPrint (eLogError, "Suggested floodfills are not presented in netDb");
|
||||
LogPrint (eLogError, "Destination: Suggested floodfills are not presented in netDb");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST," floodfills");
|
||||
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
|
||||
if (!found)
|
||||
{
|
||||
if (request->requestComplete) request->requestComplete (nullptr);
|
||||
delete request;
|
||||
m_LeaseSetRequests.erase (key);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint ("Request for ", key.ToBase64 (), " not found");
|
||||
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
@@ -353,7 +355,7 @@ namespace client
|
||||
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||
if (msgID == m_PublishReplyToken)
|
||||
{
|
||||
LogPrint (eLogDebug, "Publishing confirmed");
|
||||
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed");
|
||||
m_ExcludedFloodfills.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
}
|
||||
@@ -373,30 +375,30 @@ namespace client
|
||||
{
|
||||
if (!m_LeaseSet || !m_Pool)
|
||||
{
|
||||
LogPrint (eLogError, "Can't publish non-existing LeaseSet");
|
||||
LogPrint (eLogError, "Destination: Can't publish non-existing LeaseSet");
|
||||
return;
|
||||
}
|
||||
if (m_PublishReplyToken)
|
||||
{
|
||||
LogPrint (eLogInfo, "Publishing is pending");
|
||||
LogPrint (eLogDebug, "Destination: Publishing LeaseSet is pending");
|
||||
return;
|
||||
}
|
||||
auto outbound = m_Pool->GetNextOutboundTunnel ();
|
||||
if (!outbound)
|
||||
{
|
||||
LogPrint ("Can't publish LeaseSet. No outbound tunnels");
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
|
||||
return;
|
||||
}
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (m_LeaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||
if (!floodfill)
|
||||
{
|
||||
LogPrint ("Can't publish LeaseSet. No more floodfills found");
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
m_ExcludedFloodfills.clear ();
|
||||
return;
|
||||
}
|
||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||
LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||
auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken));
|
||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||
@@ -411,7 +413,7 @@ namespace client
|
||||
{
|
||||
if (m_PublishReplyToken)
|
||||
{
|
||||
LogPrint (eLogWarning, "Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, "seconds. Try again");
|
||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
|
||||
m_PublishReplyToken = 0;
|
||||
Publish ();
|
||||
}
|
||||
@@ -434,7 +436,7 @@ namespace client
|
||||
if (dest)
|
||||
dest->HandleDataMessagePayload (buf, length);
|
||||
else
|
||||
LogPrint ("Missing streaming destination");
|
||||
LogPrint (eLogError, "Destination: Missing streaming destination");
|
||||
}
|
||||
break;
|
||||
case PROTOCOL_TYPE_DATAGRAM:
|
||||
@@ -442,10 +444,10 @@ namespace client
|
||||
if (m_DatagramDestination)
|
||||
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length);
|
||||
else
|
||||
LogPrint ("Missing streaming destination");
|
||||
LogPrint (eLogError, "Destination: Missing datagram destination");
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Data: unexpected protocol ", buf[9]);
|
||||
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,52 +529,61 @@ namespace client
|
||||
{
|
||||
if (!m_Pool || !IsReady ())
|
||||
{
|
||||
if (requestComplete) requestComplete (false);
|
||||
if (requestComplete) requestComplete (nullptr);
|
||||
return false;
|
||||
}
|
||||
m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientDestination::CancelDestinationRequest (const i2p::data::IdentHash& dest)
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([dest, s](void)
|
||||
{
|
||||
auto it = s->m_LeaseSetRequests.find (dest);
|
||||
if (it != s->m_LeaseSetRequests.end ())
|
||||
s->m_LeaseSetRequests.erase (it);
|
||||
});
|
||||
}
|
||||
|
||||
void ClientDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete)
|
||||
{
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
LeaseSetRequest * request = new LeaseSetRequest (m_Service);
|
||||
auto request = std::make_shared<LeaseSetRequest> (m_Service);
|
||||
request->requestComplete = requestComplete;
|
||||
auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, LeaseSetRequest *>(dest,request));
|
||||
auto ret = m_LeaseSetRequests.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> >(dest,request));
|
||||
if (ret.second) // inserted
|
||||
{
|
||||
if (!SendLeaseSetRequest (dest, floodfill, request))
|
||||
{
|
||||
// request failed
|
||||
if (request->requestComplete) request->requestComplete (nullptr);
|
||||
delete request;
|
||||
m_LeaseSetRequests.erase (dest);
|
||||
}
|
||||
}
|
||||
else // duplicate
|
||||
{
|
||||
LogPrint (eLogError, "Request of ", dest.ToBase64 (), " is pending already");
|
||||
LogPrint (eLogWarning, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
|
||||
// TODO: queue up requests
|
||||
if (request->requestComplete) request->requestComplete (nullptr);
|
||||
delete request;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "No floodfills found");
|
||||
LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found");
|
||||
}
|
||||
|
||||
bool ClientDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, LeaseSetRequest * request)
|
||||
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
|
||||
{
|
||||
auto replyTunnel = m_Pool->GetNextInboundTunnel ();
|
||||
if (!replyTunnel) LogPrint (eLogError, "No inbound tunnels found");
|
||||
if (!replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
|
||||
|
||||
auto outboundTunnel = m_Pool->GetNextOutboundTunnel ();
|
||||
if (!outboundTunnel) LogPrint (eLogError, "No outbound tunnels found");
|
||||
if (!outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
|
||||
|
||||
if (replyTunnel && outboundTunnel)
|
||||
{
|
||||
@@ -624,14 +635,13 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
|
||||
LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (done)
|
||||
{
|
||||
if (it->second->requestComplete) it->second->requestComplete (false);
|
||||
delete it->second;
|
||||
if (it->second->requestComplete) it->second->requestComplete (nullptr);
|
||||
m_LeaseSetRequests.erase (it);
|
||||
}
|
||||
}
|
||||
@@ -656,12 +666,40 @@ namespace client
|
||||
{
|
||||
if (!it->second->HasNonExpiredLeases ()) // all leases expired
|
||||
{
|
||||
LogPrint ("Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
it = m_RemoteLeaseSets.erase (it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::PersistTemporaryKeys ()
|
||||
{
|
||||
auto path = i2p::util::filesystem::GetDefaultDataDir() / "destinations";
|
||||
auto filename = path / (GetIdentHash ().ToBase32 () + ".dat");
|
||||
std::ifstream f(filename.string (), std::ifstream::binary);
|
||||
if (f)
|
||||
{
|
||||
f.read ((char *)m_EncryptionPublicKey, 256);
|
||||
f.read ((char *)m_EncryptionPrivateKey, 256);
|
||||
}
|
||||
if (!f)
|
||||
{
|
||||
LogPrint (eLogInfo, "Creating new temporary keys for address ", GetIdentHash ().ToBase32 ());
|
||||
i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
if (!boost::filesystem::exists (path))
|
||||
{
|
||||
if (!boost::filesystem::create_directory (path))
|
||||
LogPrint (eLogError, "Failed to create destinations directory");
|
||||
}
|
||||
std::ofstream f1 (filename.string (), std::ofstream::binary | std::ofstream::out);
|
||||
if (f1)
|
||||
{
|
||||
f1.write ((char *)m_EncryptionPublicKey, 256);
|
||||
f1.write ((char *)m_EncryptionPrivateKey, 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace client
|
||||
const int PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int LEASESET_REQUEST_TIMEOUT = 5; // in seconds
|
||||
const int MAX_LEASESET_REQUEST_TIMEOUT = 40; // in seconds
|
||||
const int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
||||
const int DESTINATION_CLEANUP_TIMEOUT = 20; // in minutes
|
||||
const unsigned int MAX_NUM_FLOODFILLS_PER_REQUEST = 7;
|
||||
|
||||
// I2CP
|
||||
const char I2CP_PARAM_INBOUND_TUNNEL_LENGTH[] = "inbound.length";
|
||||
@@ -73,6 +73,7 @@ namespace client
|
||||
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);
|
||||
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
|
||||
void CancelDestinationRequest (const i2p::data::IdentHash& dest);
|
||||
|
||||
// streaming
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port); // additional
|
||||
@@ -118,11 +119,12 @@ namespace client
|
||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
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, std::shared_ptr<LeaseSetRequest> request);
|
||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
void CleanupRemoteLeaseSets ();
|
||||
|
||||
void PersistTemporaryKeys ();
|
||||
|
||||
private:
|
||||
|
||||
volatile bool m_IsRunning;
|
||||
@@ -132,7 +134,7 @@ namespace client
|
||||
i2p::data::PrivateKeys m_Keys;
|
||||
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::map<i2p::data::IdentHash, LeaseSetRequest *> m_LeaseSetRequests;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||
std::shared_ptr<i2p::data::LeaseSet> m_LeaseSet;
|
||||
|
||||
48
Garlic.cpp
48
Garlic.cpp
@@ -61,7 +61,7 @@ namespace garlic
|
||||
if (msgID == m_LeaseSetUpdateMsgID)
|
||||
{
|
||||
m_LeaseSetUpdateStatus = eLeaseSetUpToDate;
|
||||
LogPrint (eLogInfo, "LeaseSet update confirmed");
|
||||
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
|
||||
}
|
||||
else
|
||||
CleanupExpiredTags ();
|
||||
@@ -112,7 +112,7 @@ namespace garlic
|
||||
|
||||
std::shared_ptr<I2NPMessage> GarlicRoutingSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
auto m = ToSharedI2NPMessage(NewI2NPMessage ());
|
||||
auto m = NewI2NPMessage ();
|
||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||
size_t len = 0;
|
||||
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||
@@ -139,10 +139,10 @@ namespace garlic
|
||||
// create message
|
||||
if (!tagFound) // new session
|
||||
{
|
||||
LogPrint ("No garlic tags available. Use ElGamal");
|
||||
LogPrint (eLogWarning, "Garlic: No tags available. Use ElGamal");
|
||||
if (!m_Destination)
|
||||
{
|
||||
LogPrint ("Can't use ElGamal for unknown destination");
|
||||
LogPrint (eLogError, "Garlic: Can't use ElGamal for unknown destination");
|
||||
return nullptr;
|
||||
}
|
||||
// create ElGamal block
|
||||
@@ -237,7 +237,7 @@ namespace garlic
|
||||
m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
|
||||
}
|
||||
else
|
||||
LogPrint ("DeliveryStatus clove was not created");
|
||||
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
|
||||
}
|
||||
// attach LeaseSet
|
||||
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
|
||||
@@ -337,10 +337,10 @@ namespace garlic
|
||||
size += 3;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "No inbound tunnels in the pool for DeliveryStatus");
|
||||
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
|
||||
}
|
||||
else
|
||||
LogPrint ("Missing local LeaseSet");
|
||||
LogPrint (eLogWarning, "Garlic: Missing local LeaseSet");
|
||||
|
||||
return size;
|
||||
}
|
||||
@@ -372,7 +372,7 @@ namespace garlic
|
||||
uint32_t length = bufbe32toh (buf);
|
||||
if (length > msg->GetLength ())
|
||||
{
|
||||
LogPrint (eLogError, "Garlic message length ", length, " exceeds I2NP message length ", msg->GetLength ());
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
|
||||
return;
|
||||
}
|
||||
buf += 4; // length
|
||||
@@ -389,7 +389,7 @@ namespace garlic
|
||||
HandleAESBlock (buf + 32, length - 32, it->second, msg->from);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Garlic message length ", length, " is less than 32 bytes");
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
|
||||
m_Tags.erase (it); // tag might be used only once
|
||||
}
|
||||
else
|
||||
@@ -407,7 +407,7 @@ namespace garlic
|
||||
HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Failed to decrypt garlic");
|
||||
LogPrint (eLogError, "Garlic: Failed to decrypt message");
|
||||
}
|
||||
|
||||
// cleanup expired tags
|
||||
@@ -427,7 +427,7 @@ namespace garlic
|
||||
else
|
||||
it++;
|
||||
}
|
||||
LogPrint (numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
|
||||
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ());
|
||||
}
|
||||
m_LastTagsCleanupTime = ts;
|
||||
}
|
||||
@@ -442,7 +442,7 @@ namespace garlic
|
||||
{
|
||||
if (tagCount*32 > len)
|
||||
{
|
||||
LogPrint (eLogError, "Tag count ", tagCount, " exceeds length ", len);
|
||||
LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len);
|
||||
return ;
|
||||
}
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
@@ -454,7 +454,7 @@ namespace garlic
|
||||
uint32_t payloadSize = bufbe32toh (buf);
|
||||
if (payloadSize > len)
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected payload size ", payloadSize);
|
||||
LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize);
|
||||
return;
|
||||
}
|
||||
buf += 4;
|
||||
@@ -469,7 +469,7 @@ namespace garlic
|
||||
SHA256 (buf, payloadSize, digest);
|
||||
if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match
|
||||
{
|
||||
LogPrint ("Wrong payload hash");
|
||||
LogPrint (eLogError, "Garlic: wrong payload hash");
|
||||
return;
|
||||
}
|
||||
HandleGarlicPayload (buf, payloadSize, from);
|
||||
@@ -479,7 +479,7 @@ namespace garlic
|
||||
{
|
||||
const uint8_t * buf1 = buf;
|
||||
int numCloves = buf[0];
|
||||
LogPrint (numCloves," cloves");
|
||||
LogPrint (eLogDebug, "Garlic: ", numCloves," cloves");
|
||||
buf++;
|
||||
for (int i = 0; i < numCloves; i++)
|
||||
{
|
||||
@@ -489,24 +489,24 @@ namespace garlic
|
||||
if (flag & 0x80) // encrypted?
|
||||
{
|
||||
// TODO: implement
|
||||
LogPrint ("Clove encrypted");
|
||||
LogPrint (eLogWarning, "Garlic: clove encrypted");
|
||||
buf += 32;
|
||||
}
|
||||
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
|
||||
switch (deliveryType)
|
||||
{
|
||||
case eGarlicDeliveryTypeLocal:
|
||||
LogPrint ("Garlic type local");
|
||||
LogPrint (eLogDebug, "Garlic: type local");
|
||||
HandleI2NPMessage (buf, len, from);
|
||||
break;
|
||||
case eGarlicDeliveryTypeDestination:
|
||||
LogPrint ("Garlic type destination");
|
||||
LogPrint (eLogDebug, "Garlic: type destination");
|
||||
buf += 32; // destination. check it later or for multiple destinations
|
||||
HandleI2NPMessage (buf, len, from);
|
||||
break;
|
||||
case eGarlicDeliveryTypeTunnel:
|
||||
{
|
||||
LogPrint ("Garlic type tunnel");
|
||||
LogPrint (eLogDebug, "Garlic: type tunnel");
|
||||
// gwHash and gwTunnel sequence is reverted
|
||||
uint8_t * gwHash = buf;
|
||||
buf += 32;
|
||||
@@ -521,15 +521,15 @@ namespace garlic
|
||||
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg);
|
||||
}
|
||||
else
|
||||
LogPrint ("No outbound tunnels available for garlic clove");
|
||||
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
||||
break;
|
||||
}
|
||||
case eGarlicDeliveryTypeRouter:
|
||||
LogPrint ("Garlic type router not supported");
|
||||
LogPrint (eLogWarning, "Garlic: type router not supported");
|
||||
buf += 32;
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Unknow garlic delivery type ", (int)deliveryType);
|
||||
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
|
||||
}
|
||||
buf += GetI2NPMessageLength (buf); // I2NP
|
||||
buf += 4; // CloveID
|
||||
@@ -537,7 +537,7 @@ namespace garlic
|
||||
buf += 3; // Certificate
|
||||
if (buf - buf1 > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic clove is too long");
|
||||
LogPrint (eLogError, "Garlic: clove is too long");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -601,7 +601,7 @@ namespace garlic
|
||||
{
|
||||
it->second->MessageConfirmed (msgID);
|
||||
m_CreatedSessions.erase (it);
|
||||
LogPrint (eLogInfo, "Garlic message ", msgID, " acknowledged");
|
||||
LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,8 +285,8 @@ namespace proxy
|
||||
}
|
||||
}
|
||||
|
||||
HTTPProxyServer::HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
||||
TCPIPAcceptor(port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
||||
HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
|
||||
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace proxy
|
||||
{
|
||||
public:
|
||||
|
||||
HTTPProxyServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||
HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||
~HTTPProxyServer() {};
|
||||
|
||||
protected:
|
||||
|
||||
445
HTTPServer.cpp
445
HTTPServer.cpp
@@ -1,3 +1,5 @@
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
@@ -174,293 +176,7 @@ namespace util
|
||||
|
||||
const std::string HTTPConnection::itoopieFavicon =
|
||||
"data:image/vnd.microsoft.icon;base64,"
|
||||
"AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAABsAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgQAAAIMAAACEAAAAg"
|
||||
"wAAAIAAAACCAAAASQAAACUAAAAmAAAAOwAAAFIAAABgAAAAVAAAACcAAAAVAAAADQAAAAcAAAADAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACjAAAA/wAAAP4AAAD+AAAA/gAAAP4AAAD+A"
|
||||
"AAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/"
|
||||
"AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAACbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAP8AA"
|
||||
"AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4A"
|
||||
"AAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/wAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAKQAAAAAAAAAAAAAAAADbAAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP8AAAD/AAAA/gAA"
|
||||
"AP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAIA/gAAAPwAAAD/AAAA/gAAAP4AAAD+AAAA/gA"
|
||||
"AAP4AAAD+AAAA/wAAAFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAApAAAAAAAAAAAAHAAAAP8AAAD+AAAA/gAAAPwACwD9ABEA"
|
||||
"/QASAPgAFgD4ABUA+AATAP0ADQD8AAIA/AAAAP8AAAD+AAAA/gAAAP8ADQD7ACMA/QAlAP8AJwD/ACI"
|
||||
"A/QATAPwAAAD8AAAA/gAAAP4AAAD+AAAA/gAAAKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADe"
|
||||
"AAAA/gAAAPwAJAD+AAwA+wAAAP8AAAD/AAAA/wAEAPwAEgD8ACQA/gAmAP8AHAD8AAEA/gAAAP4ACwD"
|
||||
"8ACUA/wAkAP8AFwD8AAkA/AAQAP0AIwD+ACQA/wANAPsAAAD+AAAA/gAAAP8AAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAEAAABNAAAA/wAAAP8AGAD8AAAA/QAYAPMARQDyAFEA9wBOAPIAPAD0ABEA8QAAAP8"
|
||||
"AGgD7ACMA/wAVAP0AAAD9ACMA/QAkAP8ADwD9AAgA+ABBAPUALADyAAAA/AAUAPwAJgD/ABgA/AAAAP"
|
||||
"0AAAD/AAAAdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+AAAAP4ADQD8AAgA/wAqAPAAcAD/AGoA/wB"
|
||||
"qAP8AagD/AGoA/wBvAP8ATwDvAAAA/QAbAP0AEwD8AAYA/QAkAP8AGAD8AAsA9wBuAPgAagD/AGsA/w"
|
||||
"BjAPkADAD3AAQA/QAiAP4AGgD9AAAA/gAAAP8AAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZgAAAP8AAAD+ABY"
|
||||
"A+wAQAPQAcQD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBTAPEAAAD/AAcA/AAMAPwAIQD9AA"
|
||||
"AA+gBoAPgAagD/AGoA/wBqAP8AagD/AHAA/gAuAO0AAAD/AB8A/QAPAPwAAAD+AAAA+AAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAANIAAAD+AAwA+QAAAP0AZQD1AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8Abg"
|
||||
"D/ABcA8QAAAP4ACAD9AAAA+QBeAPkAagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AbQD/ADkA7wAAAP8AJ"
|
||||
"AD9AAAA/gAAAP8AAAAfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAALi8AAAAAAAAAAAAAAAD/AAAA/QAAAP8AKwD1AGsA/wBqAP8AagD/AGoA/wBqAP"
|
||||
"8AagD/AGoA/wBqAP8AagD/AGoA/wA9APUAAAD/AAAA/wBKAPMAagD/AGoA/wBqAP8AagD/AGoA/wBqA"
|
||||
"P8AagD/AGoA/wBxAP8ADgD1ABMA/AAHAPsAAAD/AAAARQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzPAIAAAAgAAAA/wAAAPwAAAD/AGQA9A"
|
||||
"BqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8ASQD1AAAA/wASAPMAcAD/AGoA/"
|
||||
"wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AawD/ACsA+QAOAP4ADQD8AAAA/wAAAEUAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7gAAAAAAAADgwAQAYLwAA//8AAA"
|
||||
"ICIwAAAP8AAAD+AAYA8wBwAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/A"
|
||||
"EIA9QAAAP8AMADvAGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGsA/wApAP0AEQD8"
|
||||
"AAIA/QAAAP8AAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAVgEAAA"
|
||||
"AAACJ5AQA2ygAAND8BAHV+AgAAAAAAAAH/AAAA/gAcAPQAbAD/AGoA/wBqAP8AagD/AGoA/wBqAP8Aa"
|
||||
"gD/AGoA/wBqAP8AagD/AGsA/wApAPYAAAD+AB4A+gBsAP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8A"
|
||||
"agD/AGoA/wBrAP8ALADxAAAA/AAAAP4AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAABYAhQAfAE8ABgBWAQAAAAAAIoABAAAAAAA5UgEAAAAAAAAA+AAAAP4AJQD2AGsA/wBqA"
|
||||
"P8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBsAPgAAAD6AAAA/gANAPAAbgD/AGoA/wBq"
|
||||
"AP8AagD/AGoA/wBqAP8AagD/AGoA/wBqAP8AagD/ADsA+QAAAP8AAAD+AAAA4AAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtQAAAAAAAABYABgAZgEGAIMBAAAAAAA+fgEAAAAAAAAAA"
|
||||
"AACA8wAAAH+ACkA9wBgAPgARQDwADoA9gA5APYASgD0AHAA9wBrAP8AagD/AGoA/wBxAP0AFQD0AAAA"
|
||||
"/gAAAP4AAAD5AHMA/QBqAP8AagD/AGoA/wBqAP8AagD/AGoA/wBvAP0ATgDxAEwA9AA1AOkAAAD/AAA"
|
||||
"A/gAAAP8AAAB3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAvAAzAKcBAADXAAAAAAAcAFYBF"
|
||||
"gB4ASAAZwEAXT8BADpdAgAAAAAAAQG+AAEB/gAAAf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAPsAJAD1"
|
||||
"AEQA9ABEAPMACQD3AAAA/wAAAP4AAAD+AAAA/wAiAPMASAD4AE8A9gBuAPgAbQD/AGoA/wBvAP8AFQD"
|
||||
"yAAAA/wAAAP8AAAD/AAAA/gAAAP4AAAD+AAAA/wAAABoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAABgCuAQAAAAAAAAAAAAAAACEAkQIWAJMBGQBXAQCWlAIAAAAAAAAA7gABAf4AAQD+AAAA/wAAAP8A"
|
||||
"AAD0AAAA/gAAAP8AAAD/AAAA/gAAAP8AAAD/AAAA/gAAAP4IAAn9JwAs/TsARP5CAEz+PQBG/ioAMP4"
|
||||
"EAAX6ABkA9gBAAPUAUwDrAAAA/wADEfUAFXztAA5U9wAAAPcAAAD/AAAA/gAAAP4AAACYAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAABcAugAkALIAAAAAAAAAAAAJABQAHwCaAR8AhwMNKUwCAAMDRgAB"
|
||||
"Af8AAAD+AAAA+QAbn/MAK/zwACz//wAs//cAIMDkAAAA+QAAAP4AAAD+CAAK/V0Aav6TAKn+nQC0/5c"
|
||||
"Arf+VAKv/lACq/5QAq/+WAK3/nwC3/4IAlv5FAE/+AAAA/wAAAP8AHKnzACnx/wAq9v8ALP/5AAo+9A"
|
||||
"AAAP4AAAD+AAAA7QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACtAQAAAAAAAKoACABt"
|
||||
"AQwAYwAAAAAAAQAERQAAAP8AAAD+AAAA/wAfuPEAKfL/ACnz/wAq+v8AIsrwAAEH9gAAAP4AAAD+JAA"
|
||||
"p/ZoAsf+TAKj/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/lACq/0sAVv4AAAD/AC"
|
||||
"PQ8gAp8/8AKfP/ACny/wAYke4AAAD/AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAgAAAAK0AAAAAAGsA/wAAAAAAAAACSgAAAf8AAQH+AAAA/gAAAP8AGZHnACfm+AAdqvIACjz"
|
||||
"tAAAA/wAAAP4AAAD+CgAL/ZwAtP+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAK"
|
||||
"n/kwCp/5IAqP9OAFn+AAAA/wAetPMAKfP/ACny/wAq+PcAAQfyAAAA/gAAAP4AAAD/AAAAEgAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKkAAAAAAAUAFwAAAAAAAAABeQAAAP8AAAH+AAAA/wMBBf0"
|
||||
"AAAH+AAAA/wAAAP8AAAD/AAEB/gAAAP4AAAD9AAAB/k4AWv6SAKj/kwCp/5MAqf+TAKn/kwCp/5MAqf"
|
||||
"+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/ZwB2/gAAAP4ACC32ACHC9AAZk/AAAQX3AAAA/gAAA"
|
||||
"P4AAAD+AAAA/wAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAYQEAAAAAAAAAwAA"
|
||||
"AAP8BAAH+EwAV/YkAnfJ6AIzzBQAH/QAAAP4AAAD+AAEB/gARF/0Aa5P9AMb//gACAv4oAC7+lwCu/5"
|
||||
"MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5oAsv8YABv9AAAA/"
|
||||
"gAAAP8AAAD/AAAA/ksAVv0SABX9AAAA/gAAAP8AAABmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAEAAAATAAAA6AAAAP0AAAD+IgAo+5oAsfCSAKnxlQCr8RYAGvwAAQH+AAAA/gAAAP4AQFf9AL"
|
||||
"r//wC3/P8AXn79AAAA/o8ApP6TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/k"
|
||||
"wCp/5MAqf+TAKn/mgCx/0QATv4AAAD+AAAA/gAAAP2gALj/WQBn/gAAAP4AAAD+AAAAtwAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAA9gAAAP0AAAD+HwAk+5wAs/CSAKnxkwCp8VEAXfcAAA"
|
||||
"D+AAAB/gAAAP4AAQH+AAAA/QDD//8At/v/ALDz/gAAAP5aAGf+kwCo/5MAqf+TAKn/kwCp/5MAqf+TA"
|
||||
"Kn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf9sAHz+AAAA/gAAAP4AAAD9nwC3/5YArf8A"
|
||||
"AAD+AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2AAAAP0AAAD+AAAA/pgAr/"
|
||||
"CTAKnxkwCp8ZIAqPGHAJvyAAAA/wAAAP4AAAD+AAEB/gAAAP4Ae6X9ALb7/wC+//8AJjX9KgAw/ZcAr"
|
||||
"f+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/mQCv/wAA"
|
||||
"AP4AAAD+AAAA/Z8Atv+YAK//HwAk/QAAAP4AAAD/AAAAZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHA"
|
||||
"AAAP8AAAD+AAAA/gAAAP+RAKbxkgCo8ZMAqfGTAKnxkgCo8XYAiPQEAAX+AAAA/yUAK/sBAAH+ACg3/"
|
||||
"QC+//8Atvr/AG6W/QAAAP6YAK//kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp"
|
||||
"/5MAqf+TAKn/kwCp/5MAqf9oAHf+AAAA/kAASf6UAKv/kwCp/0cAUv4AAAD+AAAA/gAAAMkAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAACRAAAA/wAAAP4AAAD+BQAG/nsAjfOUAKrxkwCp8ZMAqfGTAKjxn"
|
||||
"QC08JcArvCYAK/xSQBU9wAAAP4Aqen+ALf7/wC3+v4AAAD+WwBo/pMAqf+TAKn/kwCp/5MAqf+TAKn/"
|
||||
"kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5wAs/6ZAK//kwCp/5MAqf9bAGj"
|
||||
"+AAAA/gAAAP4AAAD/AAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE0AAAD7AAAA/QAAAP4AA"
|
||||
"AD/TABY+J0AtPCTAKnxkwCp8ZMAqfGTAKnxkwCp8Y4ApPEAAAD/AFRx/QC4/P8Avf//AC0+/RQAGP2c"
|
||||
"ALP/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+"
|
||||
"TAKn/kwCp/5MAqf+TAKn/YQBv/wAAAP4AAAD+AAAA/wAAAG0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAABAAAAAAAAALgAAAD/AAAA/gABAP4bAB78jwCk8pMAqfGTAKnxkwCp8ZMAqfGXAK3xKwAy+wAC"
|
||||
"BP0Axv//ALb6/wBvlf0AAAD+dwCJ/p8Atv+dALT+lgCt/p4Atv6eALb/lwCu/5MAqf+TAKn/kwCp/5M"
|
||||
"Aqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCo/1IAXv0AAAD+AAAA/gAAAP4AAACRAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATgAAAP8AAAD9AAAB/gAAAP5ZAGf2ngC1"
|
||||
"8JMAqfGTAKnxkwCp8WAAb/UAAAD+AJLH/gC3+/8As/X+AAAA/gsADP0AAAD9AAAA/gAAAP4AAAD+AQA"
|
||||
"C/SMAKP1NAFj+gQCU/pwAs/+TAKn/kwCp/5MAqf+TAKn/kwCp/5MAqf+TAKn/kwCp/5sAsv8cACH9AA"
|
||||
"AA/gAAAP4AAAD/AAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO"
|
||||
"AAAA1QAAAP8AAAD+AAAA/hMAFfxzAIT0nQC08JMAqfF5AIrzAAAA/gA6T/0Au///ALn//wBkh/4AERj"
|
||||
"9ACs7/QBFX/0AT2z9AElk/gAxQ/0AAgT9AAAA/gAAAP4UABf9bwCA/pcArv+TAKn/kwCp/5MAqf+TAK"
|
||||
"n/kwCp/5MAqv9rAHr+AAAA/gAAAP4AAAD/AAAAhgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+AAAA/wAAAP4AAAD+AAAA/hQAF/xJAFP4GwAf/AAAAP4"
|
||||
"ABgn9AMP//wC3+/8Auf7/AML//wC8//8Auf7/ALj9/wC5/v8AvP//AMb//wCj4P0AWnj9AAAA/QAAAP"
|
||||
"42AD/9mgCx/5MAqP+TAKn/lACq/54Atv9YAGX+AAAA/gAAAP4AAAD/AAAArAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAh4AAADVAAAA/gA"
|
||||
"AAP4AAAD+AAAA/gAAAP4AEhr9AJ3V/gC3+v8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/w"
|
||||
"C3+/8At/v/ALf8/wDB//8AYYT9AAAA/ggACv1cAGn+bAB9/UEAS/4CAAL+AAAA/gAAAP4AAAD/AAAAl"
|
||||
"gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAABAAEBFAAAAP8AAAD+AAAA/gAAAP4AUGz9AML//wC2+/8At/v/ALf7/wC3+/8At/v/AL"
|
||||
"f7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf8/wCq5v4AERj+AAEA/gAAAP4AAAD+A"
|
||||
"AAA/gAAAP4AAAD/AAAAdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOgAAAD+AAAA/gAAAP4Aeqf9ALz//wC3+/8At/"
|
||||
"v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At"
|
||||
"/r/ALz//gAcJvwAAQH+AAAA/gAAAP4AAAD/AAAAfwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI0AAAD/AAAA/gAAAP"
|
||||
"4Ac579ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+"
|
||||
"/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Avf/+ABcg/QAAAf4AAAD+AAAA/wAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAABIAAAD/AAAA/gAAAP4AP1X9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/"
|
||||
"wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wCy8v4AAAD+AAAA"
|
||||
"/gAAAP8AAACKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAACoAAAA/QAAAP4ABAb9AL7//wC3+/8At/v/ALf7/wC3+/8At/v/A"
|
||||
"Lf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/"
|
||||
"ALf7/wC3+/8Atvr/AHmm/QAAAP4AAAD+AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA/wAAAP4AAAD+AHWh/QC2+v8At"
|
||||
"/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8A"
|
||||
"t/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDD//8AGSP9AAAA/gAAAP8AAABuAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAA"
|
||||
"P8AAAD+AAUH/QDE//8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3"
|
||||
"+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atvv/AH+s/gA"
|
||||
"AAP4AAAD+AAAA2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAALMAAAD+AAAA/gBZd/0At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7"
|
||||
"/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf"
|
||||
"7/wC3+/8At/v/ALf7/wDF//8AAAD9AAAA/gAAAP8AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwAAAA/gAAAP4Al9D9ALf7/wC3+/8At/v/"
|
||||
"ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v"
|
||||
"/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Auf7/AERe/QAAAP4AAAD/AAAAUQAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAP4A"
|
||||
"AAD9AMb//gC3+/8At/v/ALf7/wC3+/8Auf7/AMb//gC2+f4AwP/+AMT//wC4/f8At/v/ALf7/wC3+/8"
|
||||
"At/v/ALf7/wC3+/8At/v/ALf7/wC8//8Avf//ALn+/wC3+/8At/v/ALf7/wC3+/8At/v/ALb7/wBvlf"
|
||||
"4AAAD+AAAA/gAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAACgAAAP8AAAD+ABgg/QDA//8At/v/ALf7/wC2+v8AuPz+AEVe/QAAAP0AAAD+AAAA/gA"
|
||||
"EBv0AU2/9ALz//wC3+/8At/v/ALf7/wC3+/8Atvr/AL7//wBmi/0ALj/9ACQx/QBJZP0Ai739AMD//w"
|
||||
"C3+/8At/v/ALf7/wC3+/8Aksj+AAAA/gAAAP4AAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABcAAAD/AAAA/gAtPf4AvP//ALf7/wC3+/8As/T+AAo"
|
||||
"O/QAAAP0SEhLtAAAA/gAAAP4AAAD+AAAA/gAWH/0Av///ALf7/wC3+/8At/v/ALHx/gANEv0AAAD+AA"
|
||||
"AA/gAAAP4AAAD/AAAA/wAuP/0Avv//ALf7/wC3+/8At/v/AKjm/QAAAP4AAAD+AAAApwAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAA/wAAAP4AL0H"
|
||||
"+ALz//wC3+/8AvP//ADJE/QAAAPfc3Nz1TExM6wAAAP4AAAD+AAAA/gAAAP8AAAD+AGeN/gC3+/8At/"
|
||||
"v/AML//wAeKf0AAAH/AAAA/gAAAP4AAAD+cXFx3YSEhOoAAAD9AEVe/QC6//8At/v/ALf7/wCs7P8AA"
|
||||
"AD+AAAA/gAAAKEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAP8AAAD+ACAt/QC+//8At/v/ALP1/gAAAP95eXns/////2FhYeoBAQH/AAAA/gEBAf"
|
||||
"9eXl7lDQ0N9gAgLP0Av///ALf7/wCNwf4AAAD/NDQ03AAAAP8AAAD+AAAA/6Ojo+b/////eXl55AAAA"
|
||||
"P8AtPf+ALf7/wC3+/8AoNv9AAAA/gAAAP4AAACHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAAA/gAAAP0Ax///ALf7/wCIu/0AAAD/ysrK6/"
|
||||
"/////8/Pz6Hx8f6wAAAP8kJCTm/f39/WVlZe4ABAX8AMT//wC3/P8AV3X9ERER7/////9MTEzrAAAA6"
|
||||
"ElJSeb///////////X19e8AAAD/AHuo/QC3+/8At/v/AIW2/gAAAP4AAAD/AAAAZAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0wAAAP4AAAD+AK"
|
||||
"fl/gC3+/8AjcH+AAAA/83Nze/////////////////////w//////////9gYGDsAA8V/QDC//8Auv//A"
|
||||
"EJa/UFBQeb////////////////////////////////////vAAAA/wBvlfwAt/v/ALf7/wBdff0AAAD+"
|
||||
"AAAA/wAAAC0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAI4AAAD+AAAA/gBnjP0At/v/ALz//gAAAP+CgoLx/////////////////////////////"
|
||||
"///CAkJ8QBCXP4Auf7/ALj8/wBScf0DAwPw////////////////////////////////tra26AAAAP8A"
|
||||
"hrf+ALf7/wDA//8AHCf9AAAA/gAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3AAAA/wAAAP4AEBb9AMT//wC6//8AQVn+AAAA9+Pj4"
|
||||
"/L/////////////////////cnJy1gAAAP8AlMr9ALf7/wC3+/8AhLT+AAAA/5mZmeL/////////////"
|
||||
"/////////////R0dHesAAAD9AL///gC3+/8ApuX+AAAA/gAAAP4AAAC1AAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPMAAAD+AAAA/"
|
||||
"gCGtv0Atvr/ALn+/wARF/0AAAD3cHBw7bGxseqioqLuOjo67QAAAP8ARFz9ALz//wC3+/8At/v/AML/"
|
||||
"/wAbJf0AAAD/jo6O5v////b//////f397zw8PPEAAAD/AGCC/QC4/P8Auv//AEJb/QAAAP4AAAD/AAA"
|
||||
"AUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAABpAAAA/wAAAP4AERf9AMP//wC3+/8Auv/+AEVf/AAAAP8AAAD/AAAA/wAAAP0AWnn9"
|
||||
"AMH//wC3+/8At/v/ALf7/wC3+/8AtPf+ABsm/QAAAP8AAADwDg4O+QAAAPwAAAD+AD1T/QDB//8At/v"
|
||||
"/AKLd/gAAAP4AAAD+AAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPIAAAD+AAAA/gBfgP0Auf7/ALf7/wC5/v8A"
|
||||
"wv//AJnS/gCWzv4Awf//ALj9/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wDC//8Ahbb+AFBt/QA3TP0"
|
||||
"ATGn9AI/D/gC+//8At/v/AMD//wATGv0AAAD+AAAA/wAAAE4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAA9AAAA/wAA"
|
||||
"AP4AAAD+AJPJ/QC2+v8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC"
|
||||
"3+/8At/v/ALf7/wC4/f8Au///ALj9/wC3+/8At/v/AML//wA0SP0AAAD+AAAA/QAAAMMAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAJYAAAD/AAAA/gAAAP4Andj9ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf"
|
||||
"7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/AML//wA+Vf0AAAD+AA"
|
||||
"AA/gAAAPYAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwwAAAP4AAAD+AAAA/gCGt/0AvP/"
|
||||
"/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/8Atv"
|
||||
"r/ALr//gAoNv0AAAD+AAAA/gAAAP8AAAAeAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAC9AAAA/wAAAP4AAAD+AEFY/QC6/f4At/z/ALf7/wC3+/8At/v/ALf7/wC3+/8At/v/ALf7/wC3+/"
|
||||
"8At/v/ALf7/wC2+v8Aw///AICv/gAEBv0AAAH+AAAA/QAAAP8AAAAiAAAAAQAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIMAAAD/AAAA/gAAAP4AAAD9AFl3/QCt7/4AwP//ALj9/w"
|
||||
"C2+/8At/v/ALf7/wC3+/8At/v/ALz//wDB//4AeKP+ABki/QAAAP4AAAD+AAAA/wAAAOEAAAASAAAAA"
|
||||
"QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAOUAAAD/AA"
|
||||
"AA/gAAAP4AAAD+ABcg/QBQbv0AbJD9AH2s/gCBsP0Ac5v+AFt6/QAtPv0AAAD9AAAA/gAAAP4AAAD+A"
|
||||
"AAA/wAAAIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAWgAAAOIAAAD/AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AA"
|
||||
"AD+AAAA/gAAAP8AAAD/AAAAmQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAIgAAADRAAAA/wAAA"
|
||||
"P8AAAD/AAAA/wAAAP8AAAD/AAAA5QAAAJoAAABWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAIAAAACQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA///gAf///////4AAAAD/////wAAAAP////"
|
||||
"/AAAAB/////+AAAAH/////4AAAA//////gAAAD/////8AAAAH/////wAAAAP////+AAAAA/////4AAA"
|
||||
"AD/////gAAAAP////+AAAAA/////4AAAAD/////gAAAAP////+AAAAA/////4AAAAB/////gAAAAD//"
|
||||
"//+AAAAAP////wAAAAA////+AAAAAD////wAAAAAP///8AAAAAA////gAAAAAB///8AAAAAAH///gAA"
|
||||
"AAAAf//+AAAAAAA///4AAAAAAD///4AAAAAAP///wAAAAAAf///wAAAAAD////gAAAAAP////gAAAAB"
|
||||
"/////AAAAAP////+AAAAD/////wAAAAf////+AAAAB/////4AAAAD/////AAAAAP////8AAAAA/////"
|
||||
"wAAAAB////+AAAAAH////4AAAAAf////gAAAAA////+AAAAAD////4AAAAAP////gAAAAA////+AAAA"
|
||||
"AD////4AAAAAf////gAAAAB////+AAAAAH////8AAAAAf////wAAAAD/////gAAAAP////+AAAAB///"
|
||||
"//8AAAAH/////wAAAA//////gAAAH//////AAAA//////+AAAH//////+AAA///////+AAP///////+"
|
||||
"AH//////////////8=";
|
||||
"";
|
||||
|
||||
const char HTTP_COMMAND_TUNNELS[] = "tunnels";
|
||||
const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels";
|
||||
@@ -488,21 +204,25 @@ namespace util
|
||||
std::vector<boost::asio::const_buffer> buffers;
|
||||
if (headers.size () > 0)
|
||||
{
|
||||
status_string = "HTTP/1.1 ";
|
||||
status_string += std::to_string (status);
|
||||
status_string += " ";
|
||||
switch (status)
|
||||
{
|
||||
case 105: buffers.push_back(boost::asio::buffer("HTTP/1.1 105 Name Not Resolved\r\n")); break;
|
||||
case 200: buffers.push_back(boost::asio::buffer("HTTP/1.1 200 OK\r\n")); break;
|
||||
case 400: buffers.push_back(boost::asio::buffer("HTTP/1.1 400 Bad Request\r\n")); break;
|
||||
case 404: buffers.push_back(boost::asio::buffer("HTTP/1.1 404 Not Found\r\n")); break;
|
||||
case 408: buffers.push_back(boost::asio::buffer("HTTP/1.1 408 Request Timeout\r\n")); break;
|
||||
case 500: buffers.push_back(boost::asio::buffer("HTTP/1.1 500 Internal Server Error\r\n")); break;
|
||||
case 502: buffers.push_back(boost::asio::buffer("HTTP/1.1 502 Bad Gateway\r\n")); break;
|
||||
case 503: buffers.push_back(boost::asio::buffer("HTTP/1.1 503 Not Implemented\r\n")); break;
|
||||
case 504: buffers.push_back(boost::asio::buffer("HTTP/1.1 504 Gateway Timeout\r\n")); break;
|
||||
default:
|
||||
buffers.push_back(boost::asio::buffer("HTTP/1.1 200 OK\r\n"));
|
||||
case 105: status_string += "Name Not Resolved"; break;
|
||||
case 200: status_string += "OK"; break;
|
||||
case 400: status_string += "Bad Request"; break;
|
||||
case 404: status_string += "Not Found"; break;
|
||||
case 408: status_string += "Request Timeout"; break;
|
||||
case 500: status_string += "Internal Server Error"; break;
|
||||
case 502: status_string += "Bad Gateway"; break;
|
||||
case 503: status_string += "Not Implemented"; break;
|
||||
case 504: status_string += "Gateway Timeout"; break;
|
||||
default: status_string += "WTF";
|
||||
}
|
||||
|
||||
buffers.push_back(boost::asio::buffer(status_string, status_string.size()));
|
||||
buffers.push_back(boost::asio::buffer(misc_strings::crlf));
|
||||
|
||||
for (std::size_t i = 0; i < headers.size(); ++i)
|
||||
{
|
||||
header& h = headers[i];
|
||||
@@ -520,14 +240,9 @@ namespace util
|
||||
void HTTPConnection::Terminate ()
|
||||
{
|
||||
if (!m_Stream) return;
|
||||
m_Socket->close ();
|
||||
m_Stream->Close ();
|
||||
|
||||
m_Socket->get_io_service ().post ([=](void)
|
||||
{
|
||||
m_Stream.reset ();
|
||||
m_Stream = nullptr;
|
||||
});
|
||||
m_Stream = nullptr;
|
||||
m_Socket->close ();
|
||||
}
|
||||
|
||||
void HTTPConnection::Receive ()
|
||||
@@ -596,7 +311,7 @@ namespace util
|
||||
{
|
||||
end = str.find ('&', pos);
|
||||
std::string param = str.substr (pos, end - pos);
|
||||
LogPrint (param);
|
||||
LogPrint (eLogDebug, "HTTPServer: extracted parameters: ", param);
|
||||
size_t e = param.find ('=');
|
||||
if (e != std::string::npos)
|
||||
params[param.substr(0, e)] = param.substr(e+1);
|
||||
@@ -631,10 +346,20 @@ namespace util
|
||||
std::stringstream s;
|
||||
// Html5 head start
|
||||
s << "<!DOCTYPE html>\n<html lang=\"en\">"; // TODO: Add support for locale.
|
||||
s << "<head><meta charset=\"utf-8\" />"; // TODO: Find something to parse html/template system. This is horrible.
|
||||
s << "<link rel='shortcut icon' href='";
|
||||
s << itoopieFavicon;
|
||||
s << "' /><title>Purple I2P " << VERSION " Webconsole</title></head>";
|
||||
s << "<head><meta charset=\"utf-8\">"; // TODO: Find something to parse html/template system. This is horrible.
|
||||
// s << "<link rel='shortcut icon' href='";
|
||||
// s << itoopieFavicon;
|
||||
// s << "' />";
|
||||
s << "<title>Purple I2P " << VERSION " Webconsole</title>";
|
||||
s << "<style>";
|
||||
s << "body {font: 100%/1.5em sans-serif; margin: 0; padding: 0; background: #FAFAFA;}";
|
||||
s << "a {text-decoration: none;}";
|
||||
s << "body, a {color: #103456}";
|
||||
s << ".header {font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84;}";
|
||||
s << ".wrapper {margin: 0 auto; padding: 1em; max-width: 48em;}";
|
||||
s << ".left {width: 28em; float:left;}";
|
||||
s << "</style>";
|
||||
s << "</head>";
|
||||
// Head end
|
||||
if (address.length () > 1)
|
||||
HandleCommand (address.substr (2), s);
|
||||
@@ -646,7 +371,9 @@ namespace util
|
||||
|
||||
void HTTPConnection::FillContent (std::stringstream& s)
|
||||
{
|
||||
s << "<h2>Welcome to the Webconsole!</h2><br>";
|
||||
s << "<div class=header><b>i2pd </b>webconsole</div>";
|
||||
s << "<div class=wrapper>";
|
||||
s << "<div class=left>";
|
||||
s << "<b>Uptime:</b> " << boost::posix_time::to_simple_string (
|
||||
boost::posix_time::time_duration (boost::posix_time::seconds (
|
||||
i2p::context.GetUptime ()))) << "<br>";
|
||||
@@ -687,25 +414,22 @@ namespace util
|
||||
}
|
||||
s << address.host.to_string() << ":" << address.port << "<br>";
|
||||
}
|
||||
s << "<br><b>Routers:</b> <i>" << i2p::data::netdb.GetNumRouters () << "</i> ";
|
||||
s << "<b>Floodfills:</b> <i>" << i2p::data::netdb.GetNumFloodfills () << "</i> ";
|
||||
s << "<b>LeaseSets:</b> <i>" << i2p::data::netdb.GetNumLeaseSets () << "</i><br>";
|
||||
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_LOCAL_DESTINATIONS << ">Local destinations</a></b>";
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_TUNNELS << ">Tunnels</a></b>";
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_TRANSIT_TUNNELS << ">Transit tunnels</a></b>";
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_TRANSPORTS << ">Transports</a></b>";
|
||||
s << "<br><b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>";
|
||||
s << "</div><div>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_LOCAL_DESTINATIONS << ">Local destinations</a> ]<br>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_TUNNELS << ">Tunnels</a> ]<br>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_TRANSIT_TUNNELS << ">Transit tunnels</a> ]<br>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_TRANSPORTS << ">Transports</a> ]<br>";
|
||||
if (i2p::client::context.GetSAMBridge ())
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_SAM_SESSIONS << ">SAM sessions</a></b>";
|
||||
s << "<br>";
|
||||
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_SAM_SESSIONS << ">SAM sessions</a> ]<br><br>";
|
||||
if (i2p::context.AcceptsTunnels ())
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << ">Stop accepting tunnels</a></b><br>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_STOP_ACCEPTING_TUNNELS << ">Stop accepting tunnels</a> ]<br><br>";
|
||||
else
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << ">Start accepting tunnels</a></b><br>";
|
||||
s << "<br><b><a href=/?" << HTTP_COMMAND_RUN_PEER_TEST << ">Run peer test</a></b><br>";
|
||||
|
||||
s << "<p><a href=\"zmw2cyw2vj7f6obx3msmdvdepdhnw2ctc4okza2zjxlukkdfckhq.b32.i2p\">Flibusta</a></p>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_START_ACCEPTING_TUNNELS << ">Start accepting tunnels</a> ]<br><br>";
|
||||
s << "[ <a href=/?" << HTTP_COMMAND_RUN_PEER_TEST << ">Run peer test</a> ]<br><br>";
|
||||
s << "</div></div></body>";
|
||||
}
|
||||
|
||||
void HTTPConnection::HandleCommand (const std::string& command, std::stringstream& s)
|
||||
@@ -771,7 +495,6 @@ namespace util
|
||||
s << "<br>SSU<br>";
|
||||
for (auto it: ssuServer->GetSessions ())
|
||||
{
|
||||
// incoming connections don't have remote router
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second->IsOutgoing ()) s << "-->";
|
||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||
@@ -779,8 +502,17 @@ namespace util
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
if (it.second->GetRelayTag ())
|
||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||
s << "<br>";
|
||||
s << std::endl;
|
||||
s << "<br>" << std::endl;
|
||||
}
|
||||
s << "<br>SSU6<br>";
|
||||
for (auto it: ssuServer->GetSessionsV6 ())
|
||||
{
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second->IsOutgoing ()) s << "-->";
|
||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||
if (!it.second->IsOutgoing ()) s << "-->";
|
||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||
s << "<br>" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -958,8 +690,8 @@ namespace util
|
||||
|
||||
void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri)
|
||||
{
|
||||
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n";
|
||||
LogPrint("HTTP Client Request: ", request);
|
||||
std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n\r\n";
|
||||
LogPrint(eLogDebug, "HTTPServer: client request: ", request);
|
||||
SendToAddress (address, 80, request.c_str (), request.size ());
|
||||
}
|
||||
|
||||
@@ -968,7 +700,7 @@ namespace util
|
||||
i2p::data::IdentHash destination;
|
||||
if (!i2p::client::context.GetAddressBook ().GetIdentHash (address, destination))
|
||||
{
|
||||
LogPrint ("Unknown address ", address);
|
||||
LogPrint (eLogWarning, "HTTPServer: Unknown address ", address);
|
||||
SendReply ("<html>" + itoopieImage + "<br>Unknown address " + address + "</html>", 404);
|
||||
return;
|
||||
}
|
||||
@@ -1040,22 +772,28 @@ namespace util
|
||||
void HTTPConnection::SendReply (const std::string& content, int status)
|
||||
{
|
||||
m_Reply.content = content;
|
||||
m_Reply.headers.resize(2);
|
||||
m_Reply.headers[0].name = "Content-Length";
|
||||
m_Reply.headers[0].value = boost::lexical_cast<std::string>(m_Reply.content.size());
|
||||
m_Reply.headers[1].name = "Content-Type";
|
||||
m_Reply.headers[1].value = "text/html";
|
||||
|
||||
m_Reply.headers.resize(3);
|
||||
// we need the date header to be complaint with http 1.1
|
||||
std::time_t time_now = std::time(nullptr);
|
||||
char time_buff[128];
|
||||
if (std::strftime(time_buff, sizeof(time_buff), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&time_now)))
|
||||
{
|
||||
m_Reply.headers[0].name = "Date";
|
||||
m_Reply.headers[0].value = std::string(time_buff);
|
||||
m_Reply.headers[1].name = "Content-Length";
|
||||
m_Reply.headers[1].value = boost::lexical_cast<std::string>(m_Reply.content.size());
|
||||
m_Reply.headers[2].name = "Content-Type";
|
||||
m_Reply.headers[2].value = "text/html";
|
||||
}
|
||||
|
||||
boost::asio::async_write (*m_Socket, m_Reply.to_buffers(status),
|
||||
std::bind (&HTTPConnection::HandleWriteReply, shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
HTTPServer::HTTPServer (int port):
|
||||
HTTPServer::HTTPServer (const std::string& address, int port):
|
||||
m_Thread (nullptr), m_Work (m_Service),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
||||
m_NewSocket (nullptr)
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
HTTPServer::~HTTPServer ()
|
||||
@@ -1065,7 +803,7 @@ namespace util
|
||||
|
||||
void HTTPServer::Start ()
|
||||
{
|
||||
m_Thread = new std::thread (std::bind (&HTTPServer::Run, this));
|
||||
m_Thread = std::unique_ptr<std::thread>(new std::thread (std::bind (&HTTPServer::Run, this)));
|
||||
m_Acceptor.listen ();
|
||||
Accept ();
|
||||
}
|
||||
@@ -1077,7 +815,6 @@ namespace util
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1089,25 +826,27 @@ namespace util
|
||||
|
||||
void HTTPServer::Accept ()
|
||||
{
|
||||
m_NewSocket = new boost::asio::ip::tcp::socket (m_Service);
|
||||
m_Acceptor.async_accept (*m_NewSocket, boost::bind (&HTTPServer::HandleAccept, this,
|
||||
boost::asio::placeholders::error));
|
||||
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
|
||||
m_Acceptor.async_accept (*newSocket, boost::bind (&HTTPServer::HandleAccept, this,
|
||||
boost::asio::placeholders::error, newSocket));
|
||||
}
|
||||
|
||||
void HTTPServer::HandleAccept(const boost::system::error_code& ecode)
|
||||
void HTTPServer::HandleAccept(const boost::system::error_code& ecode,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
CreateConnection(m_NewSocket);
|
||||
CreateConnection(newSocket);
|
||||
Accept ();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServer::CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket)
|
||||
void HTTPServer::CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
|
||||
{
|
||||
auto conn = std::make_shared<HTTPConnection> (m_NewSocket);
|
||||
auto conn = std::make_shared<HTTPConnection> (newSocket);
|
||||
conn->Receive ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
18
HTTPServer.h
18
HTTPServer.h
@@ -39,17 +39,15 @@ namespace util
|
||||
struct reply
|
||||
{
|
||||
std::vector<header> headers;
|
||||
std::string content;
|
||||
|
||||
std::string status_string, content;
|
||||
std::vector<boost::asio::const_buffer> to_buffers (int status);
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
HTTPConnection (boost::asio::ip::tcp::socket * socket):
|
||||
HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket):
|
||||
m_Socket (socket), m_Timer (socket->get_io_service ()),
|
||||
m_Stream (nullptr), m_BufferLen (0) {};
|
||||
~HTTPConnection() { delete m_Socket; }
|
||||
void Receive ();
|
||||
|
||||
private:
|
||||
@@ -81,7 +79,7 @@ namespace util
|
||||
|
||||
protected:
|
||||
|
||||
boost::asio::ip::tcp::socket * m_Socket;
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
std::shared_ptr<i2p::stream::Stream> m_Stream;
|
||||
char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1], m_StreamBuffer[HTTP_CONNECTION_BUFFER_SIZE + 1];
|
||||
@@ -108,7 +106,7 @@ namespace util
|
||||
{
|
||||
public:
|
||||
|
||||
HTTPServer (int port);
|
||||
HTTPServer (const std::string& address, int port);
|
||||
virtual ~HTTPServer ();
|
||||
|
||||
void Start ();
|
||||
@@ -118,18 +116,18 @@ namespace util
|
||||
|
||||
void Run ();
|
||||
void Accept ();
|
||||
void HandleAccept(const boost::system::error_code& ecode);
|
||||
void HandleAccept(const boost::system::error_code& ecode,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
|
||||
|
||||
private:
|
||||
|
||||
std::thread * m_Thread;
|
||||
std::unique_ptr<std::thread> m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_service::work m_Work;
|
||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||
boost::asio::ip::tcp::socket * m_NewSocket;
|
||||
|
||||
protected:
|
||||
virtual void CreateConnection(boost::asio::ip::tcp::socket * m_NewSocket);
|
||||
virtual void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
154
I2NPProtocol.cpp
154
I2NPProtocol.cpp
@@ -18,30 +18,20 @@ using namespace i2p::transport;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
I2NPMessage * NewI2NPMessage ()
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
|
||||
{
|
||||
return new I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE>();
|
||||
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >();
|
||||
}
|
||||
|
||||
I2NPMessage * NewI2NPShortMessage ()
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ()
|
||||
{
|
||||
return new I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE>();
|
||||
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
|
||||
}
|
||||
|
||||
I2NPMessage * NewI2NPMessage (size_t len)
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
|
||||
{
|
||||
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||
}
|
||||
|
||||
void DeleteI2NPMessage (I2NPMessage * msg)
|
||||
{
|
||||
delete msg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg)
|
||||
{
|
||||
return std::shared_ptr<I2NPMessage>(msg, DeleteI2NPMessage);
|
||||
}
|
||||
|
||||
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID)
|
||||
{
|
||||
@@ -61,23 +51,18 @@ namespace i2p
|
||||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000);
|
||||
}
|
||||
|
||||
I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID)
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPMessage (len);
|
||||
if (msg->len + len < msg->maxLen)
|
||||
{
|
||||
memcpy (msg->GetPayload (), buf, len);
|
||||
msg->len += len;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2NP message length ", len, " exceeds max length");
|
||||
auto msg = NewI2NPMessage (len);
|
||||
if (msg->Concat (buf, len) < len)
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (msgType, replyMsgID);
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPMessage ();
|
||||
auto msg = NewI2NPMessage ();
|
||||
if (msg->offset + len < msg->maxLen)
|
||||
{
|
||||
memcpy (msg->GetBuffer (), buf, len);
|
||||
@@ -85,13 +70,13 @@ namespace i2p
|
||||
msg->from = from;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2NP message length ", len, " exceeds max length");
|
||||
return ToSharedI2NPMessage(msg);
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length");
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
|
||||
{
|
||||
I2NPMessage * m = NewI2NPShortMessage ();
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * buf = m->GetPayload ();
|
||||
if (msgID)
|
||||
{
|
||||
@@ -106,13 +91,13 @@ namespace i2p
|
||||
}
|
||||
m->len += DELIVERY_STATUS_SIZE;
|
||||
m->FillI2NPMessageHeader (eI2NPDeliveryStatus);
|
||||
return ToSharedI2NPMessage (m);
|
||||
return m;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
|
||||
{
|
||||
auto m = ToSharedI2NPMessage (excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ());
|
||||
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
uint8_t * buf = m->GetPayload ();
|
||||
memcpy (buf, key, 32); // key
|
||||
buf += 32;
|
||||
@@ -159,7 +144,7 @@ namespace i2p
|
||||
const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
|
||||
{
|
||||
int cnt = excludedFloodfills.size ();
|
||||
auto m = ToSharedI2NPMessage (cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ());
|
||||
auto m = cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
uint8_t * buf = m->GetPayload ();
|
||||
memcpy (buf, dest, 32); // key
|
||||
buf += 32;
|
||||
@@ -194,7 +179,7 @@ namespace i2p
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
|
||||
std::vector<i2p::data::IdentHash> routers)
|
||||
{
|
||||
auto m = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * buf = m->GetPayload ();
|
||||
size_t len = 0;
|
||||
memcpy (buf, ident, 32);
|
||||
@@ -218,7 +203,7 @@ namespace i2p
|
||||
if (!router) // we send own RouterInfo
|
||||
router = context.GetSharedRouterInfo ();
|
||||
|
||||
auto m = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
|
||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32);
|
||||
@@ -253,7 +238,7 @@ namespace i2p
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken)
|
||||
{
|
||||
if (!leaseSet) return nullptr;
|
||||
auto m = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
|
||||
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
|
||||
@@ -278,6 +263,12 @@ namespace i2p
|
||||
m->FillI2NPMessageHeader (eI2NPDatabaseStore);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (!msg || msg->GetTypeID () != eI2NPDatabaseStore) return false;
|
||||
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
||||
}
|
||||
|
||||
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
||||
{
|
||||
@@ -286,7 +277,7 @@ namespace i2p
|
||||
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||
{
|
||||
LogPrint ("Record ",i," is ours");
|
||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||
|
||||
i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText);
|
||||
// replace record to reply
|
||||
@@ -330,22 +321,22 @@ namespace i2p
|
||||
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint ("VariableTunnelBuild ", num, " records");
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
// endpoint of inbound tunnel
|
||||
LogPrint ("VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
@@ -358,14 +349,14 @@ namespace i2p
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
ToSharedI2NPMessage (CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,75 +370,75 @@ namespace i2p
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
ToSharedI2NPMessage (CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
ToSharedI2NPMessage (CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))));
|
||||
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
}
|
||||
|
||||
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint ("VariableTunnelBuildReplyMsg replyMsgID=", replyMsgID);
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg replyMsgID=", replyMsgID);
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
// reply for outbound tunnel
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddOutboundTunnel (tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint ("Pending tunnel for message ", replyMsgID, " not found");
|
||||
LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
|
||||
}
|
||||
|
||||
|
||||
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf)
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPShortMessage ();
|
||||
memcpy (msg->GetPayload (), buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
|
||||
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
return msg;
|
||||
}
|
||||
|
||||
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPShortMessage ();
|
||||
memcpy (msg->GetPayload () + 4, payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
htobe32buf (msg->GetPayload (), tunnelID);
|
||||
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
|
||||
msg->len += 4; // tunnelID
|
||||
msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ()
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPShortMessage ();
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
|
||||
return ToSharedI2NPMessage (msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPMessage (len);
|
||||
auto msg = NewI2NPMessage (len);
|
||||
uint8_t * payload = msg->GetPayload ();
|
||||
htobe32buf (payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID);
|
||||
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
|
||||
memcpy (payload + TUNNEL_GATEWAY_HEADER_SIZE, buf, len);
|
||||
msg->len += TUNNEL_GATEWAY_HEADER_SIZE + len;
|
||||
msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
if (msg->Concat (buf, len) < len)
|
||||
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
|
||||
return msg;
|
||||
}
|
||||
@@ -467,21 +458,18 @@ namespace i2p
|
||||
return msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
I2NPMessage * msg1 = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
|
||||
return ToSharedI2NPMessage (msg1);
|
||||
}
|
||||
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
|
||||
}
|
||||
|
||||
I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||
const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
||||
{
|
||||
I2NPMessage * msg = NewI2NPMessage (len);
|
||||
auto msg = NewI2NPMessage (len);
|
||||
size_t gatewayMsgOffset = I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
msg->offset += gatewayMsgOffset;
|
||||
msg->len += gatewayMsgOffset;
|
||||
memcpy (msg->GetPayload (), buf, len);
|
||||
msg->len += len;
|
||||
if (msg->Concat (buf, len) < len)
|
||||
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message
|
||||
len = msg->GetLength ();
|
||||
msg->offset -= gatewayMsgOffset;
|
||||
@@ -501,30 +489,26 @@ namespace i2p
|
||||
{
|
||||
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
|
||||
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
|
||||
LogPrint ("I2NP msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
|
||||
uint8_t * buf = msg + I2NP_HEADER_SIZE;
|
||||
int size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
LogPrint ("VariableTunnelBuild");
|
||||
HandleVariableTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
LogPrint ("VariableTunnelBuildReply");
|
||||
HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
LogPrint ("TunnelBuild");
|
||||
HandleTunnelBuildMsg (buf, size);
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
LogPrint ("TunnelBuildReply");
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Unexpected message ", (int)typeID);
|
||||
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,25 +516,24 @@ namespace i2p
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
switch (msg->GetTypeID ())
|
||||
uint8_t typeID = msg->GetTypeID ();
|
||||
LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID);
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPTunnelData:
|
||||
LogPrint ("TunnelData");
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPTunnelGateway:
|
||||
LogPrint ("TunnelGateway");
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPGarlic:
|
||||
{
|
||||
LogPrint ("Garlic");
|
||||
if (msg->from)
|
||||
{
|
||||
if (msg->from->GetTunnelPool ())
|
||||
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
|
||||
else
|
||||
LogPrint (eLogInfo, "Local destination for garlic doesn't exist anymore");
|
||||
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
|
||||
}
|
||||
else
|
||||
i2p::context.ProcessGarlicMessage (msg);
|
||||
@@ -564,7 +547,6 @@ namespace i2p
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
{
|
||||
LogPrint ("DeliveryStatus");
|
||||
if (msg->from && msg->from->GetTunnelPool ())
|
||||
msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg);
|
||||
else
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace i2p
|
||||
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
|
||||
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
|
||||
|
||||
const int MAX_NUM_TRANSIT_TUNNELS = 2500;
|
||||
const unsigned int MAX_NUM_TRANSIT_TUNNELS = 2500;
|
||||
|
||||
namespace tunnel
|
||||
{
|
||||
@@ -155,6 +155,15 @@ namespace tunnel
|
||||
}
|
||||
}
|
||||
|
||||
size_t Concat (const uint8_t * buf1, size_t len1)
|
||||
{
|
||||
// make sure with don't write beyond maxLen
|
||||
if (len + len1 > maxLen) len1 = maxLen - len;
|
||||
memcpy (buf + len, buf1, len1);
|
||||
len += len1;
|
||||
return len1;
|
||||
}
|
||||
|
||||
I2NPMessage& operator=(const I2NPMessage& other)
|
||||
{
|
||||
memcpy (buf + offset, other.buf + other.offset, other.GetLength ());
|
||||
@@ -193,17 +202,15 @@ namespace tunnel
|
||||
struct I2NPMessageBuffer: public I2NPMessage
|
||||
{
|
||||
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; };
|
||||
uint8_t m_Buffer[sz + 16];
|
||||
uint8_t m_Buffer[sz + 32]; // 16 alignment + 16 padding
|
||||
};
|
||||
|
||||
I2NPMessage * NewI2NPMessage ();
|
||||
I2NPMessage * NewI2NPShortMessage ();
|
||||
I2NPMessage * NewI2NPMessage (size_t len);
|
||||
void DeleteI2NPMessage (I2NPMessage * msg);
|
||||
std::shared_ptr<I2NPMessage> ToSharedI2NPMessage (I2NPMessage * msg);
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
|
||||
|
||||
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> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
|
||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||
@@ -215,18 +222,19 @@ namespace tunnel
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet, uint32_t replyToken = 0);
|
||||
|
||||
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
|
||||
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
|
||||
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
|
||||
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
|
||||
|
||||
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf);
|
||||
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf);
|
||||
std::shared_ptr<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, I2NPMessageType msgType,
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
|
||||
195
I2PControl.cpp
195
I2PControl.cpp
@@ -1,11 +1,13 @@
|
||||
// There is bug in boost 1.49 with gcc 4.7 coming with Debian Wheezy
|
||||
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
|
||||
|
||||
#include "I2PControl.h"
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/date_time/local_time/local_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#if !GCC47_BOOST149
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#endif
|
||||
@@ -17,16 +19,38 @@
|
||||
#include "Timestamp.h"
|
||||
#include "Transports.h"
|
||||
#include "version.h"
|
||||
#include "I2PControl.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
I2PControlService::I2PControlService (int port):
|
||||
I2PControlService::I2PControlService (const std::string& address, int port):
|
||||
m_Password (I2P_CONTROL_DEFAULT_PASSWORD), m_IsRunning (false), m_Thread (nullptr),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
|
||||
m_SSLContext (m_Service, boost::asio::ssl::context::sslv23),
|
||||
m_ShutdownTimer (m_Service)
|
||||
{
|
||||
LoadConfig ();
|
||||
// certificate
|
||||
auto path = GetPath ();
|
||||
if (!boost::filesystem::exists (path))
|
||||
{
|
||||
if (!boost::filesystem::create_directory (path))
|
||||
LogPrint (eLogError, "Failed to create i2pcontrol directory");
|
||||
}
|
||||
if (!boost::filesystem::exists (path / I2P_CONTROL_KEY_FILE) ||
|
||||
!boost::filesystem::exists (path / I2P_CONTROL_CERT_FILE))
|
||||
{
|
||||
// create new certificate
|
||||
CreateCertificate ();
|
||||
LogPrint (eLogInfo, "I2PControl certificates created");
|
||||
}
|
||||
m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use);
|
||||
m_SSLContext.use_certificate_file ((path / I2P_CONTROL_CERT_FILE).string (), boost::asio::ssl::context::pem);
|
||||
m_SSLContext.use_private_key_file ((path / I2P_CONTROL_KEY_FILE).string (), boost::asio::ssl::context::pem);
|
||||
|
||||
// handlers
|
||||
m_MethodHandlers[I2P_CONTROL_METHOD_AUTHENTICATE] = &I2PControlService::AuthenticateHandler;
|
||||
m_MethodHandlers[I2P_CONTROL_METHOD_ECHO] = &I2PControlService::EchoHandler;
|
||||
m_MethodHandlers[I2P_CONTROL_METHOD_I2PCONTROL] = &I2PControlService::I2PControlHandler;
|
||||
@@ -34,6 +58,9 @@ namespace client
|
||||
m_MethodHandlers[I2P_CONTROL_METHOD_ROUTER_MANAGER] = &I2PControlService::RouterManagerHandler;
|
||||
m_MethodHandlers[I2P_CONTROL_METHOD_NETWORK_SETTING] = &I2PControlService::NetworkSettingHandler;
|
||||
|
||||
// I2PControl
|
||||
m_I2PControlHandlers[I2P_CONTROL_I2PCONTROL_PASSWORD] = &I2PControlService::PasswordHandler;
|
||||
|
||||
// RouterInfo
|
||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_UPTIME] = &I2PControlService::UptimeHandler;
|
||||
m_RouterInfoHandlers[I2P_CONTROL_ROUTER_INFO_VERSION] = &I2PControlService::VersionHandler;
|
||||
@@ -56,6 +83,49 @@ namespace client
|
||||
Stop ();
|
||||
}
|
||||
|
||||
void I2PControlService::LoadConfig ()
|
||||
{
|
||||
auto path = GetPath ();
|
||||
if (!boost::filesystem::exists (path))
|
||||
{
|
||||
if (!boost::filesystem::create_directory (path))
|
||||
LogPrint (eLogError, "Failed to create i2pcontrol directory");
|
||||
}
|
||||
boost::property_tree::ptree pt;
|
||||
auto filename = path / I2P_CONTROL_CONFIG_FILE;
|
||||
bool isNew = true;
|
||||
if (boost::filesystem::exists (filename))
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_ini (filename.string (), pt);
|
||||
isNew = false;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Can't read ", filename, ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
m_Password = pt.get (I2P_CONTROL_I2PCONTROL_PASSWORD, I2P_CONTROL_DEFAULT_PASSWORD);
|
||||
if (isNew) SaveConfig ();
|
||||
}
|
||||
|
||||
void I2PControlService::SaveConfig ()
|
||||
{
|
||||
boost::property_tree::ptree pt;
|
||||
pt.put (I2P_CONTROL_I2PCONTROL_PASSWORD, m_Password);
|
||||
auto filename = GetPath () / I2P_CONTROL_CONFIG_FILE;
|
||||
// we take care about directory in LoadConfig
|
||||
try
|
||||
{
|
||||
boost::property_tree::write_ini (filename.string (), pt);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Can't write ", filename, ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::Start ()
|
||||
{
|
||||
if (!m_IsRunning)
|
||||
@@ -99,27 +169,43 @@ namespace client
|
||||
|
||||
void I2PControlService::Accept ()
|
||||
{
|
||||
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service);
|
||||
m_Acceptor.async_accept (*newSocket, std::bind (&I2PControlService::HandleAccept, this,
|
||||
auto newSocket = std::make_shared<ssl_socket> (m_Service, m_SSLContext);
|
||||
m_Acceptor.async_accept (newSocket->lowest_layer(), std::bind (&I2PControlService::HandleAccept, this,
|
||||
std::placeholders::_1, newSocket));
|
||||
}
|
||||
|
||||
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||
void I2PControlService::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Accept ();
|
||||
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "New I2PControl request from ", socket->remote_endpoint ());
|
||||
std::this_thread::sleep_for (std::chrono::milliseconds(5));
|
||||
ReadRequest (socket);
|
||||
LogPrint (eLogInfo, "New I2PControl request from ", socket->lowest_layer ().remote_endpoint ());
|
||||
Handshake (socket);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl accept error: ", ecode.message ());
|
||||
}
|
||||
|
||||
void I2PControlService::ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket)
|
||||
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
|
||||
{
|
||||
socket->async_handshake(boost::asio::ssl::stream_base::server,
|
||||
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
|
||||
}
|
||||
|
||||
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
//std::this_thread::sleep_for (std::chrono::milliseconds(5));
|
||||
ReadRequest (socket);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl handshake error: ", ecode.message ());
|
||||
}
|
||||
|
||||
void I2PControlService::ReadRequest (std::shared_ptr<ssl_socket> socket)
|
||||
{
|
||||
auto request = std::make_shared<I2PControlBuffer>();
|
||||
socket->async_read_some (
|
||||
@@ -133,7 +219,7 @@ namespace client
|
||||
}
|
||||
|
||||
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
|
||||
size_t bytes_transferred, std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
|
||||
std::shared_ptr<I2PControlBuffer> buf)
|
||||
{
|
||||
if (ecode)
|
||||
@@ -150,13 +236,25 @@ namespace client
|
||||
if (isHtml)
|
||||
{
|
||||
std::string header;
|
||||
size_t contentLength = 0;
|
||||
while (!ss.eof () && header != "\r")
|
||||
{
|
||||
std::getline(ss, header);
|
||||
auto colon = header.find (':');
|
||||
if (colon != std::string::npos && header.substr (0, colon) == "Content-Length")
|
||||
contentLength = std::stoi (header.substr (colon + 1));
|
||||
}
|
||||
if (ss.eof ())
|
||||
{
|
||||
LogPrint (eLogError, "Malformed I2PControl request. HTTP header expected");
|
||||
return; // TODO:
|
||||
}
|
||||
std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read
|
||||
if (rem > 0)
|
||||
{
|
||||
bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), rem));
|
||||
ss.write (buf->data (), bytes_transferred);
|
||||
}
|
||||
}
|
||||
#if GCC47_BOOST149
|
||||
LogPrint (eLogError, "json_read is not supported due bug in boost 1.49 with gcc 4.7");
|
||||
@@ -209,7 +307,7 @@ namespace client
|
||||
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
|
||||
}
|
||||
|
||||
void I2PControlService::SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
|
||||
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
|
||||
{
|
||||
size_t len = response.str ().length (), offset = 0;
|
||||
@@ -236,11 +334,10 @@ namespace client
|
||||
}
|
||||
|
||||
void I2PControlService::HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf)
|
||||
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf)
|
||||
{
|
||||
if (ecode)
|
||||
LogPrint (eLogError, "I2PControl write error: ", ecode.message ());
|
||||
socket->close ();
|
||||
}
|
||||
|
||||
// handlers
|
||||
@@ -277,12 +374,23 @@ namespace client
|
||||
LogPrint (eLogDebug, it.first);
|
||||
auto it1 = m_I2PControlHandlers.find (it.first);
|
||||
if (it1 != m_I2PControlHandlers.end ())
|
||||
{
|
||||
(this->*(it1->second))(it.second.data ());
|
||||
InsertParam (results, it.first, "");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl NetworkSetting unknown request ", it.first);
|
||||
LogPrint (eLogError, "I2PControl I2PControl unknown request ", it.first);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::PasswordHandler (const std::string& value)
|
||||
{
|
||||
LogPrint (eLogDebug, "I2PControl new password=", value);
|
||||
m_Password = value;
|
||||
m_Tokens.clear ();
|
||||
SaveConfig ();
|
||||
}
|
||||
|
||||
// RouterInfo
|
||||
|
||||
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
@@ -290,11 +398,13 @@ namespace client
|
||||
LogPrint (eLogDebug, "I2PControl RouterInfo");
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
{
|
||||
if (it != params.begin ()) results << ",";
|
||||
LogPrint (eLogDebug, it->first);
|
||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||
if (it1 != m_RouterInfoHandlers.end ())
|
||||
{
|
||||
if (it != params.begin ()) results << ",";
|
||||
(this->*(it1->second))(results);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl RouterInfo unknown request ", it->first);
|
||||
}
|
||||
@@ -412,5 +522,56 @@ namespace client
|
||||
}
|
||||
}
|
||||
|
||||
// certificate
|
||||
void I2PControlService::CreateCertificate ()
|
||||
{
|
||||
EVP_PKEY * pkey = EVP_PKEY_new ();
|
||||
RSA * rsa = RSA_new ();
|
||||
BIGNUM * e = BN_dup (i2p::crypto::GetRSAE ());
|
||||
RSA_generate_key_ex (rsa, 4096, e, NULL);
|
||||
BN_free (e);
|
||||
if (rsa)
|
||||
{
|
||||
EVP_PKEY_assign_RSA (pkey, rsa);
|
||||
X509 * x509 = X509_new ();
|
||||
ASN1_INTEGER_set (X509_get_serialNumber (x509), 1);
|
||||
X509_gmtime_adj (X509_get_notBefore (x509), 0);
|
||||
X509_gmtime_adj (X509_get_notAfter (x509), I2P_CONTROL_CERTIFICATE_VALIDITY*24*60*60); // expiration
|
||||
X509_set_pubkey (x509, pkey); // public key
|
||||
X509_NAME * name = X509_get_subject_name (x509);
|
||||
X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *)"RU", -1, -1, 0); // country (Russia by default)
|
||||
X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_ORGANIZATION, -1, -1, 0); // organization
|
||||
X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *)I2P_CONTROL_CERTIFICATE_COMMON_NAME, -1, -1, 0); // common name
|
||||
X509_set_issuer_name (x509, name); // set issuer to ourselves
|
||||
X509_sign (x509, pkey, EVP_sha1 ()); // sign
|
||||
// save key and certificate
|
||||
// keys
|
||||
auto filename = GetPath () / I2P_CONTROL_KEY_FILE;
|
||||
FILE * f= fopen (filename.string ().c_str (), "wb");
|
||||
if (f)
|
||||
{
|
||||
PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
|
||||
fclose (f);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't open file ", filename);
|
||||
// certificate
|
||||
filename = GetPath () / I2P_CONTROL_CERT_FILE;
|
||||
f= fopen (filename.string ().c_str (), "wb");
|
||||
if (f)
|
||||
{
|
||||
PEM_write_X509 (f, x509);
|
||||
fclose (f);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't open file ", filename);
|
||||
|
||||
X509_free (x509);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Couldn't create RSA key for certificate");
|
||||
EVP_PKEY_free (pkey);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
36
I2PControl.h
36
I2PControl.h
@@ -10,7 +10,10 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -19,6 +22,10 @@ namespace client
|
||||
const size_t I2P_CONTROL_MAX_REQUEST_SIZE = 1024;
|
||||
typedef std::array<char, I2P_CONTROL_MAX_REQUEST_SIZE> I2PControlBuffer;
|
||||
|
||||
const char I2P_CONTROL_PATH[] = "ipcontrol";
|
||||
const char I2P_CONTROL_KEY_FILE[] = "key.pem";
|
||||
const char I2P_CONTROL_CERT_FILE[] = "cert.pem";
|
||||
const char I2P_CONTROL_CONFIG_FILE[] = "i2pcontrol.conf";
|
||||
const char I2P_CONTROL_DEFAULT_PASSWORD[] = "itoopie";
|
||||
|
||||
const char I2P_CONTROL_PROPERTY_ID[] = "id";
|
||||
@@ -62,11 +69,17 @@ namespace client
|
||||
const char I2P_CONTROL_ROUTER_MANAGER_SHUTDOWN_GRACEFUL[] = "ShutdownGraceful";
|
||||
const char I2P_CONTROL_ROUTER_MANAGER_RESEED[] = "Reseed";
|
||||
|
||||
// Certificate
|
||||
const long I2P_CONTROL_CERTIFICATE_VALIDITY = 365*10; // 10 years
|
||||
const char I2P_CONTROL_CERTIFICATE_COMMON_NAME[] = "i2pd.i2pcontrol";
|
||||
const char I2P_CONTROL_CERTIFICATE_ORGANIZATION[] = "Purple I2P";
|
||||
|
||||
class I2PControlService
|
||||
{
|
||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
||||
public:
|
||||
|
||||
I2PControlService (int port);
|
||||
I2PControlService (const std::string& address, int port);
|
||||
~I2PControlService ();
|
||||
|
||||
void Start ();
|
||||
@@ -74,16 +87,25 @@ namespace client
|
||||
|
||||
private:
|
||||
|
||||
void LoadConfig ();
|
||||
void SaveConfig ();
|
||||
|
||||
void Run ();
|
||||
void Accept ();
|
||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||
void ReadRequest (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
|
||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
|
||||
void Handshake (std::shared_ptr<ssl_socket> socket);
|
||||
void HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket);
|
||||
void ReadRequest (std::shared_ptr<ssl_socket> socket);
|
||||
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||
void SendResponse (std::shared_ptr<boost::asio::ip::tcp::socket> socket,
|
||||
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||
void SendResponse (std::shared_ptr<ssl_socket> socket,
|
||||
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml);
|
||||
void HandleResponseSent (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||
|
||||
boost::filesystem::path GetPath () const { return i2p::util::filesystem::GetDefaultDataDir() / I2P_CONTROL_PATH; };
|
||||
void CreateCertificate ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -103,6 +125,7 @@ namespace client
|
||||
|
||||
// I2PControl
|
||||
typedef void (I2PControlService::*I2PControlRequestHandler)(const std::string& value);
|
||||
void PasswordHandler (const std::string& value);
|
||||
|
||||
// RouterInfo
|
||||
typedef void (I2PControlService::*RouterInfoRequestHandler)(std::ostringstream& results);
|
||||
@@ -133,6 +156,7 @@ namespace client
|
||||
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||
boost::asio::ssl::context m_SSLContext;
|
||||
boost::asio::deadline_timer m_ShutdownTimer;
|
||||
std::set<std::string> m_Tokens;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD_kernel__)
|
||||
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
|
||||
#include <endian.h>
|
||||
#elif __FreeBSD__
|
||||
#include <sys/endian.h>
|
||||
|
||||
@@ -81,13 +81,13 @@ namespace client
|
||||
class TCPIPAcceptor: public I2PService
|
||||
{
|
||||
public:
|
||||
TCPIPAcceptor (int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
|
||||
TCPIPAcceptor (const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination = nullptr) :
|
||||
I2PService(localDestination),
|
||||
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
||||
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
|
||||
m_Timer (GetService ()) {}
|
||||
TCPIPAcceptor (int port, i2p::data::SigningKeyType kt) :
|
||||
TCPIPAcceptor (const std::string& address, int port, i2p::data::SigningKeyType kt) :
|
||||
I2PService(kt),
|
||||
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)),
|
||||
m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
|
||||
m_Timer (GetService ()) {}
|
||||
virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); }
|
||||
//If you override this make sure you call it from the children
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("I2PTunnel read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PTunnel: read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -103,7 +103,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("I2PTunnel write error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PTunnel: write error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -124,7 +124,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("I2PTunnel stream read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PTunnel: stream read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -142,12 +142,12 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("I2PTunnel connect error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PTunnel: connect error: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("I2PTunnel connected");
|
||||
LogPrint (eLogDebug, "I2PTunnel: connected");
|
||||
if (m_IsQuiet)
|
||||
StreamReceive ();
|
||||
else
|
||||
@@ -165,7 +165,7 @@ 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)
|
||||
I2PTunnelConnection (owner, stream, socket, target), m_Host (host), m_HeaderSent (false), m_From (stream->GetRemoteIdentity ())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -193,6 +193,12 @@ namespace client
|
||||
else
|
||||
break;
|
||||
}
|
||||
// add X-I2P fields
|
||||
if (m_From)
|
||||
{
|
||||
m_OutHeader << X_I2P_DEST_HASH << ": " << m_From->GetIdentHash ().ToBase64 () << "\r\n";
|
||||
// m_OutHeader << X_I2P_DEST_B64 << ": " << m_From->ToBase64 () << "\r\n";
|
||||
}
|
||||
|
||||
if (endOfHeader)
|
||||
{
|
||||
@@ -232,7 +238,7 @@ namespace client
|
||||
if (stream)
|
||||
{
|
||||
if (Kill()) return;
|
||||
LogPrint (eLogInfo,"New I2PTunnel connection");
|
||||
LogPrint (eLogDebug, "I2PTunnel: new connection");
|
||||
auto connection = std::make_shared<I2PTunnelConnection>(GetOwner(), m_Socket, stream);
|
||||
GetOwner()->AddHandler (connection);
|
||||
connection->I2PConnect ();
|
||||
@@ -240,7 +246,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError,"I2P Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
|
||||
LogPrint (eLogError, "I2PTunnel: Client Tunnel Issue when creating the stream, check the previous warnings for more info.");
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
@@ -256,9 +262,8 @@ namespace client
|
||||
Done(shared_from_this());
|
||||
}
|
||||
|
||||
I2PClientTunnel::I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
||||
TCPIPAcceptor (port,localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort)
|
||||
{}
|
||||
I2PClientTunnel::I2PClientTunnel (const std::string& destination, const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort):
|
||||
TCPIPAcceptor (address, port, localDestination), m_Destination (destination), m_DestinationIdentHash (nullptr), m_DestinationPort (destinationPort) {}
|
||||
|
||||
void I2PClientTunnel::Start ()
|
||||
{
|
||||
@@ -283,7 +288,7 @@ namespace client
|
||||
if (i2p::client::context.GetAddressBook ().GetIdentHash (m_Destination, identHash))
|
||||
m_DestinationIdentHash = new i2p::data::IdentHash (identHash);
|
||||
else
|
||||
LogPrint (eLogWarning,"Remote destination ", m_Destination, " not found");
|
||||
LogPrint (eLogWarning, "I2PTunnel: Remote destination ", m_Destination, " not found");
|
||||
}
|
||||
return m_DestinationIdentHash;
|
||||
}
|
||||
@@ -334,12 +339,12 @@ namespace client
|
||||
if (!ecode)
|
||||
{
|
||||
auto addr = (*it).endpoint ().address ();
|
||||
LogPrint (eLogInfo, "server tunnel ", (*it).host_name (), " has been resolved to ", addr);
|
||||
LogPrint (eLogInfo, "I2PTunnel: 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 ());
|
||||
LogPrint (eLogError, "I2PTunnel: Unable to resolve server tunnel address: ", ecode.message ());
|
||||
}
|
||||
|
||||
void I2PServerTunnel::SetAccessList (const std::set<i2p::data::IdentHash>& accessList)
|
||||
@@ -360,7 +365,7 @@ namespace client
|
||||
localDestination->AcceptStreams (std::bind (&I2PServerTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint ("Local destination not set for server tunnel");
|
||||
LogPrint (eLogError, "I2PTunnel: Local destination not set for server tunnel");
|
||||
}
|
||||
|
||||
void I2PServerTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
@@ -371,7 +376,7 @@ namespace client
|
||||
{
|
||||
if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ()))
|
||||
{
|
||||
LogPrint (eLogWarning, "Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
|
||||
LogPrint (eLogWarning, "I2PTunnel: Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped");
|
||||
stream->Close ();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ namespace client
|
||||
const size_t I2P_TUNNEL_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int I2P_TUNNEL_CONNECTION_MAX_IDLE = 3600; // in seconds
|
||||
const int I2P_TUNNEL_DESTINATION_REQUEST_TIMEOUT = 10; // in seconds
|
||||
|
||||
// for HTTP tunnels
|
||||
const char X_I2P_DEST_HASH[] = "X-I2P-DestHash"; // hash in base64
|
||||
//const char X_I2P_DEST_B64[] = "X-I2P-DestB64"; // full address in base64
|
||||
//const char X_I2P_DEST_B32[] = "X-I2P-DestB32"; // full address in base32
|
||||
|
||||
class I2PTunnelConnection: public I2PServiceHandler, public std::enable_shared_from_this<I2PTunnelConnection>
|
||||
{
|
||||
@@ -74,6 +77,7 @@ namespace client
|
||||
std::string m_Host;
|
||||
std::stringstream m_InHeader, m_OutHeader;
|
||||
bool m_HeaderSent;
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_From;
|
||||
};
|
||||
|
||||
class I2PClientTunnel: public TCPIPAcceptor
|
||||
@@ -86,7 +90,7 @@ namespace client
|
||||
|
||||
public:
|
||||
|
||||
I2PClientTunnel (const std::string& destination, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
|
||||
I2PClientTunnel (const std::string& destination, const std::string& address, int port, std::shared_ptr<ClientDestination> localDestination, int destinationPort = 0);
|
||||
~I2PClientTunnel () {}
|
||||
|
||||
void Start ();
|
||||
|
||||
31
Identity.cpp
31
Identity.cpp
@@ -16,7 +16,7 @@ namespace data
|
||||
{
|
||||
// copy public and signing keys together
|
||||
memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey));
|
||||
memset (&certificate, 0, sizeof (certificate));
|
||||
memset (certificate, 0, sizeof (certificate));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -101,12 +101,12 @@ namespace data
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint ("Signing key type ", (int)type, " is not supported");
|
||||
LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported");
|
||||
}
|
||||
m_ExtendedLen = 4 + excessLen; // 4 bytes extra + excess length
|
||||
// fill certificate
|
||||
m_StandardIdentity.certificate.type = CERTIFICATE_TYPE_KEY;
|
||||
m_StandardIdentity.certificate.length = htobe16 (m_ExtendedLen);
|
||||
m_StandardIdentity.certificate[0] = CERTIFICATE_TYPE_KEY;
|
||||
htobe16buf (m_StandardIdentity.certificate + 1, m_ExtendedLen);
|
||||
// fill extended buffer
|
||||
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
|
||||
htobe16buf (m_ExtendedBuffer, type);
|
||||
@@ -125,7 +125,7 @@ namespace data
|
||||
else // DSA-SHA1
|
||||
{
|
||||
memcpy (m_StandardIdentity.signingKey, signingKey, sizeof (m_StandardIdentity.signingKey));
|
||||
memset (&m_StandardIdentity.certificate, 0, sizeof (m_StandardIdentity.certificate));
|
||||
memset (m_StandardIdentity.certificate, 0, sizeof (m_StandardIdentity.certificate));
|
||||
m_IdentHash = m_StandardIdentity.Hash ();
|
||||
m_ExtendedLen = 0;
|
||||
m_ExtendedBuffer = nullptr;
|
||||
@@ -194,15 +194,15 @@ namespace data
|
||||
{
|
||||
if (len < DEFAULT_IDENTITY_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "Identity buffer length ", len, " is too small");
|
||||
LogPrint (eLogError, "Identity: buffer length ", len, " is too small");
|
||||
return 0;
|
||||
}
|
||||
memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
|
||||
|
||||
delete[] m_ExtendedBuffer;
|
||||
if (m_StandardIdentity.certificate.length)
|
||||
m_ExtendedLen = bufbe16toh (m_StandardIdentity.certificate + 1);
|
||||
if (m_ExtendedLen)
|
||||
{
|
||||
m_ExtendedLen = be16toh (m_StandardIdentity.certificate.length);
|
||||
if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len)
|
||||
{
|
||||
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
|
||||
@@ -210,7 +210,7 @@ namespace data
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
|
||||
LogPrint (eLogError, "Identity: Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -272,7 +272,7 @@ namespace data
|
||||
if (!m_Verifier) CreateVerifier ();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetSignatureLen ();
|
||||
return 40;
|
||||
return i2p::crypto::DSA_SIGNATURE_LENGTH;
|
||||
}
|
||||
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
@@ -284,14 +284,14 @@ namespace data
|
||||
|
||||
SigningKeyType IdentityEx::GetSigningKeyType () const
|
||||
{
|
||||
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
|
||||
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
|
||||
return bufbe16toh (m_ExtendedBuffer); // signing key
|
||||
return SIGNING_KEY_TYPE_DSA_SHA1;
|
||||
}
|
||||
|
||||
CryptoKeyType IdentityEx::GetCryptoKeyType () const
|
||||
{
|
||||
if (m_StandardIdentity.certificate.type == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
|
||||
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedBuffer)
|
||||
return bufbe16toh (m_ExtendedBuffer + 2); // crypto key
|
||||
return CRYPTO_KEY_TYPE_ELGAMAL;
|
||||
}
|
||||
@@ -359,12 +359,13 @@ namespace data
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint ("Signing key type ", (int)keyType, " is not supported");
|
||||
LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
void IdentityEx::DropVerifier () const
|
||||
{
|
||||
// TODO: potential race condition with Verify
|
||||
m_Verifier = nullptr;
|
||||
}
|
||||
|
||||
@@ -470,7 +471,7 @@ namespace data
|
||||
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey));
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
|
||||
LogPrint (eLogError, "Identity: Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +506,7 @@ namespace data
|
||||
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
|
||||
break;
|
||||
default:
|
||||
LogPrint ("Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
|
||||
LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
|
||||
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
|
||||
}
|
||||
// encryption
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace data
|
||||
return ident.ToBase64 ().substr (0, 4);
|
||||
}
|
||||
|
||||
#pragma pack(1)
|
||||
struct Keys
|
||||
{
|
||||
uint8_t privateKey[256];
|
||||
@@ -38,11 +37,7 @@ namespace data
|
||||
{
|
||||
uint8_t publicKey[256];
|
||||
uint8_t signingKey[128];
|
||||
struct
|
||||
{
|
||||
uint8_t type;
|
||||
uint16_t length;
|
||||
} certificate;
|
||||
uint8_t certificate[3]; // byte 1 - type, bytes 2-3 - length
|
||||
|
||||
Identity () = default;
|
||||
Identity (const Keys& keys) { *this = keys; };
|
||||
@@ -50,7 +45,7 @@ namespace data
|
||||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||
IdentHash Hash () const;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
Keys CreateRandomKeys ();
|
||||
|
||||
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
|
||||
|
||||
17
LeaseSet.cpp
17
LeaseSet.cpp
@@ -21,17 +21,18 @@ namespace data
|
||||
ReadFromBuffer ();
|
||||
}
|
||||
|
||||
LeaseSet::LeaseSet (const i2p::tunnel::TunnelPool& pool):
|
||||
LeaseSet::LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool):
|
||||
m_IsValid (true)
|
||||
{
|
||||
if (!pool) return;
|
||||
// header
|
||||
const i2p::data::LocalDestination * localDestination = pool.GetLocalDestination ();
|
||||
auto localDestination = pool->GetLocalDestination ();
|
||||
if (!localDestination)
|
||||
{
|
||||
m_Buffer = nullptr;
|
||||
m_BufferLen = 0;
|
||||
m_IsValid = false;
|
||||
LogPrint (eLogError, "Destination for local LeaseSet doesn't exist");
|
||||
LogPrint (eLogError, "LeaseSet: Destination for local LeaseSet doesn't exist");
|
||||
return;
|
||||
}
|
||||
m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE];
|
||||
@@ -41,7 +42,7 @@ namespace data
|
||||
auto signingKeyLen = localDestination->GetIdentity ()->GetSigningPublicKeyLen ();
|
||||
memset (m_Buffer + m_BufferLen, 0, signingKeyLen);
|
||||
m_BufferLen += signingKeyLen;
|
||||
auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum
|
||||
auto tunnels = pool->GetInboundTunnels (5); // 5 tunnels maximum
|
||||
m_Buffer[m_BufferLen] = tunnels.size (); // num leases
|
||||
m_BufferLen++;
|
||||
// leases
|
||||
@@ -60,7 +61,7 @@ namespace data
|
||||
// signature
|
||||
localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen);
|
||||
m_BufferLen += localDestination->GetIdentity ()->GetSignatureLen ();
|
||||
LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created");
|
||||
LogPrint (eLogDebug, "LeaseSet: Local LeaseSet of ", tunnels.size (), " leases created");
|
||||
|
||||
ReadFromBuffer ();
|
||||
}
|
||||
@@ -89,7 +90,7 @@ namespace data
|
||||
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
|
||||
uint8_t num = m_Buffer[size];
|
||||
size++; // num
|
||||
LogPrint ("LeaseSet num=", (int)num);
|
||||
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
|
||||
if (!num) m_IsValid = false;
|
||||
|
||||
// process leases
|
||||
@@ -109,7 +110,7 @@ namespace data
|
||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||
{
|
||||
// if not found request it
|
||||
LogPrint (eLogInfo, "Lease's tunnel gateway not found. Requested");
|
||||
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
|
||||
netdb.RequestDestination (lease.tunnelGateway);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +118,7 @@ namespace data
|
||||
// verify
|
||||
if (!m_Identity->Verify (m_Buffer, leases - m_Buffer, leases))
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet verification failed");
|
||||
LogPrint (eLogWarning, "LeaseSet: verification failed");
|
||||
m_IsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace data
|
||||
public:
|
||||
|
||||
LeaseSet (const uint8_t * buf, size_t len);
|
||||
LeaseSet (const i2p::tunnel::TunnelPool& pool);
|
||||
LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool);
|
||||
~LeaseSet () { delete[] m_Buffer; };
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
|
||||
17
Log.cpp
17
Log.cpp
@@ -24,7 +24,7 @@ void LogMsg::Process()
|
||||
|
||||
const std::string& Log::GetTimestamp ()
|
||||
{
|
||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6)
|
||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__)
|
||||
auto ts = std::chrono::monotonic_clock::now ();
|
||||
#else
|
||||
auto ts = std::chrono::steady_clock::now ();
|
||||
@@ -49,12 +49,25 @@ void Log::SetLogFile (const std::string& fullFilePath)
|
||||
if (logFile->is_open ())
|
||||
{
|
||||
SetLogStream (logFile);
|
||||
LogPrint("Logging to file ", fullFilePath, " enabled.");
|
||||
LogPrint(eLogInfo, "Log: will send messages to ", fullFilePath);
|
||||
}
|
||||
else
|
||||
delete logFile;
|
||||
}
|
||||
|
||||
void Log::SetLogLevel (const std::string& level)
|
||||
{
|
||||
if (level == "error") { m_MinLevel = eLogError; }
|
||||
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
||||
else if (level == "info") { m_MinLevel = eLogInfo; }
|
||||
else if (level == "debug") { m_MinLevel = eLogDebug; }
|
||||
else {
|
||||
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogInfo, "Log: min msg level set to ", level);
|
||||
}
|
||||
|
||||
void Log::SetLogStream (std::ostream * logStream)
|
||||
{
|
||||
if (m_LogStream) delete m_LogStream;
|
||||
|
||||
18
Log.h
18
Log.h
@@ -38,9 +38,11 @@ class Log: public i2p::util::MsgQueue<LogMsg>
|
||||
~Log () { delete m_LogStream; };
|
||||
|
||||
void SetLogFile (const std::string& fullFilePath);
|
||||
void SetLogLevel (const std::string& level);
|
||||
void SetLogStream (std::ostream * logStream);
|
||||
std::ostream * GetLogStream () const { return m_LogStream; };
|
||||
const std::string& GetTimestamp ();
|
||||
LogLevel GetLogLevel () { return m_MinLevel; };
|
||||
|
||||
private:
|
||||
|
||||
@@ -49,8 +51,9 @@ class Log: public i2p::util::MsgQueue<LogMsg>
|
||||
private:
|
||||
|
||||
std::ostream * m_LogStream;
|
||||
enum LogLevel m_MinLevel;
|
||||
std::string m_Timestamp;
|
||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) // gcc 4.6
|
||||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 6) && !defined(__clang__) // gcc 4.6
|
||||
std::chrono::monotonic_clock::time_point m_LastTimestampUpdate;
|
||||
#else
|
||||
std::chrono::steady_clock::time_point m_LastTimestampUpdate;
|
||||
@@ -108,22 +111,17 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
|
||||
template<typename... TArgs>
|
||||
void LogPrint (LogLevel level, TArgs... args)
|
||||
{
|
||||
if (g_Log && level > g_Log->GetLogLevel ())
|
||||
return;
|
||||
LogMsg * msg = new LogMsg (g_Log, level);
|
||||
LogPrint (msg->s, args...);
|
||||
msg->s << std::endl;
|
||||
if (g_Log)
|
||||
if (g_Log) {
|
||||
g_Log->Put (msg);
|
||||
else
|
||||
{
|
||||
} else {
|
||||
msg->Process ();
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
void LogPrint (TArgs... args)
|
||||
{
|
||||
LogPrint (eLogInfo, args...);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
13
Makefile
13
Makefile
@@ -3,7 +3,7 @@ SHLIB := libi2pd.so
|
||||
ARLIB := libi2pd.a
|
||||
SHLIB_CLIENT := libi2pdclient.so
|
||||
ARLIB_CLIENT := libi2pdclient.a
|
||||
I2PD := i2p
|
||||
I2PD := i2pd
|
||||
GREP := fgrep
|
||||
DEPS := obj/make.dep
|
||||
|
||||
@@ -21,16 +21,18 @@ else ifeq ($(shell echo $(UNAME) | $(GREP) -c FreeBSD),1)
|
||||
else ifeq ($(UNAME),Linux)
|
||||
DAEMON_SRC += DaemonLinux.cpp
|
||||
include Makefile.linux
|
||||
else # win32
|
||||
DAEMON_SRC += DaemonWin32.cpp
|
||||
else # win32 mingw
|
||||
DAEMON_SRC += DaemonWin32.cpp Win32/Win32Service.cpp
|
||||
include Makefile.mingw
|
||||
endif
|
||||
|
||||
all: mk_build_dir $(SHLIB) $(SHLIB_CLIENT) $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
|
||||
all: mk_build_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
|
||||
|
||||
mk_build_dir:
|
||||
mkdir -p obj
|
||||
|
||||
api: $(SHLIB) $(ARLIB)
|
||||
api: mk_build_dir $(SHLIB) $(ARLIB)
|
||||
api_client: mk_build_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||
|
||||
## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
@@ -82,4 +84,5 @@ dist:
|
||||
.PHONY: deps
|
||||
.PHONY: dist
|
||||
.PHONY: api
|
||||
.PHONY: api_client
|
||||
.PHONY: mk_build_dir
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CXX = g++
|
||||
CXX = clang++
|
||||
CXXFLAGS = -O2
|
||||
## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
@@ -6,7 +6,7 @@ CXXFLAGS = -O2
|
||||
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
|
||||
## -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.
|
||||
NEEDED_CXXFLAGS = -std=c++11
|
||||
NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
CXXFLAGS = -g -Wall
|
||||
INCFLAGS =
|
||||
# set defaults instead redefine
|
||||
CXXFLAGS ?= -g -Wall
|
||||
INCFLAGS ?=
|
||||
|
||||
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
||||
## **without** overwriting the CXXFLAGS which we need in order to build.
|
||||
@@ -15,7 +16,7 @@ ifeq ($(shell expr match $(CXX) 'clang'),5)
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
||||
NEEDED_CXXFLAGS += -std=c++0x
|
||||
else ifeq ($(shell expr match ${CXXVER} "5\.[0-9]"),3) # gcc >= 5.0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CXX = g++
|
||||
CXXFLAGS = -O2 -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
|
||||
NEEDED_CXXFLAGS = -std=c++11
|
||||
BOOST_SUFFIX = -mgw48-mt-1_59
|
||||
INCFLAGS = -I/usr/include/ -I/usr/local/include/ -I/c/dev/openssl/include -I/c/dev/boost/include/boost-1_59
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/c/dev/openssl -L/c/dev/boost/lib
|
||||
LDLIBS = -lboost_system-mgw48-mt-1_59 -lboost_date_time-mgw48-mt-1_59 -lboost_filesystem-mgw48-mt-1_59 -lboost_regex-mgw48-mt-1_59 -lboost_program_options-mgw48-mt-1_59 -lssl -lcrypto -lz -lpthread -lwsock32 -lws2_32 -lgdi32
|
||||
LDLIBS = -lboost_system$(BOOST_SUFFIX) -lboost_date_time$(BOOST_SUFFIX) -lboost_filesystem$(BOOST_SUFFIX) -lboost_regex$(BOOST_SUFFIX) -lboost_program_options$(BOOST_SUFFIX) -lssl -lcrypto -lz -lwsock32 -lws2_32 -lgdi32 -liphlpapi -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread
|
||||
|
||||
10
Makefile.osx
10
Makefile.osx
@@ -1,9 +1,9 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS = -g -Wall -std=c++11 -DCRYPTOPP_DISABLE_ASM -DMAC_OSX
|
||||
#CXXFLAGS = -g -O2 -Wall -std=c++11 -DCRYPTOPP_DISABLE_ASM
|
||||
INCFLAGS = -I/usr/local/include
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX
|
||||
#CXXFLAGS = -g -O2 -Wall -std=c++11
|
||||
INCFLAGS = -I/usr/local/include -I/usr/local/ssl/include
|
||||
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -L/usr/local/ssl/lib
|
||||
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
|
||||
|
||||
ifeq ($(USE_UPNP),1)
|
||||
LDFLAGS += -ldl
|
||||
|
||||
123
NTCPSession.cpp
123
NTCPSession.cpp
@@ -56,7 +56,7 @@ namespace transport
|
||||
nonZero++;
|
||||
if (nonZero - sharedKey > 32)
|
||||
{
|
||||
LogPrint (eLogWarning, "First 32 bytes of shared key is all zeros. Ignored");
|
||||
LogPrint (eLogWarning, "NTCP: First 32 bytes of shared key is all zeros, ignored");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ namespace transport
|
||||
m_SendQueue.clear ();
|
||||
m_NextMessage = nullptr;
|
||||
m_TerminationTimer.cancel ();
|
||||
LogPrint (eLogInfo, "NTCP session terminated");
|
||||
LogPrint (eLogDebug, "NTCP: session terminated");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Couldn't send Phase 1 message: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: couldn't send Phase 1 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -152,7 +152,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Phase 1 read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: phase 1 read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -166,7 +166,7 @@ namespace transport
|
||||
{
|
||||
if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i])
|
||||
{
|
||||
LogPrint (eLogError, "Wrong ident");
|
||||
LogPrint (eLogError, "NTCP: phase 1 error: ident mismatch");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -187,8 +187,8 @@ namespace transport
|
||||
memcpy (xy + 256, y, 256);
|
||||
SHA256(xy, 512, m_Establisher->phase2.encrypted.hxy);
|
||||
uint32_t tsB = htobe32 (i2p::util::GetSecondsSinceEpoch ());
|
||||
m_Establisher->phase2.encrypted.timestamp = tsB;
|
||||
// TODO: fill filler
|
||||
memcpy (m_Establisher->phase2.encrypted.timestamp, &tsB, 4);
|
||||
RAND_bytes (m_Establisher->phase2.encrypted.filler, 12);
|
||||
|
||||
i2p::crypto::AESKey aesKey;
|
||||
CreateAESKey (m_Establisher->phase1.pubKey, aesKey);
|
||||
@@ -207,7 +207,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Couldn't send Phase 2 message: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: Couldn't send Phase 2 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -223,7 +223,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
|
||||
LogPrint (eLogError, "NTCP: Phase 2 read error: ", ecode.message (), ". Wrong ident assumed");
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
// this RI is not valid
|
||||
@@ -251,7 +251,7 @@ namespace transport
|
||||
SHA256 (xy, 512, digest);
|
||||
if (memcmp(m_Establisher->phase2.encrypted.hxy, digest, 32))
|
||||
{
|
||||
LogPrint (eLogError, "Incorrect hash");
|
||||
LogPrint (eLogError, "NTCP: Phase 2 process error: incorrect hash");
|
||||
transports.ReuseDHKeysPair (m_DHKeysPair);
|
||||
m_DHKeysPair = nullptr;
|
||||
Terminate ();
|
||||
@@ -287,7 +287,7 @@ namespace transport
|
||||
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
||||
s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident
|
||||
s.Insert (tsA); // tsA
|
||||
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
|
||||
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
|
||||
s.Sign (keys, buf);
|
||||
|
||||
m_Encryption.Encrypt(m_ReceiveBuffer, len, m_ReceiveBuffer);
|
||||
@@ -299,7 +299,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Couldn't send Phase 3 message: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: Couldn't send Phase 3 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -319,7 +319,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Phase 3 read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: Phase 3 read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -331,7 +331,7 @@ namespace transport
|
||||
SetRemoteIdentity (std::make_shared<i2p::data::IdentityEx> (buf + 2, size));
|
||||
if (m_Server.FindNTCPSession (m_RemoteIdentity->GetIdentHash ()))
|
||||
{
|
||||
LogPrint (eLogError, "NTCP session already exists");
|
||||
LogPrint (eLogError, "NTCP: session already exists");
|
||||
Terminate ();
|
||||
}
|
||||
size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity->GetSignatureLen ();
|
||||
@@ -354,7 +354,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Phase 3 extra read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: Phase 3 extra read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -380,7 +380,7 @@ namespace transport
|
||||
s.Insert (tsB); // tsB
|
||||
if (!s.Verify (m_RemoteIdentity, buf))
|
||||
{
|
||||
LogPrint (eLogError, "signature verification failed");
|
||||
LogPrint (eLogError, "NTCP: signature verification failed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -411,13 +411,13 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "Couldn't send Phase 4 message: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP: Couldn't send Phase 4 message: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP server session from ", m_Socket.remote_endpoint (), " connected");
|
||||
LogPrint (eLogInfo, "NTCP: Server session from ", m_Socket.remote_endpoint (), " connected");
|
||||
m_Server.AddNTCPSession (shared_from_this ());
|
||||
|
||||
Connected ();
|
||||
@@ -431,7 +431,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Phase 4 read error: ", ecode.message (), ". Check your clock");
|
||||
LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock");
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
// this router doesn't like us
|
||||
@@ -449,15 +449,15 @@ namespace transport
|
||||
s.Insert (m_Establisher->phase2.pubKey, 256); // y
|
||||
s.Insert (i2p::context.GetIdentHash (), 32); // ident
|
||||
s.Insert (tsA); // tsA
|
||||
s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB
|
||||
s.Insert (m_Establisher->phase2.encrypted.timestamp, 4); // tsB
|
||||
|
||||
if (!s.Verify (m_RemoteIdentity, m_ReceiveBuffer))
|
||||
{
|
||||
LogPrint (eLogError, "signature verification failed");
|
||||
LogPrint (eLogError, "NTCP: Phase 4 process error: signature verification failed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
LogPrint (eLogInfo, "NTCP session to ", m_Socket.remote_endpoint (), " connected");
|
||||
LogPrint (eLogDebug, "NTCP: session to ", m_Socket.remote_endpoint (), " connected");
|
||||
Connected ();
|
||||
|
||||
m_ReceiveBufferOffset = 0;
|
||||
@@ -477,7 +477,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: Read error: ", ecode.message ());
|
||||
if (!m_NumReceivedBytes) m_Server.Ban (m_ConnectedFrom);
|
||||
//if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
@@ -519,7 +519,7 @@ namespace transport
|
||||
moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes));
|
||||
if (ec)
|
||||
{
|
||||
LogPrint (eLogError, "Read more bytes error: ", ec.message ());
|
||||
LogPrint (eLogError, "NTCP: Read more bytes error: ", ec.message ());
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -542,20 +542,20 @@ namespace transport
|
||||
{
|
||||
if (!m_NextMessage) // new message, header expected
|
||||
{
|
||||
// descrypt header and extract length
|
||||
// decrypt header and extract length
|
||||
uint8_t buf[16];
|
||||
m_Decryption.Decrypt (encrypted, buf);
|
||||
uint16_t dataSize = bufbe16toh (buf);
|
||||
if (dataSize)
|
||||
{
|
||||
// new message
|
||||
if (dataSize > NTCP_MAX_MESSAGE_SIZE)
|
||||
if (dataSize + 16U > NTCP_MAX_MESSAGE_SIZE - 2) // + 6 + padding
|
||||
{
|
||||
LogPrint (eLogError, "NTCP data size ", dataSize, " exceeds max size");
|
||||
LogPrint (eLogError, "NTCP: data size ", dataSize, " exceeds max size");
|
||||
return false;
|
||||
}
|
||||
auto msg = dataSize <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||
m_NextMessage = ToSharedI2NPMessage (msg);
|
||||
auto msg = (dataSize + 16U) <= I2NP_MAX_SHORT_MESSAGE_SIZE - 2 ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||
m_NextMessage = msg;
|
||||
memcpy (m_NextMessage->buf, buf, 16);
|
||||
m_NextMessageOffset = 16;
|
||||
m_NextMessage->offset = 2; // size field
|
||||
@@ -564,7 +564,7 @@ namespace transport
|
||||
else
|
||||
{
|
||||
// timestamp
|
||||
LogPrint ("Timestamp");
|
||||
LogPrint (eLogDebug, "NTCP: Timestamp");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -582,7 +582,7 @@ namespace transport
|
||||
if (!memcmp (m_NextMessage->buf + m_NextMessageOffset - 4, checksum, 4))
|
||||
m_Handler.PutNextMessage (m_NextMessage);
|
||||
else
|
||||
LogPrint (eLogWarning, "Incorrect adler checksum of NTCP message. Dropped");
|
||||
LogPrint (eLogWarning, "NTCP: Incorrect adler checksum of message, dropped");
|
||||
m_NextMessage = nullptr;
|
||||
}
|
||||
return true;
|
||||
@@ -604,7 +604,7 @@ namespace transport
|
||||
{
|
||||
// regular I2NP
|
||||
if (msg->offset < 2)
|
||||
LogPrint (eLogError, "Malformed I2NP message"); // TODO:
|
||||
LogPrint (eLogError, "NTCP: Malformed I2NP message"); // TODO:
|
||||
sendBuffer = msg->GetBuffer () - 2;
|
||||
len = msg->GetLength ();
|
||||
htobe16buf (sendBuffer, len);
|
||||
@@ -644,7 +644,7 @@ namespace transport
|
||||
m_IsSending = false;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "Couldn't send msgs: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP: Couldn't send msgs: ", ecode.message ());
|
||||
// we shouldn't call Terminate () here, because HandleReceive takes care
|
||||
// TODO: 'delete this' statement in Terminate () must be eliminated later
|
||||
// Terminate ();
|
||||
@@ -699,7 +699,7 @@ namespace transport
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint ("No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
|
||||
LogPrint (eLogWarning, "NTCP: No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
|
||||
//Terminate ();
|
||||
m_Socket.close ();// invoke Terminate () from HandleReceive
|
||||
}
|
||||
@@ -732,7 +732,7 @@ namespace transport
|
||||
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service,
|
||||
boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address.port));
|
||||
|
||||
LogPrint (eLogInfo, "Start listening TCP port ", address.port);
|
||||
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address.port);
|
||||
auto conn = std::make_shared<NTCPSession>(*this);
|
||||
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this,
|
||||
conn, std::placeholders::_1));
|
||||
@@ -745,7 +745,7 @@ namespace transport
|
||||
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address.port));
|
||||
m_NTCPV6Acceptor->listen ();
|
||||
|
||||
LogPrint (eLogInfo, "Start listening V6 TCP port ", address.port);
|
||||
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address.port);
|
||||
auto conn = std::make_shared<NTCPSession> (*this);
|
||||
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6,
|
||||
this, conn, std::placeholders::_1));
|
||||
@@ -788,32 +788,33 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("NTCP server: ", ex.what ());
|
||||
LogPrint (eLogError, "NTCP: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTCPServer::AddNTCPSession (std::shared_ptr<NTCPSession> session)
|
||||
bool NTCPServer::AddNTCPSession (std::shared_ptr<NTCPSession> session)
|
||||
{
|
||||
if (session && session->GetRemoteIdentity ())
|
||||
if (!session || !session->GetRemoteIdentity ()) return false;
|
||||
auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
|
||||
auto it = m_NTCPSessions.find (ident);
|
||||
if (it != m_NTCPSessions.end ())
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_NTCPSessionsMutex);
|
||||
m_NTCPSessions[session->GetRemoteIdentity ()->GetIdentHash ()] = session;
|
||||
LogPrint (eLogWarning, "NTCP: session to ", ident.ToBase64 (), " already exists");
|
||||
return false;
|
||||
}
|
||||
m_NTCPSessions.insert (std::pair<i2p::data::IdentHash, std::shared_ptr<NTCPSession> >(ident, session));
|
||||
return true;
|
||||
}
|
||||
|
||||
void NTCPServer::RemoveNTCPSession (std::shared_ptr<NTCPSession> session)
|
||||
{
|
||||
if (session && session->GetRemoteIdentity ())
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_NTCPSessionsMutex);
|
||||
m_NTCPSessions.erase (session->GetRemoteIdentity ()->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<NTCPSession> NTCPServer::FindNTCPSession (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_NTCPSessionsMutex);
|
||||
auto it = m_NTCPSessions.find (ident);
|
||||
if (it != m_NTCPSessions.end ())
|
||||
return it->second;
|
||||
@@ -828,14 +829,14 @@ namespace transport
|
||||
auto ep = conn->GetSocket ().remote_endpoint(ec);
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogInfo, "Connected from ", ep);
|
||||
LogPrint (eLogDebug, "NTCP: Connected from ", ep);
|
||||
auto it = m_BanList.find (ep.address ());
|
||||
if (it != m_BanList.end ())
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts < it->second)
|
||||
{
|
||||
LogPrint (eLogInfo, ep.address (), " is banned for ", it->second - ts, " more seconds");
|
||||
LogPrint (eLogWarning, "NTCP: ", ep.address (), " is banned for ", it->second - ts, " more seconds");
|
||||
conn = nullptr;
|
||||
}
|
||||
else
|
||||
@@ -845,7 +846,7 @@ namespace transport
|
||||
conn->ServerLogin ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Connected from error ", ec.message ());
|
||||
LogPrint (eLogError, "NTCP: Connected from error ", ec.message ());
|
||||
}
|
||||
|
||||
|
||||
@@ -865,14 +866,14 @@ namespace transport
|
||||
auto ep = conn->GetSocket ().remote_endpoint(ec);
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogInfo, "Connected from ", ep);
|
||||
LogPrint (eLogDebug, "NTCP: Connected from ", ep);
|
||||
auto it = m_BanList.find (ep.address ());
|
||||
if (it != m_BanList.end ())
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts < it->second)
|
||||
{
|
||||
LogPrint (eLogInfo, ep.address (), " is banned for ", it->second - ts, " more seconds");
|
||||
LogPrint (eLogWarning, "NTCP: ", ep.address (), " is banned for ", it->second - ts, " more seconds");
|
||||
conn = nullptr;
|
||||
}
|
||||
else
|
||||
@@ -882,7 +883,7 @@ namespace transport
|
||||
conn->ServerLogin ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Connected from error ", ec.message ());
|
||||
LogPrint (eLogError, "NTCP: Connected from error ", ec.message ());
|
||||
}
|
||||
|
||||
if (error != boost::asio::error::operation_aborted)
|
||||
@@ -895,27 +896,27 @@ namespace transport
|
||||
|
||||
void NTCPServer::Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn)
|
||||
{
|
||||
LogPrint (eLogInfo, "Connecting to ", address ,":", port);
|
||||
m_Service.post([conn, this]()
|
||||
{
|
||||
this->AddNTCPSession (conn);
|
||||
});
|
||||
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port),
|
||||
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn));
|
||||
LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port);
|
||||
m_Service.post([=]()
|
||||
{
|
||||
if (this->AddNTCPSession (conn))
|
||||
conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port),
|
||||
std::bind (&NTCPServer::HandleConnect, this, std::placeholders::_1, conn));
|
||||
});
|
||||
}
|
||||
|
||||
void NTCPServer::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCPSession> conn)
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "Connect error: ", ecode.message ());
|
||||
LogPrint (eLogError, "NTCP: Connect error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
||||
conn->Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "Connected to ", conn->GetSocket ().remote_endpoint ());
|
||||
LogPrint (eLogDebug, "NTCP: Connected to ", conn->GetSocket ().remote_endpoint ());
|
||||
if (conn->GetSocket ().local_endpoint ().protocol () == boost::asio::ip::tcp::v6()) // ipv6
|
||||
context.UpdateNTCPV6Address (conn->GetSocket ().local_endpoint ().address ());
|
||||
conn->ClientLogin ();
|
||||
@@ -926,7 +927,7 @@ namespace transport
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_BanList[addr] = ts + NTCP_BAN_EXPIRATION_TIMEOUT;
|
||||
LogPrint (eLogInfo, addr, " has been banned for ", NTCP_BAN_EXPIRATION_TIMEOUT, " seconds");
|
||||
LogPrint (eLogWarning, "NTCP: ", addr, " has been banned for ", NTCP_BAN_EXPIRATION_TIMEOUT, " seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
|
||||
#pragma pack(1)
|
||||
struct NTCPPhase1
|
||||
{
|
||||
uint8_t pubKey[256];
|
||||
@@ -31,12 +29,10 @@ namespace transport
|
||||
struct
|
||||
{
|
||||
uint8_t hxy[32];
|
||||
uint32_t timestamp;
|
||||
uint8_t timestamp[4];
|
||||
uint8_t filler[12];
|
||||
} encrypted;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
|
||||
const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028)
|
||||
@@ -143,7 +139,7 @@ namespace transport
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
void AddNTCPSession (std::shared_ptr<NTCPSession> session);
|
||||
bool AddNTCPSession (std::shared_ptr<NTCPSession> session);
|
||||
void RemoveNTCPSession (std::shared_ptr<NTCPSession> session);
|
||||
std::shared_ptr<NTCPSession> FindNTCPSession (const i2p::data::IdentHash& ident);
|
||||
void Connect (const boost::asio::ip::address& address, int port, std::shared_ptr<NTCPSession> conn);
|
||||
@@ -166,8 +162,7 @@ namespace transport
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::io_service::work m_Work;
|
||||
boost::asio::ip::tcp::acceptor * m_NTCPAcceptor, * m_NTCPV6Acceptor;
|
||||
std::mutex m_NTCPSessionsMutex;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<NTCPSession> > m_NTCPSessions; // access from m_Thread only
|
||||
std::map<boost::asio::ip::address, uint32_t> m_BanList; // IP -> ban expiration time in seconds
|
||||
|
||||
public:
|
||||
|
||||
128
NetDb.cpp
128
NetDb.cpp
@@ -80,22 +80,20 @@ namespace data
|
||||
int numMsgs = 0;
|
||||
while (msg)
|
||||
{
|
||||
LogPrint(eLogDebug, "NetDb: got request with type ", (int) msg->GetTypeID ());
|
||||
switch (msg->GetTypeID ())
|
||||
{
|
||||
case eI2NPDatabaseStore:
|
||||
LogPrint ("DatabaseStore");
|
||||
HandleDatabaseStoreMsg (msg);
|
||||
break;
|
||||
case eI2NPDatabaseSearchReply:
|
||||
LogPrint ("DatabaseSearchReply");
|
||||
HandleDatabaseSearchReplyMsg (msg);
|
||||
break;
|
||||
case eI2NPDatabaseLookup:
|
||||
LogPrint ("DatabaseLookup");
|
||||
HandleDatabaseLookupMsg (msg);
|
||||
break;
|
||||
default: // WTF?
|
||||
LogPrint (eLogError, "NetDb: unexpected message type ", msg->GetTypeID ());
|
||||
LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ());
|
||||
//i2p::HandleI2NPMessage (msg);
|
||||
}
|
||||
if (numMsgs > 100) break;
|
||||
@@ -128,6 +126,11 @@ namespace data
|
||||
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
|
||||
{
|
||||
auto numRouters = m_RouterInfos.size ();
|
||||
if (numRouters == 0)
|
||||
{
|
||||
LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed");
|
||||
break;
|
||||
}
|
||||
if (numRouters < 2500 || ts - lastExploratory >= 90)
|
||||
{
|
||||
numRouters = 800/numRouters;
|
||||
@@ -141,7 +144,7 @@ namespace data
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("NetDb: ", ex.what ());
|
||||
LogPrint (eLogError, "NetDb: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,11 +164,11 @@ namespace data
|
||||
auto ts = r->GetTimestamp ();
|
||||
r->Update (buf, len);
|
||||
if (r->GetTimestamp () > ts)
|
||||
LogPrint ("RouterInfo updated");
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase32());
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("New RouterInfo added");
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase32());
|
||||
r = std::make_shared<RouterInfo> (buf, len);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
@@ -191,10 +194,10 @@ namespace data
|
||||
{
|
||||
it->second->Update (buf, len);
|
||||
if (it->second->IsValid ())
|
||||
LogPrint (eLogInfo, "LeaseSet updated");
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "LeaseSet update failed");
|
||||
LogPrint (eLogWarning, "NetDb: LeaseSet update failed: ", ident.ToBase32());
|
||||
m_LeaseSets.erase (it);
|
||||
}
|
||||
}
|
||||
@@ -203,11 +206,11 @@ namespace data
|
||||
auto leaseSet = std::make_shared<LeaseSet> (buf, len);
|
||||
if (leaseSet->IsValid ())
|
||||
{
|
||||
LogPrint (eLogInfo, "New LeaseSet added");
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32());
|
||||
m_LeaseSets[ident] = leaseSet;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "New LeaseSet validation failed");
|
||||
LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase32());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,24 +250,23 @@ namespace data
|
||||
// TODO: Move to reseed and/or scheduled tasks. (In java version, scheduler fix this as well as sort RIs.)
|
||||
bool NetDb::CreateNetDb(boost::filesystem::path directory)
|
||||
{
|
||||
LogPrint (directory.string(), " doesn't exist, trying to create it.");
|
||||
LogPrint (eLogInfo, "NetDb: storage directory doesn't exist, trying to create it.");
|
||||
if (!boost::filesystem::create_directory (directory))
|
||||
{
|
||||
LogPrint("Failed to create directory ", directory.string());
|
||||
LogPrint (eLogError, "NetDb: failed to create directory ", directory);
|
||||
return false;
|
||||
}
|
||||
|
||||
// list of chars might appear in base64 string
|
||||
const char * chars = GetBase64SubstitutionTable (); // 64 bytes
|
||||
boost::filesystem::path suffix;
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
suffix = std::string ("/r") + chars[i];
|
||||
#else
|
||||
suffix = std::string ("\\r") + chars[i];
|
||||
#endif
|
||||
if (!boost::filesystem::create_directory( boost::filesystem::path (directory / suffix) )) return false;
|
||||
auto p = directory / (std::string ("r") + chars[i]);
|
||||
if (!boost::filesystem::exists (p) && !boost::filesystem::create_directory (p))
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: failed to create directory ", p);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -280,7 +282,7 @@ namespace data
|
||||
while (reseedRetries < 10 && !m_Reseeder->ReseedNowSU3 ())
|
||||
reseedRetries++;
|
||||
if (reseedRetries >= 10)
|
||||
LogPrint (eLogWarning, "Failed to reseed after 10 attempts");
|
||||
LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts");
|
||||
}
|
||||
|
||||
void NetDb::Load ()
|
||||
@@ -328,8 +330,7 @@ namespace data
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (numRouters, " routers loaded");
|
||||
LogPrint (m_Floodfills.size (), " floodfills loaded");
|
||||
LogPrint (eLogInfo, "NetDb: ", numRouters, " routers loaded (", m_Floodfills.size (), " floodfils)");
|
||||
}
|
||||
|
||||
void NetDb::SaveUpdated ()
|
||||
@@ -407,10 +408,10 @@ namespace data
|
||||
}
|
||||
}
|
||||
if (count > 0)
|
||||
LogPrint (count," new/updated routers saved");
|
||||
LogPrint (eLogInfo, "NetDb: ", count, " new/updated routers saved");
|
||||
if (deletedCount > 0)
|
||||
{
|
||||
LogPrint (deletedCount," routers deleted");
|
||||
LogPrint (eLogDebug, "NetDb: ", deletedCount, " routers deleted");
|
||||
// clean up RouterInfos table
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
|
||||
@@ -431,7 +432,7 @@ namespace data
|
||||
auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination ", destination.ToBase64(), " is requested already");
|
||||
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase32(), " is requested already");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -440,7 +441,7 @@ namespace data
|
||||
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "No floodfills found");
|
||||
LogPrint (eLogError, "NetDb: ", destination.ToBase32(), " destination requested, but no floodfills found");
|
||||
m_Requests.RequestComplete (destination, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -452,7 +453,7 @@ namespace data
|
||||
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
if (ident.IsZero ())
|
||||
{
|
||||
LogPrint (eLogError, "Database store with zero ident. Dropped");
|
||||
LogPrint (eLogError, "NetDb: database store with zero ident, dropped");
|
||||
return;
|
||||
}
|
||||
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
|
||||
@@ -471,43 +472,49 @@ namespace data
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
|
||||
else
|
||||
LogPrint (eLogError, "No outbound tunnels for DatabaseStore reply found");
|
||||
LogPrint (eLogError, "NetDb: no outbound tunnels for DatabaseStore reply found");
|
||||
}
|
||||
offset += 32;
|
||||
|
||||
if (context.IsFloodfill ())
|
||||
{
|
||||
// flood it
|
||||
auto floodMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
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;
|
||||
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
|
||||
std::set<IdentHash> excluded;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto floodfill = GetClosestFloodfill (ident, excluded);
|
||||
if (floodfill)
|
||||
transports.SendMessage (floodfill->GetIdentHash (), floodMsg);
|
||||
auto msgLen = len - offset;
|
||||
floodMsg->len += DATABASE_STORE_HEADER_SIZE + msgLen;
|
||||
if (floodMsg->len < floodMsg->maxLen)
|
||||
{
|
||||
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + offset, msgLen);
|
||||
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
|
||||
std::set<IdentHash> excluded;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
auto floodfill = GetClosestFloodfill (ident, excluded);
|
||||
if (floodfill)
|
||||
transports.SendMessage (floodfill->GetIdentHash (), floodMsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Database store message is too long ", floodMsg->len);
|
||||
}
|
||||
}
|
||||
|
||||
if (buf[DATABASE_STORE_TYPE_OFFSET]) // type
|
||||
{
|
||||
LogPrint ("LeaseSet");
|
||||
LogPrint (eLogDebug, "NetDb: store request: LeaseSet");
|
||||
AddLeaseSet (ident, buf + offset, len - offset, m->from);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("RouterInfo");
|
||||
LogPrint (eLogDebug, "NetDb: store request: RouterInfo");
|
||||
size_t size = bufbe16toh (buf + offset);
|
||||
offset += 2;
|
||||
if (size > 2048 || size > len - offset)
|
||||
{
|
||||
LogPrint ("Invalid RouterInfo length ", (int)size);
|
||||
LogPrint (eLogError, "NetDb: invalid RouterInfo length ", (int)size);
|
||||
return;
|
||||
}
|
||||
uint8_t uncompressed[2048];
|
||||
@@ -524,7 +531,7 @@ namespace data
|
||||
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
||||
key[l] = 0;
|
||||
int num = buf[32]; // num
|
||||
LogPrint ("DatabaseSearchReply for ", key, " num=", num);
|
||||
LogPrint (eLogDebug, "NetDb: DatabaseSearchReply for ", key, " num=", num);
|
||||
IdentHash ident (buf);
|
||||
auto dest = m_Requests.FindRequest (ident);
|
||||
if (dest)
|
||||
@@ -556,7 +563,7 @@ namespace data
|
||||
});
|
||||
|
||||
// request destination
|
||||
LogPrint ("Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
|
||||
LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
|
||||
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
@@ -567,7 +574,7 @@ namespace data
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (key, " was not found on 7 floodfills");
|
||||
LogPrint (eLogWarning, "NetDb: ", key, " was not found on ", count, " floodfills");
|
||||
|
||||
if (msgs.size () > 0)
|
||||
outbound->SendTunnelDataMsg (msgs);
|
||||
@@ -583,7 +590,7 @@ namespace data
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
}
|
||||
else
|
||||
LogPrint ("Requested destination for ", key, " not found");
|
||||
LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found");
|
||||
|
||||
// try responses
|
||||
for (int i = 0; i < num; i++)
|
||||
@@ -592,17 +599,17 @@ namespace data
|
||||
char peerHash[48];
|
||||
int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48);
|
||||
peerHash[l1] = 0;
|
||||
LogPrint (i,": ", peerHash);
|
||||
LogPrint (eLogDebug, "NetDb: ", i, ": ", peerHash);
|
||||
|
||||
auto r = FindRouter (router);
|
||||
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
|
||||
{
|
||||
// router with ident not found or too old (1 hour)
|
||||
LogPrint ("Found new/outdated router. Requesting RouterInfo ...");
|
||||
LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ...");
|
||||
RequestDestination (router);
|
||||
}
|
||||
else
|
||||
LogPrint ("Bayan");
|
||||
LogPrint (eLogDebug, "NetDb: [:|||:]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -612,14 +619,14 @@ namespace data
|
||||
IdentHash ident (buf);
|
||||
if (ident.IsZero ())
|
||||
{
|
||||
LogPrint (eLogError, "DatabaseLookup for zero ident. Ignored");
|
||||
LogPrint (eLogError, "NetDb: DatabaseLookup for zero ident. Ignored");
|
||||
return;
|
||||
}
|
||||
char key[48];
|
||||
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
|
||||
key[l] = 0;
|
||||
uint8_t flag = buf[64];
|
||||
LogPrint ("DatabaseLookup for ", key, " recieved flags=", (int)flag);
|
||||
LogPrint (eLogDebug, "NetDb: DatabaseLookup for ", key, " recieved flags=", (int)flag);
|
||||
uint8_t lookupType = flag & DATABASE_LOOKUP_TYPE_FLAGS_MASK;
|
||||
const uint8_t * excluded = buf + 65;
|
||||
uint32_t replyTunnelID = 0;
|
||||
@@ -632,14 +639,14 @@ namespace data
|
||||
excluded += 2;
|
||||
if (numExcluded > 512)
|
||||
{
|
||||
LogPrint ("Number of excluded peers", numExcluded, " exceeds 512");
|
||||
LogPrint (eLogWarning, "NetDb: number of excluded peers", numExcluded, " exceeds 512");
|
||||
numExcluded = 0; // TODO:
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> replyMsg;
|
||||
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
|
||||
{
|
||||
LogPrint ("Exploratory close to ", key, " ", numExcluded, " excluded");
|
||||
LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded");
|
||||
std::set<IdentHash> excludedRouters;
|
||||
for (int i = 0; i < numExcluded; i++)
|
||||
{
|
||||
@@ -666,7 +673,7 @@ namespace data
|
||||
auto router = FindRouter (ident);
|
||||
if (router)
|
||||
{
|
||||
LogPrint ("Requested RouterInfo ", key, " found");
|
||||
LogPrint (eLogDebug, "NetDb: requested RouterInfo ", key, " found");
|
||||
router->LoadBuffer ();
|
||||
if (router->GetBuffer ())
|
||||
replyMsg = CreateDatabaseStoreMsg (router);
|
||||
@@ -679,14 +686,14 @@ namespace data
|
||||
auto leaseSet = FindLeaseSet (ident);
|
||||
if (leaseSet) // we don't send back our LeaseSets
|
||||
{
|
||||
LogPrint ("Requested LeaseSet ", key, " found");
|
||||
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
|
||||
replyMsg = CreateDatabaseStoreMsg (leaseSet);
|
||||
}
|
||||
}
|
||||
|
||||
if (!replyMsg)
|
||||
{
|
||||
LogPrint ("Requested ", key, " not found. ", numExcluded, " excluded");
|
||||
LogPrint (eLogWarning, "NetDb: Requested ", key, " not found. ", numExcluded, " excluded");
|
||||
std::set<IdentHash> excludedRouters;
|
||||
for (int i = 0; i < numExcluded; i++)
|
||||
{
|
||||
@@ -736,14 +743,14 @@ namespace data
|
||||
uint8_t randomHash[32];
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
std::set<const RouterInfo *> floodfills;
|
||||
LogPrint ("Exploring new ", numDestinations, " routers ...");
|
||||
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
|
||||
for (int i = 0; i < numDestinations; i++)
|
||||
{
|
||||
RAND_bytes (randomHash, 32);
|
||||
auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "Exploratory destination is requested already");
|
||||
LogPrint (eLogWarning, "NetDb: exploratory destination is requested already");
|
||||
return;
|
||||
}
|
||||
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
||||
@@ -779,6 +786,7 @@ namespace data
|
||||
|
||||
void NetDb::Publish ()
|
||||
{
|
||||
i2p::context.UpdateStats (); // for floodfill
|
||||
std::set<IdentHash> excluded; // TODO: fill up later
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -787,7 +795,7 @@ namespace data
|
||||
{
|
||||
uint32_t replyToken;
|
||||
RAND_bytes ((uint8_t *)&replyToken, 4);
|
||||
LogPrint ("Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||
excluded.insert (floodfill->GetIdentHash ());
|
||||
}
|
||||
@@ -973,7 +981,7 @@ namespace data
|
||||
{
|
||||
if (!it->second->HasNonExpiredLeases ()) // all leases expired
|
||||
{
|
||||
LogPrint ("LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
LogPrint (eLogWarning, "NetDb: LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
it = m_LeaseSets.erase (it);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace data
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
auto path1 = path / (std::string ("p") + chars[i]);
|
||||
if (!boost::filesystem::create_directory (path1))
|
||||
if (!boost::filesystem::exists (path1) && !boost::filesystem::create_directory (path1))
|
||||
{
|
||||
LogPrint (eLogError, "Failed to create directory ", path1);
|
||||
return;
|
||||
|
||||
128
README.md
128
README.md
@@ -17,129 +17,25 @@ BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
|
||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
|
||||
|
||||
Requirements for Linux/FreeBSD/OSX
|
||||
----------------------------------
|
||||
|
||||
GCC 4.6 or newer, Boost 1.46 or newer, openssl, zlib. Clang can be used instead of
|
||||
GCC.
|
||||
|
||||
Requirements for Windows
|
||||
------------------------
|
||||
|
||||
VS2013 (known to work with 12.0.21005.1 or newer), Boost 1.46 or newer,
|
||||
crypto++ 5.62. See Win32/README-Build.txt for instructions on how to build i2pd
|
||||
and its dependencies.
|
||||
|
||||
Downloads
|
||||
------------
|
||||
|
||||
Official binary releases could be found at:
|
||||
http://i2pd.website/releases/
|
||||
older releases
|
||||
http://download.i2p.io/purplei2p/i2pd/releases/
|
||||
|
||||
|
||||
Build Statuses
|
||||
---------------
|
||||
|
||||
- Linux x64 - [](https://jenkins.nordcloud.no/job/i2pd-linux/)
|
||||
- Linux ARM - To be added
|
||||
- Mac OS X - Got it working, but not well tested. (Only works with clang, not GCC.)
|
||||
- Microsoft VC13 - To be added
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
First, build it.
|
||||
|
||||
On Ubuntu/Debian based
|
||||
* sudo apt-get install libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-regex-dev libboost-date-time-dev libssl-dev zlib1g-dev
|
||||
* $ cd i2pd
|
||||
* $ make
|
||||
|
||||
Then, run it:
|
||||
|
||||
$ ./i2p
|
||||
|
||||
The client should now reseed by itself.
|
||||
|
||||
To visit an I2P page, you need to find the b32 address of your destination.
|
||||
After that, go to the webconsole and add it behind the url. (Remove http:// from the address)
|
||||
|
||||
This should resulting in for example:
|
||||
http://localhost:7070/4oes3rlgrpbkmzv4lqcfili23h3cvpwslqcfjlk6vvguxyggspwa.b32.i2p
|
||||
|
||||
|
||||
Cmdline options
|
||||
---------------
|
||||
|
||||
* --host= - The external IP (deprecated).
|
||||
* --port= - The port to listen on
|
||||
* --httpport= - The http port to listen on
|
||||
* --log= - Enable or disable logging to file. 1 for yes, 0 for no.
|
||||
* --daemon= - Enable or disable daemon mode. 1 for yes, 0 for no.
|
||||
* --service= - 1 if uses system folders (/var/run/i2pd.pid, /var/log/i2pd.log, /var/lib/i2pd).
|
||||
* --v6= - 1 if supports communication through ipv6, off by default
|
||||
* --floodfill= - 1 if router is floodfill, off by default
|
||||
* --bandwidth= - L if bandwidth is limited to 32Kbs/sec, O if not. Always O if floodfill, otherwise L by default.
|
||||
* --httpproxyport= - The port to listen on (HTTP Proxy)
|
||||
* --socksproxyport= - The port to listen on (SOCKS Proxy)
|
||||
* --proxykeys= - optional keys file for proxy's local destination
|
||||
* --ircport= - The local port of IRC tunnel to listen on. 6668 by default
|
||||
* --ircdest= - I2P destination address of IRC server. For example irc.postman.i2p
|
||||
* --irckeys= - optional keys file for tunnel's local destination
|
||||
* --eepkeys= - File name containing destination keys, for example privKeys.dat.
|
||||
The file will be created if it does not already exist (issue #110).
|
||||
* --eephost= - Address incoming trafic forward to. 127.0.0.1 by default
|
||||
* --eepport= - Port incoming trafic forward to. 80 by default
|
||||
* --samport= - Port of SAM bridge. Usually 7656. SAM is off if not specified
|
||||
* --bobport= - Port of BOB command channel. Usually 2827. BOB is off if not specified
|
||||
* --i2pcontrolport= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
|
||||
* --conf= - Config file (default: ~/.i2pd/i2p.conf or /var/lib/i2pd/i2p.conf)
|
||||
This parameter will be silently ignored if the specified config file does not exist.
|
||||
Options specified on the command line take precedence over those in the config file.
|
||||
|
||||
Config files
|
||||
Supported OS
|
||||
------------
|
||||
|
||||
INI-like, syntax is the following : <key> = <value>.
|
||||
All command-line parameters are allowed as keys, for example:
|
||||
* Linux x86/x64 - Proved working.
|
||||
* Mac OS X - Not well tested. (Only works with clang, not GCC)
|
||||
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||
|
||||
i2p.conf:
|
||||
More documentation
|
||||
------------------
|
||||
|
||||
log = 1
|
||||
v6 = 0
|
||||
ircdest = irc.postman.i2p
|
||||
|
||||
tunnels.cfg (filename of this config is subject of change):
|
||||
|
||||
; outgoing tunnel sample, to remote service
|
||||
; mandatory parameters:
|
||||
; * type -- always "client"
|
||||
; * port -- local port to listen to
|
||||
; * destination -- i2p hostname
|
||||
; optional parameters (may be omitted)
|
||||
; * 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
|
||||
[IRC]
|
||||
type = client
|
||||
port = 6668
|
||||
destination = irc.echelon.i2p
|
||||
keys = irc-keys.dat
|
||||
|
||||
; incoming tunnel sample, for local service
|
||||
; mandatory parameters:
|
||||
; * type -- always "server"
|
||||
; * 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>]
|
||||
* [Building from source / unix](docs/build_notes_unix.md)
|
||||
* [Building from source / windows](docs/build_notes_windows.md)
|
||||
* [Configuring your i2pd](docs/configuration.md)
|
||||
* [Github wiki](https://github.com/PurpleI2P/i2pd/wiki/)
|
||||
|
||||
53
Reseed.cpp
53
Reseed.cpp
@@ -30,6 +30,7 @@ namespace data
|
||||
"https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required
|
||||
"https://us.reseed.i2p2.no:444/",
|
||||
"https://uk.reseed.i2p2.no:444/",
|
||||
"https://www.torontocrypto.org:8443/"
|
||||
"https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support
|
||||
"https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support
|
||||
"https://ieb9oopo.mooo.com/" // Only HTTPS and SU3 (v3) support
|
||||
@@ -47,14 +48,14 @@ namespace data
|
||||
{
|
||||
auto ind = rand () % httpsReseedHostList.size ();
|
||||
std::string& reseedHost = httpsReseedHostList[ind];
|
||||
return ReseedFromSU3 (reseedHost, true);
|
||||
return ReseedFromSU3 (reseedHost);
|
||||
}
|
||||
|
||||
int Reseeder::ReseedFromSU3 (const std::string& host, bool https)
|
||||
int Reseeder::ReseedFromSU3 (const std::string& host)
|
||||
{
|
||||
std::string url = host + "i2pseeds.su3";
|
||||
LogPrint (eLogInfo, "Dowloading SU3 from ", host);
|
||||
std::string su3 = https ? HttpsRequest (url) : i2p::util::http::httpRequest (url);
|
||||
LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", host);
|
||||
std::string su3 = HttpsRequest (url);
|
||||
if (su3.length () > 0)
|
||||
{
|
||||
std::stringstream s(su3);
|
||||
@@ -62,7 +63,7 @@ namespace data
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SU3 download failed");
|
||||
LogPrint (eLogWarning, "Reseed: SU3 download failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +75,7 @@ namespace data
|
||||
return ProcessSU3Stream (s);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Can't open file ", filename);
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -89,7 +90,7 @@ namespace data
|
||||
s.read (magicNumber, 7); // magic number and zero byte 6
|
||||
if (strcmp (magicNumber, SU3_MAGIC_NUMBER))
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected SU3 magic number");
|
||||
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
|
||||
return 0;
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // su3 file format version
|
||||
@@ -113,7 +114,7 @@ namespace data
|
||||
s.read ((char *)&fileType, 1); // file type
|
||||
if (fileType != 0x00) // zip file
|
||||
{
|
||||
LogPrint (eLogError, "Can't handle file type ", (int)fileType);
|
||||
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
|
||||
return 0;
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
@@ -121,7 +122,7 @@ namespace data
|
||||
s.read ((char *)&contentType, 1); // content type
|
||||
if (contentType != 0x03) // reseed data
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected content type ", (int)contentType);
|
||||
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
|
||||
return 0;
|
||||
}
|
||||
s.seekg (12, std::ios::cur); // unused
|
||||
@@ -155,13 +156,13 @@ namespace data
|
||||
BIGNUM * s = BN_new (), * n = BN_new ();
|
||||
BN_bin2bn (signature, signatureLength, s);
|
||||
BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n);
|
||||
BN_mod_exp (s, s, i2p::crypto::rsae, n, bnctx); // s = s^e mod n
|
||||
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
|
||||
uint8_t * enSigBuf = new uint8_t[signatureLength];
|
||||
i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
|
||||
// digest is right aligned
|
||||
// we can't use RSA_verify due wrong padding in SU3
|
||||
if (memcmp (enSigBuf + (signatureLength - 64), digest, 64))
|
||||
LogPrint (eLogWarning, "SU3 signature verification failed");
|
||||
LogPrint (eLogWarning, "Reseed: SU3 signature verification failed");
|
||||
delete[] enSigBuf;
|
||||
BN_free (s); BN_free (n);
|
||||
BN_CTX_free (bnctx);
|
||||
@@ -172,10 +173,10 @@ namespace data
|
||||
s.seekg (pos, std::ios::beg);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Signature type ", signatureType, " is not supported");
|
||||
LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Certificate for ", signerID, " not loaded");
|
||||
LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
|
||||
|
||||
// handle content
|
||||
int numFiles = 0;
|
||||
@@ -219,7 +220,7 @@ namespace data
|
||||
size_t pos = s.tellg ();
|
||||
if (!FindZipDataDescriptor (s))
|
||||
{
|
||||
LogPrint (eLogError, "SU3 archive data descriptor not found");
|
||||
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
|
||||
return numFiles;
|
||||
}
|
||||
s.read ((char *)&crc_32, 4);
|
||||
@@ -233,10 +234,10 @@ namespace data
|
||||
s.seekg (pos, std::ios::beg); // back to compressed data
|
||||
}
|
||||
|
||||
LogPrint (eLogDebug, "Proccessing file ", localFileName, " ", compressedSize, " bytes");
|
||||
LogPrint (eLogDebug, "Reseed: Proccessing file ", localFileName, " ", compressedSize, " bytes");
|
||||
if (!compressedSize)
|
||||
{
|
||||
LogPrint (eLogWarning, "Unexpected size 0. Skipped");
|
||||
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -262,10 +263,10 @@ namespace data
|
||||
numFiles++;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "CRC32 verification failed");
|
||||
LogPrint (eLogError, "Reseed: CRC32 verification failed");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "decompression error ", err);
|
||||
LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
|
||||
delete[] uncompressed;
|
||||
inflateEnd (&inflator);
|
||||
}
|
||||
@@ -281,7 +282,7 @@ namespace data
|
||||
else
|
||||
{
|
||||
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
|
||||
LogPrint (eLogWarning, "Missing zip central directory header");
|
||||
LogPrint (eLogWarning, "Reseed: Missing zip central directory header");
|
||||
break; // no more files
|
||||
}
|
||||
size_t end = s.tellg ();
|
||||
@@ -334,7 +335,7 @@ namespace data
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't open certificate file ", filename);
|
||||
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
}
|
||||
|
||||
@@ -344,7 +345,7 @@ namespace data
|
||||
|
||||
if (!boost::filesystem::exists (reseedDir))
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed certificates not loaded. ", reseedDir, " doesn't exist");
|
||||
LogPrint (eLogWarning, "Reseed: certificates not loaded, ", reseedDir, " doesn't exist");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -358,7 +359,7 @@ namespace data
|
||||
numCertificates++;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, numCertificates, " certificates loaded");
|
||||
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
|
||||
}
|
||||
|
||||
std::string Reseeder::HttpsRequest (const std::string& address)
|
||||
@@ -381,7 +382,7 @@ namespace data
|
||||
s.handshake (boost::asio::ssl::stream_base::client, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "Connected to ", u.host_, ":", u.port_);
|
||||
LogPrint (eLogInfo, "Reseed: Connected to ", u.host_, ":", u.port_);
|
||||
// send request
|
||||
std::stringstream ss;
|
||||
ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_
|
||||
@@ -400,13 +401,13 @@ namespace data
|
||||
return i2p::util::http::GetHttpContent (rs);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSL handshake failed: ", ecode.message ());
|
||||
LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Couldn't connect to ", u.host_, ": ", ecode.message ());
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to ", u.host_, ": ", ecode.message ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Couldn't resolve address ", u.host_, ": ", ecode.message ());
|
||||
LogPrint (eLogError, "Reseed: Couldn't resolve address ", u.host_, ": ", ecode.message ());
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
2
Reseed.h
2
Reseed.h
@@ -29,7 +29,7 @@ namespace data
|
||||
|
||||
void LoadCertificate (const std::string& filename);
|
||||
|
||||
int ReseedFromSU3 (const std::string& host, bool https = false);
|
||||
int ReseedFromSU3 (const std::string& host);
|
||||
int ProcessSU3File (const char * filename);
|
||||
int ProcessSU3Stream (std::istream& s);
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ namespace i2p
|
||||
int port = i2p::util::config::GetArg("-port", 0);
|
||||
if (!port)
|
||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
routerInfo.AddSSUAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port, routerInfo.GetIdentHash ());
|
||||
routerInfo.AddNTCPAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port);
|
||||
routerInfo.AddSSUAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port, routerInfo.GetIdentHash ());
|
||||
routerInfo.AddNTCPAddress (i2p::util::config::GetArg("-host", "127.0.0.1").c_str (), port);
|
||||
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
||||
i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC
|
||||
routerInfo.SetProperty ("coreVersion", I2P_VERSION);
|
||||
@@ -147,22 +147,31 @@ namespace i2p
|
||||
|
||||
void RouterContext::SetHighBandwidth ()
|
||||
{
|
||||
if (!m_RouterInfo.IsHighBandwidth ())
|
||||
if (!m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth);
|
||||
m_RouterInfo.SetCaps ((m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eHighBandwidth) & ~i2p::data::RouterInfo::eExtraBandwidth);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetLowBandwidth ()
|
||||
{
|
||||
if (m_RouterInfo.IsHighBandwidth ())
|
||||
if (m_RouterInfo.IsHighBandwidth () || m_RouterInfo.IsExtraBandwidth ())
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth);
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eHighBandwidth & ~i2p::data::RouterInfo::eExtraBandwidth);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetExtraBandwidth ()
|
||||
{
|
||||
if (!m_RouterInfo.IsExtraBandwidth () || !m_RouterInfo.IsHighBandwidth ())
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eExtraBandwidth | i2p::data::RouterInfo::eHighBandwidth);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterContext::IsUnreachable () const
|
||||
{
|
||||
return m_RouterInfo.GetCaps () & i2p::data::RouterInfo::eUnreachable;
|
||||
@@ -255,8 +264,11 @@ namespace i2p
|
||||
auto mtu = i2p::util::net::GetMTU (host);
|
||||
if (mtu)
|
||||
{
|
||||
LogPrint ("Our v6 MTU=", mtu);
|
||||
if (mtu > 1472) mtu = 1472;
|
||||
LogPrint (eLogDebug, "Router: Our v6 MTU=", mtu);
|
||||
if (mtu > 1472) { // TODO: magic constant
|
||||
mtu = 1472;
|
||||
LogPrint(eLogWarning, "Router: MTU dropped to upper limit of 1472 bytes");
|
||||
}
|
||||
}
|
||||
m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu ? mtu : 1472); // TODO
|
||||
updated = true;
|
||||
|
||||
@@ -39,6 +39,12 @@ namespace i2p
|
||||
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
|
||||
[](const i2p::data::RouterInfo *) {});
|
||||
}
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
|
||||
{
|
||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||
[](i2p::garlic::GarlicDestination *) {});
|
||||
}
|
||||
|
||||
uint32_t GetUptime () const;
|
||||
uint32_t GetStartupTime () const { return m_StartupTime; };
|
||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
@@ -56,6 +62,7 @@ namespace i2p
|
||||
void SetFloodfill (bool floodfill);
|
||||
void SetHighBandwidth ();
|
||||
void SetLowBandwidth ();
|
||||
void SetExtraBandwidth ();
|
||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||
|
||||
@@ -62,10 +62,9 @@ namespace data
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo signature verification failed");
|
||||
LogPrint (eLogError, "RouterInfo: signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
m_RouterIdentity->DropVerifier ();
|
||||
}
|
||||
|
||||
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
|
||||
@@ -83,7 +82,7 @@ namespace data
|
||||
m_BufferLen = s.tellg ();
|
||||
if (m_BufferLen < 40)
|
||||
{
|
||||
LogPrint(eLogError, "File", m_FullPath, " is malformed");
|
||||
LogPrint(eLogError, "RouterInfo: File", m_FullPath, " is malformed");
|
||||
return false;
|
||||
}
|
||||
s.seekg(0, std::ios::beg);
|
||||
@@ -93,7 +92,7 @@ namespace data
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Can't open file ", m_FullPath);
|
||||
LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -117,7 +116,7 @@ namespace data
|
||||
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
|
||||
if (!m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo signature verification failed");
|
||||
LogPrint (eLogError, "RouterInfo: signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
m_RouterIdentity->DropVerifier ();
|
||||
@@ -171,9 +170,8 @@ namespace data
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: resolve address for SSU
|
||||
LogPrint (eLogWarning, "Unexpected SSU address ", value);
|
||||
isValidAddress = false;
|
||||
m_SupportedTransports |= eSSUV4; // TODO:
|
||||
address.addressString = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -266,6 +264,10 @@ namespace data
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH3:
|
||||
m_Caps |= Caps::eHighBandwidth;
|
||||
break;
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH2:
|
||||
m_Caps |= Caps::eExtraBandwidth;
|
||||
break;
|
||||
case CAPS_FLAG_HIDDEN:
|
||||
m_Caps |= Caps::eHidden;
|
||||
break;
|
||||
@@ -292,11 +294,15 @@ namespace data
|
||||
std::string caps;
|
||||
if (m_Caps & eFloodfill)
|
||||
{
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // highest bandwidth
|
||||
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
|
||||
caps += CAPS_FLAG_FLOODFILL; // floodfill
|
||||
}
|
||||
else
|
||||
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth
|
||||
{
|
||||
if (m_Caps & eExtraBandwidth) caps += CAPS_FLAG_EXTRA_BANDWIDTH1;
|
||||
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 : CAPS_FLAG_LOW_BANDWIDTH2; // bandwidth
|
||||
}
|
||||
if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
|
||||
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
|
||||
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
|
||||
@@ -433,7 +439,7 @@ namespace data
|
||||
if (!m_Buffer)
|
||||
{
|
||||
if (LoadFile ())
|
||||
LogPrint ("Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
|
||||
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
|
||||
}
|
||||
return m_Buffer;
|
||||
}
|
||||
@@ -464,10 +470,10 @@ namespace data
|
||||
if (f.is_open ())
|
||||
f.write ((char *)m_Buffer, m_BufferLen);
|
||||
else
|
||||
LogPrint(eLogError, "Can't save RouterInfo to ", fullPath);
|
||||
LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't save RouterInfo m_Buffer==NULL");
|
||||
LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
|
||||
}
|
||||
|
||||
size_t RouterInfo::ReadString (char * str, std::istream& s)
|
||||
@@ -514,7 +520,7 @@ namespace data
|
||||
for (auto it: m_Addresses) // don't insert same address twice
|
||||
if (it == addr) return;
|
||||
m_Addresses.push_back(addr);
|
||||
m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4;
|
||||
m_SupportedTransports |= addr.host.is_v6 () ? eSSUV6 : eSSUV4;
|
||||
m_Caps |= eSSUTesting;
|
||||
m_Caps |= eSSUIntroducer;
|
||||
}
|
||||
|
||||
18
RouterInfo.h
18
RouterInfo.h
@@ -23,7 +23,9 @@ namespace data
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M';
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N';
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O';
|
||||
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P';
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X';
|
||||
|
||||
const char CAPS_FLAG_SSU_TESTING = 'B';
|
||||
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
||||
|
||||
@@ -44,11 +46,12 @@ namespace data
|
||||
{
|
||||
eFloodfill = 0x01,
|
||||
eHighBandwidth = 0x02,
|
||||
eReachable = 0x04,
|
||||
eSSUTesting = 0x08,
|
||||
eSSUIntroducer = 0x10,
|
||||
eHidden = 0x20,
|
||||
eUnreachable = 0x40
|
||||
eExtraBandwidth = 0x04,
|
||||
eReachable = 0x08,
|
||||
eSSUTesting = 0x10,
|
||||
eSSUIntroducer = 0x20,
|
||||
eHidden = 0x40,
|
||||
eUnreachable = 0x80
|
||||
};
|
||||
|
||||
enum TransportStyle
|
||||
@@ -131,7 +134,8 @@ namespace data
|
||||
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
||||
bool IsHidden () const { return m_Caps & eHidden; };
|
||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t caps);
|
||||
void SetCaps (const char * caps);
|
||||
|
||||
84
SAM.cpp
84
SAM.cpp
@@ -78,7 +78,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM handshake read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: handshake read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -88,7 +88,7 @@ namespace client
|
||||
char * eol = (char *)memchr (m_Buffer, '\n', bytes_transferred);
|
||||
if (eol)
|
||||
*eol = 0;
|
||||
LogPrint ("SAM handshake ", m_Buffer);
|
||||
LogPrint (eLogDebug, "SAM: handshake ", m_Buffer);
|
||||
char * separator = strchr (m_Buffer, ' ');
|
||||
if (separator)
|
||||
{
|
||||
@@ -127,7 +127,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("SAM handshake mismatch");
|
||||
LogPrint (eLogError, "SAM: handshake mismatch");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
@@ -137,7 +137,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM handshake reply send error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: handshake reply send error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -168,7 +168,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM reply send error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: reply send error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -185,7 +185,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -240,19 +240,19 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SAM unexpected message ", m_Buffer);
|
||||
LogPrint (eLogError, "SAM: unexpected message ", m_Buffer);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SAM malformed message ", m_Buffer);
|
||||
LogPrint (eLogError, "SAM: malformed message ", m_Buffer);
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SAM incomplete message ", bytes_transferred);
|
||||
LogPrint (eLogWarning, "SAM: incomplete message ", bytes_transferred);
|
||||
m_BufferOffset = bytes_transferred;
|
||||
// try to receive remaining message
|
||||
Receive ();
|
||||
@@ -262,7 +262,7 @@ namespace client
|
||||
|
||||
void SAMSocket::ProcessSessionCreate (char * buf, size_t len)
|
||||
{
|
||||
LogPrint ("SAM session create: ", buf);
|
||||
LogPrint (eLogDebug, "SAM: session create: ", buf);
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (buf, params);
|
||||
std::string& style = params[SAM_PARAM_STYLE];
|
||||
@@ -333,7 +333,7 @@ namespace client
|
||||
|
||||
void SAMSocket::ProcessStreamConnect (char * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM stream connect: ", buf);
|
||||
LogPrint (eLogDebug, "SAM: stream connect: ", buf);
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (buf, params);
|
||||
std::string& id = params[SAM_PARAM_ID];
|
||||
@@ -382,14 +382,14 @@ namespace client
|
||||
Connect (leaseSet);
|
||||
else
|
||||
{
|
||||
LogPrint ("SAM destination to connect not found");
|
||||
LogPrint (eLogError, "SAM: destination to connect not found");
|
||||
SendMessageReply (SAM_STREAM_STATUS_CANT_REACH_PEER, strlen(SAM_STREAM_STATUS_CANT_REACH_PEER), true);
|
||||
}
|
||||
}
|
||||
|
||||
void SAMSocket::ProcessStreamAccept (char * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM stream accept: ", buf);
|
||||
LogPrint (eLogDebug, "SAM: stream accept: ", buf);
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (buf, params);
|
||||
std::string& id = params[SAM_PARAM_ID];
|
||||
@@ -415,7 +415,7 @@ namespace client
|
||||
|
||||
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM datagram send: ", buf, " ", len);
|
||||
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (buf, params);
|
||||
size_t size = boost::lexical_cast<int>(params[SAM_PARAM_SIZE]), offset = data - buf;
|
||||
@@ -431,14 +431,14 @@ namespace client
|
||||
d->SendDatagramTo ((const uint8_t *)data, size, dest.GetIdentHash ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SAM missing datagram destination");
|
||||
LogPrint (eLogError, "SAM: missing datagram destination");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SAM session is not created from DATAGRAM SEND");
|
||||
LogPrint (eLogError, "SAM: session is not created from DATAGRAM SEND");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SAM sent datagram size ", size, " exceeds buffer ", len - offset);
|
||||
LogPrint (eLogWarning, "SAM: sent datagram size ", size, " exceeds buffer ", len - offset);
|
||||
return 0; // try to receive more
|
||||
}
|
||||
return offset + size;
|
||||
@@ -446,7 +446,7 @@ namespace client
|
||||
|
||||
void SAMSocket::ProcessDestGenerate ()
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM dest generate");
|
||||
LogPrint (eLogDebug, "SAM: dest generate");
|
||||
auto keys = i2p::data::PrivateKeys::CreateRandomKeys ();
|
||||
#ifdef _MSC_VER
|
||||
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
|
||||
@@ -460,7 +460,7 @@ namespace client
|
||||
|
||||
void SAMSocket::ProcessNamingLookup (char * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM naming lookup: ", buf);
|
||||
LogPrint (eLogDebug, "SAM: naming lookup: ", buf);
|
||||
std::map<std::string, std::string> params;
|
||||
ExtractParams (buf, params);
|
||||
std::string& name = params[SAM_PARAM_NAME];
|
||||
@@ -483,7 +483,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("SAM naming failed. Unknown address ", name);
|
||||
LogPrint (eLogError, "SAM: naming failed, unknown address ", name);
|
||||
#ifdef _MSC_VER
|
||||
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY, name.c_str());
|
||||
#else
|
||||
@@ -502,7 +502,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "SAM naming lookup failed. LeaseSet for ", ident.ToBase32 (), " not found");
|
||||
LogPrint (eLogError, "SAM: naming lookup failed. LeaseSet for ", ident.ToBase32 (), " not found");
|
||||
#ifdef _MSC_VER
|
||||
size_t len = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY_INVALID_KEY,
|
||||
context.GetAddressBook ().ToAddress (ident).c_str());
|
||||
@@ -548,7 +548,7 @@ namespace client
|
||||
{
|
||||
if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "Buffer is full. Terminate");
|
||||
LogPrint (eLogError, "SAM: Buffer is full, terminate");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -561,7 +561,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -595,7 +595,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM stream read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: stream read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -610,7 +610,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint ("SAM socket write error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: socket write error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
@@ -622,7 +622,7 @@ namespace client
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
LogPrint ("SAM incoming I2P connection for session ", m_ID);
|
||||
LogPrint (eLogDebug, "SAM: incoming I2P connection for session ", m_ID);
|
||||
m_Stream = stream;
|
||||
context.GetAddressBook ().InsertAddress (stream->GetRemoteIdentity ());
|
||||
auto session = m_Owner.FindSession (m_ID);
|
||||
@@ -642,12 +642,12 @@ namespace client
|
||||
I2PReceive ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "SAM I2P acceptor has been reset");
|
||||
LogPrint (eLogWarning, "SAM: I2P acceptor has been reset");
|
||||
}
|
||||
|
||||
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SAM datagram received ", len);
|
||||
LogPrint (eLogDebug, "SAM: datagram received ", len);
|
||||
auto base64 = from.ToBase64 ();
|
||||
#ifdef _MSC_VER
|
||||
size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
|
||||
@@ -661,7 +661,7 @@ namespace client
|
||||
std::bind (&SAMSocket::HandleWriteI2PData, shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SAM received datagram size ", len," exceeds buffer");
|
||||
LogPrint (eLogWarning, "SAM: received datagram size ", len," exceeds buffer");
|
||||
}
|
||||
|
||||
SAMSession::SAMSession (std::shared_ptr<ClientDestination> dest):
|
||||
@@ -686,10 +686,10 @@ namespace client
|
||||
sockets.clear ();
|
||||
}
|
||||
|
||||
SAMBridge::SAMBridge (int port):
|
||||
SAMBridge::SAMBridge (const std::string& address, int port):
|
||||
m_IsRunning (false), m_Thread (nullptr),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
|
||||
m_DatagramEndpoint (boost::asio::ip::udp::v4 (), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)),
|
||||
m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (m_Service, m_DatagramEndpoint)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -733,7 +733,7 @@ namespace client
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("SAM: ", ex.what ());
|
||||
LogPrint (eLogError, "SAM: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -753,14 +753,14 @@ namespace client
|
||||
auto ep = socket->GetSocket ().remote_endpoint (ec);
|
||||
if (!ec)
|
||||
{
|
||||
LogPrint ("New SAM connection from ", ep);
|
||||
LogPrint (eLogDebug, "SAM: new connection from ", ep);
|
||||
socket->ReceiveHandshake ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SAM connection from error ", ec.message ());
|
||||
LogPrint (eLogError, "SAM: incoming connection error ", ec.message ());
|
||||
}
|
||||
else
|
||||
LogPrint ("SAM accept error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: accept error: ", ecode.message ());
|
||||
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Accept ();
|
||||
@@ -794,7 +794,7 @@ namespace client
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
auto ret = m_Sessions.insert (std::pair<std::string, SAMSession *>(id, new SAMSession (localDestination)));
|
||||
if (!ret.second)
|
||||
LogPrint ("Session ", id, " already exists");
|
||||
LogPrint (eLogWarning, "SAM: Session ", id, " already exists");
|
||||
return ret.first->second;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -839,7 +839,7 @@ namespace client
|
||||
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
|
||||
*eol = 0; eol++;
|
||||
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
|
||||
LogPrint ("SAM datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
|
||||
LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
|
||||
char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' ');
|
||||
if (sessionID)
|
||||
{
|
||||
@@ -857,17 +857,17 @@ namespace client
|
||||
SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ());
|
||||
}
|
||||
else
|
||||
LogPrint ("Session ", sessionID, " not found");
|
||||
LogPrint (eLogError, "SAM: Session ", sessionID, " not found");
|
||||
}
|
||||
else
|
||||
LogPrint ("Missing destination key");
|
||||
LogPrint (eLogError, "SAM: Missing destination key");
|
||||
}
|
||||
else
|
||||
LogPrint ("Missing sessionID");
|
||||
LogPrint (eLogError, "SAM: Missing sessionID");
|
||||
ReceiveDatagram ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SAM datagram receive error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SAM: datagram receive error: ", ecode.message ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
SAM.h
4
SAM.h
@@ -41,7 +41,7 @@ namespace client
|
||||
const char SAM_DEST_REPLY_I2P_ERROR[] = "DEST REPLY RESULT=I2P_ERROR\n";
|
||||
const char SAM_NAMING_LOOKUP[] = "NAMING LOOKUP";
|
||||
const char SAM_NAMING_REPLY[] = "NAMING REPLY RESULT=OK NAME=ME VALUE=%s\n";
|
||||
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%lu\n";
|
||||
const char SAM_DATAGRAM_RECEIVED[] = "DATAGRAM RECEIVED DESTINATION=%s SIZE=%zu\n";
|
||||
const char SAM_NAMING_REPLY_INVALID_KEY[] = "NAMING REPLY RESULT=INVALID_KEY NAME=%s\n";
|
||||
const char SAM_NAMING_REPLY_KEY_NOT_FOUND[] = "NAMING REPLY RESULT=INVALID_KEY_NOT_FOUND NAME=%s\n";
|
||||
const char SAM_PARAM_MIN[] = "MIN";
|
||||
@@ -146,7 +146,7 @@ namespace client
|
||||
{
|
||||
public:
|
||||
|
||||
SAMBridge (int port);
|
||||
SAMBridge (const std::string& address, int port);
|
||||
~SAMBridge ();
|
||||
|
||||
void Start ();
|
||||
|
||||
@@ -560,8 +560,8 @@ namespace proxy
|
||||
}
|
||||
}
|
||||
|
||||
SOCKSServer::SOCKSServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination) :
|
||||
TCPIPAcceptor (port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
||||
SOCKSServer::SOCKSServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination) :
|
||||
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
2
SOCKS.h
2
SOCKS.h
@@ -15,7 +15,7 @@ namespace proxy
|
||||
{
|
||||
public:
|
||||
|
||||
SOCKSServer(int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||
SOCKSServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
|
||||
~SOCKSServer() {};
|
||||
|
||||
protected:
|
||||
|
||||
229
SSU.cpp
229
SSU.cpp
@@ -86,7 +86,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU server: ", ex.what ());
|
||||
LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU V6 server: ", ex.what ());
|
||||
LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU receivers: ", ex.what ());
|
||||
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,12 +174,12 @@ namespace transport
|
||||
moreBytes = m_Socket.available();
|
||||
}
|
||||
|
||||
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets));
|
||||
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
|
||||
Receive ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("SSU receive error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SSU: receive error: ", ecode.message ());
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
@@ -201,17 +201,18 @@ namespace transport
|
||||
moreBytes = m_SocketV6.available();
|
||||
}
|
||||
|
||||
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets));
|
||||
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
|
||||
ReceiveV6 ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("SSU V6 receive error: ", ecode.message ());
|
||||
LogPrint (eLogError, "SSU: v6 receive error: ", ecode.message ());
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets)
|
||||
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
|
||||
{
|
||||
std::shared_ptr<SSUSession> session;
|
||||
for (auto it1: packets)
|
||||
@@ -222,17 +223,14 @@ namespace transport
|
||||
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
|
||||
{
|
||||
if (session) session->FlushData ();
|
||||
auto it = m_Sessions.find (packet->from);
|
||||
if (it != m_Sessions.end ())
|
||||
auto it = sessions->find (packet->from);
|
||||
if (it != sessions->end ())
|
||||
session = it->second;
|
||||
if (!session)
|
||||
{
|
||||
session = std::make_shared<SSUSession> (*this, packet->from);
|
||||
session->WaitForConnect ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
m_Sessions[packet->from] = session;
|
||||
}
|
||||
(*sessions)[packet->from] = session;
|
||||
LogPrint (eLogInfo, "New SSU session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
|
||||
}
|
||||
}
|
||||
@@ -265,100 +263,135 @@ namespace transport
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
|
||||
{
|
||||
auto it = m_Sessions.find (e);
|
||||
if (it != m_Sessions.end ())
|
||||
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
|
||||
auto it = sessions.find (e);
|
||||
if (it != sessions.end ())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
|
||||
|
||||
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
|
||||
{
|
||||
auto address = router->GetSSUAddress (!context.SupportsV6 ());
|
||||
if (address)
|
||||
CreateSession (router, address->host, address->port, peerTest);
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
||||
}
|
||||
|
||||
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
const boost::asio::ip::address& addr, int port, bool peerTest)
|
||||
{
|
||||
std::shared_ptr<SSUSession> session;
|
||||
if (router)
|
||||
{
|
||||
auto address = router->GetSSUAddress (!context.SupportsV6 ());
|
||||
if (router->UsesIntroducer ())
|
||||
m_Service.post (std::bind (&SSUServer::CreateSessionThroughIntroducer, this, router, peerTest)); // always V4 thread
|
||||
else
|
||||
{
|
||||
boost::asio::ip::udp::endpoint remoteEndpoint (addr, port);
|
||||
auto& s = addr.is_v6 () ? m_ServiceV6 : m_Service;
|
||||
s.post (std::bind (&SSUServer::CreateDirectSession, this, router, remoteEndpoint, peerTest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest)
|
||||
{
|
||||
auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
|
||||
auto it = sessions.find (remoteEndpoint);
|
||||
if (it != sessions.end ())
|
||||
{
|
||||
auto session = it->second;
|
||||
if (peerTest && session->GetState () == eSessionStateEstablished)
|
||||
session->SendPeerTest ();
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise create new session
|
||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
||||
sessions[remoteEndpoint] = session;
|
||||
// connect
|
||||
LogPrint (eLogInfo, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
|
||||
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
|
||||
session->Connect ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
|
||||
{
|
||||
if (router && router->UsesIntroducer ())
|
||||
{
|
||||
auto address = router->GetSSUAddress (true); // v4 only for now
|
||||
if (address)
|
||||
{
|
||||
boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port);
|
||||
auto it = m_Sessions.find (remoteEndpoint);
|
||||
// check if session if presented alredy
|
||||
if (it != m_Sessions.end ())
|
||||
{
|
||||
session = it->second;
|
||||
auto session = it->second;
|
||||
if (peerTest && session->GetState () == eSessionStateEstablished)
|
||||
session->SendPeerTest ();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
// create new session
|
||||
int numIntroducers = address->introducers.size ();
|
||||
if (numIntroducers > 0)
|
||||
{
|
||||
// otherwise create new session
|
||||
session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
||||
std::shared_ptr<SSUSession> introducerSession;
|
||||
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
|
||||
// we might have a session to introducer already
|
||||
for (int i = 0; i < numIntroducers; i++)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
m_Sessions[remoteEndpoint] = session;
|
||||
}
|
||||
if (!router->UsesIntroducer ())
|
||||
{
|
||||
// connect directly
|
||||
LogPrint ("Creating new SSU session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
|
||||
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
|
||||
session->Connect ();
|
||||
}
|
||||
else
|
||||
{
|
||||
// connect through introducer
|
||||
int numIntroducers = address->introducers.size ();
|
||||
if (numIntroducers > 0)
|
||||
{
|
||||
std::shared_ptr<SSUSession> introducerSession;
|
||||
const i2p::data::RouterInfo::Introducer * introducer = nullptr;
|
||||
// we might have a session to introducer already
|
||||
for (int i = 0; i < numIntroducers; i++)
|
||||
{
|
||||
introducer = &(address->introducers[i]);
|
||||
it = m_Sessions.find (boost::asio::ip::udp::endpoint (introducer->iHost, introducer->iPort));
|
||||
if (it != m_Sessions.end ())
|
||||
{
|
||||
introducerSession = it->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (introducerSession) // session found
|
||||
LogPrint ("Session to introducer already exists");
|
||||
else // create new
|
||||
{
|
||||
LogPrint ("Creating new session to introducer");
|
||||
introducer = &(address->introducers[0]); // TODO:
|
||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
||||
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
m_Sessions[introducerEndpoint] = introducerSession;
|
||||
}
|
||||
// introduce
|
||||
LogPrint ("Introduce new SSU session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
|
||||
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
||||
session->WaitForIntroduction ();
|
||||
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
||||
{
|
||||
uint8_t buf[1];
|
||||
Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||
}
|
||||
introducerSession->Introduce (*introducer);
|
||||
}
|
||||
else
|
||||
auto intr = &(address->introducers[i]);
|
||||
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
|
||||
if (ep.address ().is_v4 ()) // ipv4 only
|
||||
{
|
||||
LogPrint (eLogWarning, "Can't connect to unreachable router. No introducers presented");
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
m_Sessions.erase (remoteEndpoint);
|
||||
session.reset ();
|
||||
}
|
||||
if (!introducer) introducer = intr; // we pick first one for now
|
||||
it = m_Sessions.find (ep);
|
||||
if (it != m_Sessions.end ())
|
||||
{
|
||||
introducerSession = it->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!introducer)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 introducers present");
|
||||
return;
|
||||
}
|
||||
|
||||
if (introducerSession) // session found
|
||||
LogPrint (eLogInfo, "SSU: Session to introducer already exists");
|
||||
else // create new
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU: Creating new session to introducer");
|
||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
||||
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
|
||||
m_Sessions[introducerEndpoint] = introducerSession;
|
||||
}
|
||||
// create session
|
||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
||||
m_Sessions[remoteEndpoint] = session;
|
||||
// introduce
|
||||
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
|
||||
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
||||
session->WaitForIntroduction ();
|
||||
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
||||
{
|
||||
uint8_t buf[1];
|
||||
Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||
}
|
||||
introducerSession->Introduce (*introducer, router);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
||||
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
void SSUServer::DeleteSession (std::shared_ptr<SSUSession> session)
|
||||
@@ -366,21 +399,27 @@ namespace transport
|
||||
if (session)
|
||||
{
|
||||
session->Close ();
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
m_Sessions.erase (session->GetRemoteEndpoint ());
|
||||
auto& ep = session->GetRemoteEndpoint ();
|
||||
if (ep.address ().is_v6 ())
|
||||
m_SessionsV6.erase (ep);
|
||||
else
|
||||
m_Sessions.erase (ep);
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::DeleteAllSessions ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
for (auto it: m_Sessions)
|
||||
it.second->Close ();
|
||||
m_Sessions.clear ();
|
||||
|
||||
for (auto it: m_SessionsV6)
|
||||
it.second->Close ();
|
||||
m_SessionsV6.clear ();
|
||||
}
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<SSUSession> SSUServer::GetRandomSession (Filter filter)
|
||||
std::shared_ptr<SSUSession> SSUServer::GetRandomV4Session (Filter filter) // v4 only
|
||||
{
|
||||
std::vector<std::shared_ptr<SSUSession> > filteredSessions;
|
||||
for (auto s :m_Sessions)
|
||||
@@ -393,9 +432,9 @@ namespace transport
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded)
|
||||
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
|
||||
{
|
||||
return GetRandomSession (
|
||||
return GetRandomV4Session (
|
||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
||||
{
|
||||
return session->GetState () == eSessionStateEstablished && !session->IsV6 () &&
|
||||
@@ -410,7 +449,7 @@ namespace transport
|
||||
std::set<SSUSession *> ret;
|
||||
for (int i = 0; i < maxNumIntroducers; i++)
|
||||
{
|
||||
auto session = GetRandomSession (
|
||||
auto session = GetRandomV4Session (
|
||||
[&ret, ts](std::shared_ptr<SSUSession> session)->bool
|
||||
{
|
||||
return session->GetRelayTag () && !ret.count (session.get ()) &&
|
||||
@@ -487,11 +526,11 @@ namespace transport
|
||||
}
|
||||
}
|
||||
m_Introducers = newList;
|
||||
if (m_Introducers.empty ())
|
||||
if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS)
|
||||
{
|
||||
auto introducer = i2p::data::netdb.GetRandomIntroducer ();
|
||||
if (introducer)
|
||||
GetSession (introducer);
|
||||
CreateSession (introducer);
|
||||
}
|
||||
ScheduleIntroducersUpdateTimer ();
|
||||
}
|
||||
@@ -556,7 +595,7 @@ namespace transport
|
||||
it++;
|
||||
}
|
||||
if (numDeleted > 0)
|
||||
LogPrint (eLogInfo, numDeleted, " peer tests have been expired");
|
||||
LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired");
|
||||
SchedulePeerTestsCleanupTimer ();
|
||||
}
|
||||
}
|
||||
|
||||
17
SSU.h
17
SSU.h
@@ -40,10 +40,13 @@ namespace transport
|
||||
~SSUServer ();
|
||||
void Start ();
|
||||
void Stop ();
|
||||
std::shared_ptr<SSUSession> GetSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
|
||||
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
|
||||
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
const boost::asio::ip::address& addr, int port, bool peerTest = false);
|
||||
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
|
||||
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
|
||||
std::shared_ptr<SSUSession> FindSession (const boost::asio::ip::udp::endpoint& e) const;
|
||||
std::shared_ptr<SSUSession> GetRandomEstablishedSession (std::shared_ptr<const SSUSession> excluded);
|
||||
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
|
||||
void DeleteSession (std::shared_ptr<SSUSession> session);
|
||||
void DeleteAllSessions ();
|
||||
|
||||
@@ -69,10 +72,12 @@ namespace transport
|
||||
void ReceiveV6 ();
|
||||
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
||||
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
|
||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets);
|
||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
|
||||
|
||||
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
|
||||
template<typename Filter>
|
||||
std::shared_ptr<SSUSession> GetRandomSession (Filter filter);
|
||||
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
|
||||
|
||||
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
|
||||
void ScheduleIntroducersUpdateTimer ();
|
||||
@@ -98,14 +103,14 @@ namespace transport
|
||||
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
|
||||
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_PeerTestsCleanupTimer;
|
||||
std::list<boost::asio::ip::udp::endpoint> m_Introducers; // introducers we are connected to
|
||||
mutable std::mutex m_SessionsMutex;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
|
||||
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer
|
||||
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
|
||||
|
||||
public:
|
||||
// for HTTP only
|
||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||
const decltype(m_SessionsV6)& GetSessionsV6 () const { return m_SessionsV6; };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
46
SSUData.cpp
46
SSUData.cpp
@@ -14,13 +14,13 @@ namespace transport
|
||||
{
|
||||
if (msg->len + fragmentSize > msg->maxLen)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU I2NP message size ", msg->maxLen, " is not enough");
|
||||
auto newMsg = ToSharedI2NPMessage(NewI2NPMessage ());
|
||||
LogPrint (eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough");
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *msg;
|
||||
msg = newMsg;
|
||||
}
|
||||
memcpy (msg->buf + msg->len, fragment, fragmentSize);
|
||||
msg->len += fragmentSize;
|
||||
if (msg->Concat (fragment, fragmentSize) < fragmentSize)
|
||||
LogPrint (eLogError, "SSU: I2NP buffer overflow ", msg->maxLen);
|
||||
nextFragmentNum++;
|
||||
}
|
||||
|
||||
@@ -64,11 +64,11 @@ namespace transport
|
||||
m_PacketSize >>= 4;
|
||||
m_PacketSize <<= 4;
|
||||
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
|
||||
LogPrint ("MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
|
||||
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Unexpected MTU ", ssuAddress->mtu);
|
||||
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->mtu);
|
||||
m_PacketSize = m_MaxPacketSize;
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ namespace transport
|
||||
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
||||
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "Fragment size ", fragmentSize, "exceeds max SSU packet size");
|
||||
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace transport
|
||||
if (it == m_IncompleteMessages.end ())
|
||||
{
|
||||
// create new message
|
||||
auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
msg->len -= I2NP_SHORT_HEADER_SIZE;
|
||||
it = m_IncompleteMessages.insert (std::make_pair (msgID,
|
||||
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
|
||||
@@ -199,23 +199,23 @@ namespace transport
|
||||
break;
|
||||
}
|
||||
if (isLast)
|
||||
LogPrint (eLogDebug, "Message ", msgID, " complete");
|
||||
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
||||
// duplicate fragment
|
||||
LogPrint (eLogWarning, "Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ". Ignored");
|
||||
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
|
||||
else
|
||||
{
|
||||
// missing fragment
|
||||
LogPrint (eLogWarning, "Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
||||
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
||||
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
|
||||
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
|
||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
else
|
||||
LogPrint (eLogWarning, "Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
||||
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
||||
}
|
||||
isLast = false;
|
||||
}
|
||||
@@ -241,18 +241,18 @@ namespace transport
|
||||
m_Handler.PutNextMessage (msg);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU message ", msgID, " already received");
|
||||
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
|
||||
}
|
||||
else
|
||||
{
|
||||
// we expect DeliveryStatus
|
||||
if (msg->GetTypeID () == eI2NPDeliveryStatus)
|
||||
{
|
||||
LogPrint ("SSU session established");
|
||||
LogPrint (eLogDebug, "SSU: session established");
|
||||
m_Session.Established ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU unexpected message ", (int)msg->GetTypeID ());
|
||||
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -271,7 +271,7 @@ namespace transport
|
||||
//uint8_t * start = buf;
|
||||
uint8_t flag = *buf;
|
||||
buf++;
|
||||
LogPrint (eLogDebug, "Process SSU data flags=", (int)flag, " len=", len);
|
||||
LogPrint (eLogDebug, "SSU: Process data, flags=", (int)flag, ", len=", len);
|
||||
// process acks if presented
|
||||
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
||||
ProcessAcks (buf, flag);
|
||||
@@ -280,7 +280,7 @@ namespace transport
|
||||
{
|
||||
uint8_t extendedDataSize = *buf;
|
||||
buf++; // size
|
||||
LogPrint (eLogDebug, "SSU extended data of ", extendedDataSize, " bytes presented");
|
||||
LogPrint (eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
|
||||
buf += extendedDataSize;
|
||||
}
|
||||
// process data
|
||||
@@ -292,7 +292,7 @@ namespace transport
|
||||
uint32_t msgID = msg->ToSSU ();
|
||||
if (m_SentMessages.count (msgID) > 0)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU message ", msgID, " already sent");
|
||||
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
|
||||
return;
|
||||
}
|
||||
if (m_SentMessages.empty ()) // schedule resend at first message only
|
||||
@@ -349,7 +349,7 @@ namespace transport
|
||||
}
|
||||
catch (boost::system::system_error& ec)
|
||||
{
|
||||
LogPrint (eLogError, "Can't send SSU fragment ", ec.what ());
|
||||
LogPrint (eLogError, "SSU: Can't send data fragment ", ec.what ());
|
||||
}
|
||||
if (!isLast)
|
||||
{
|
||||
@@ -383,7 +383,7 @@ namespace transport
|
||||
{
|
||||
if (fragmentNum > 64)
|
||||
{
|
||||
LogPrint (eLogWarning, "Fragment number ", fragmentNum, " exceeds 64");
|
||||
LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
|
||||
return;
|
||||
}
|
||||
uint8_t buf[64 + 18];
|
||||
@@ -437,7 +437,7 @@ namespace transport
|
||||
}
|
||||
catch (boost::system::system_error& ec)
|
||||
{
|
||||
LogPrint (eLogError, "Can't resend SSU fragment ", ec.what ());
|
||||
LogPrint (eLogError, "SSU: Can't resend data fragment ", ec.what ());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU message has not been ACKed after ", MAX_NUM_RESENDS, " attempts. Deleted");
|
||||
LogPrint (eLogError, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||
it = m_SentMessages.erase (it);
|
||||
}
|
||||
}
|
||||
@@ -491,7 +491,7 @@ namespace transport
|
||||
{
|
||||
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
||||
{
|
||||
LogPrint (eLogError, "SSU message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds. Deleted");
|
||||
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace transport
|
||||
const int RESEND_INTERVAL = 3; // in seconds
|
||||
const int MAX_NUM_RESENDS = 5;
|
||||
const int DECAY_INTERVAL = 20; // in seconds
|
||||
const int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
|
||||
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
||||
const unsigned int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
|
||||
// data flags
|
||||
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
|
||||
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
|
||||
|
||||
228
SSUSession.cpp
228
SSUSession.cpp
@@ -70,7 +70,7 @@ namespace transport
|
||||
nonZero++;
|
||||
if (nonZero - sharedKey > 32)
|
||||
{
|
||||
LogPrint ("First 32 bytes of shared key is all zeros. Ignored");
|
||||
LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,7 @@ namespace transport
|
||||
if (m_State == eSessionStateIntroduced)
|
||||
{
|
||||
// HolePunch received
|
||||
LogPrint ("SSU HolePunch of ", len, " bytes received");
|
||||
LogPrint (eLogDebug, "SSU: HolePunch of ", len, " bytes received");
|
||||
m_State = eSessionStateUnknown;
|
||||
Connect ();
|
||||
}
|
||||
@@ -120,7 +120,7 @@ namespace transport
|
||||
Decrypt (buf, len, address->key);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "MAC verification failed ", len, " bytes from ", senderEndpoint);
|
||||
LogPrint (eLogError, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
return;
|
||||
}
|
||||
@@ -131,10 +131,10 @@ namespace transport
|
||||
}
|
||||
}
|
||||
|
||||
size_t SSUSession::GetSSUHeaderSize (uint8_t * buf) const
|
||||
size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const
|
||||
{
|
||||
size_t s = sizeof (SSUHeader);
|
||||
if (((SSUHeader *)buf)->IsExtendedOptions ())
|
||||
if (((const SSUHeader *)buf)->IsExtendedOptions ())
|
||||
s += buf[s] + 1; // byte right after header is extended options length
|
||||
return s;
|
||||
}
|
||||
@@ -145,6 +145,11 @@ namespace transport
|
||||
if (len <= sizeof (SSUHeader)) return; // drop empty message
|
||||
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "SSU header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
switch (header->GetPayloadType ())
|
||||
{
|
||||
@@ -152,64 +157,70 @@ namespace transport
|
||||
ProcessData (buf + headerSize, len - headerSize);
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_REQUEST:
|
||||
ProcessSessionRequest (buf, len, senderEndpoint);
|
||||
ProcessSessionRequest (buf + headerSize, len - headerSize, senderEndpoint);
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_CREATED:
|
||||
ProcessSessionCreated (buf, len);
|
||||
ProcessSessionCreated (buf, len); // buf with header
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_CONFIRMED:
|
||||
ProcessSessionConfirmed (buf, len);
|
||||
ProcessSessionConfirmed (buf, len); // buf with header
|
||||
break;
|
||||
case PAYLOAD_TYPE_PEER_TEST:
|
||||
LogPrint (eLogDebug, "SSU peer test received");
|
||||
LogPrint (eLogDebug, "SSU: peer test received");
|
||||
ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU session destroy received");
|
||||
LogPrint (eLogDebug, "SSU: session destroy received");
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
break;
|
||||
}
|
||||
case PAYLOAD_TYPE_RELAY_RESPONSE:
|
||||
ProcessRelayResponse (buf, len);
|
||||
ProcessRelayResponse (buf + headerSize, len - headerSize);
|
||||
if (m_State != eSessionStateEstablished)
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
break;
|
||||
case PAYLOAD_TYPE_RELAY_REQUEST:
|
||||
LogPrint (eLogDebug, "SSU relay request received");
|
||||
LogPrint (eLogDebug, "SSU: relay request received");
|
||||
ProcessRelayRequest (buf + headerSize, len - headerSize, senderEndpoint);
|
||||
break;
|
||||
case PAYLOAD_TYPE_RELAY_INTRO:
|
||||
LogPrint (eLogDebug, "SSU relay intro received");
|
||||
LogPrint (eLogDebug, "SSU: relay intro received");
|
||||
ProcessRelayIntro (buf + headerSize, len - headerSize);
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "Unexpected SSU payload type ", (int)header->GetPayloadType ());
|
||||
LogPrint (eLogWarning, "SSU: Unexpected payload type ", (int)header->GetPayloadType ());
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
{
|
||||
LogPrint (eLogDebug, "Session request received");
|
||||
LogPrint (eLogDebug, "SSU message: session request");
|
||||
m_RemoteEndpoint = senderEndpoint;
|
||||
if (!m_DHKeysPair)
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
CreateAESandMacKey (buf + sizeof (SSUHeader));
|
||||
SendSessionCreated (buf + sizeof (SSUHeader));
|
||||
CreateAESandMacKey (buf);
|
||||
SendSessionCreated (buf);
|
||||
}
|
||||
|
||||
void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len)
|
||||
{
|
||||
if (!IsOutgoing () || !m_DHKeysPair)
|
||||
{
|
||||
LogPrint (eLogWarning, "Unsolicited session created message");
|
||||
LogPrint (eLogWarning, "SSU: Unsolicited session created message");
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrint (eLogDebug, "Session created received");
|
||||
LogPrint (eLogDebug, "SSU message: session created");
|
||||
m_Timer.cancel (); // connect timer
|
||||
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
uint8_t * payload = buf + headerSize;
|
||||
uint8_t * y = payload;
|
||||
CreateAESandMacKey (y);
|
||||
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
|
||||
@@ -236,7 +247,7 @@ namespace transport
|
||||
uint16_t ourPort = bufbe16toh (payload);
|
||||
s.Insert (payload, 2); // our port
|
||||
payload += 2; // port
|
||||
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||
i2p::context.UpdateAddress (ourIP);
|
||||
if (m_RemoteEndpoint.address ().is_v4 ())
|
||||
s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP v4
|
||||
@@ -253,18 +264,24 @@ namespace transport
|
||||
if (paddingSize > 0) signatureLen += (16 - paddingSize);
|
||||
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
|
||||
m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv);
|
||||
m_SessionKeyDecryption.Decrypt (payload, signatureLen, payload);
|
||||
m_SessionKeyDecryption.Decrypt (payload, signatureLen, payload); // TODO: non-const payload
|
||||
// verify
|
||||
if (!s.Verify (m_RemoteIdentity, payload))
|
||||
LogPrint (eLogError, "Session created SSU signature verification failed");
|
||||
LogPrint (eLogError, "SSU: message 'created' signature verification failed");
|
||||
|
||||
SendSessionConfirmed (y, ourAddress, addressSize + 2);
|
||||
}
|
||||
|
||||
void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len)
|
||||
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "Session confirmed received");
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
LogPrint (eLogDebug, "SSU: Session confirmed received");
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
const uint8_t * payload = buf + headerSize;
|
||||
payload++; // identity fragment info
|
||||
uint16_t identitySize = bufbe16toh (payload);
|
||||
payload += 2; // size of identity fragment
|
||||
@@ -280,7 +297,7 @@ namespace transport
|
||||
payload += paddingSize;
|
||||
// verify
|
||||
if (m_SignedData && !m_SignedData->Verify (m_RemoteIdentity, payload))
|
||||
LogPrint (eLogError, "Session confirmed SSU signature verification failed");
|
||||
LogPrint (eLogError, "SSU message 'confirmed' signature verification failed");
|
||||
m_Data.Send (CreateDeliveryStatusMsg (0));
|
||||
Established ();
|
||||
}
|
||||
@@ -308,7 +325,7 @@ namespace transport
|
||||
m_Server.Send (buf, isV4 ? 304 : 320, m_RemoteEndpoint);
|
||||
}
|
||||
|
||||
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer)
|
||||
void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce)
|
||||
{
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||
if (!address)
|
||||
@@ -329,7 +346,7 @@ namespace transport
|
||||
payload++;
|
||||
memcpy (payload, (const uint8_t *)address->key, 32);
|
||||
payload += 32;
|
||||
RAND_bytes (payload, 4); // nonce
|
||||
htobe32buf (payload, nonce); // nonce
|
||||
|
||||
uint8_t iv[16];
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
@@ -384,7 +401,7 @@ namespace transport
|
||||
s.Insert (address->host.to_v6 ().to_bytes ().data (), 16); // our IP V6
|
||||
s.Insert<uint16_t> (htobe16 (address->port)); // our port
|
||||
uint32_t relayTag = 0;
|
||||
if (i2p::context.GetRouterInfo ().IsIntroducer ())
|
||||
if (i2p::context.GetRouterInfo ().IsIntroducer () && !IsV6 ())
|
||||
{
|
||||
RAND_bytes((uint8_t *)&relayTag, 4);
|
||||
if (!relayTag) relayTag = 1;
|
||||
@@ -461,7 +478,7 @@ namespace transport
|
||||
Send (buf, msgLen);
|
||||
}
|
||||
|
||||
void SSUSession::ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
|
||||
void SSUSession::ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
|
||||
{
|
||||
uint32_t relayTag = bufbe32toh (buf);
|
||||
auto session = m_Server.FindRelaySession (relayTag);
|
||||
@@ -475,11 +492,11 @@ namespace transport
|
||||
uint8_t challengeSize = *buf;
|
||||
buf++; // challenge size
|
||||
buf += challengeSize;
|
||||
uint8_t * introKey = buf;
|
||||
const uint8_t * introKey = buf;
|
||||
buf += 32; // introkey
|
||||
uint32_t nonce = bufbe32toh (buf);
|
||||
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
|
||||
SendRelayIntro (session.get (), from);
|
||||
SendRelayIntro (session, from);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +508,7 @@ namespace transport
|
||||
// Charlie's address always v4
|
||||
if (!to.address ().is_v4 ())
|
||||
{
|
||||
LogPrint (eLogError, "Charlie's IP must be v4");
|
||||
LogPrint (eLogError, "SSU: Charlie's IP must be v4");
|
||||
return;
|
||||
}
|
||||
*payload = 4;
|
||||
@@ -534,16 +551,16 @@ namespace transport
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
|
||||
m_Server.Send (buf, isV4 ? 64 : 80, from);
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU relay response sent");
|
||||
LogPrint (eLogDebug, "SSU: relay response sent");
|
||||
}
|
||||
|
||||
void SSUSession::SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from)
|
||||
void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from)
|
||||
{
|
||||
if (!session) return;
|
||||
// Alice's address always v4
|
||||
if (!from.address ().is_v4 ())
|
||||
{
|
||||
LogPrint (eLogError, "Alice's IP must be v4");
|
||||
LogPrint (eLogError, "SSU: Alice's IP must be v4");
|
||||
return;
|
||||
}
|
||||
uint8_t buf[48 + 18];
|
||||
@@ -559,42 +576,62 @@ namespace transport
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey);
|
||||
m_Server.Send (buf, 48, session->m_RemoteEndpoint);
|
||||
LogPrint (eLogDebug, "SSU relay intro sent");
|
||||
LogPrint (eLogDebug, "SSU: relay intro sent");
|
||||
}
|
||||
|
||||
void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len)
|
||||
void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "Relay response received");
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
uint8_t remoteSize = *payload;
|
||||
payload++; // remote size
|
||||
//boost::asio::ip::address_v4 remoteIP (bufbe32toh (payload));
|
||||
payload += remoteSize; // remote address
|
||||
//uint16_t remotePort = bufbe16toh (payload);
|
||||
payload += 2; // remote port
|
||||
uint8_t ourSize = *payload;
|
||||
payload++; // our size
|
||||
LogPrint (eLogDebug, "SSU message: Relay response received");
|
||||
uint8_t remoteSize = *buf;
|
||||
buf++; // remote size
|
||||
boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf));
|
||||
buf += remoteSize; // remote address
|
||||
uint16_t remotePort = bufbe16toh (buf);
|
||||
buf += 2; // remote port
|
||||
uint8_t ourSize = *buf;
|
||||
buf++; // our size
|
||||
boost::asio::ip::address ourIP;
|
||||
if (ourSize == 4)
|
||||
{
|
||||
boost::asio::ip::address_v4::bytes_type bytes;
|
||||
memcpy (bytes.data (), payload, 4);
|
||||
memcpy (bytes.data (), buf, 4);
|
||||
ourIP = boost::asio::ip::address_v4 (bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::ip::address_v6::bytes_type bytes;
|
||||
memcpy (bytes.data (), payload, 16);
|
||||
memcpy (bytes.data (), buf, 16);
|
||||
ourIP = boost::asio::ip::address_v6 (bytes);
|
||||
}
|
||||
payload += ourSize; // our address
|
||||
uint16_t ourPort = bufbe16toh (payload);
|
||||
payload += 2; // our port
|
||||
LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||
buf += ourSize; // our address
|
||||
uint16_t ourPort = bufbe16toh (buf);
|
||||
buf += 2; // our port
|
||||
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||
i2p::context.UpdateAddress (ourIP);
|
||||
uint32_t nonce = bufbe32toh (buf);
|
||||
buf += 4; // nonce
|
||||
auto it = m_RelayRequests.find (nonce);
|
||||
if (it != m_RelayRequests.end ())
|
||||
{
|
||||
// check if we are waiting for introduction
|
||||
boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort);
|
||||
if (!m_Server.FindSession (remoteEndpoint))
|
||||
{
|
||||
// we didn't have correct endpoint when sent relay request
|
||||
// now we do
|
||||
LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint);
|
||||
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
||||
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||
m_Server.CreateDirectSession (it->second, remoteEndpoint, false);
|
||||
}
|
||||
// delete request
|
||||
m_RelayRequests.erase (it);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce);
|
||||
}
|
||||
|
||||
void SSUSession::ProcessRelayIntro (uint8_t * buf, size_t len)
|
||||
void SSUSession::ProcessRelayIntro (const uint8_t * buf, size_t len)
|
||||
{
|
||||
uint8_t size = *buf;
|
||||
if (size == 4)
|
||||
@@ -603,11 +640,11 @@ namespace transport
|
||||
boost::asio::ip::address_v4 address (bufbe32toh (buf));
|
||||
buf += 4; // address
|
||||
uint16_t port = bufbe16toh (buf);
|
||||
// send hole punch of 1 byte
|
||||
// send hole punch of 0 bytes
|
||||
m_Server.Send (buf, 0, boost::asio::ip::udp::endpoint (address, port));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Address size ", size, " is not supported");
|
||||
LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported");
|
||||
}
|
||||
|
||||
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
|
||||
@@ -615,14 +652,13 @@ namespace transport
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected SSU packet length ", len);
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return;
|
||||
}
|
||||
//TODO: we are using a dirty solution here but should work for now
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
memcpy (header->iv, iv, 16);
|
||||
header->flag = payloadType << 4; // MSB is 0
|
||||
htobe32buf (&(header->time), i2p::util::GetSecondsSinceEpoch ());
|
||||
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
i2p::crypto::CBCEncryption encryption;
|
||||
@@ -639,15 +675,14 @@ namespace transport
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected SSU packet length ", len);
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return;
|
||||
}
|
||||
//TODO: we are using a dirty solution here but should work for now
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
RAND_bytes (header->iv, 16); // random iv
|
||||
m_SessionKeyEncryption.SetIV (header->iv);
|
||||
header->flag = payloadType << 4; // MSB is 0
|
||||
htobe32buf (&(header->time), i2p::util::GetSecondsSinceEpoch ());
|
||||
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
|
||||
@@ -661,10 +696,9 @@ namespace transport
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected SSU packet length ", len);
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return;
|
||||
}
|
||||
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
@@ -678,10 +712,9 @@ namespace transport
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected SSU packet length ", len);
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return;
|
||||
}
|
||||
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
@@ -696,10 +729,9 @@ namespace transport
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "Unexpected SSU packet length ", len);
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return false;
|
||||
}
|
||||
//TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
@@ -727,7 +759,7 @@ namespace transport
|
||||
if (!IsOutgoing ()) // incoming session
|
||||
ScheduleConnectTimer ();
|
||||
else
|
||||
LogPrint (eLogError, "SSU wait for connect for outgoing session");
|
||||
LogPrint (eLogError, "SSU: wait for connect for outgoing session");
|
||||
}
|
||||
|
||||
void SSUSession::ScheduleConnectTimer ()
|
||||
@@ -743,12 +775,13 @@ namespace transport
|
||||
if (!ecode)
|
||||
{
|
||||
// timeout expired
|
||||
LogPrint ("SSU session was not established after ", SSU_CONNECT_TIMEOUT, " second");
|
||||
LogPrint (eLogWarning, "SSU: session was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer)
|
||||
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> to)
|
||||
{
|
||||
if (m_State == eSessionStateUnknown)
|
||||
{
|
||||
@@ -756,8 +789,11 @@ namespace transport
|
||||
m_Timer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
|
||||
m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
SendRelayRequest (introducer);
|
||||
}
|
||||
uint32_t nonce;
|
||||
RAND_bytes ((uint8_t *)&nonce, 4);
|
||||
m_RelayRequests[nonce] = to;
|
||||
SendRelayRequest (introducer, nonce);
|
||||
}
|
||||
|
||||
void SSUSession::WaitForIntroduction ()
|
||||
@@ -817,7 +853,7 @@ namespace transport
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint ("SSU no activity fo ", SSU_TERMINATION_TIMEOUT, " seconds");
|
||||
LogPrint (eLogInfo, "SSU: no activity for", SSU_TERMINATION_TIMEOUT, " seconds");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
@@ -861,7 +897,7 @@ namespace transport
|
||||
const uint8_t * introKey = buf + size + 7;
|
||||
if (port && !address)
|
||||
{
|
||||
LogPrint (eLogWarning, "Address of ", size, " bytes not supported");
|
||||
LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported");
|
||||
return;
|
||||
}
|
||||
switch (m_Server.GetPeerTestParticipant (nonce))
|
||||
@@ -871,13 +907,13 @@ namespace transport
|
||||
{
|
||||
if (m_State == eSessionStateEstablished)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU peer test from Bob. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK
|
||||
i2p::context.SetStatus (eRouterStatusFirewalled);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU first peer test from Charlie. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice");
|
||||
i2p::context.SetStatus (eRouterStatusOK);
|
||||
m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
|
||||
SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
|
||||
@@ -888,11 +924,11 @@ namespace transport
|
||||
case ePeerTestParticipantAlice2:
|
||||
{
|
||||
if (m_State == eSessionStateEstablished)
|
||||
LogPrint (eLogDebug, "SSU peer test from Bob. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
|
||||
else
|
||||
{
|
||||
// peer test successive
|
||||
LogPrint (eLogDebug, "SSU second peer test from Charlie. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: second peer test from Charlie. We are Alice");
|
||||
i2p::context.SetStatus (eRouterStatusOK);
|
||||
m_Server.RemovePeerTest (nonce);
|
||||
}
|
||||
@@ -900,7 +936,7 @@ namespace transport
|
||||
}
|
||||
case ePeerTestParticipantBob:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU peer test from Charlie. We are Bob");
|
||||
LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob");
|
||||
auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
|
||||
if (session && session->m_State == eSessionStateEstablished)
|
||||
session->Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Alice
|
||||
@@ -909,7 +945,7 @@ namespace transport
|
||||
}
|
||||
case ePeerTestParticipantCharlie:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU peer test from Alice. We are Charlie");
|
||||
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
|
||||
SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (),
|
||||
senderEndpoint.port (), introKey); // to Alice with her actual address
|
||||
m_Server.RemovePeerTest (nonce); // nonce has been used
|
||||
@@ -923,15 +959,15 @@ namespace transport
|
||||
// new test
|
||||
if (port)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU peer test from Bob. We are Charlie");
|
||||
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie");
|
||||
m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie);
|
||||
Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob
|
||||
SendPeerTest (nonce, be32toh (address), be16toh (port), introKey); // to Alice with her address received from Bob
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob");
|
||||
auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // Charlie
|
||||
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Bob");
|
||||
auto session = m_Server.GetRandomEstablishedV4Session (shared_from_this ()); // Charlie, TODO: implement v6 support
|
||||
if (session)
|
||||
{
|
||||
m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ());
|
||||
@@ -941,7 +977,7 @@ namespace transport
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU unexpected peer test");
|
||||
LogPrint (eLogError, "SSU: unexpected peer test");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1004,7 +1040,7 @@ namespace transport
|
||||
void SSUSession::SendPeerTest ()
|
||||
{
|
||||
// we are Alice
|
||||
LogPrint (eLogDebug, "SSU sending peer test");
|
||||
LogPrint (eLogDebug, "SSU: sending peer test");
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||
if (!address)
|
||||
{
|
||||
@@ -1031,7 +1067,7 @@ namespace transport
|
||||
// encrypt message with session key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
||||
Send (buf, 48);
|
||||
LogPrint (eLogDebug, "SSU keep-alive sent");
|
||||
LogPrint (eLogDebug, "SSU: keep-alive sent");
|
||||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
@@ -1049,9 +1085,9 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU send session destoriyed exception ", ex.what ());
|
||||
LogPrint (eLogError, "SSU: exception while send session destoriyed: ", ex.what ());
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU session destroyed sent");
|
||||
LogPrint (eLogDebug, "SSU: session destroyed sent");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1063,7 +1099,7 @@ namespace transport
|
||||
if (paddingSize > 0) msgSize += (16 - paddingSize);
|
||||
if (msgSize > SSU_MTU_V4)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU payload size ", msgSize, " exceeds MTU");
|
||||
LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU");
|
||||
return;
|
||||
}
|
||||
memcpy (buf + sizeof (SSUHeader), payload, len);
|
||||
|
||||
24
SSUSession.h
24
SSUSession.h
@@ -14,18 +14,16 @@ namespace i2p
|
||||
namespace transport
|
||||
{
|
||||
const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04;
|
||||
#pragma pack(1)
|
||||
struct SSUHeader
|
||||
{
|
||||
uint8_t mac[16];
|
||||
uint8_t iv[16];
|
||||
uint8_t flag;
|
||||
uint32_t time;
|
||||
uint8_t time[4];
|
||||
|
||||
uint8_t GetPayloadType () const { return flag >> 4; };
|
||||
bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||
@@ -71,7 +69,8 @@ namespace transport
|
||||
|
||||
void Connect ();
|
||||
void WaitForConnect ();
|
||||
void Introduce (const i2p::data::RouterInfo::Introducer& introducer);
|
||||
void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
|
||||
void WaitForIntroduction ();
|
||||
void Close ();
|
||||
void Done ();
|
||||
@@ -95,22 +94,22 @@ namespace transport
|
||||
|
||||
boost::asio::io_service& GetService ();
|
||||
void CreateAESandMacKey (const uint8_t * pubKey);
|
||||
size_t GetSSUHeaderSize (uint8_t * buf) const;
|
||||
size_t GetSSUHeaderSize (const uint8_t * buf) const;
|
||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||
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 (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||
void SendSessionRequest ();
|
||||
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer);
|
||||
void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer, uint32_t nonce);
|
||||
void ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||
void SendSessionCreated (const uint8_t * x);
|
||||
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
||||
void ProcessSessionConfirmed (const uint8_t * buf, size_t len);
|
||||
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, size_t ourAddressLen);
|
||||
void ProcessRelayRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
|
||||
void ProcessRelayRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from);
|
||||
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
|
||||
const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
|
||||
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
|
||||
void ProcessRelayResponse (uint8_t * buf, size_t len);
|
||||
void ProcessRelayIntro (uint8_t * buf, size_t len);
|
||||
void SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from);
|
||||
void ProcessRelayResponse (const uint8_t * buf, size_t len);
|
||||
void ProcessRelayIntro (const uint8_t * buf, size_t len);
|
||||
void Established ();
|
||||
void Failed ();
|
||||
void ScheduleConnectTimer ();
|
||||
@@ -150,6 +149,7 @@ namespace transport
|
||||
SSUData m_Data;
|
||||
bool m_IsDataReceived;
|
||||
std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only
|
||||
std::map<uint32_t, std::shared_ptr<const i2p::data::RouterInfo> > m_RelayRequests; // nonce->Charlie
|
||||
};
|
||||
|
||||
|
||||
|
||||
201
Signature.cpp
201
Signature.cpp
@@ -13,19 +13,16 @@ namespace crypto
|
||||
Ed25519 ()
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * two = BN_new (), * tmp = BN_new ();
|
||||
BN_set_word (two, 2);
|
||||
BIGNUM * tmp = BN_new ();
|
||||
|
||||
q = BN_new ();
|
||||
// 2^255-19
|
||||
BN_set_word (tmp, 255);
|
||||
BN_exp (q, two, tmp, ctx);
|
||||
BN_set_bit (q, 255); // 2^255
|
||||
BN_sub_word (q, 19);
|
||||
|
||||
l = BN_new ();
|
||||
// 2^252 + 27742317777372353535851937790883648493
|
||||
BN_set_word (tmp, 252);
|
||||
BN_exp (l, two, tmp, ctx);
|
||||
BN_set_bit (l, 252);
|
||||
two_252_2 = BN_dup (l);
|
||||
BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
|
||||
BN_add (l, l, tmp);
|
||||
@@ -45,8 +42,10 @@ namespace crypto
|
||||
tmp = BN_dup (q);
|
||||
BN_sub_word (tmp, 1);
|
||||
BN_div_word (tmp, 4);
|
||||
BN_mod_exp (I, two, tmp, q, ctx);
|
||||
|
||||
BN_set_word (I, 2);
|
||||
BN_mod_exp (I, I, tmp, q, ctx);
|
||||
BN_free (tmp);
|
||||
|
||||
// 4*inv(5)
|
||||
BIGNUM * By = BN_new ();
|
||||
BN_set_word (By, 5);
|
||||
@@ -54,24 +53,32 @@ namespace crypto
|
||||
BN_mul_word (By, 4);
|
||||
BIGNUM * Bx = RecoverX (By, ctx);
|
||||
BN_mod (Bx, Bx, q, ctx); // % q
|
||||
BN_mod (By, By, q, ctx); // % q
|
||||
B = {Bx, By};
|
||||
|
||||
BN_free (two);
|
||||
BN_free (tmp);
|
||||
BN_mod (By, By, q, ctx); // % q
|
||||
|
||||
// precalculate Bi16 table
|
||||
Bi16[0][0] = { BN_dup (Bx), BN_dup (By) };
|
||||
for (int i = 0; i < 64; i++)
|
||||
// precalculate Bi256 table
|
||||
Bi256Carry = { Bx, By }; // B
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
if (i) Bi16[i][0] = Sum (Bi16[i-1][14], Bi16[i-1][0], ctx);
|
||||
for (int j = 1; j < 15; j++)
|
||||
Bi16[i][j] = Sum (Bi16[i][j-1], Bi16[i][0], ctx); // (16+j+1)^i*B
|
||||
Bi256[i][0] = Bi256Carry; // first point
|
||||
for (int j = 1; j < 128; j++)
|
||||
Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B
|
||||
Bi256Carry = Bi256[i][127];
|
||||
for (int j = 0; j < 128; j++) // add first point 128 more times
|
||||
Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx);
|
||||
}
|
||||
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)),
|
||||
d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)),
|
||||
Bi256Carry (other.Bi256Carry)
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (int j = 0; j < 128; j++)
|
||||
Bi256[i][j] = other.Bi256[i][j];
|
||||
}
|
||||
|
||||
~Ed25519 ()
|
||||
{
|
||||
BN_free (q);
|
||||
@@ -97,8 +104,9 @@ namespace crypto
|
||||
EncodePoint (Normalize (publicKey, ctx), buf);
|
||||
}
|
||||
|
||||
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature, BN_CTX * ctx) const
|
||||
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
// signature 0..31 - R, 32..63 - S
|
||||
// B*S = R + PK*h => R = B*S - PK*h
|
||||
@@ -110,14 +118,16 @@ namespace crypto
|
||||
EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
|
||||
bool passed = !memcmp (signature, diff, 32); // R
|
||||
BN_free (h);
|
||||
BN_CTX_free (ctx);
|
||||
if (!passed)
|
||||
LogPrint (eLogError, "25519 signature verification failed");
|
||||
return passed;
|
||||
}
|
||||
|
||||
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len,
|
||||
uint8_t * signature, BN_CTX * bnCtx) const
|
||||
uint8_t * signature) const
|
||||
{
|
||||
BN_CTX * bnCtx = BN_CTX_new ();
|
||||
// calculate r
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
@@ -143,6 +153,7 @@ namespace crypto
|
||||
memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
|
||||
EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
|
||||
BN_free (r); BN_free (h); BN_free (a);
|
||||
BN_CTX_free (bnCtx);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -154,36 +165,42 @@ namespace crypto
|
||||
// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
|
||||
// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
|
||||
BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
|
||||
BIGNUM * z1 = p1.z, * t1 = p1.t;
|
||||
if (!z1) { z1 = BN_new (); BN_one (z1); }
|
||||
|
||||
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
|
||||
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
|
||||
|
||||
BIGNUM * t1 = p1.t, * t2 = p2.t;
|
||||
if (!t1) { t1 = BN_new (); BN_mul (t1, p1.x, p1.y, ctx); }
|
||||
|
||||
BIGNUM * z2 = p2.z, * t2 = p2.t;
|
||||
if (!z2) { z2 = BN_new (); BN_one (z2); }
|
||||
if (!t2) { t2 = BN_new (); BN_mul (t2, p2.x, p2.y, ctx); }
|
||||
|
||||
BIGNUM * A = BN_new (), * B = BN_new (), * C = BN_new (), * D = BN_new ();
|
||||
BN_mul (A, p1.x, p2.x, ctx); // A = x1*x2
|
||||
BN_mul (B, p1.y, p2.y, ctx); // B = y1*y2
|
||||
BN_mul (C, t1, t2, ctx);
|
||||
BN_mul (C, C, d, ctx); // C = d*t1*t2
|
||||
BN_mul (D, z1, z2, ctx); // D = z1*z2
|
||||
BN_mul (t3, t1, t2, ctx);
|
||||
BN_mul (t3, t3, d, ctx); // C = d*t1*t2
|
||||
if (!p1.t) BN_free (t1);
|
||||
if (!p2.t) BN_free (t2);
|
||||
|
||||
if (p1.z)
|
||||
{
|
||||
if (p2.z)
|
||||
BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2
|
||||
else
|
||||
BN_copy (z3, p1.z); // D = z1
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p2.z)
|
||||
BN_copy (z3, p2.z); // D = z2
|
||||
else
|
||||
BN_one (z3); // D = 1
|
||||
}
|
||||
|
||||
BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
|
||||
BN_add (x3, p1.x, p1.y);
|
||||
BN_add (y3, p2.x, p2.y);
|
||||
BN_mul (E, x3, y3, ctx); // (x1 + y1)*(x2 + y2)
|
||||
BN_sub (E, E, A);
|
||||
BN_sub (E, E, B); // E = (x1 + y1)*(x2 + y2) - A - B
|
||||
BN_sub (F, D, C); // F = D - C
|
||||
BN_add (G, D, C); // G = D + C
|
||||
BN_add (H, B, A); // H = B + A
|
||||
|
||||
BN_free (A); BN_free (B); BN_free (C); BN_free (D);
|
||||
if (!p1.z) BN_free (z1);
|
||||
if (!p1.t) BN_free (t1);
|
||||
if (!p2.z) BN_free (z2);
|
||||
if (!p2.t) BN_free (t2);
|
||||
BN_add (E, p1.x, p1.y);
|
||||
BN_add (F, p2.x, p2.y);
|
||||
BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
|
||||
BN_sub (E, E, x3);
|
||||
BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
|
||||
BN_sub (F, z3, t3); // F = D - C
|
||||
BN_add (G, z3, t3); // G = D + C
|
||||
BN_add (H, y3, x3); // H = B + A
|
||||
|
||||
BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F
|
||||
BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H
|
||||
@@ -198,27 +215,30 @@ namespace crypto
|
||||
EDDSAPoint Double (const EDDSAPoint& p, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * x2 = BN_new (), * y2 = BN_new (), * z2 = BN_new (), * t2 = BN_new ();
|
||||
BIGNUM * z = p.z, * t = p.t;
|
||||
if (!z) { z = BN_new (); BN_one (z); }
|
||||
if (!t) { t = BN_new (); BN_mul (t, p.x, p.y, ctx); }
|
||||
|
||||
BN_sqr (x2, p.x, ctx); // x2 = A = x^2
|
||||
BN_sqr (y2, p.y, ctx); // y2 = B = y^2
|
||||
BN_sqr (t2, t, ctx);
|
||||
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
|
||||
BN_sqr (z2, z, ctx); // z2 = D = z^2
|
||||
if (p.t)
|
||||
BN_sqr (t2, p.t, ctx); // t2 = t^2
|
||||
else
|
||||
{
|
||||
BN_mul (t2, p.x, p.y, ctx); // t = x*y
|
||||
BN_sqr (t2, t2, ctx); // t2 = t^2
|
||||
}
|
||||
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
|
||||
if (p.z)
|
||||
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
|
||||
else
|
||||
BN_one (z2); // z2 = 1
|
||||
|
||||
BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
|
||||
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
|
||||
BN_mul (E, p.x, p.y, ctx);
|
||||
BN_mul_word (E, 2); // E =2*x*y
|
||||
BN_lshift1 (E, E); // E =2*x*y
|
||||
BN_sub (F, z2, t2); // F = D - C
|
||||
BN_add (G, z2, t2); // G = D + C
|
||||
BN_add (H, y2, x2); // H = B + A
|
||||
|
||||
if (!p.z) BN_free (z);
|
||||
if (!p.t) BN_free (t);
|
||||
|
||||
BN_mod_mul (x2, E, F, q, ctx); // x2 = E*F
|
||||
BN_mod_mul (y2, G, H, q, ctx); // y2 = G*H
|
||||
BN_mod_mul (z2, F, G, q, ctx); // z2 = F*G
|
||||
@@ -246,20 +266,37 @@ namespace crypto
|
||||
return res;
|
||||
}
|
||||
|
||||
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e. e is 32 bytes Little Endian
|
||||
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian
|
||||
{
|
||||
BIGNUM * zero = BN_new (), * one = BN_new ();
|
||||
BN_zero (zero); BN_one (one);
|
||||
EDDSAPoint res {zero, one};
|
||||
bool carry = false;
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
uint8_t x = e[i] & 0x0F; // 4 low bits
|
||||
uint8_t x = e[i];
|
||||
if (carry)
|
||||
{
|
||||
if (x < 255)
|
||||
{
|
||||
x++;
|
||||
carry = false;
|
||||
}
|
||||
else
|
||||
x = 0;
|
||||
}
|
||||
if (x > 0)
|
||||
res = Sum (res, Bi16[i*2][x-1], ctx);
|
||||
x = e[i] >> 4; // 4 high bits
|
||||
if (x > 0)
|
||||
res = Sum (res, Bi16[i*2+1][x-1], ctx);
|
||||
{
|
||||
if (x <= 128)
|
||||
res = Sum (res, Bi256[i][x-1], ctx);
|
||||
else
|
||||
{
|
||||
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
|
||||
carry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (carry) res = Sum (res, Bi256Carry, ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -341,7 +378,9 @@ namespace crypto
|
||||
auto x = RecoverX (y, ctx);
|
||||
if (BN_is_bit_set (x, 0) != isHighestBitSet)
|
||||
BN_sub (x, q, x); // x = q - x
|
||||
EDDSAPoint p {x, y};
|
||||
BIGNUM * z = BN_new (), * t = BN_new ();
|
||||
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
|
||||
EDDSAPoint p {x, y, z, t};
|
||||
if (!IsOnCurve (p, ctx))
|
||||
LogPrint (eLogError, "Decoded point is not on 25519");
|
||||
return p;
|
||||
@@ -384,42 +423,46 @@ namespace crypto
|
||||
private:
|
||||
|
||||
BIGNUM * q, * l, * d, * I;
|
||||
EDDSAPoint B; // base point
|
||||
// transient values
|
||||
BIGNUM * two_252_2; // 2^252-2
|
||||
EDDSAPoint Bi16[64][15]; // per 4-bits, Bi16[i][j] = (16+j+1)^i*B, we don't store zeroes
|
||||
EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes
|
||||
// if j > 128 we use 256 - j and carry 1 to next byte
|
||||
// Bi256[0][0] = B, base point
|
||||
EDDSAPoint Bi256Carry; // Bi256[32][0]
|
||||
};
|
||||
|
||||
static std::unique_ptr<Ed25519> g_Ed25519;
|
||||
std::unique_ptr<Ed25519>& GetEd25519 ()
|
||||
{
|
||||
if (!g_Ed25519)
|
||||
g_Ed25519.reset (new Ed25519 ());
|
||||
g_Ed25519.reset (new Ed25519());
|
||||
|
||||
return g_Ed25519;
|
||||
}
|
||||
|
||||
|
||||
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey):
|
||||
m_Ctx (BN_CTX_new ()),
|
||||
m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey, m_Ctx))
|
||||
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
|
||||
{
|
||||
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[64];
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
uint8_t digest[64];
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
return GetEd25519 ()->Verify (m_PublicKey, digest, signature, m_Ctx);
|
||||
|
||||
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
|
||||
}
|
||||
|
||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey):
|
||||
m_Ctx (BN_CTX_new ())
|
||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
// expand key
|
||||
SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey);
|
||||
@@ -427,13 +470,15 @@ namespace crypto
|
||||
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x1F; // drop first 3 bits
|
||||
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
|
||||
// generate and encode public key
|
||||
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, m_Ctx);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, m_Ctx);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature, m_Ctx);
|
||||
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
Signature.h
54
Signature.h
@@ -44,11 +44,7 @@ namespace crypto
|
||||
|
||||
DSAVerifier (const uint8_t * signingKey)
|
||||
{
|
||||
m_PublicKey = DSA_new ();
|
||||
m_PublicKey->p = BN_dup (dsap);
|
||||
m_PublicKey->q = BN_dup (dsaq);
|
||||
m_PublicKey->g = BN_dup (dsag);
|
||||
m_PublicKey->priv_key = NULL;
|
||||
m_PublicKey = CreateDSA ();
|
||||
m_PublicKey->pub_key = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL);
|
||||
}
|
||||
|
||||
@@ -86,12 +82,8 @@ namespace crypto
|
||||
|
||||
DSASigner (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
m_PrivateKey = DSA_new ();
|
||||
m_PrivateKey->p = BN_dup (dsap);
|
||||
m_PrivateKey->q = BN_dup (dsaq);
|
||||
m_PrivateKey->g = BN_dup (dsag);
|
||||
m_PrivateKey = CreateDSA ();
|
||||
m_PrivateKey->priv_key = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL);
|
||||
m_PrivateKey->pub_key = NULL;
|
||||
}
|
||||
|
||||
~DSASigner ()
|
||||
@@ -116,12 +108,7 @@ namespace crypto
|
||||
|
||||
inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
DSA * dsa = DSA_new ();
|
||||
dsa->p = BN_dup (dsap);
|
||||
dsa->q = BN_dup (dsaq);
|
||||
dsa->g = BN_dup (dsag);
|
||||
dsa->priv_key = NULL;
|
||||
dsa->pub_key = NULL;
|
||||
DSA * dsa = CreateDSA ();
|
||||
DSA_generate_key (dsa);
|
||||
bn2buf (dsa->priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||
bn2buf (dsa->pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||
@@ -285,7 +272,7 @@ namespace crypto
|
||||
{
|
||||
m_PublicKey = RSA_new ();
|
||||
memset (m_PublicKey, 0, sizeof (RSA));
|
||||
m_PublicKey->e = BN_dup (rsae);
|
||||
m_PublicKey->e = BN_dup (GetRSAE ());
|
||||
m_PublicKey->n = BN_bin2bn (signingKey, keyLen, NULL);
|
||||
}
|
||||
|
||||
@@ -319,7 +306,7 @@ namespace crypto
|
||||
{
|
||||
m_PrivateKey = RSA_new ();
|
||||
memset (m_PrivateKey, 0, sizeof (RSA));
|
||||
m_PrivateKey->e = BN_dup (rsae);
|
||||
m_PrivateKey->e = BN_dup (GetRSAE ());
|
||||
m_PrivateKey->n = BN_bin2bn (signingPrivateKey, keyLen, NULL);
|
||||
m_PrivateKey->d = BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL);
|
||||
}
|
||||
@@ -345,10 +332,12 @@ namespace crypto
|
||||
inline void CreateRSARandomKeys (size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
RSA * rsa = RSA_new ();
|
||||
RSA_generate_key_ex (rsa, publicKeyLen*8, rsae, NULL);
|
||||
BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const
|
||||
RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL);
|
||||
bn2buf (rsa->n, signingPrivateKey, publicKeyLen);
|
||||
bn2buf (rsa->d, signingPrivateKey + publicKeyLen, publicKeyLen);
|
||||
bn2buf (rsa->n, signingPublicKey, publicKeyLen);
|
||||
BN_free (e); // this e is not assigned to rsa->e
|
||||
RSA_free (rsa);
|
||||
}
|
||||
|
||||
@@ -373,6 +362,8 @@ namespace crypto
|
||||
BIGNUM * x, * y;
|
||||
BIGNUM * z, * t; // projective coordinates
|
||||
EDDSAPoint (): x(nullptr), y(nullptr), z(nullptr), t(nullptr) {};
|
||||
EDDSAPoint (const EDDSAPoint& other): x(nullptr), y(nullptr), z(nullptr), t(nullptr)
|
||||
{ *this = other; };
|
||||
EDDSAPoint (EDDSAPoint&& other): x(nullptr), y(nullptr), z(nullptr), t(nullptr)
|
||||
{ *this = std::move (other); };
|
||||
EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr): x(x1), y(y1), z(z1), t(t1) {};
|
||||
@@ -380,17 +371,22 @@ namespace crypto
|
||||
|
||||
EDDSAPoint& operator=(EDDSAPoint&& other)
|
||||
{
|
||||
if (x) BN_free (x);
|
||||
if (y) BN_free (y);
|
||||
if (z) BN_free (z);
|
||||
if (t) BN_free (t);
|
||||
x = other.x; other.x = nullptr;
|
||||
y = other.y; other.y = nullptr;
|
||||
z = other.z; other.z = nullptr;
|
||||
t = other.t; other.t = nullptr;
|
||||
if (x) BN_free (x); x = other.x; other.x = nullptr;
|
||||
if (y) BN_free (y); y = other.y; other.y = nullptr;
|
||||
if (z) BN_free (z); z = other.z; other.z = nullptr;
|
||||
if (t) BN_free (t); t = other.t; other.t = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EDDSAPoint& operator=(const EDDSAPoint& other)
|
||||
{
|
||||
if (x) BN_free (x); x = other.x ? BN_dup (other.x) : nullptr;
|
||||
if (y) BN_free (y); y = other.y ? BN_dup (other.y) : nullptr;
|
||||
if (z) BN_free (z); z = other.z ? BN_dup (other.z) : nullptr;
|
||||
if (t) BN_free (t); t = other.t ? BN_dup (other.t) : nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
EDDSAPoint operator-() const
|
||||
{
|
||||
BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL;
|
||||
@@ -410,7 +406,6 @@ namespace crypto
|
||||
public:
|
||||
|
||||
EDDSA25519Verifier (const uint8_t * signingKey);
|
||||
~EDDSA25519Verifier () { BN_CTX_free (m_Ctx); };
|
||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
|
||||
|
||||
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
|
||||
@@ -418,7 +413,6 @@ namespace crypto
|
||||
|
||||
private:
|
||||
|
||||
BN_CTX * m_Ctx;
|
||||
EDDSAPoint m_PublicKey;
|
||||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
};
|
||||
@@ -428,13 +422,11 @@ namespace crypto
|
||||
public:
|
||||
|
||||
EDDSA25519Signer (const uint8_t * signingPrivateKey);
|
||||
~EDDSA25519Signer () { BN_CTX_free (m_Ctx); };
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; };
|
||||
|
||||
private:
|
||||
|
||||
BN_CTX * m_Ctx;
|
||||
uint8_t m_ExpandedPrivateKey[64];
|
||||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
};
|
||||
|
||||
116
Streaming.cpp
116
Streaming.cpp
@@ -53,7 +53,7 @@ namespace stream
|
||||
delete it;
|
||||
m_SavedPackets.clear ();
|
||||
|
||||
LogPrint (eLogDebug, "Stream deleted");
|
||||
LogPrint (eLogDebug, "Streaming: Stream deleted");
|
||||
}
|
||||
|
||||
void Stream::Terminate ()
|
||||
@@ -83,12 +83,12 @@ namespace stream
|
||||
if (!receivedSeqn && !isSyn)
|
||||
{
|
||||
// plain ack
|
||||
LogPrint (eLogDebug, "Plain ACK received");
|
||||
LogPrint (eLogDebug, "Streaming: Plain ACK received");
|
||||
delete packet;
|
||||
return;
|
||||
}
|
||||
|
||||
LogPrint (eLogDebug, "Received seqn=", receivedSeqn);
|
||||
LogPrint (eLogDebug, "Streaming: Received seqn=", receivedSeqn);
|
||||
if (isSyn || receivedSeqn == m_LastReceivedSequenceNumber + 1)
|
||||
{
|
||||
// we have received next in sequence message
|
||||
@@ -128,13 +128,13 @@ namespace stream
|
||||
if (receivedSeqn <= m_LastReceivedSequenceNumber)
|
||||
{
|
||||
// we have received duplicate
|
||||
LogPrint (eLogWarning, "Duplicate message ", receivedSeqn, " received");
|
||||
LogPrint (eLogWarning, "Streaming: Duplicate message ", receivedSeqn, " received");
|
||||
SendQuickAck (); // resend ack for previous message again
|
||||
delete packet; // packet dropped
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
|
||||
LogPrint (eLogWarning, "Streaming: Missing messages from ", m_LastReceivedSequenceNumber + 1, " to ", receivedSeqn - 1);
|
||||
// save message and wait for missing message again
|
||||
SavePacket (packet);
|
||||
if (m_LastReceivedSequenceNumber >= 0)
|
||||
@@ -169,44 +169,38 @@ namespace stream
|
||||
// process flags
|
||||
uint32_t receivedSeqn = packet->GetSeqn ();
|
||||
uint16_t flags = packet->GetFlags ();
|
||||
LogPrint (eLogDebug, "Process seqn=", receivedSeqn, ", flags=", flags);
|
||||
LogPrint (eLogDebug, "Streaming: Process seqn=", receivedSeqn, ", flags=", flags);
|
||||
|
||||
const uint8_t * optionData = packet->GetOptionData ();
|
||||
if (flags & PACKET_FLAG_SYNCHRONIZE)
|
||||
LogPrint (eLogDebug, "Synchronize");
|
||||
|
||||
if (flags & PACKET_FLAG_DELAY_REQUESTED)
|
||||
{
|
||||
optionData += 2;
|
||||
}
|
||||
|
||||
if (flags & PACKET_FLAG_FROM_INCLUDED)
|
||||
{
|
||||
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ());
|
||||
optionData += m_RemoteIdentity->GetFullLen ();
|
||||
LogPrint (eLogInfo, "From identity ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
|
||||
if (!m_RemoteLeaseSet)
|
||||
LogPrint (eLogDebug, "Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
|
||||
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 ());
|
||||
}
|
||||
|
||||
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
|
||||
{
|
||||
uint16_t maxPacketSize = bufbe16toh (optionData);
|
||||
LogPrint (eLogDebug, "Max packet size ", maxPacketSize);
|
||||
LogPrint (eLogDebug, "Streaming: Max packet size ", maxPacketSize);
|
||||
optionData += 2;
|
||||
}
|
||||
|
||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||
{
|
||||
LogPrint (eLogDebug, "Signature");
|
||||
uint8_t signature[256];
|
||||
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
||||
memcpy (signature, optionData, signatureLen);
|
||||
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
|
||||
if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature))
|
||||
{
|
||||
LogPrint (eLogError, "Signature verification failed");
|
||||
Close ();
|
||||
LogPrint (eLogError, "Streaming: Signature verification failed");
|
||||
Close ();
|
||||
flags |= PACKET_FLAG_CLOSE;
|
||||
}
|
||||
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
|
||||
@@ -226,7 +220,6 @@ namespace stream
|
||||
|
||||
if (flags & (PACKET_FLAG_CLOSE | PACKET_FLAG_RESET))
|
||||
{
|
||||
LogPrint (eLogInfo, (flags & PACKET_FLAG_RESET) ? "Reset" : "Closed");
|
||||
m_Status = eStreamStatusReset;
|
||||
Close ();
|
||||
}
|
||||
@@ -254,7 +247,7 @@ namespace stream
|
||||
}
|
||||
if (nacked)
|
||||
{
|
||||
LogPrint (eLogDebug, "Packet ", seqn, " NACK");
|
||||
LogPrint (eLogDebug, "Streaming: Packet ", seqn, " NACK");
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
@@ -418,7 +411,7 @@ namespace stream
|
||||
}
|
||||
if (lastReceivedSeqn < 0)
|
||||
{
|
||||
LogPrint (eLogError, "No packets have been received yet");
|
||||
LogPrint (eLogError, "Streaming: No packets have been received yet");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -474,7 +467,7 @@ namespace stream
|
||||
p.len = size;
|
||||
|
||||
SendPackets (std::vector<Packet *> { &p });
|
||||
LogPrint ("Quick Ack sent. ", (int)numNacks, " NACKs");
|
||||
LogPrint (eLogDebug, "Streaming: Quick Ack sent. ", (int)numNacks, " NACKs");
|
||||
}
|
||||
|
||||
void Stream::Close ()
|
||||
@@ -485,7 +478,7 @@ namespace stream
|
||||
m_Status = eStreamStatusClosing;
|
||||
Close (); // recursion
|
||||
if (m_Status == eStreamStatusClosing) //still closing
|
||||
LogPrint (eLogInfo, "Trying to send stream data before closing");
|
||||
LogPrint (eLogInfo, "Streaming: Trying to send stream data before closing");
|
||||
break;
|
||||
case eStreamStatusReset:
|
||||
SendClose ();
|
||||
@@ -507,7 +500,7 @@ namespace stream
|
||||
m_LocalDestination.DeleteStream (shared_from_this ());
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "Unexpected stream status ", (int)m_Status);
|
||||
LogPrint (eLogWarning, "Streaming: Unexpected stream status ", (int)m_Status);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -539,7 +532,7 @@ namespace stream
|
||||
|
||||
p->len = size;
|
||||
m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p));
|
||||
LogPrint ("FIN sent");
|
||||
LogPrint (eLogDebug, "Streaming: FIN sent");
|
||||
}
|
||||
|
||||
size_t Stream::ConcatenatePackets (uint8_t * buf, size_t len)
|
||||
@@ -593,7 +586,7 @@ namespace stream
|
||||
UpdateCurrentRemoteLease ();
|
||||
if (!m_RemoteLeaseSet)
|
||||
{
|
||||
LogPrint (eLogError, "Can't send packets. Missing remote LeaseSet");
|
||||
LogPrint (eLogError, "Streaming: Can't send packets, missing remote LeaseSet");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -601,7 +594,7 @@ namespace stream
|
||||
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel);
|
||||
if (!m_CurrentOutboundTunnel)
|
||||
{
|
||||
LogPrint (eLogError, "No outbound tunnels in the pool");
|
||||
LogPrint (eLogError, "Streaming: No outbound tunnels in the pool");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -625,7 +618,7 @@ namespace stream
|
||||
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "All leases are expired");
|
||||
LogPrint (eLogWarning, "Streaming: All leases are expired");
|
||||
}
|
||||
|
||||
|
||||
@@ -644,7 +637,7 @@ namespace stream
|
||||
// check for resend attempts
|
||||
if (m_NumResendAttempts >= MAX_NUM_RESEND_ATTEMPTS)
|
||||
{
|
||||
LogPrint (eLogWarning, "Stream packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts. Terminate");
|
||||
LogPrint (eLogWarning, "Streaming: packet was not ACKed after ", MAX_NUM_RESEND_ATTEMPTS, " attempts, terminate");
|
||||
m_Status = eStreamStatusReset;
|
||||
Close ();
|
||||
return;
|
||||
@@ -678,12 +671,12 @@ namespace stream
|
||||
// no break here
|
||||
case 4:
|
||||
UpdateCurrentRemoteLease (); // pick another lease
|
||||
LogPrint (eLogWarning, "Another remote lease has been selected for stream");
|
||||
LogPrint (eLogWarning, "Streaming: Another remote lease has been selected for stream");
|
||||
break;
|
||||
case 3:
|
||||
// pick another outbound tunnel
|
||||
m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel);
|
||||
LogPrint (eLogWarning, "Another outbound tunnel has been selected for stream");
|
||||
LogPrint (eLogWarning, "Streaming: Another outbound tunnel has been selected for stream");
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
@@ -699,7 +692,7 @@ namespace stream
|
||||
{
|
||||
if (m_LastReceivedSequenceNumber < 0)
|
||||
{
|
||||
LogPrint (eLogWarning, "SYN has not been recived after ", ACK_SEND_TIMEOUT, " milliseconds after follow on. Terminate");
|
||||
LogPrint (eLogWarning, "Streaming: SYN has not been recived after ", ACK_SEND_TIMEOUT, " milliseconds after follow on, terminate");
|
||||
m_Status = eStreamStatusReset;
|
||||
Close ();
|
||||
return;
|
||||
@@ -716,7 +709,7 @@ namespace stream
|
||||
{
|
||||
m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (!m_RemoteLeaseSet)
|
||||
LogPrint ("LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
|
||||
LogPrint (eLogError, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
|
||||
}
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
@@ -764,13 +757,14 @@ namespace stream
|
||||
|
||||
std::shared_ptr<I2NPMessage> Stream::CreateDataMessage (const uint8_t * payload, size_t len)
|
||||
{
|
||||
auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE)
|
||||
m_LocalDestination.m_Deflator.SetCompressionLevel (Z_NO_COMPRESSION);
|
||||
else
|
||||
m_LocalDestination.m_Deflator.SetCompressionLevel (Z_DEFAULT_COMPRESSION);
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
buf += 4; // reserve for lengthlength
|
||||
msg->len += 4;
|
||||
size_t size = m_LocalDestination.m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len);
|
||||
if (size)
|
||||
{
|
||||
@@ -778,7 +772,7 @@ namespace stream
|
||||
htobe16buf (buf + 4, m_LocalDestination.GetLocalPort ()); // source port
|
||||
htobe16buf (buf + 6, m_Port); // destination port
|
||||
buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol
|
||||
msg->len += size + 4;
|
||||
msg->len += size;
|
||||
msg->FillI2NPMessageHeader (eI2NPData);
|
||||
}
|
||||
else
|
||||
@@ -787,7 +781,7 @@ namespace stream
|
||||
}
|
||||
|
||||
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort):
|
||||
m_Owner (owner), m_LocalPort (localPort)
|
||||
m_Owner (owner), m_LocalPort (localPort), m_PendingIncomingTimer (m_Owner->GetService ())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -802,6 +796,7 @@ namespace stream
|
||||
void StreamingDestination::Stop ()
|
||||
{
|
||||
ResetAcceptor ();
|
||||
m_PendingIncomingTimer.cancel ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||
m_Streams.clear ();
|
||||
@@ -818,7 +813,7 @@ namespace stream
|
||||
it->second->HandleNextPacket (packet);
|
||||
else
|
||||
{
|
||||
LogPrint ("Unknown stream sendStreamID=", sendStreamID);
|
||||
LogPrint (eLogError, "Streaming: Unknown stream sendStreamID=", sendStreamID);
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
@@ -832,8 +827,21 @@ namespace stream
|
||||
m_Acceptor (incomingStream);
|
||||
else
|
||||
{
|
||||
LogPrint ("Acceptor for incoming stream is not set");
|
||||
DeleteStream (incomingStream);
|
||||
LogPrint (eLogWarning, "Streaming: Acceptor for incoming stream is not set");
|
||||
if (m_PendingIncomingStreams.size () < MAX_PENDING_INCOMING_BACKLOG)
|
||||
{
|
||||
m_PendingIncomingStreams.push_back (incomingStream);
|
||||
m_PendingIncomingTimer.cancel ();
|
||||
m_PendingIncomingTimer.expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT));
|
||||
m_PendingIncomingTimer.async_wait (std::bind (&StreamingDestination::HandlePendingIncomingTimer,
|
||||
this, std::placeholders::_1));
|
||||
LogPrint (eLogDebug, "Streaming: Pending incoming stream added");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Streaming: Pending incoming streams backlog exceeds ", MAX_PENDING_INCOMING_BACKLOG);
|
||||
incomingStream->Close ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else // follow on packet without SYN
|
||||
@@ -847,12 +855,12 @@ namespace stream
|
||||
return;
|
||||
}
|
||||
// TODO: should queue it up
|
||||
LogPrint ("Unknown stream receiveStreamID=", receiveStreamID);
|
||||
LogPrint (eLogError, "Streaming: Unknown stream receiveStreamID=", receiveStreamID);
|
||||
delete packet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Stream> StreamingDestination::CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
||||
{
|
||||
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this, remote, port);
|
||||
@@ -880,6 +888,36 @@ namespace stream
|
||||
}
|
||||
}
|
||||
|
||||
void StreamingDestination::SetAcceptor (const Acceptor& acceptor)
|
||||
{
|
||||
m_Owner->GetService ().post([acceptor, this](void)
|
||||
{
|
||||
m_Acceptor = acceptor;
|
||||
for (auto it: m_PendingIncomingStreams)
|
||||
if (it->GetStatus () == eStreamStatusOpen) // still open?
|
||||
m_Acceptor (it);
|
||||
m_PendingIncomingStreams.clear ();
|
||||
m_PendingIncomingTimer.cancel ();
|
||||
});
|
||||
}
|
||||
|
||||
void StreamingDestination::ResetAcceptor ()
|
||||
{
|
||||
if (m_Acceptor) m_Acceptor (nullptr);
|
||||
m_Acceptor = nullptr;
|
||||
}
|
||||
|
||||
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogWarning, "Streaming: Pending incoming timeout expired");
|
||||
for (auto it: m_PendingIncomingStreams)
|
||||
it->Close ();
|
||||
m_PendingIncomingStreams.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len)
|
||||
{
|
||||
// unzip it
|
||||
|
||||
@@ -49,6 +49,8 @@ namespace stream
|
||||
const int MAX_WINDOW_SIZE = 128;
|
||||
const int INITIAL_RTT = 8000; // in milliseconds
|
||||
const int INITIAL_RTO = 9000; // in milliseconds
|
||||
const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
|
||||
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
|
||||
|
||||
struct Packet
|
||||
{
|
||||
@@ -201,8 +203,8 @@ namespace stream
|
||||
|
||||
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||
void DeleteStream (std::shared_ptr<Stream> stream);
|
||||
void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; };
|
||||
void ResetAcceptor () { if (m_Acceptor) m_Acceptor (nullptr); m_Acceptor = nullptr; };
|
||||
void SetAcceptor (const Acceptor& acceptor);
|
||||
void ResetAcceptor ();
|
||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
|
||||
uint16_t GetLocalPort () const { return m_LocalPort; };
|
||||
@@ -213,6 +215,7 @@ namespace stream
|
||||
|
||||
void HandleNextPacket (Packet * packet);
|
||||
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
||||
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
||||
@@ -221,6 +224,8 @@ namespace stream
|
||||
std::mutex m_StreamsMutex;
|
||||
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams;
|
||||
Acceptor m_Acceptor;
|
||||
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
|
||||
boost::asio::deadline_timer m_PendingIncomingTimer;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace tunnel
|
||||
{
|
||||
auto num = m_TunnelDataMsgs.size ();
|
||||
if (num > 1)
|
||||
LogPrint (eLogDebug, "TransitTunnel: ",GetTunnelID (),"->", GetNextTunnelID (), " ", num);
|
||||
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
|
||||
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
|
||||
m_TunnelDataMsgs.clear ();
|
||||
}
|
||||
@@ -53,12 +53,12 @@ namespace tunnel
|
||||
|
||||
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
LogPrint (eLogError, "We are not a gateway for transit tunnel ", GetTunnelID ());
|
||||
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
|
||||
}
|
||||
|
||||
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||
{
|
||||
LogPrint (eLogError, "Incoming tunnel message is not supported ", GetTunnelID ());
|
||||
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
|
||||
}
|
||||
|
||||
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
@@ -81,7 +81,7 @@ namespace tunnel
|
||||
auto newMsg = CreateEmptyTunnelDataMsg ();
|
||||
EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||
|
||||
LogPrint (eLogDebug, "TransitTunnel endpoint for ", GetTunnelID ());
|
||||
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());
|
||||
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
|
||||
}
|
||||
|
||||
@@ -92,12 +92,12 @@ namespace tunnel
|
||||
{
|
||||
if (isEndpoint)
|
||||
{
|
||||
LogPrint (eLogInfo, "TransitTunnel endpoint: ", receiveTunnelID, " created");
|
||||
LogPrint (eLogInfo, "TransitTunnel: endpoint ", receiveTunnelID, " created");
|
||||
return new TransitTunnelEndpoint (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
else if (isGateway)
|
||||
{
|
||||
LogPrint (eLogInfo, "TransitTunnel gateway: ", receiveTunnelID, " created");
|
||||
LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
|
||||
return new TransitTunnelGateway (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
else
|
||||
|
||||
109
Transports.cpp
109
Transports.cpp
@@ -126,12 +126,12 @@ namespace transport
|
||||
if (!m_SSUServer)
|
||||
{
|
||||
m_SSUServer = new SSUServer (address.port);
|
||||
LogPrint ("Start listening UDP port ", address.port);
|
||||
LogPrint (eLogInfo, "Transports: Start listening UDP port ", address.port);
|
||||
m_SSUServer->Start ();
|
||||
DetectExternalIP ();
|
||||
}
|
||||
else
|
||||
LogPrint ("SSU server already exists");
|
||||
LogPrint (eLogError, "Transports: SSU server already exists");
|
||||
}
|
||||
}
|
||||
m_PeerCleanupTimer.expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||
@@ -176,7 +176,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("Transports: ", ex.what ());
|
||||
LogPrint (eLogError, "Transports: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,8 +200,9 @@ namespace transport
|
||||
|
||||
bool Transports::IsBandwidthExceeded () const
|
||||
{
|
||||
if (i2p::context.GetRouterInfo ().IsHighBandwidth ()) return false;
|
||||
return std::max (m_InBandwidth, m_OutBandwidth) > LOW_BANDWIDTH_LIMIT;
|
||||
if (i2p::context.GetRouterInfo ().IsExtraBandwidth ()) return false;
|
||||
auto bw = std::max (m_InBandwidth, m_OutBandwidth);
|
||||
return bw > (i2p::context.GetRouterInfo ().IsHighBandwidth () ? HIGH_BANDWIDTH_LIMIT : LOW_BANDWIDTH_LIMIT);
|
||||
}
|
||||
|
||||
void Transports::SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
@@ -231,12 +232,12 @@ namespace transport
|
||||
{
|
||||
auto r = netdb.FindRouter (ident);
|
||||
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
|
||||
i2p::util::GetSecondsSinceEpoch () })).first;
|
||||
i2p::util::GetSecondsSinceEpoch (), {} })).first;
|
||||
connected = ConnectToPeer (ident, it->second);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Transports::PostMessages ", ex.what ());
|
||||
LogPrint (eLogError, "Transports: PostMessages exception:", ex.what ());
|
||||
}
|
||||
if (!connected) return;
|
||||
}
|
||||
@@ -278,30 +279,51 @@ namespace transport
|
||||
{
|
||||
if (address->addressString.length () > 0) // trying to resolve
|
||||
{
|
||||
LogPrint (eLogInfo, "Resolving ", address->addressString);
|
||||
LogPrint (eLogDebug, "Transports: Resolving NTCP ", address->addressString);
|
||||
NTCPResolve (address->addressString, ident);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU");
|
||||
}
|
||||
else if (peer.numAttempts == 1)// SSU
|
||||
if (peer.numAttempts == 1)// SSU
|
||||
{
|
||||
peer.numAttempts++;
|
||||
if (m_SSUServer)
|
||||
{
|
||||
if (m_SSUServer->GetSession (peer.router))
|
||||
if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ()))
|
||||
{
|
||||
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
|
||||
#if BOOST_VERSION >= 104900
|
||||
if (!address->host.is_unspecified ()) // we have address now
|
||||
#else
|
||||
boost::system::error_code ecode;
|
||||
address->host.to_string (ecode);
|
||||
if (!ecode)
|
||||
#endif
|
||||
{
|
||||
m_SSUServer->CreateSession (peer.router, address->host, address->port);
|
||||
return true;
|
||||
}
|
||||
else // we don't have address
|
||||
{
|
||||
if (address->addressString.length () > 0) // trying to resolve
|
||||
{
|
||||
LogPrint (eLogDebug, "Transports: Resolving SSU ", address->addressString);
|
||||
SSUResolve (address->addressString, ident);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "No NTCP and SSU addresses available");
|
||||
LogPrint (eLogError, "Transports: No NTCP or SSU addresses available");
|
||||
peer.Done ();
|
||||
m_Peers.erase (ident);
|
||||
return false;
|
||||
}
|
||||
else // otherwise request RI
|
||||
{
|
||||
LogPrint ("Router not found. Requested");
|
||||
LogPrint (eLogInfo, "Transports: RouterInfo for ", ident.ToBase64 (), " not found, requested");
|
||||
i2p::data::netdb.RequestDestination (ident, std::bind (
|
||||
&Transports::RequestComplete, this, std::placeholders::_1, ident));
|
||||
}
|
||||
@@ -313,20 +335,20 @@ namespace transport
|
||||
m_Service.post (std::bind (&Transports::HandleRequestComplete, this, r, ident));
|
||||
}
|
||||
|
||||
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident)
|
||||
void Transports::HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident)
|
||||
{
|
||||
auto it = m_Peers.find (ident);
|
||||
if (it != m_Peers.end ())
|
||||
{
|
||||
if (r)
|
||||
{
|
||||
LogPrint ("Router found. Trying to connect");
|
||||
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, Trying to connect");
|
||||
it->second.router = r;
|
||||
ConnectToPeer (ident, it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("Router not found. Failed to send messages");
|
||||
LogPrint (eLogError, "Transports: RouterInfo not found, Failed to send messages");
|
||||
m_Peers.erase (it);
|
||||
}
|
||||
}
|
||||
@@ -350,7 +372,7 @@ namespace transport
|
||||
if (!ecode && peer.router)
|
||||
{
|
||||
auto address = (*it).endpoint ().address ();
|
||||
LogPrint (eLogInfo, (*it).host_name (), " has been resolved to ", address);
|
||||
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
|
||||
auto addr = peer.router->GetNTCPAddress ();
|
||||
if (addr)
|
||||
{
|
||||
@@ -359,7 +381,38 @@ namespace transport
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Unable to resolve NTCP address: ", ecode.message ());
|
||||
LogPrint (eLogError, "Transports: Unable to resolve NTCP address: ", ecode.message ());
|
||||
m_Peers.erase (it1);
|
||||
}
|
||||
}
|
||||
|
||||
void Transports::SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident)
|
||||
{
|
||||
auto resolver = std::make_shared<boost::asio::ip::tcp::resolver>(m_Service);
|
||||
resolver->async_resolve (boost::asio::ip::tcp::resolver::query (addr, ""),
|
||||
std::bind (&Transports::HandleSSUResolve, this,
|
||||
std::placeholders::_1, std::placeholders::_2, ident, resolver));
|
||||
}
|
||||
|
||||
void Transports::HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver)
|
||||
{
|
||||
auto it1 = m_Peers.find (ident);
|
||||
if (it1 != m_Peers.end ())
|
||||
{
|
||||
auto& peer = it1->second;
|
||||
if (!ecode && peer.router)
|
||||
{
|
||||
auto address = (*it).endpoint ().address ();
|
||||
LogPrint (eLogDebug, "Transports: ", (*it).host_name (), " has been resolved to ", address);
|
||||
auto addr = peer.router->GetSSUAddress (!context.SupportsV6 ());;
|
||||
if (addr)
|
||||
{
|
||||
m_SSUServer->CreateSession (peer.router, address, addr->port);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Transports: Unable to resolve SSU address: ", ecode.message ());
|
||||
m_Peers.erase (it1);
|
||||
}
|
||||
}
|
||||
@@ -376,7 +429,7 @@ namespace transport
|
||||
if (ssuSession) // try SSU first
|
||||
{
|
||||
m_SSUServer->DeleteSession (ssuSession);
|
||||
LogPrint ("SSU session closed");
|
||||
LogPrint (eLogDebug, "Transports: SSU session closed");
|
||||
}
|
||||
// TODO: delete NTCP
|
||||
}
|
||||
@@ -389,19 +442,19 @@ namespace transport
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
|
||||
if (router && router->IsSSU ())
|
||||
m_SSUServer->GetSession (router, true); // peer test
|
||||
if (router && router->IsSSU (!context.SupportsV6 ()))
|
||||
m_SSUServer->CreateSession (router, true); // peer test
|
||||
else
|
||||
{
|
||||
// if not peer test capable routers found pick any
|
||||
router = i2p::data::netdb.GetRandomRouter ();
|
||||
if (router && router->IsSSU ())
|
||||
m_SSUServer->GetSession (router); // no peer test
|
||||
m_SSUServer->CreateSession (router); // no peer test
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't detect external IP. SSU is not available");
|
||||
LogPrint (eLogError, "Transports: Can't detect external IP. SSU is not available");
|
||||
}
|
||||
|
||||
void Transports::PeerTest ()
|
||||
@@ -412,14 +465,14 @@ namespace transport
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
auto router = i2p::data::netdb.GetRandomPeerTestRouter ();
|
||||
if (router && router->IsSSU ())
|
||||
if (router && router->IsSSU (!context.SupportsV6 ()))
|
||||
{
|
||||
if (!statusChanged)
|
||||
{
|
||||
statusChanged = true;
|
||||
i2p::context.SetStatus (eRouterStatusTesting); // first time only
|
||||
}
|
||||
m_SSUServer->GetSession (router, true); // peer test
|
||||
m_SSUServer->CreateSession (router, true); // peer test
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,7 +502,7 @@ namespace transport
|
||||
it->second.delayedMessages.clear ();
|
||||
}
|
||||
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 (), {} }));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -489,7 +542,7 @@ namespace transport
|
||||
{
|
||||
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 (eLogWarning, "Transports: Session to peer ", it->first.ToBase64 (), " has not been created in ", SESSION_CREATION_TIMEOUT, " seconds");
|
||||
it = m_Peers.erase (it);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -67,6 +67,7 @@ namespace transport
|
||||
|
||||
const size_t SESSION_CREATION_TIMEOUT = 10; // in seconds
|
||||
const uint32_t LOW_BANDWIDTH_LIMIT = 32*1024; // 32KBs
|
||||
const uint32_t HIGH_BANDWIDTH_LIMIT = 256*1024; // 256KBs
|
||||
class Transports
|
||||
{
|
||||
public:
|
||||
@@ -105,7 +106,7 @@ namespace transport
|
||||
|
||||
void Run ();
|
||||
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, i2p::data::IdentHash ident);
|
||||
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
||||
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
||||
@@ -114,6 +115,9 @@ namespace transport
|
||||
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
|
||||
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||
void SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident);
|
||||
void HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||
|
||||
void UpdateBandwidth ();
|
||||
void DetectExternalIP ();
|
||||
|
||||
63
Tunnel.cpp
63
Tunnel.cpp
@@ -85,14 +85,14 @@ namespace tunnel
|
||||
|
||||
// send message
|
||||
if (outboundTunnel)
|
||||
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, ToSharedI2NPMessage (msg));
|
||||
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg);
|
||||
else
|
||||
i2p::transport::transports.SendMessage (GetNextIdentHash (), ToSharedI2NPMessage (msg));
|
||||
i2p::transport::transports.SendMessage (GetNextIdentHash (), msg);
|
||||
}
|
||||
|
||||
bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len)
|
||||
{
|
||||
LogPrint ("TunnelBuildResponse ", (int)msg[0], " records.");
|
||||
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
|
||||
|
||||
i2p::crypto::CBCDecryption decryption;
|
||||
TunnelHopConfig * hop = m_Config->GetLastHop ();
|
||||
@@ -111,7 +111,7 @@ namespace tunnel
|
||||
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
|
||||
}
|
||||
else
|
||||
LogPrint ("Tunnel hop index ", idx, " is out of range");
|
||||
LogPrint (eLogWarning, "Tunnel: hop index ", idx, " is out of range");
|
||||
hop1 = hop1->prev;
|
||||
}
|
||||
hop = hop->prev;
|
||||
@@ -123,7 +123,7 @@ namespace tunnel
|
||||
{
|
||||
const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE;
|
||||
uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET];
|
||||
LogPrint ("Ret code=", (int)ret);
|
||||
LogPrint (eLogDebug, "Tunnel: Build response ret code=", (int)ret);
|
||||
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
|
||||
if (profile)
|
||||
profile->TunnelBuildResponse (ret);
|
||||
@@ -163,7 +163,7 @@ namespace tunnel
|
||||
|
||||
void Tunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
LogPrint (eLogInfo, "Can't send I2NP messages without delivery instructions");
|
||||
LogPrint (eLogInfo, "Tunnel: Can't send I2NP messages without delivery instructions");
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > Tunnel::GetPeers () const
|
||||
@@ -181,6 +181,15 @@ namespace tunnel
|
||||
ret.push_back (it->ident);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Tunnel::PrintHops (std::stringstream& s) const
|
||||
{
|
||||
for (auto& it: m_Hops)
|
||||
{
|
||||
s << "-->";
|
||||
s << i2p::data::GetIdentHashAbbreviation (it->ident->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
|
||||
void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
@@ -193,9 +202,8 @@ namespace tunnel
|
||||
|
||||
void InboundTunnel::Print (std::stringstream& s) const
|
||||
{
|
||||
s << "-->" << i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()) << ":" << GetNextTunnelID ();
|
||||
s << "-->" << (GetNumHops () - 1) << " hops ";
|
||||
s << GetTunnelID () << ":me";
|
||||
PrintHops (s);
|
||||
s << "-->" << GetTunnelID () << ":me";
|
||||
}
|
||||
|
||||
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
@@ -235,8 +243,9 @@ namespace tunnel
|
||||
|
||||
void OutboundTunnel::Print (std::stringstream& s) const
|
||||
{
|
||||
s << "me-->" << i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()) << ":" << GetNextTunnelID ();
|
||||
s << "-->" << (GetNumHops () - 1) << " hops-->";
|
||||
s << GetTunnelID () << ":me";
|
||||
PrintHops (s);
|
||||
s << "-->";
|
||||
}
|
||||
|
||||
Tunnels tunnels;
|
||||
@@ -324,9 +333,10 @@ namespace tunnel
|
||||
return tunnel;
|
||||
}
|
||||
|
||||
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
|
||||
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops,
|
||||
int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
|
||||
{
|
||||
auto pool = std::make_shared<TunnelPool> (localDestination, numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
|
||||
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
|
||||
std::unique_lock<std::mutex> l(m_PoolsMutex);
|
||||
m_Pools.push_back (pool);
|
||||
return pool;
|
||||
@@ -432,7 +442,7 @@ namespace tunnel
|
||||
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Unexpected messsage type ", (int)typeID);
|
||||
LogPrint (eLogError, "Tunnel: Unexpected messsage type ", (int)typeID);
|
||||
}
|
||||
|
||||
msg = m_Queue.Get ();
|
||||
@@ -456,7 +466,7 @@ namespace tunnel
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint ("Tunnels: ", ex.what ());
|
||||
LogPrint (eLogError, "Tunnel: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -476,7 +486,7 @@ namespace tunnel
|
||||
auto typeID = msg->GetTypeID ();
|
||||
LogPrint (eLogDebug, "TunnelGateway of ", (int)len, " bytes for tunnel ", tunnel->GetTunnelID (), ". Msg type ", (int)typeID);
|
||||
|
||||
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply)
|
||||
if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
|
||||
// transit DatabaseStore my contain new/updated RI
|
||||
// or DatabaseSearchReply with new routers
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
@@ -511,7 +521,7 @@ namespace tunnel
|
||||
case eTunnelStatePending:
|
||||
if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
|
||||
{
|
||||
LogPrint ("Pending tunnel build request ", it->first, " timeout. Deleted");
|
||||
LogPrint (eLogError, "Tunnel: Pending build request ", it->first, " timeout, deleted");
|
||||
// update stats
|
||||
auto config = tunnel->GetTunnelConfig ();
|
||||
if (config)
|
||||
@@ -536,7 +546,7 @@ namespace tunnel
|
||||
it++;
|
||||
break;
|
||||
case eTunnelStateBuildFailed:
|
||||
LogPrint ("Pending tunnel build request ", it->first, " failed. Deleted");
|
||||
LogPrint (eLogError, "Tunnel: Pending build request ", it->first, " failed, deleted");
|
||||
it = pendingTunnels.erase (it);
|
||||
m_NumFailedTunnelCreations++;
|
||||
break;
|
||||
@@ -561,7 +571,7 @@ namespace tunnel
|
||||
auto tunnel = *it;
|
||||
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired");
|
||||
LogPrint (eLogDebug, "Tunnel: ", tunnel->GetTunnelID (), " expired");
|
||||
auto pool = tunnel->GetTunnelPool ();
|
||||
if (pool)
|
||||
pool->TunnelExpired (tunnel);
|
||||
@@ -592,7 +602,7 @@ namespace tunnel
|
||||
auto inboundTunnel = GetNextInboundTunnel ();
|
||||
auto router = i2p::data::netdb.GetRandomRouter ();
|
||||
if (!inboundTunnel || !router) return;
|
||||
LogPrint ("Creating one hop outbound tunnel...");
|
||||
LogPrint (eLogDebug, "Creating one hop outbound tunnel");
|
||||
CreateTunnel<OutboundTunnel> (
|
||||
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () },
|
||||
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())
|
||||
@@ -609,7 +619,7 @@ namespace tunnel
|
||||
auto tunnel = it->second;
|
||||
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
LogPrint ("Tunnel ", tunnel->GetTunnelID (), " expired");
|
||||
LogPrint (eLogDebug, "Tunnel: ", tunnel->GetTunnelID (), " expired");
|
||||
auto pool = tunnel->GetTunnelPool ();
|
||||
if (pool)
|
||||
pool->TunnelExpired (tunnel);
|
||||
@@ -637,10 +647,13 @@ namespace tunnel
|
||||
|
||||
if (m_InboundTunnels.empty ())
|
||||
{
|
||||
LogPrint ("Creating zero hops inbound tunnel...");
|
||||
LogPrint (eLogDebug, "Creating zero hops inbound tunnel...");
|
||||
CreateZeroHopsInboundTunnel ();
|
||||
if (!m_ExploratoryPool)
|
||||
m_ExploratoryPool = CreateTunnelPool (&i2p::context, 2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
|
||||
{
|
||||
m_ExploratoryPool = CreateTunnelPool (2, 2, 5, 5); // 2-hop exploratory, 5 tunnels
|
||||
m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -648,7 +661,7 @@ namespace tunnel
|
||||
{
|
||||
// trying to create one more inbound tunnel
|
||||
auto router = i2p::data::netdb.GetRandomRouter ();
|
||||
LogPrint ("Creating one hop inbound tunnel...");
|
||||
LogPrint (eLogDebug, "Creating one hop inbound tunnel...");
|
||||
CreateTunnel<InboundTunnel> (
|
||||
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () })
|
||||
);
|
||||
@@ -663,7 +676,7 @@ namespace tunnel
|
||||
if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
auto tmp = it->second;
|
||||
LogPrint ("Transit tunnel ", tmp->GetTunnelID (), " expired");
|
||||
LogPrint (eLogDebug, "Transit tunnel ", tmp->GetTunnelID (), " expired");
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_TransitTunnelsMutex);
|
||||
it = m_TransitTunnels.erase (it);
|
||||
|
||||
10
Tunnel.h
10
Tunnel.h
@@ -62,7 +62,6 @@ namespace tunnel
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
|
||||
TunnelState GetState () const { return m_State; };
|
||||
void SetState (TunnelState state) { m_State = state; };
|
||||
int GetNumHops () const { return m_Hops.size (); }
|
||||
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
|
||||
bool IsFailed () const { return m_State == eTunnelStateFailed; };
|
||||
bool IsRecreated () const { return m_IsRecreated; };
|
||||
@@ -76,7 +75,11 @@ namespace tunnel
|
||||
// implements TunnelBase
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void PrintHops (std::stringstream& s) const;
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<const TunnelConfig> m_Config;
|
||||
@@ -150,7 +153,8 @@ namespace tunnel
|
||||
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<OutboundTunnel> tunnel);
|
||||
std::shared_ptr<TunnelPool> CreateTunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops,
|
||||
int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
|
||||
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace tunnel
|
||||
{
|
||||
RAND_bytes (layerKey, 32);
|
||||
RAND_bytes (ivKey, 32);
|
||||
RAND_bytes (replyKey, 32);
|
||||
RAND_bytes (replyIV, 16);
|
||||
RAND_bytes ((uint8_t *)&tunnelID, 4);
|
||||
isGateway = true;
|
||||
@@ -100,7 +101,7 @@ namespace tunnel
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
|
||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
|
||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
|
||||
// TODO: fill padding
|
||||
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
|
||||
i2p::crypto::ElGamalEncryption elGamalEncryption (ident->GetEncryptionPublicKey ());
|
||||
elGamalEncryption.Encrypt (clearText, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET);
|
||||
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
|
||||
@@ -194,25 +195,6 @@ namespace tunnel
|
||||
}
|
||||
return peers;
|
||||
}
|
||||
|
||||
void Print (std::stringstream& s) const
|
||||
{
|
||||
TunnelHopConfig * hop = m_FirstHop;
|
||||
if (!IsInbound ()) // outbound
|
||||
s << "me";
|
||||
s << "-->" << m_FirstHop->tunnelID;
|
||||
while (hop)
|
||||
{
|
||||
s << ":" << GetIdentHashAbbreviation (hop->ident->GetIdentHash ()) << "-->";
|
||||
if (!hop->isEndpoint)
|
||||
s << hop->nextTunnelID;
|
||||
else
|
||||
return;
|
||||
hop = hop->next;
|
||||
}
|
||||
// we didn't reach enpoint that mean we are last hop
|
||||
s << ":me";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ namespace tunnel
|
||||
if (fragment + size < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||
{
|
||||
// this is not last message. we have to copy it
|
||||
m.data = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
m.data = NewI2NPShortMessage ();
|
||||
m.data->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
|
||||
m.data->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
*(m.data) = *msg;
|
||||
@@ -148,12 +148,12 @@ namespace tunnel
|
||||
if (msg.data->len + size > msg.data->maxLen)
|
||||
{
|
||||
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *(msg.data);
|
||||
msg.data = newMsg;
|
||||
}
|
||||
memcpy (msg.data->buf + msg.data->len, fragment, size); // concatenate fragment
|
||||
msg.data->len += size;
|
||||
if (msg.data->Concat (fragment, size) < size) // concatenate fragment
|
||||
LogPrint (eLogError, "Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
|
||||
if (isLastFragment)
|
||||
{
|
||||
// message complete
|
||||
@@ -204,12 +204,12 @@ namespace tunnel
|
||||
if (msg.data->len + size > msg.data->maxLen)
|
||||
{
|
||||
LogPrint (eLogInfo, "Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
auto newMsg = ToSharedI2NPMessage (NewI2NPMessage ());
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
*newMsg = *(msg.data);
|
||||
msg.data = newMsg;
|
||||
}
|
||||
memcpy (msg.data->buf + msg.data->len, it->second.data->GetBuffer (), size); // concatenate out-of-sync fragment
|
||||
msg.data->len += size;
|
||||
if (msg.data->Concat (it->second.data->GetBuffer (), size) < size) // concatenate out-of-sync fragment
|
||||
LogPrint (eLogError, "Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
|
||||
if (it->second.isLastFragment)
|
||||
{
|
||||
// message complete
|
||||
@@ -225,36 +225,32 @@ namespace tunnel
|
||||
|
||||
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
|
||||
{
|
||||
LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)msg.data->GetTypeID ());
|
||||
auto typeID = msg.data->GetTypeID ();
|
||||
LogPrint (eLogInfo, "TunnelMessage: handle fragment of ", msg.data->GetLength ()," bytes. Msg type ", (int)typeID);
|
||||
switch (msg.deliveryType)
|
||||
{
|
||||
case eDeliveryTypeLocal:
|
||||
i2p::HandleI2NPMessage (msg.data);
|
||||
break;
|
||||
case eDeliveryTypeTunnel:
|
||||
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
||||
break;
|
||||
case eDeliveryTypeRouter:
|
||||
if (msg.hash == i2p::context.GetRouterInfo ().GetIdentHash ()) // check if message is sent to us
|
||||
i2p::HandleI2NPMessage (msg.data);
|
||||
if (!m_IsInbound) // outbound transit tunnel
|
||||
i2p::transport::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data));
|
||||
else
|
||||
{
|
||||
// to somebody else
|
||||
if (!m_IsInbound) // outbound transit tunnel
|
||||
{
|
||||
/* auto typeID = msg.data->GetTypeID ();
|
||||
if (typeID == eI2NPDatabaseStore || typeID == eI2NPDatabaseSearchReply )
|
||||
// catch RI or reply with new list of routers
|
||||
i2p::data::netdb.PostI2NPMsg (msg.data);*/
|
||||
i2p::transport::transports.SendMessage (msg.hash, msg.data);
|
||||
}
|
||||
else // we shouldn't send this message. possible leakage
|
||||
LogPrint (eLogError, "Message to another router arrived from an inbound tunnel. Dropped");
|
||||
}
|
||||
LogPrint (eLogError, "Delivery type tunnel arrived from an inbound tunnel. Dropped");
|
||||
break;
|
||||
case eDeliveryTypeRouter:
|
||||
if (!m_IsInbound) // outbound transit tunnel
|
||||
i2p::transport::transports.SendMessage (msg.hash, msg.data);
|
||||
else // we shouldn't send this message. possible leakage
|
||||
LogPrint (eLogError, "Delivery type router arrived from an inbound tunnel. Dropped");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
||||
};
|
||||
// catch RI or reply with new list of routers
|
||||
if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) &&
|
||||
!m_IsInbound && msg.deliveryType != eDeliveryTypeLocal)
|
||||
i2p::data::netdb.PostI2NPMsg (msg.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace tunnel
|
||||
|
||||
void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage ()
|
||||
{
|
||||
m_CurrentTunnelDataMsg = ToSharedI2NPMessage (NewI2NPShortMessage ());
|
||||
m_CurrentTunnelDataMsg = NewI2NPShortMessage ();
|
||||
m_CurrentTunnelDataMsg->Align (12);
|
||||
// we reserve space for padding
|
||||
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
TunnelPool::TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
||||
m_LocalDestination (localDestination), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
||||
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
||||
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
||||
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true)
|
||||
{
|
||||
}
|
||||
@@ -34,12 +34,12 @@ namespace tunnel
|
||||
if (m_NumInboundHops > size)
|
||||
{
|
||||
m_NumInboundHops = size;
|
||||
LogPrint (eLogInfo, "Inbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
||||
LogPrint (eLogInfo, "Tunnels: 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");
|
||||
LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has beed adjusted to ", size, " for explicit peers");
|
||||
}
|
||||
m_NumInboundTunnels = 1;
|
||||
m_NumOutboundTunnels = 1;
|
||||
@@ -203,7 +203,7 @@ namespace tunnel
|
||||
{
|
||||
for (auto it: m_Tests)
|
||||
{
|
||||
LogPrint ("Tunnel test ", (int)it.first, " failed");
|
||||
LogPrint (eLogWarning, "Tunnels: test of ", (int)it.first, " failed");
|
||||
// if test failed again with another tunnel we consider it failed
|
||||
if (it.second.first)
|
||||
{
|
||||
@@ -266,7 +266,7 @@ namespace tunnel
|
||||
if (m_LocalDestination)
|
||||
m_LocalDestination->ProcessGarlicMessage (msg);
|
||||
else
|
||||
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
|
||||
LogPrint (eLogWarning, "Tunnels: local destination doesn't exist, dropped");
|
||||
}
|
||||
|
||||
void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg)
|
||||
@@ -284,7 +284,7 @@ namespace tunnel
|
||||
it->second.first->SetState (eTunnelStateEstablished);
|
||||
if (it->second.second->GetState () == eTunnelStateTestFailed)
|
||||
it->second.second->SetState (eTunnelStateEstablished);
|
||||
LogPrint ("Tunnel test ", it->first, " successive. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
|
||||
LogPrint (eLogDebug, "Tunnels: test of ", it->first, " successful. ", i2p::util::GetMillisecondsSinceEpoch () - timestamp, " milliseconds");
|
||||
m_Tests.erase (it);
|
||||
}
|
||||
else
|
||||
@@ -292,13 +292,13 @@ namespace tunnel
|
||||
if (m_LocalDestination)
|
||||
m_LocalDestination->ProcessDeliveryStatusMessage (msg);
|
||||
else
|
||||
LogPrint (eLogWarning, "Local destination doesn't exist. Dropped");
|
||||
LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const
|
||||
{
|
||||
bool isExploratory = (m_LocalDestination == &i2p::context); // TODO: implement it better
|
||||
bool isExploratory = (i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this ());
|
||||
auto hop = isExploratory ? i2p::data::netdb.GetRandomRouter (prevHop):
|
||||
i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop);
|
||||
|
||||
@@ -328,7 +328,7 @@ namespace tunnel
|
||||
auto hop = SelectNextHop (prevHop);
|
||||
if (!hop)
|
||||
{
|
||||
LogPrint (eLogError, "Can't select next hop");
|
||||
LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ());
|
||||
return false;
|
||||
}
|
||||
prevHop = hop;
|
||||
@@ -353,7 +353,7 @@ namespace tunnel
|
||||
peers.push_back (r->GetRouterIdentity ());
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ());
|
||||
LogPrint (eLogInfo, "Tunnels: Can't find router for ", ident.ToBase64 ());
|
||||
i2p::data::netdb.RequestDestination (ident);
|
||||
return false;
|
||||
}
|
||||
@@ -366,7 +366,7 @@ namespace tunnel
|
||||
auto outboundTunnel = GetNextOutboundTunnel ();
|
||||
if (!outboundTunnel)
|
||||
outboundTunnel = tunnels.GetNextOutboundTunnel ();
|
||||
LogPrint ("Creating destination inbound tunnel...");
|
||||
LogPrint (eLogDebug, "Tunnels: Creating destination inbound tunnel...");
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
|
||||
if (SelectPeers (peers, true))
|
||||
{
|
||||
@@ -375,7 +375,7 @@ namespace tunnel
|
||||
tunnel->SetTunnelPool (shared_from_this ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't create inbound tunnel. No peers available");
|
||||
LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available");
|
||||
}
|
||||
|
||||
void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel)
|
||||
@@ -383,7 +383,7 @@ namespace tunnel
|
||||
auto outboundTunnel = GetNextOutboundTunnel ();
|
||||
if (!outboundTunnel)
|
||||
outboundTunnel = tunnels.GetNextOutboundTunnel ();
|
||||
LogPrint ("Re-creating destination inbound tunnel...");
|
||||
LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel...");
|
||||
auto newTunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig>(tunnel->GetPeers ()), outboundTunnel);
|
||||
newTunnel->SetTunnelPool (shared_from_this());
|
||||
}
|
||||
@@ -395,7 +395,7 @@ namespace tunnel
|
||||
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
||||
if (inboundTunnel)
|
||||
{
|
||||
LogPrint ("Creating destination outbound tunnel...");
|
||||
LogPrint (eLogDebug, "Tunnels: Creating destination outbound tunnel...");
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
|
||||
if (SelectPeers (peers, false))
|
||||
{
|
||||
@@ -404,10 +404,10 @@ namespace tunnel
|
||||
tunnel->SetTunnelPool (shared_from_this ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't create outbound tunnel. No peers available");
|
||||
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Can't create outbound tunnel. No inbound tunnels found");
|
||||
LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found");
|
||||
}
|
||||
|
||||
void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel)
|
||||
@@ -417,19 +417,19 @@ namespace tunnel
|
||||
inboundTunnel = tunnels.GetNextInboundTunnel ();
|
||||
if (inboundTunnel)
|
||||
{
|
||||
LogPrint ("Re-creating destination outbound tunnel...");
|
||||
LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel...");
|
||||
auto newTunnel = tunnels.CreateTunnel<OutboundTunnel> (
|
||||
std::make_shared<TunnelConfig> (tunnel->GetPeers (),
|
||||
inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()));
|
||||
newTunnel->SetTunnelPool (shared_from_this ());
|
||||
}
|
||||
else
|
||||
LogPrint ("Can't re-create outbound tunnel. No inbound tunnels found");
|
||||
LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found");
|
||||
}
|
||||
|
||||
void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel)
|
||||
{
|
||||
LogPrint (eLogInfo, "Creating paired inbound tunnel...");
|
||||
LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel...");
|
||||
auto tunnel = tunnels.CreateTunnel<InboundTunnel> (std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers ()), outboundTunnel);
|
||||
tunnel->SetTunnelPool (shared_from_this ());
|
||||
}
|
||||
|
||||
@@ -27,11 +27,11 @@ namespace tunnel
|
||||
{
|
||||
public:
|
||||
|
||||
TunnelPool (i2p::garlic::GarlicDestination * localDestination, int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels);
|
||||
~TunnelPool ();
|
||||
|
||||
i2p::garlic::GarlicDestination * GetLocalDestination () const { return m_LocalDestination; };
|
||||
void SetLocalDestination (i2p::garlic::GarlicDestination * destination) { m_LocalDestination = destination; };
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> GetLocalDestination () const { return m_LocalDestination; };
|
||||
void SetLocalDestination (std::shared_ptr<i2p::garlic::GarlicDestination> destination) { m_LocalDestination = destination; };
|
||||
void SetExplicitPeers (std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers);
|
||||
|
||||
void CreateTunnels ();
|
||||
@@ -67,7 +67,7 @@ namespace tunnel
|
||||
|
||||
private:
|
||||
|
||||
i2p::garlic::GarlicDestination * m_LocalDestination;
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> m_LocalDestination;
|
||||
int m_NumInboundHops, m_NumOutboundHops, m_NumInboundTunnels, m_NumOutboundTunnels;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > m_ExplicitPeers;
|
||||
mutable std::mutex m_InboundTunnelsMutex;
|
||||
|
||||
16
UPnP.cpp
16
UPnP.cpp
@@ -46,7 +46,7 @@ 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!");
|
||||
LogPrint(eLogError, "UPnP: Error resolving ", name, " from library, version mismatch?");
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ namespace transport
|
||||
#endif
|
||||
if (m_Module == NULL)
|
||||
{
|
||||
LogPrint ("Error loading UPNP library. This often happens if there is version mismatch!");
|
||||
LogPrint (eLogError, "UPnP: Error loading UPNP library, version mismatch?");
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -144,20 +144,20 @@ namespace transport
|
||||
r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||
if(r != UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LogPrint ("UPnP: UPNP_GetExternalIPAddress () returned ", r);
|
||||
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_externalIPAddress[0])
|
||||
{
|
||||
LogPrint ("UPnP: ExternalIPAddress = ", m_externalIPAddress);
|
||||
LogPrint (eLogInfo, "UPnP: ExternalIPAddress = ", m_externalIPAddress);
|
||||
i2p::context.UpdateAddress (boost::asio::ip::address::from_string (m_externalIPAddress));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("UPnP: GetExternalIPAddress failed.");
|
||||
LogPrint (eLogError, "UPnP: GetExternalIPAddress failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -189,12 +189,12 @@ namespace transport
|
||||
#endif
|
||||
if (r!=UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LogPrint ("AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
|
||||
LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint ("UPnP Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")");
|
||||
LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort.c_str(), " type ", strType.c_str () ," -> ", m_externalIPAddress ,":", strPort.c_str() ,")");
|
||||
return;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::minutes(20)); // c++11
|
||||
@@ -224,7 +224,7 @@ namespace transport
|
||||
}
|
||||
int r = 0;
|
||||
r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
|
||||
LogPrint ("UPNP_DeletePortMapping() returned : ", r, "\n");
|
||||
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n");
|
||||
}
|
||||
|
||||
void UPnP::Close ()
|
||||
|
||||
14
Win32/Itoopie.cmd
Normal file
14
Win32/Itoopie.cmd
Normal file
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
convert Itoopie.svg ^
|
||||
-fuzz 90%% -fill transparent -floodfill 2x2 white -fuzz 20%% -fill #AE0E99 -opaque red ^
|
||||
-fill #FBBC11 -opaque yellow ^
|
||||
( -clone 0 -resize 256x256 ) ^
|
||||
( -clone 0 -resize 128x128 ) ^
|
||||
( -clone 0 -resize 64x64 ) ^
|
||||
( -clone 0 -resize 48x48 ) ^
|
||||
( -clone 0 -resize 32x32 ) ^
|
||||
( -clone 0 -resize 24x24 ) ^
|
||||
( -clone 0 -resize 16x16 ) ^
|
||||
( -size 150x57 xc:white -clone 0 -geometry 57x57+46+0 -composite -gravity center -write BMP3:ictoopie.bmp +delete ) ^
|
||||
( -clone 0 -write Itoopie_purple.png +delete ) ^
|
||||
-delete 0 ictoopie.ico
|
||||
@@ -1,84 +0,0 @@
|
||||
Building i2pd for Windows
|
||||
=========================
|
||||
|
||||
Requirements for building:
|
||||
|
||||
* Visual Studio 2013 (tested with VS2013 Update 1, Update 3, and Update 4)
|
||||
* Boost (tested with 1.56, 1.57, and 1.58)
|
||||
* Crypto++ (tested with 5.6.2)
|
||||
|
||||
|
||||
Building Boost (32-bit)
|
||||
-----------------------
|
||||
|
||||
Open a Visual Studio x86 command prompt and run the following:
|
||||
|
||||
cd C:\path\to\boost\sources
|
||||
bootstrap
|
||||
b2 toolset=msvc-12.0 --build-type=complete --libdir=C:\Boost\lib\Win32 install --with-filesystem --with-program_options --with-regex --with-date_time
|
||||
|
||||
|
||||
Building Boost (64-bit)
|
||||
-----------------------
|
||||
|
||||
Open a Visual Studio x64 command prompt and run the following:
|
||||
|
||||
cd C:\path\to\boost\sources
|
||||
bootstrap
|
||||
b2 toolset=msvc-12.0 --build-type=complete --libdir=C:\Boost\lib\x64 architecture=x86 address-model=64 install --with-filesystem --with-program_options --with-regex --with-date_time
|
||||
|
||||
After Boost is compiled, set the environment variable `BOOST` to the directory
|
||||
Boost was installed to. If you followed the instructions outlined here, you
|
||||
should set it to `C:\Boost`. Additionally, set the BOOSTVER variable to the
|
||||
version of Boost that you're using, but instead of a '.' use a '_'. For
|
||||
example, I have `BOOSTVER` set to `1_58`.
|
||||
|
||||
Building Crypto++
|
||||
-----------------
|
||||
|
||||
* Open the crypttest Solution in VS2013
|
||||
* Visual Studio will ask to update the Solution/Project. Allow it.
|
||||
* Build the `cryptopp` project, both the Debug and Release targets and for both
|
||||
Win32 and x64.
|
||||
* Create a folder called `cryptopp` in the crypto++ source directory, then copy
|
||||
the header files to this new directory.
|
||||
* Set the `CRYPTOPP` environment variable pointing to the Crypto++ source directory.
|
||||
|
||||
|
||||
Building i2pd
|
||||
-------------
|
||||
|
||||
## Prep work ##
|
||||
|
||||
I strongly advise setting up your own `INCLUDES` and `LIBS` instead of relying
|
||||
on the settings in the i2pd project file. By using your own settings, if the
|
||||
i2pd devs change the paths in the project file, your builds will still work.
|
||||
|
||||
To do this, create or edit the file
|
||||
`%localappdata%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.Win32.user`.
|
||||
|
||||
For comparison, my file is reproduced below:
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets">
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<LibraryPath>$(CRYPTOPP)\$(Platform)\Output\$(Configuration);$(BOOST)\lib\$(Platform);$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>$(CRYPTOPP);$(BOOST)\include\boost-$(BOOSTVER);$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup />
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
|
||||
|
||||
If you want to build x64 binaries as well, you'll want to edit or create the
|
||||
file `%localappdata%\Microsoft\MSBuild\v4.0\Microsoft.Cpp.x64.user`. If you
|
||||
followed the steps outlined earlier you can copy (or link) the win32 file to
|
||||
the x64 one.
|
||||
|
||||
## Anti-Climatic End ##
|
||||
|
||||
After following the above instructions, you'll be able to build Debug Win32,
|
||||
Debug x64, Release Win32, and Release x64 i2pd binaries.
|
||||
Binary file not shown.
47
Win32/Resource.rc2
Normal file
47
Win32/Resource.rc2
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Resource.RC2 - resources Microsoft Visual C++ does not edit directly
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#error this file is not editable by Microsoft Visual C++
|
||||
#endif //APSTUDIO_INVOKED
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH
|
||||
PRODUCTVERSION I2P_VERSION_MAJOR,I2P_VERSION_MINOR,I2P_VERSION_MICRO,I2P_VERSION_PATCH
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x1L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Purple I2P"
|
||||
VALUE "FileDescription", "C++ I2P daemon"
|
||||
VALUE "FileVersion", I2PD_VERSION
|
||||
VALUE "InternalName", CODENAME
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2015, The PurpleI2P Project"
|
||||
VALUE "OriginalFilename", "i2pd"
|
||||
VALUE "ProductName", "Purple I2P"
|
||||
VALUE "ProductVersion", I2P_VERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
@@ -76,7 +76,7 @@ I2PService::I2PService(PSTR pszServiceName,
|
||||
BOOL fCanShutdown,
|
||||
BOOL fCanPauseContinue)
|
||||
{
|
||||
m_name = (pszServiceName == NULL) ? "" : pszServiceName;
|
||||
m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
|
||||
|
||||
m_statusHandle = NULL;
|
||||
|
||||
@@ -132,13 +132,13 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint("Win32Service Start", dwError);
|
||||
LogPrint(eLogError, "Win32Service Start", dwError);
|
||||
|
||||
SetServiceStatus(SERVICE_STOPPED, dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint("Win32Service failed to start.", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service failed to start.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
@@ -147,7 +147,7 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
|
||||
|
||||
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
LogPrint("Win32Service in OnStart",
|
||||
LogPrint(eLogInfo, "Win32Service in OnStart",
|
||||
EVENTLOG_INFORMATION_TYPE);
|
||||
|
||||
Daemon.start();
|
||||
@@ -186,13 +186,13 @@ void I2PService::Stop()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint("Win32Service Stop", dwError);
|
||||
LogPrint(eLogInfo, "Win32Service Stop", dwError);
|
||||
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint("Win32Service failed to stop.", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service failed to stop.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
@@ -202,7 +202,7 @@ void I2PService::Stop()
|
||||
void I2PService::OnStop()
|
||||
{
|
||||
// Log a service stop message to the Application log.
|
||||
LogPrint("Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE);
|
||||
LogPrint(eLogInfo, "Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE);
|
||||
|
||||
Daemon.stop();
|
||||
|
||||
@@ -228,13 +228,13 @@ void I2PService::Pause()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint("Win32Service Pause", dwError);
|
||||
LogPrint(eLogError, "Win32Service Pause", dwError);
|
||||
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint("Win32Service failed to pause.", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service failed to pause.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
@@ -258,13 +258,13 @@ void I2PService::Continue()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint("Win32Service Continue", dwError);
|
||||
LogPrint(eLogError, "Win32Service Continue", dwError);
|
||||
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint("Win32Service failed to resume.", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service failed to resume.", EVENTLOG_ERROR_TYPE);
|
||||
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
@@ -286,11 +286,11 @@ void I2PService::Shutdown()
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint("Win32Service Shutdown", dwError);
|
||||
LogPrint(eLogError, "Win32Service Shutdown", dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint("Win32Service failed to shut down.", EVENTLOG_ERROR_TYPE);
|
||||
LogPrint(eLogError, "Win32Service failed to shut down.", EVENTLOG_ERROR_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
Win32/ictoopie.bmp
Normal file
BIN
Win32/ictoopie.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 176 KiB |
BIN
Win32/resource.h
BIN
Win32/resource.h
Binary file not shown.
6
Win32/winres.h
Normal file
6
Win32/winres.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef WINRES_H__
|
||||
#define WINRES_H__
|
||||
|
||||
#include <winresrc.h>
|
||||
|
||||
#endif
|
||||
21
api.cpp
21
api.cpp
@@ -7,6 +7,7 @@
|
||||
#include "RouterContext.h"
|
||||
#include "Identity.h"
|
||||
#include "Destination.h"
|
||||
#include "Crypto.h"
|
||||
#include "util.h"
|
||||
#include "api.h"
|
||||
|
||||
@@ -18,32 +19,38 @@ namespace api
|
||||
{
|
||||
i2p::util::filesystem::SetAppName (appName);
|
||||
i2p::util::config::OptionParser(argc, argv);
|
||||
i2p::crypto::InitCrypto ();
|
||||
i2p::context.Init ();
|
||||
}
|
||||
|
||||
void TerminateI2P ()
|
||||
{
|
||||
i2p::crypto::TerminateCrypto ();
|
||||
}
|
||||
|
||||
void StartI2P (std::ostream * logStream)
|
||||
{
|
||||
if (logStream)
|
||||
StartLog (logStream);
|
||||
else
|
||||
StartLog (i2p::util::filesystem::GetFullPath (i2p::util::filesystem::GetAppName () + ".log"));
|
||||
LogPrint(eLogInfo, "API: starting NetDB");
|
||||
i2p::data::netdb.Start();
|
||||
LogPrint("NetDB started");
|
||||
LogPrint(eLogInfo, "API: starting Transports");
|
||||
i2p::transport::transports.Start();
|
||||
LogPrint("Transports started");
|
||||
LogPrint(eLogInfo, "API: starting Tunnels");
|
||||
i2p::tunnel::tunnels.Start();
|
||||
LogPrint("Tunnels started");
|
||||
}
|
||||
|
||||
void StopI2P ()
|
||||
{
|
||||
LogPrint("Shutdown started.");
|
||||
LogPrint(eLogInfo, "API: shutting down");
|
||||
LogPrint(eLogInfo, "API: stopping Tunnels");
|
||||
i2p::tunnel::tunnels.Stop();
|
||||
LogPrint("Tunnels stopped");
|
||||
LogPrint(eLogInfo, "API: stopping Transports");
|
||||
i2p::transport::transports.Stop();
|
||||
LogPrint("Transports stopped");
|
||||
LogPrint(eLogInfo, "API: stopping NetDB");
|
||||
i2p::data::netdb.Stop();
|
||||
LogPrint("NetDB stopped");
|
||||
StopLog ();
|
||||
}
|
||||
|
||||
|
||||
1
api.h
1
api.h
@@ -13,6 +13,7 @@ namespace api
|
||||
{
|
||||
// initialization start and stop
|
||||
void InitI2P (int argc, char* argv[], const char * appName);
|
||||
void TerminateI2P ();
|
||||
void StartI2P (std::ostream * logStream = nullptr);
|
||||
// write system log to logStream, if not specified to <appName>.log in application's folder
|
||||
void StopI2P ();
|
||||
|
||||
197
appveyor.yml
Normal file
197
appveyor.yml
Normal file
@@ -0,0 +1,197 @@
|
||||
version: 1.0.{build}
|
||||
pull_requests:
|
||||
do_not_increment_build_number: true
|
||||
branches:
|
||||
only:
|
||||
- openssl
|
||||
skip_tags: true
|
||||
os: Visual Studio 2015
|
||||
shallow_clone: true
|
||||
clone_depth: 1
|
||||
init:
|
||||
- cmd: >-
|
||||
mkdir \projects\instdir
|
||||
|
||||
rem Appveyor has win32 openssl pre-installed that is picked up erroneously even for 64-bit. Cleaning the mess... Should happen before restoring cache.
|
||||
|
||||
rem Might consider passing OPENSSL_ROOT_DIR
|
||||
|
||||
if exist \OpenSSL-Win32 rmdir /S /Q \OpenSSL-Win32
|
||||
|
||||
if exist \OpenSSL-Win64 rmdir /S /Q \OpenSSL-Win64
|
||||
|
||||
if exist \OpenSSL rmdir /S /Q \OpenSSL
|
||||
environment:
|
||||
BOOST_ROOT: C:\Libraries\boost_1_59_0
|
||||
MINIUPNPC: miniupnpc-1.9.20151026
|
||||
OPENSSL: OpenSSL_1_0_2e
|
||||
ZLIB: zlib-1.2.8
|
||||
matrix:
|
||||
# - type: static
|
||||
# msvc: 14
|
||||
# x64: 0
|
||||
# - type: static
|
||||
# variant: Release
|
||||
# # FIXME why is this necessary with Appveyor???
|
||||
# cmake: -DSSL_EAY=/mingw32/lib/libssl.a -DLIB_EAY=/mingw32/lib/libcrypto.a
|
||||
- type: shared
|
||||
variant: Release
|
||||
- type: static
|
||||
msvc: 12
|
||||
x64: 1
|
||||
variant: RelWithDebInfo
|
||||
- type: static
|
||||
msvc: 14
|
||||
variant: RelWithDebInfo
|
||||
cmake: -DWITH_PCH=ON
|
||||
# - type: static
|
||||
# msvc: 12
|
||||
# - type: shared
|
||||
# msvc: 14
|
||||
# variant: Debug
|
||||
# - type: shared
|
||||
# variant: Release
|
||||
# cmake: -DWITH_PCH=ON
|
||||
# x64: 1
|
||||
install:
|
||||
- if not exist \projects\miniupnpc\ (
|
||||
mkdir \projects\miniupnpc
|
||||
&& curl -sL http://miniupnp.free.fr/files/download.php?file=%MINIUPNPC%.tar.gz -o \projects\miniupnpc\%MINIUPNPC%.tar.gz
|
||||
)
|
||||
- tar --strip-components=1 --directory=\projects\miniupnpc -xzf \projects\miniupnpc\%MINIUPNPC%.tar.gz
|
||||
- if not exist \projects\zlib\ (
|
||||
mkdir \projects\zlib
|
||||
&& cd \projects\zlib
|
||||
&& curl -sLO http://zlib.net/%ZLIB%.tar.gz
|
||||
)
|
||||
- tar --strip-components=1 --directory=\projects\zlib -xzf \projects\zlib\%ZLIB%.tar.gz
|
||||
- patch -p0 C:/projects/zlib/CMakeLists.txt %APPVEYOR_BUILD_FOLDER%/build/cmake-zlib-static.patch
|
||||
- patch -p0 C:/projects/zlib/CMakeLists.txt %APPVEYOR_BUILD_FOLDER%/build/cmake-zlib-amd64.patch
|
||||
- if "%type%" == "static" (
|
||||
set "static=ON"
|
||||
&& set "boostlib=lib"
|
||||
) else (
|
||||
set "static=OFF"
|
||||
&& set "dll=dll"
|
||||
)
|
||||
- if "%x64%"=="1" (
|
||||
set "bitness=64"
|
||||
&& set "openssl_target=VC-WIN64A"
|
||||
&& set "zlib_asm=-DAMD64=ON"
|
||||
) else (
|
||||
set "bitness=32"
|
||||
&& set "openssl_target=VC-WIN32"
|
||||
&& set "zlib_asm=-DASM686=ON "-DCMAKE_ASM_MASM_FLAGS=/W0 /safeseh""
|
||||
)
|
||||
- C:\msys64\usr\bin\bash -lc "export PATH=/mingw%bitness%/bin:/usr/bin:. && cd /c/projects/miniupnpc && CC=gcc make -f Makefile.mingw init miniupnpc.dll > c:\projects\instdir\build_miniupnpc.log 2>&1 || cat c:\projects\instdir\build_miniupnpc.log"
|
||||
- set /a generator=%msvc%+2001
|
||||
- if defined msvc (
|
||||
(
|
||||
if "%x64%" == "1" (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio %msvc%.0\VC\vcvarsall.bat" amd64
|
||||
&& set "generator=Visual Studio %msvc% %generator% Win64"
|
||||
) else (
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio %msvc%.0\VC\vcvarsall.bat" x86
|
||||
&& set "generator=Visual Studio %msvc% %generator%"
|
||||
)
|
||||
)
|
||||
&& set "zlib_root=C:/stage/zlib-Win%bitness%-vc%msvc%-%type%"
|
||||
&& if "%variant%" neq "Debug" (
|
||||
set "boost_variant=variant=release"
|
||||
&& set "boostdbg=-gd"
|
||||
)
|
||||
) else (
|
||||
set "generator=Unix Makefiles"
|
||||
)
|
||||
- if defined msvc if not exist %zlib_root% (
|
||||
mkdir \projects\zlib-build
|
||||
&& cd \projects\zlib-build
|
||||
&& cmake ../zlib -G "%generator%" %zlib_asm% -DWITH_STATIC=%static% -DCMAKE_INSTALL_PREFIX=%zlib_root% > c:\projects\instdir\build_zlib.log
|
||||
&& cmake --build . --config Release --target INSTALL >> c:\projects\instdir\build_zlib.log
|
||||
|| type c:\projects\instdir\build_zlib.log
|
||||
)
|
||||
- cmd: >-
|
||||
rem cinst nasm
|
||||
|
||||
cd \projects
|
||||
|
||||
if not exist nasm-2.11.08-installer.exe curl --silent --location --remote-name http://www.nasm.us/pub/nasm/releasebuilds/2.11.08/win32/nasm-2.11.08-installer.exe
|
||||
|
||||
nasm-2.11.08-installer.exe /S
|
||||
|
||||
set "PATH=%PATH%;C:\Program Files (x86)\nasm"
|
||||
|
||||
if not exist %OPENSSL%.zip curl --silent --location --remote-name https://github.com/openssl/openssl/archive/%OPENSSL%.zip
|
||||
- cd %BOOST_ROOT%
|
||||
- if defined msvc if not exist "stage%bitness%\lib\%boostlib%boost_system-vc%msvc%0-mt%boostdbg%*" (
|
||||
bootstrap > c:\projects\instdir\build_boost.log
|
||||
&& b2 toolset=msvc-%msvc%.0 %boost_variant% link=%type% runtime-link=%type% address-model=%bitness% --build-type=minimal --with-filesystem --with-program_options --with-regex --with-date_time --stagedir=stage%bitness% >> c:\projects\instdir\build_boost.log
|
||||
|| type c:\projects\instdir\build_boost.log
|
||||
)
|
||||
- if defined msvc if not exist C:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type%\ (
|
||||
cd \projects
|
||||
&& 7z x %OPENSSL%.zip > NUL
|
||||
&& cd openssl-%OPENSSL%
|
||||
&& perl Configure %openssl_target% no-rc2 no-rc4 no-rc5 no-idea no-bf no-cast no-whirlpool no-md2 no-md4 no-ripemd no-mdc2 no-camellia no-seed no-comp no-krb5 no-gmp no-rfc3779 no-ec2m no-ssl2 no-jpake no-srp no-sctp no-srtp --prefix=c:\stage\OpenSSL-Win%bitness%-vc%msvc%-%type% > c:\projects\instdir\build_openssl.log
|
||||
&& ( if "%x64%" == "1" ( ms\do_win64a >> c:\projects\instdir\build_openssl.log ) else ( ms\do_nasm >> c:\projects\instdir\build_openssl.log ) )
|
||||
&& nmake -f ms\nt%dll%.mak install >> c:\projects\instdir\build_openssl.log 2>&1
|
||||
|| type c:\projects\instdir\build_openssl.log
|
||||
)
|
||||
- mklink /J \OpenSSL \stage\OpenSSL-Win%bitness%-vc%msvc%-%type%
|
||||
- rem already there: mingw-w64-i686-openssl mingw-w64-i686-gcc cmake
|
||||
- if not defined msvc (
|
||||
C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy bash pacman pacman-mirrors msys2-runtime msys2-runtime-devel"
|
||||
&& if "%x64%" == "1" (
|
||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
|
||||
) else (
|
||||
C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-boost mingw-w64-i686-miniupnpc"
|
||||
)
|
||||
)
|
||||
cache:
|
||||
- C:\projects\%OPENSSL%.zip
|
||||
- C:\projects\nasm-2.11.08-installer.exe
|
||||
- C:\projects\miniupnpc\%MINIUPNPC%.tar.gz
|
||||
- C:\stage
|
||||
- '%BOOST_ROOT%\stage32'
|
||||
- '%BOOST_ROOT%\stage64'
|
||||
- C:\projects\zlib\%ZLIB%.tar.gz
|
||||
build_script:
|
||||
- cmd: >-
|
||||
mkdir \projects\build
|
||||
|
||||
rem FIXME use fixup_bundle in cmake
|
||||
|
||||
rem msbuild i2pd.sln /p:Configuration=Release
|
||||
|
||||
if defined variant ( set cmake_extra=-DCMAKE_BUILD_TYPE=%variant% && set "cmake_build=--config %variant%" )
|
||||
|
||||
echo "bitness=%bitness%; static=%static%; dll=%dll%; type=%type%; generator=%generator%; variant=%variant%; cmake=%cmake%; cmake_extra=%cmake_extra%"
|
||||
- if not defined msvc (
|
||||
C:\msys64\usr\bin\bash -lc "export PATH=/mingw%bitness%/bin:/usr/bin && cd /c/projects/build && cmake /c/projects/i2pd/build -G 'Unix Makefiles' -DWITH_AESNI=ON -DWITH_UPNP=ON %cmake% %cmake_extra% -DWITH_STATIC=%static% -DWITH_HARDENING=ON -DCMAKE_INSTALL_PREFIX:PATH=/c/projects/instdir -DCMAKE_FIND_ROOT_PATH=/mingw%bitness% && make install"
|
||||
&& 7z a -tzip -mx9 -mmt C:\projects\i2pd\i2pd-mingw-win%bitness%-%type%.zip C:\projects\instdir\* C:\msys64\mingw%bitness%\bin\zlib1.dll C:\msys64\mingw%bitness%\bin\*eay32.dll
|
||||
)
|
||||
- rem We are fine with multiple generated configurations in MS solution. Will use later
|
||||
- if defined msvc (
|
||||
cd \projects\build
|
||||
&& cmake ..\i2pd\build -G "%generator%" -DWITH_UPNP=ON %cmake% -DWITH_STATIC=%static% -DZLIB_ROOT=%zlib_root% -DBoost_LIBRARY_DIR:PATH=%BOOST_ROOT%/stage%bitness%/lib -DCMAKE_INSTALL_PREFIX:PATH=c:/projects/instdir
|
||||
&& cmake --build . %cmake_build% --target install
|
||||
&& 7z a -tzip -mx9 -mmt C:\projects\i2pd\i2pd-vc%msvc%-win%bitness%-%type%.zip C:\projects\instdir\*
|
||||
&& cmake --build . %cmake_build% --target package
|
||||
&& xcopy i2pd*win*.exe ..\i2pd\
|
||||
)
|
||||
test: off
|
||||
artifacts:
|
||||
- path: i2pd-vc12-win64-static.zip
|
||||
- path: i2pd-vc12-win32-static.zip
|
||||
- path: i2pd-vc12-win64-shared.zip
|
||||
- path: i2pd-vc12-win32-shared.zip
|
||||
- path: i2pd-vc14-win64-static.zip
|
||||
- path: i2pd-vc14-win32-static.zip
|
||||
- path: i2pd-vc14-win64-shared.zip
|
||||
- path: i2pd-vc14-win32-shared.zip
|
||||
- path: i2pd-mingw-win64-static.zip
|
||||
- path: i2pd-mingw-win32-static.zip
|
||||
- path: i2pd-mingw-win64-shared.zip
|
||||
- path: i2pd-mingw-win32-shared.zip
|
||||
- path: i2pd-2.1.0-win64.exe
|
||||
- path: i2pd-2.1.0-win32.exe
|
||||
@@ -1,51 +0,0 @@
|
||||
Build notes
|
||||
===========
|
||||
|
||||
Common build/install process:
|
||||
|
||||
* git clone https://github.com/PrivacySolutions/i2pd.git
|
||||
* cd i2pd/build
|
||||
* cmake -DCMAKE_BUILD_TYPE=Release <more options> .
|
||||
* make
|
||||
* make install
|
||||
|
||||
Available cmake options:
|
||||
|
||||
* CMAKE_BUILD_TYPE -- build profile (Debug/Release)
|
||||
* WITH_AESNI -- AES-NI support (ON/OFF)
|
||||
* WITH_HARDENING -- enable hardening features (ON/OFF) (gcc only)
|
||||
|
||||
Debian
|
||||
------
|
||||
|
||||
Required "-dev" packages:
|
||||
* cmake
|
||||
* libboost-filesystem-dev
|
||||
* libboost-program-options-dev
|
||||
* libboost-regex-dev
|
||||
* libboost-system-dev
|
||||
* libboost-date-time-dev
|
||||
* libcrypto++-dev
|
||||
|
||||
FreeBSD
|
||||
-------
|
||||
|
||||
Branch 9.X has gcc v4.2, that knows nothing about required c++11 standart.
|
||||
|
||||
Required ports:
|
||||
|
||||
* devel/cmake
|
||||
* devel/boost-libs
|
||||
* lang/gcc47 # or later version
|
||||
* security/cryptopp
|
||||
|
||||
To use newer compiler you should set these variables:
|
||||
|
||||
export CC=/usr/local/bin/gcc47
|
||||
export CXX=/usr/local/bin/g++47
|
||||
|
||||
Replace "47" with your actual gcc version
|
||||
|
||||
Branch 10.X has more reliable clang version, that can finally build i2pd,
|
||||
but i still recommend to use gcc, otherwise you will fight it's bugs by
|
||||
your own.
|
||||
@@ -1,4 +1,6 @@
|
||||
cmake_minimum_required ( VERSION 2.8.12 )
|
||||
# this addresses CMP0059 with CMake > 3.3 for PCH flags
|
||||
cmake_policy( VERSION 2.8.12 )
|
||||
project ( "i2pd" )
|
||||
|
||||
# configurale options
|
||||
@@ -46,11 +48,19 @@ set (LIBI2PD_SRC
|
||||
"${CMAKE_SOURCE_DIR}/api.cpp"
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
|
||||
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
|
||||
endif ()
|
||||
|
||||
add_library(libi2pd ${LIBI2PD_SRC})
|
||||
set_target_properties(libi2pd PROPERTIES OUTPUT_NAME "i2pd")
|
||||
install(TARGETS libi2pd
|
||||
EXPORT libi2pd
|
||||
ARCHIVE DESTINATION lib
|
||||
COMPONENT Libraries)
|
||||
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
|
||||
# FIXME This pulls stdafx
|
||||
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
set (CLIENT_SRC
|
||||
"${CMAKE_SOURCE_DIR}/AddressBook.cpp"
|
||||
@@ -75,7 +85,7 @@ set (DAEMON_SRC
|
||||
|
||||
if (WITH_UPNP)
|
||||
add_definitions(-DUSE_UPNP)
|
||||
if (NOT MSVC)
|
||||
if (NOT MSVC AND NOT MSYS)
|
||||
set(DL_LIB ${CMAKE_DL_LIBS})
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -88,7 +98,16 @@ endif ()
|
||||
# compiler flags customization (by vendor)
|
||||
if (MSVC)
|
||||
add_definitions( -D_WIN32_WINNT=_WIN32_WINNT_WINXP -DWIN32_LEAN_AND_MEAN -DNOMINMAX ) #-DOPENSSL_NO_SSL2 -DOPENSSL_USE_DEPRECATED
|
||||
# TODO Check & report to Boost dev, there should be no need for these two
|
||||
add_definitions( -DBOOST_THREAD_NO_LIB -DBOOST_CHRONO_NO_LIB )
|
||||
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /INCREMENTAL:NO /LTCG" )
|
||||
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /GL" )
|
||||
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO /LTCG" )
|
||||
else()
|
||||
if (MSYS OR MINGW)
|
||||
add_definitions( -DWIN32_LEAN_AND_MEAN )
|
||||
endif ()
|
||||
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.
|
||||
@@ -102,14 +121,15 @@ include(CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" CXX0X_SUPPORTED)
|
||||
if (CXX11_SUPPORTED)
|
||||
add_definitions( "-std=c++11" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
||||
elseif (CXX0X_SUPPORTED) # gcc 4.6
|
||||
add_definitions( "-std=c++0x" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" )
|
||||
elseif (NOT MSVC)
|
||||
message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?")
|
||||
endif ()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
|
||||
if (WITH_HARDENING)
|
||||
add_definitions( "-D_FORTIFY_SOURCE=2" )
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security -Werror=format-security" )
|
||||
@@ -119,6 +139,11 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# more tweaks
|
||||
endif ()
|
||||
|
||||
if (WITH_HARDENING AND MSVC)
|
||||
# Most security options like dynamic base, buffer & stack checks are ON by default
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /guard:cf" )
|
||||
endif ()
|
||||
|
||||
# compiler flags customization (by system)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
|
||||
@@ -130,13 +155,17 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonLinux.cpp")
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
|
||||
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/DaemonWin32.cpp")
|
||||
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32Service.cpp")
|
||||
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Resource.rc")
|
||||
endif ()
|
||||
|
||||
if (WITH_AESNI)
|
||||
add_definitions ( "-maes -DAESNI" )
|
||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes" )
|
||||
add_definitions ( -DAESNI )
|
||||
endif()
|
||||
|
||||
# libraries
|
||||
@@ -151,9 +180,8 @@ endif()
|
||||
if (WITH_STATIC)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
if (WIN32)
|
||||
if (WIN32 AND NOT MSYS AND NOT MINGW)
|
||||
# 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)
|
||||
@@ -171,43 +199,44 @@ if (WITH_STATIC)
|
||||
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)
|
||||
if (NOT WIN32 AND NOT MSYS)
|
||||
# TODO: Consider separate compilation for LIBI2PD_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)
|
||||
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
||||
endif ()
|
||||
|
||||
if (WITH_PCH)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
include_directories(${CMAKE_BINARY_DIR})
|
||||
add_library(stdafx STATIC "${CMAKE_SOURCE_DIR}/stdafx.cpp")
|
||||
if(MSVC)
|
||||
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm135)
|
||||
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm155)
|
||||
add_custom_command(TARGET stdafx POST_BUILD
|
||||
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb libi2pd.dir\\$<CONFIG>\\
|
||||
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pdclient.dir\\$<CONFIG>\\
|
||||
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pd.dir\\$<CONFIG>\\
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
target_compile_options(libi2pd PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
|
||||
target_compile_options(i2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
|
||||
target_compile_options(libi2pd PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
|
||||
target_compile_options(i2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/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
|
||||
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h -o ${CMAKE_BINARY_DIR}/stdafx.h.gch
|
||||
)
|
||||
target_compile_options(libi2pd PRIVATE -include stdafx.h)
|
||||
target_compile_options(i2pdclient PRIVATE -include stdafx.h)
|
||||
endif()
|
||||
target_link_libraries(libi2pd stdafx)
|
||||
target_link_libraries(i2pdclient stdafx)
|
||||
endif()
|
||||
|
||||
find_package ( Boost COMPONENTS system filesystem regex program_options date_time thread chrono REQUIRED )
|
||||
target_link_libraries(i2pdclient libi2pd)
|
||||
|
||||
find_package ( Boost COMPONENTS system filesystem regex program_options date_time REQUIRED )
|
||||
if(NOT DEFINED Boost_INCLUDE_DIRS)
|
||||
message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!")
|
||||
endif()
|
||||
@@ -227,11 +256,21 @@ endif()
|
||||
find_package ( ZLIB )
|
||||
if (NOT ZLIB_FOUND )
|
||||
# We are probably on Windows
|
||||
find_program( PATCH patch C:/Program Files/Git/usr/bin C:/msys64/usr/bin C:/msys32/usr/bin C:/Strawberry/c/bin )
|
||||
include( ExternalProject )
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
set( ZLIB_EXTRA -DAMD64=ON )
|
||||
else()
|
||||
set( ZLIB_EXTRA -DASM686=ON "-DCMAKE_ASM_MASM_FLAGS=/W0 /safeseh" )
|
||||
endif()
|
||||
ExternalProject_Add(zlib-project
|
||||
URL http://zlib.net/zlib-1.2.8.tar.gz
|
||||
URL_MD5 44d667c142d7cda120332623eab69f40
|
||||
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/zlib
|
||||
PATCH_COMMAND "${PATCH}" -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake-zlib-static.patch
|
||||
&& "${PATCH}" -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake-zlib-amd64.patch
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
|
||||
-DWITH_STATIC=${WITH_STATIC} ${ZLIB_EXTRA}
|
||||
)
|
||||
if (WITH_PCH)
|
||||
add_dependencies( stdafx zlib-project )
|
||||
@@ -240,9 +279,14 @@ if (NOT ZLIB_FOUND )
|
||||
endif ()
|
||||
# ExternalProject_Get_Property(zlib-project install_dir)
|
||||
set ( ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/zlib/include" CACHE FILEPATH "zlib include dir" FORCE)
|
||||
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
|
||||
if (NOT WITH_STATIC)
|
||||
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
|
||||
endif ()
|
||||
endif ()
|
||||
link_directories("${CMAKE_CURRENT_BINARY_DIR}/zlib/lib")
|
||||
if (WITH_STATIC AND (MSVC OR MSYS))
|
||||
set ( ZLIB_LIBRARY debug zlibstaticd optimized zlibstatic CACHE STRING "zlib libraries" FORCE)
|
||||
endif ()
|
||||
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib ${ZLIB_ROOT}/lib)
|
||||
|
||||
# load includes
|
||||
include_directories( ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
|
||||
@@ -277,13 +321,13 @@ if (WITH_BINARY)
|
||||
|
||||
if (WITH_PCH)
|
||||
if (MSVC)
|
||||
target_compile_options("${PROJECT_NAME}" PRIVATE /FIstdafx.h /Yustdafx.h /Zm135 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
|
||||
target_compile_options("${PROJECT_NAME}" PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
|
||||
else()
|
||||
target_compile_options("${PROJECT_NAME}" 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" AND NOT MSYS AND NOT MINGW)
|
||||
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now" )
|
||||
endif ()
|
||||
|
||||
@@ -292,10 +336,125 @@ if (WITH_BINARY)
|
||||
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")
|
||||
list(REMOVE_AT Boost_LIBRARIES -1)
|
||||
endif()
|
||||
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} )
|
||||
|
||||
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} )
|
||||
if (MSYS OR MINGW)
|
||||
set (MINGW_EXTRA -lws2_32 -lmswsock -liphlpapi )
|
||||
endif ()
|
||||
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} )
|
||||
|
||||
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
|
||||
set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
set (DIRS "${Boost_LIBRARY_DIR};${OPENSSL_INCLUDE_DIR}/../bin;${ZLIB_INCLUDE_DIR}/../bin;/mingw32/bin")
|
||||
if (MSVC)
|
||||
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION "bin" CONFIGURATIONS DEBUG)
|
||||
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS DEBUG RELWITHDEBINFO COMPONENT Symbols)
|
||||
# TODO Somehow this picks lots of unrelevant stuff with MSYS. OS X testing needed.
|
||||
INSTALL(CODE "
|
||||
include(BundleUtilities)
|
||||
fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
|
||||
" COMPONENT Runtime)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
install(FILES ../LICENSE
|
||||
DESTINATION .
|
||||
COMPONENT Runtime
|
||||
)
|
||||
# Take a copy on Appveyor
|
||||
install(FILES "C:/projects/openssl-$ENV{OPENSSL}/LICENSE"
|
||||
DESTINATION .
|
||||
COMPONENT Runtime
|
||||
RENAME LICENSE_OPENSSL
|
||||
OPTIONAL # for local builds only!
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE I2PD_SOURCES "../*.cpp" "../build" "../Win32" "../Makefile*")
|
||||
install(FILES ${I2PD_SOURCES} DESTINATION src/ COMPONENT Source)
|
||||
# install(DIRECTORY ../ DESTINATION src/
|
||||
# # OPTIONAL
|
||||
# COMPONENT Source FILES_MATCHING
|
||||
# PATTERN .git EXCLUDE
|
||||
# PATTERN "*.cpp"
|
||||
# )
|
||||
|
||||
file(GLOB I2PD_HEADERS "../*.h")
|
||||
install(FILES ${I2PD_HEADERS} DESTINATION src/ COMPONENT Headers)
|
||||
# install(DIRECTORY ../ DESTINATION src/
|
||||
# # OPTIONAL
|
||||
# COMPONENT Headers FILES_MATCHING
|
||||
# PATTERN .git EXCLUDE
|
||||
# PATTERN "*.h"
|
||||
# )
|
||||
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Purple I2P, a C++ I2P daemon")
|
||||
set(CPACK_PACKAGE_VENDOR "Purple I2P")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../README.md")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE")
|
||||
file(READ ../version.h version_h)
|
||||
string(REGEX REPLACE ".*I2PD_VERSION_MAJOR ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MAJOR "${version_h}")
|
||||
string(REGEX REPLACE ".*I2PD_VERSION_MINOR ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MINOR "${version_h}")
|
||||
string(REGEX REPLACE ".*I2PD_VERSION_MICRO ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MICRO "${version_h}")
|
||||
string(REGEX REPLACE ".*I2PD_VERSION_PATCH ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_PATCH "${version_h}")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Purple I2P")# ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
|
||||
include(CPackComponent)
|
||||
cpack_add_component(Runtime
|
||||
DESCRIPTION "Main files"
|
||||
REQUIRED INSTALL_TYPES minimal)
|
||||
cpack_add_component(Symbols
|
||||
DISPLAY_NAME "Debug symbols"
|
||||
DESCRIPTION "Debug symbols for use with WinDbg or Visual Studio"
|
||||
INSTALL_TYPES recommended full
|
||||
)
|
||||
cpack_add_component(Libraries
|
||||
DESCRIPTION "Binary libraries for development"
|
||||
INSTALL_TYPES full dev3rd
|
||||
)
|
||||
cpack_add_component(Source
|
||||
DISPLAY_NAME "Source code"
|
||||
DESCRIPTION "I2pd source code"
|
||||
INSTALL_TYPES full
|
||||
)
|
||||
cpack_add_component(Headers
|
||||
DISPLAY_NAME "Header files"
|
||||
DESCRIPTION "I2pd header files for development"
|
||||
INSTALL_TYPES full dev3rd
|
||||
)
|
||||
install(FILES ${MINIUPNPC_INCLUDE_DIR}/miniupnpc/miniupnpc.dll
|
||||
DESTINATION bin
|
||||
COMPONENT MiniUPnPc
|
||||
OPTIONAL
|
||||
)
|
||||
install(FILES ${MINIUPNPC_INCLUDE_DIR}/miniupnpc/LICENSE
|
||||
DESTINATION .
|
||||
COMPONENT MiniUPnPc
|
||||
RENAME LICENSE_MINIUPNPC
|
||||
OPTIONAL
|
||||
)
|
||||
cpack_add_component(MiniUPnPc
|
||||
INSTALL_TYPES full recommended
|
||||
# DOWNLOADED
|
||||
# ARCHIVE_FILE miniupnpc-win32.zip
|
||||
)
|
||||
cpack_add_install_type(recommended DISPLAY_NAME Recommended)
|
||||
cpack_add_install_type(dev3rd DISPLAY_NAME "Third party development")
|
||||
cpack_add_install_type(full DISPLAY_NAME Full)
|
||||
cpack_add_install_type(minimal DISPLAY_NAME Minimal)
|
||||
if((WIN32 OR MSYS) AND NOT UNIX)
|
||||
# There is a bug in NSI that does not handle full unix paths properly. Make
|
||||
# sure there is at least one set of four (4) backlasshes.
|
||||
set(CPACK_NSIS_DEFINES "RequestExecutionLevel user")
|
||||
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/../Win32\\\\ictoopie.bmp")
|
||||
set(CPACK_NSIS_INSTALLED_ICON_NAME "bin/i2pd.exe")
|
||||
SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
||||
set(CPACK_NSIS_HELP_LINK "https:\\\\\\\\github.com\\\\PurpleI2P\\\\i2pd\\\\issues")
|
||||
set(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\\\\\github.com\\\\PurpleI2P\\\\i2pd")
|
||||
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Install i2pd as windows service.lnk' '$INSTDIR\\\\bin\\\\i2pd.exe' '--service=install'
|
||||
CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Remove i2pd windows service.lnk' '$INSTDIR\\\\bin\\\\i2pd.exe' '--service=remove'")
|
||||
set(CPACK_NSIS_DELETE_ICONS_EXTRA "Delete '$SMPROGRAMS\\\\$START_MENU\\\\Install i2pd as windows service.lnk'
|
||||
Delete '$SMPROGRAMS\\\\$START_MENU\\\\Remove i2pd windows service.lnk'")
|
||||
else()
|
||||
set(CPACK_STRIP_FILES "bin/i2pd")
|
||||
set(CPACK_SOURCE_STRIP_FILES "")
|
||||
endif()
|
||||
set(CPACK_PACKAGE_EXECUTABLES "i2pd" "C++ I2P daemon")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
include(CPack)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
FROM ubuntu
|
||||
|
||||
RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
|
||||
libboost-program-options-dev libboost-regex-dev libcrypto++-dev \
|
||||
libboost-date-time-dev git build-essential
|
||||
libboost-program-options-dev libboost-regex-dev libboost-date-time-dev \
|
||||
libssl-dev git build-essential
|
||||
|
||||
RUN git clone https://github.com/PurpleI2P/i2pd.git
|
||||
WORKDIR /i2pd
|
||||
RUN make
|
||||
|
||||
CMD ./i2p
|
||||
|
||||
CMD ./i2pd
|
||||
|
||||
10
build/cmake-zlib-amd64.patch
Normal file
10
build/cmake-zlib-amd64.patch
Normal file
@@ -0,0 +1,10 @@
|
||||
--- CMakeLists.txt.orig 2015-12-07 14:19:36.447689600 -0600
|
||||
+++ CMakeLists.txt 2015-12-07 14:18:23.004419900 -0600
|
||||
@@ -165,6 +165,7 @@
|
||||
ENABLE_LANGUAGE(ASM_MASM)
|
||||
set(ZLIB_ASMS
|
||||
contrib/masmx64/gvmat64.asm
|
||||
+ contrib/masmx64/inffas8664.c
|
||||
contrib/masmx64/inffasx64.asm
|
||||
)
|
||||
endif()
|
||||
28
build/cmake-zlib-static.patch
Normal file
28
build/cmake-zlib-static.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
--- CMakeLists.txt.orig 2013-04-28 17:57:10.000000000 -0500
|
||||
+++ CMakeLists.txt 2015-12-03 12:53:52.371087900 -0600
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
option(ASM686 "Enable building i686 assembly implementation")
|
||||
option(AMD64 "Enable building amd64 assembly implementation")
|
||||
+option(WITH_STATIC "Static runtime on Windows" OFF)
|
||||
|
||||
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
|
||||
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
|
||||
@@ -66,6 +67,17 @@
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
+if(WITH_STATIC AND (MSVC OR MSYS))
|
||||
+ # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
|
||||
+ foreach(flag_var
|
||||
+ CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
|
||||
+ CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
|
||||
+ if(${flag_var} MATCHES "/MD")
|
||||
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
+ endif(${flag_var} MATCHES "/MD")
|
||||
+ endforeach(flag_var)
|
||||
+endif()
|
||||
+
|
||||
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
|
||||
# If we're doing an out of source build and the user has a zconf.h
|
||||
# in their source tree...
|
||||
@@ -1,61 +0,0 @@
|
||||
# - Find Crypto++
|
||||
|
||||
if(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
|
||||
set(CRYPTO++_FOUND TRUE)
|
||||
|
||||
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
|
||||
find_path(CRYPTO++_INCLUDE_DIR cryptopp/cryptlib.h
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
$ENV{SystemDrive}/Crypto++/include
|
||||
$ENV{CRYPTOPP}
|
||||
$ENV{CRYPTOPP}/..
|
||||
$ENV{CRYPTOPP}/include
|
||||
${PROJECT_SOURCE_DIR}/../..
|
||||
)
|
||||
|
||||
find_library(CRYPTO++_LIBRARIES NAMES cryptopp
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/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)
|
||||
set(CRYPTO++_FOUND TRUE)
|
||||
message(STATUS "Found Crypto++: ${CRYPTO++_INCLUDE_DIR}, ${CRYPTO++_LIBRARIES}")
|
||||
else(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
|
||||
set(CRYPTO++_FOUND FALSE)
|
||||
message(STATUS "Crypto++ not found.")
|
||||
endif(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
|
||||
|
||||
mark_as_advanced(CRYPTO++_INCLUDE_DIR CRYPTO++_LIBRARIES)
|
||||
|
||||
endif(CRYPTO++_INCLUDE_DIR AND CRYPTO++_LIBRARIES)
|
||||
978
build/cmake_modules/NSIS.template.in
Normal file
978
build/cmake_modules/NSIS.template.in
Normal file
@@ -0,0 +1,978 @@
|
||||
; CPack install script designed for a nmake build
|
||||
|
||||
;--------------------------------
|
||||
; You must define these values
|
||||
|
||||
!define VERSION "@CPACK_PACKAGE_VERSION@"
|
||||
!define PATCH "@CPACK_PACKAGE_VERSION_PATCH@"
|
||||
!define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@"
|
||||
|
||||
;--------------------------------
|
||||
;Variables
|
||||
|
||||
Var MUI_TEMP
|
||||
Var STARTMENU_FOLDER
|
||||
Var SV_ALLUSERS
|
||||
Var START_MENU
|
||||
Var DO_NOT_ADD_TO_PATH
|
||||
Var ADD_TO_PATH_ALL_USERS
|
||||
Var ADD_TO_PATH_CURRENT_USER
|
||||
Var INSTALL_DESKTOP
|
||||
Var IS_DEFAULT_INSTALLDIR
|
||||
;--------------------------------
|
||||
;Include Modern UI
|
||||
|
||||
!include "MUI.nsh"
|
||||
|
||||
;Default installation folder
|
||||
InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
||||
|
||||
;--------------------------------
|
||||
;General
|
||||
|
||||
;Name and file
|
||||
Name "@CPACK_NSIS_PACKAGE_NAME@"
|
||||
OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@"
|
||||
|
||||
;Set compression
|
||||
SetCompressor @CPACK_NSIS_COMPRESSOR@
|
||||
|
||||
;Require administrator access
|
||||
RequestExecutionLevel admin
|
||||
|
||||
@CPACK_NSIS_DEFINES@
|
||||
|
||||
!include Sections.nsh
|
||||
|
||||
;--- Component support macros: ---
|
||||
; The code for the add/remove functionality is from:
|
||||
; http://nsis.sourceforge.net/Add/Remove_Functionality
|
||||
; It has been modified slightly and extended to provide
|
||||
; inter-component dependencies.
|
||||
Var AR_SecFlags
|
||||
Var AR_RegFlags
|
||||
@CPACK_NSIS_SECTION_SELECTED_VARS@
|
||||
|
||||
; Loads the "selected" flag for the section named SecName into the
|
||||
; variable VarName.
|
||||
!macro LoadSectionSelectedIntoVar SecName VarName
|
||||
SectionGetFlags ${${SecName}} $${VarName}
|
||||
IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits
|
||||
!macroend
|
||||
|
||||
; Loads the value of a variable... can we get around this?
|
||||
!macro LoadVar VarName
|
||||
IntOp $R0 0 + $${VarName}
|
||||
!macroend
|
||||
|
||||
; Sets the value of a variable
|
||||
!macro StoreVar VarName IntValue
|
||||
IntOp $${VarName} 0 + ${IntValue}
|
||||
!macroend
|
||||
|
||||
!macro InitSection SecName
|
||||
; This macro reads component installed flag from the registry and
|
||||
;changes checked state of the section on the components page.
|
||||
;Input: section index constant name specified in Section command.
|
||||
|
||||
ClearErrors
|
||||
;Reading component status from registry
|
||||
ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed"
|
||||
IfErrors "default_${SecName}"
|
||||
;Status will stay default if registry value not found
|
||||
;(component was never installed)
|
||||
IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits
|
||||
SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags
|
||||
IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off
|
||||
IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit
|
||||
|
||||
; Note whether this component was installed before
|
||||
!insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags
|
||||
IntOp $R0 $AR_RegFlags & $AR_RegFlags
|
||||
|
||||
;Writing modified flags
|
||||
SectionSetFlags ${${SecName}} $AR_SecFlags
|
||||
|
||||
"default_${SecName}:"
|
||||
!insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
|
||||
!macroend
|
||||
|
||||
!macro FinishSection SecName
|
||||
; This macro reads section flag set by user and removes the section
|
||||
;if it is not selected.
|
||||
;Then it writes component installed flag to registry
|
||||
;Input: section index constant name specified in Section command.
|
||||
|
||||
SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags
|
||||
;Checking lowest bit:
|
||||
IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}
|
||||
IntCmp $AR_SecFlags 1 "leave_${SecName}"
|
||||
;Section is not selected:
|
||||
;Calling Section uninstall macro and writing zero installed flag
|
||||
!insertmacro "Remove_${${SecName}}"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
|
||||
"Installed" 0
|
||||
Goto "exit_${SecName}"
|
||||
|
||||
"leave_${SecName}:"
|
||||
;Section is selected:
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \
|
||||
"Installed" 1
|
||||
|
||||
"exit_${SecName}:"
|
||||
!macroend
|
||||
|
||||
!macro RemoveSection_CPack SecName
|
||||
; This macro is used to call section's Remove_... macro
|
||||
;from the uninstaller.
|
||||
;Input: section index constant name specified in Section command.
|
||||
|
||||
!insertmacro "Remove_${${SecName}}"
|
||||
!macroend
|
||||
|
||||
; Determine whether the selection of SecName changed
|
||||
!macro MaybeSelectionChanged SecName
|
||||
!insertmacro LoadVar ${SecName}_selected
|
||||
SectionGetFlags ${${SecName}} $R1
|
||||
IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits
|
||||
|
||||
; See if the status has changed:
|
||||
IntCmp $R0 $R1 "${SecName}_unchanged"
|
||||
!insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected
|
||||
|
||||
IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected"
|
||||
!insertmacro "Deselect_required_by_${SecName}"
|
||||
goto "${SecName}_unchanged"
|
||||
|
||||
"${SecName}_was_selected:"
|
||||
!insertmacro "Select_${SecName}_depends"
|
||||
|
||||
"${SecName}_unchanged:"
|
||||
!macroend
|
||||
;--- End of Add/Remove macros ---
|
||||
|
||||
;--------------------------------
|
||||
;Interface Settings
|
||||
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
;--------------------------------
|
||||
; path functions
|
||||
|
||||
!verbose 3
|
||||
!include "WinMessages.NSH"
|
||||
!verbose 4
|
||||
|
||||
;----------------------------------------
|
||||
; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02"
|
||||
;----------------------------------------
|
||||
!verbose 3
|
||||
!include "WinMessages.NSH"
|
||||
!verbose 4
|
||||
;====================================================
|
||||
; get_NT_environment
|
||||
; Returns: the selected environment
|
||||
; Output : head of the stack
|
||||
;====================================================
|
||||
!macro select_NT_profile UN
|
||||
Function ${UN}select_NT_profile
|
||||
StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single
|
||||
DetailPrint "Selected environment for all users"
|
||||
Push "all"
|
||||
Return
|
||||
environment_single:
|
||||
DetailPrint "Selected environment for current user only."
|
||||
Push "current"
|
||||
Return
|
||||
FunctionEnd
|
||||
!macroend
|
||||
!insertmacro select_NT_profile ""
|
||||
!insertmacro select_NT_profile "un."
|
||||
;----------------------------------------------------
|
||||
!define NT_current_env 'HKCU "Environment"'
|
||||
!define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
|
||||
!ifndef WriteEnvStr_RegKey
|
||||
!ifdef ALL_USERS
|
||||
!define WriteEnvStr_RegKey \
|
||||
'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
|
||||
!else
|
||||
!define WriteEnvStr_RegKey 'HKCU "Environment"'
|
||||
!endif
|
||||
!endif
|
||||
|
||||
; AddToPath - Adds the given dir to the search path.
|
||||
; Input - head of the stack
|
||||
; Note - Win9x systems requires reboot
|
||||
|
||||
Function AddToPath
|
||||
Exch $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
|
||||
# don't add if the path doesn't exist
|
||||
IfFileExists "$0\*.*" "" AddToPath_done
|
||||
|
||||
ReadEnvStr $1 PATH
|
||||
; if the path is too long for a NSIS variable NSIS will return a 0
|
||||
; length string. If we find that, then warn and skip any path
|
||||
; modification as it will trash the existing path.
|
||||
StrLen $2 $1
|
||||
IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done
|
||||
CheckPathLength_ShowPathWarning:
|
||||
Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!"
|
||||
Goto AddToPath_done
|
||||
CheckPathLength_Done:
|
||||
Push "$1;"
|
||||
Push "$0;"
|
||||
Call StrStr
|
||||
Pop $2
|
||||
StrCmp $2 "" "" AddToPath_done
|
||||
Push "$1;"
|
||||
Push "$0\;"
|
||||
Call StrStr
|
||||
Pop $2
|
||||
StrCmp $2 "" "" AddToPath_done
|
||||
GetFullPathName /SHORT $3 $0
|
||||
Push "$1;"
|
||||
Push "$3;"
|
||||
Call StrStr
|
||||
Pop $2
|
||||
StrCmp $2 "" "" AddToPath_done
|
||||
Push "$1;"
|
||||
Push "$3\;"
|
||||
Call StrStr
|
||||
Pop $2
|
||||
StrCmp $2 "" "" AddToPath_done
|
||||
|
||||
Call IsNT
|
||||
Pop $1
|
||||
StrCmp $1 1 AddToPath_NT
|
||||
; Not on NT
|
||||
StrCpy $1 $WINDIR 2
|
||||
FileOpen $1 "$1\autoexec.bat" a
|
||||
FileSeek $1 -1 END
|
||||
FileReadByte $1 $2
|
||||
IntCmp $2 26 0 +2 +2 # DOS EOF
|
||||
FileSeek $1 -1 END # write over EOF
|
||||
FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n"
|
||||
FileClose $1
|
||||
SetRebootFlag true
|
||||
Goto AddToPath_done
|
||||
|
||||
AddToPath_NT:
|
||||
StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey
|
||||
ReadRegStr $1 ${NT_current_env} "PATH"
|
||||
Goto DoTrim
|
||||
ReadAllKey:
|
||||
ReadRegStr $1 ${NT_all_env} "PATH"
|
||||
DoTrim:
|
||||
StrCmp $1 "" AddToPath_NTdoIt
|
||||
Push $1
|
||||
Call Trim
|
||||
Pop $1
|
||||
StrCpy $0 "$1;$0"
|
||||
AddToPath_NTdoIt:
|
||||
StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey
|
||||
WriteRegExpandStr ${NT_current_env} "PATH" $0
|
||||
Goto DoSend
|
||||
WriteAllKey:
|
||||
WriteRegExpandStr ${NT_all_env} "PATH" $0
|
||||
DoSend:
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
|
||||
AddToPath_done:
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Pop $0
|
||||
FunctionEnd
|
||||
|
||||
|
||||
; RemoveFromPath - Remove a given dir from the path
|
||||
; Input: head of the stack
|
||||
|
||||
Function un.RemoveFromPath
|
||||
Exch $0
|
||||
Push $1
|
||||
Push $2
|
||||
Push $3
|
||||
Push $4
|
||||
Push $5
|
||||
Push $6
|
||||
|
||||
IntFmt $6 "%c" 26 # DOS EOF
|
||||
|
||||
Call un.IsNT
|
||||
Pop $1
|
||||
StrCmp $1 1 unRemoveFromPath_NT
|
||||
; Not on NT
|
||||
StrCpy $1 $WINDIR 2
|
||||
FileOpen $1 "$1\autoexec.bat" r
|
||||
GetTempFileName $4
|
||||
FileOpen $2 $4 w
|
||||
GetFullPathName /SHORT $0 $0
|
||||
StrCpy $0 "SET PATH=%PATH%;$0"
|
||||
Goto unRemoveFromPath_dosLoop
|
||||
|
||||
unRemoveFromPath_dosLoop:
|
||||
FileRead $1 $3
|
||||
StrCpy $5 $3 1 -1 # read last char
|
||||
StrCmp $5 $6 0 +2 # if DOS EOF
|
||||
StrCpy $3 $3 -1 # remove DOS EOF so we can compare
|
||||
StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine
|
||||
StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine
|
||||
StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine
|
||||
StrCmp $3 "" unRemoveFromPath_dosLoopEnd
|
||||
FileWrite $2 $3
|
||||
Goto unRemoveFromPath_dosLoop
|
||||
unRemoveFromPath_dosLoopRemoveLine:
|
||||
SetRebootFlag true
|
||||
Goto unRemoveFromPath_dosLoop
|
||||
|
||||
unRemoveFromPath_dosLoopEnd:
|
||||
FileClose $2
|
||||
FileClose $1
|
||||
StrCpy $1 $WINDIR 2
|
||||
Delete "$1\autoexec.bat"
|
||||
CopyFiles /SILENT $4 "$1\autoexec.bat"
|
||||
Delete $4
|
||||
Goto unRemoveFromPath_done
|
||||
|
||||
unRemoveFromPath_NT:
|
||||
StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey
|
||||
ReadRegStr $1 ${NT_current_env} "PATH"
|
||||
Goto unDoTrim
|
||||
unReadAllKey:
|
||||
ReadRegStr $1 ${NT_all_env} "PATH"
|
||||
unDoTrim:
|
||||
StrCpy $5 $1 1 -1 # copy last char
|
||||
StrCmp $5 ";" +2 # if last char != ;
|
||||
StrCpy $1 "$1;" # append ;
|
||||
Push $1
|
||||
Push "$0;"
|
||||
Call un.StrStr ; Find `$0;` in $1
|
||||
Pop $2 ; pos of our dir
|
||||
StrCmp $2 "" unRemoveFromPath_done
|
||||
; else, it is in path
|
||||
# $0 - path to add
|
||||
# $1 - path var
|
||||
StrLen $3 "$0;"
|
||||
StrLen $4 $2
|
||||
StrCpy $5 $1 -$4 # $5 is now the part before the path to remove
|
||||
StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove
|
||||
StrCpy $3 $5$6
|
||||
|
||||
StrCpy $5 $3 1 -1 # copy last char
|
||||
StrCmp $5 ";" 0 +2 # if last char == ;
|
||||
StrCpy $3 $3 -1 # remove last char
|
||||
|
||||
StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey
|
||||
WriteRegExpandStr ${NT_current_env} "PATH" $3
|
||||
Goto unDoSend
|
||||
unWriteAllKey:
|
||||
WriteRegExpandStr ${NT_all_env} "PATH" $3
|
||||
unDoSend:
|
||||
SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
|
||||
|
||||
unRemoveFromPath_done:
|
||||
Pop $6
|
||||
Pop $5
|
||||
Pop $4
|
||||
Pop $3
|
||||
Pop $2
|
||||
Pop $1
|
||||
Pop $0
|
||||
FunctionEnd
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; Uninstall sutff
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
###########################################
|
||||
# Utility Functions #
|
||||
###########################################
|
||||
|
||||
;====================================================
|
||||
; IsNT - Returns 1 if the current system is NT, 0
|
||||
; otherwise.
|
||||
; Output: head of the stack
|
||||
;====================================================
|
||||
; IsNT
|
||||
; no input
|
||||
; output, top of the stack = 1 if NT or 0 if not
|
||||
;
|
||||
; Usage:
|
||||
; Call IsNT
|
||||
; Pop $R0
|
||||
; ($R0 at this point is 1 or 0)
|
||||
|
||||
!macro IsNT un
|
||||
Function ${un}IsNT
|
||||
Push $0
|
||||
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion
|
||||
StrCmp $0 "" 0 IsNT_yes
|
||||
; we are not NT.
|
||||
Pop $0
|
||||
Push 0
|
||||
Return
|
||||
|
||||
IsNT_yes:
|
||||
; NT!!!
|
||||
Pop $0
|
||||
Push 1
|
||||
FunctionEnd
|
||||
!macroend
|
||||
!insertmacro IsNT ""
|
||||
!insertmacro IsNT "un."
|
||||
|
||||
; StrStr
|
||||
; input, top of stack = string to search for
|
||||
; top of stack-1 = string to search in
|
||||
; output, top of stack (replaces with the portion of the string remaining)
|
||||
; modifies no other variables.
|
||||
;
|
||||
; Usage:
|
||||
; Push "this is a long ass string"
|
||||
; Push "ass"
|
||||
; Call StrStr
|
||||
; Pop $R0
|
||||
; ($R0 at this point is "ass string")
|
||||
|
||||
!macro StrStr un
|
||||
Function ${un}StrStr
|
||||
Exch $R1 ; st=haystack,old$R1, $R1=needle
|
||||
Exch ; st=old$R1,haystack
|
||||
Exch $R2 ; st=old$R1,old$R2, $R2=haystack
|
||||
Push $R3
|
||||
Push $R4
|
||||
Push $R5
|
||||
StrLen $R3 $R1
|
||||
StrCpy $R4 0
|
||||
; $R1=needle
|
||||
; $R2=haystack
|
||||
; $R3=len(needle)
|
||||
; $R4=cnt
|
||||
; $R5=tmp
|
||||
loop:
|
||||
StrCpy $R5 $R2 $R3 $R4
|
||||
StrCmp $R5 $R1 done
|
||||
StrCmp $R5 "" done
|
||||
IntOp $R4 $R4 + 1
|
||||
Goto loop
|
||||
done:
|
||||
StrCpy $R1 $R2 "" $R4
|
||||
Pop $R5
|
||||
Pop $R4
|
||||
Pop $R3
|
||||
Pop $R2
|
||||
Exch $R1
|
||||
FunctionEnd
|
||||
!macroend
|
||||
!insertmacro StrStr ""
|
||||
!insertmacro StrStr "un."
|
||||
|
||||
Function Trim ; Added by Pelaca
|
||||
Exch $R1
|
||||
Push $R2
|
||||
Loop:
|
||||
StrCpy $R2 "$R1" 1 -1
|
||||
StrCmp "$R2" " " RTrim
|
||||
StrCmp "$R2" "$\n" RTrim
|
||||
StrCmp "$R2" "$\r" RTrim
|
||||
StrCmp "$R2" ";" RTrim
|
||||
GoTo Done
|
||||
RTrim:
|
||||
StrCpy $R1 "$R1" -1
|
||||
Goto Loop
|
||||
Done:
|
||||
Pop $R2
|
||||
Exch $R1
|
||||
FunctionEnd
|
||||
|
||||
Function ConditionalAddToRegisty
|
||||
Pop $0
|
||||
Pop $1
|
||||
StrCmp "$0" "" ConditionalAddToRegisty_EmptyString
|
||||
WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \
|
||||
"$1" "$0"
|
||||
;MessageBox MB_OK "Set Registry: '$1' to '$0'"
|
||||
DetailPrint "Set install registry entry: '$1' to '$0'"
|
||||
ConditionalAddToRegisty_EmptyString:
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
|
||||
!ifdef CPACK_USES_DOWNLOAD
|
||||
Function DownloadFile
|
||||
IfFileExists $INSTDIR\* +2
|
||||
CreateDirectory $INSTDIR
|
||||
Pop $0
|
||||
|
||||
; Skip if already downloaded
|
||||
IfFileExists $INSTDIR\$0 0 +2
|
||||
Return
|
||||
|
||||
StrCpy $1 "@CPACK_DOWNLOAD_SITE@"
|
||||
|
||||
try_again:
|
||||
NSISdl::download "$1/$0" "$INSTDIR\$0"
|
||||
|
||||
Pop $1
|
||||
StrCmp $1 "success" success
|
||||
StrCmp $1 "Cancelled" cancel
|
||||
MessageBox MB_OK "Download failed: $1"
|
||||
cancel:
|
||||
Return
|
||||
success:
|
||||
FunctionEnd
|
||||
!endif
|
||||
|
||||
;--------------------------------
|
||||
; Installation types
|
||||
@CPACK_NSIS_INSTALLATION_TYPES@
|
||||
|
||||
;--------------------------------
|
||||
; Component sections
|
||||
@CPACK_NSIS_COMPONENT_SECTIONS@
|
||||
|
||||
;--------------------------------
|
||||
; Define some macro setting for the gui
|
||||
@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@
|
||||
@CPACK_NSIS_INSTALLER_ICON_CODE@
|
||||
@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@
|
||||
@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
|
||||
!insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@"
|
||||
Page custom InstallOptionsPage
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
|
||||
;Start Menu Folder Page Configuration
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
|
||||
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
|
||||
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "Purple I2P"
|
||||
!insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER
|
||||
|
||||
@CPACK_NSIS_PAGE_COMPONENTS@
|
||||
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
;--------------------------------
|
||||
;Languages
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English" ;first language is the default language
|
||||
!insertmacro MUI_LANGUAGE "Albanian"
|
||||
!insertmacro MUI_LANGUAGE "Arabic"
|
||||
!insertmacro MUI_LANGUAGE "Basque"
|
||||
!insertmacro MUI_LANGUAGE "Belarusian"
|
||||
!insertmacro MUI_LANGUAGE "Bosnian"
|
||||
!insertmacro MUI_LANGUAGE "Breton"
|
||||
!insertmacro MUI_LANGUAGE "Bulgarian"
|
||||
!insertmacro MUI_LANGUAGE "Croatian"
|
||||
!insertmacro MUI_LANGUAGE "Czech"
|
||||
!insertmacro MUI_LANGUAGE "Danish"
|
||||
!insertmacro MUI_LANGUAGE "Dutch"
|
||||
!insertmacro MUI_LANGUAGE "Estonian"
|
||||
!insertmacro MUI_LANGUAGE "Farsi"
|
||||
!insertmacro MUI_LANGUAGE "Finnish"
|
||||
!insertmacro MUI_LANGUAGE "French"
|
||||
!insertmacro MUI_LANGUAGE "German"
|
||||
!insertmacro MUI_LANGUAGE "Greek"
|
||||
!insertmacro MUI_LANGUAGE "Hebrew"
|
||||
!insertmacro MUI_LANGUAGE "Hungarian"
|
||||
!insertmacro MUI_LANGUAGE "Icelandic"
|
||||
!insertmacro MUI_LANGUAGE "Indonesian"
|
||||
!insertmacro MUI_LANGUAGE "Irish"
|
||||
!insertmacro MUI_LANGUAGE "Italian"
|
||||
!insertmacro MUI_LANGUAGE "Japanese"
|
||||
!insertmacro MUI_LANGUAGE "Korean"
|
||||
!insertmacro MUI_LANGUAGE "Kurdish"
|
||||
!insertmacro MUI_LANGUAGE "Latvian"
|
||||
!insertmacro MUI_LANGUAGE "Lithuanian"
|
||||
!insertmacro MUI_LANGUAGE "Luxembourgish"
|
||||
!insertmacro MUI_LANGUAGE "Macedonian"
|
||||
!insertmacro MUI_LANGUAGE "Malay"
|
||||
!insertmacro MUI_LANGUAGE "Mongolian"
|
||||
!insertmacro MUI_LANGUAGE "Norwegian"
|
||||
!insertmacro MUI_LANGUAGE "Polish"
|
||||
!insertmacro MUI_LANGUAGE "Portuguese"
|
||||
!insertmacro MUI_LANGUAGE "PortugueseBR"
|
||||
!insertmacro MUI_LANGUAGE "Romanian"
|
||||
!insertmacro MUI_LANGUAGE "Russian"
|
||||
!insertmacro MUI_LANGUAGE "Serbian"
|
||||
!insertmacro MUI_LANGUAGE "SerbianLatin"
|
||||
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||
!insertmacro MUI_LANGUAGE "Slovak"
|
||||
!insertmacro MUI_LANGUAGE "Slovenian"
|
||||
!insertmacro MUI_LANGUAGE "Spanish"
|
||||
!insertmacro MUI_LANGUAGE "Swedish"
|
||||
!insertmacro MUI_LANGUAGE "Thai"
|
||||
!insertmacro MUI_LANGUAGE "TradChinese"
|
||||
!insertmacro MUI_LANGUAGE "Turkish"
|
||||
!insertmacro MUI_LANGUAGE "Ukrainian"
|
||||
!insertmacro MUI_LANGUAGE "Welsh"
|
||||
|
||||
|
||||
;--------------------------------
|
||||
;Reserve Files
|
||||
|
||||
;These files should be inserted before other files in the data block
|
||||
;Keep these lines before any File command
|
||||
;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)
|
||||
|
||||
ReserveFile "NSIS.InstallOptions.ini"
|
||||
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
|
||||
|
||||
;--------------------------------
|
||||
;Installer Sections
|
||||
|
||||
Section "-Core installation"
|
||||
;Use the entire tree produced by the INSTALL target. Keep the
|
||||
;list of directories here in sync with the RMDir commands below.
|
||||
SetOutPath "$INSTDIR"
|
||||
@CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@
|
||||
@CPACK_NSIS_FULL_INSTALL@
|
||||
|
||||
;Store installation folder
|
||||
WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
|
||||
|
||||
;Create uninstaller
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
Push "DisplayName"
|
||||
Push "@CPACK_NSIS_DISPLAY_NAME@"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "DisplayVersion"
|
||||
Push "@CPACK_PACKAGE_VERSION@"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "Publisher"
|
||||
Push "@CPACK_PACKAGE_VENDOR@"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "UninstallString"
|
||||
Push "$INSTDIR\Uninstall.exe"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "NoRepair"
|
||||
Push "1"
|
||||
Call ConditionalAddToRegisty
|
||||
|
||||
!ifdef CPACK_NSIS_ADD_REMOVE
|
||||
;Create add/remove functionality
|
||||
Push "ModifyPath"
|
||||
Push "$INSTDIR\AddRemove.exe"
|
||||
Call ConditionalAddToRegisty
|
||||
!else
|
||||
Push "NoModify"
|
||||
Push "1"
|
||||
Call ConditionalAddToRegisty
|
||||
!endif
|
||||
|
||||
; Optional registration
|
||||
Push "DisplayIcon"
|
||||
Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "HelpLink"
|
||||
Push "@CPACK_NSIS_HELP_LINK@"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "URLInfoAbout"
|
||||
Push "@CPACK_NSIS_URL_INFO_ABOUT@"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "Contact"
|
||||
Push "@CPACK_NSIS_CONTACT@"
|
||||
Call ConditionalAddToRegisty
|
||||
!insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State"
|
||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||
|
||||
;Create shortcuts
|
||||
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
||||
@CPACK_NSIS_CREATE_ICONS@
|
||||
@CPACK_NSIS_CREATE_ICONS_EXTRA@
|
||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
;Read a value from an InstallOptions INI file
|
||||
!insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State"
|
||||
!insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State"
|
||||
!insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State"
|
||||
|
||||
; Write special uninstall registry entries
|
||||
Push "StartMenu"
|
||||
Push "$STARTMENU_FOLDER"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "DoNotAddToPath"
|
||||
Push "$DO_NOT_ADD_TO_PATH"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "AddToPathAllUsers"
|
||||
Push "$ADD_TO_PATH_ALL_USERS"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "AddToPathCurrentUser"
|
||||
Push "$ADD_TO_PATH_CURRENT_USER"
|
||||
Call ConditionalAddToRegisty
|
||||
Push "InstallToDesktop"
|
||||
Push "$INSTALL_DESKTOP"
|
||||
Call ConditionalAddToRegisty
|
||||
|
||||
!insertmacro MUI_STARTMENU_WRITE_END
|
||||
|
||||
@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "-Add to path"
|
||||
Push $INSTDIR\bin
|
||||
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
|
||||
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
|
||||
Call AddToPath
|
||||
doNotAddToPath:
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
; Create custom pages
|
||||
Function InstallOptionsPage
|
||||
!insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@"
|
||||
!insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini"
|
||||
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
; determine admin versus local install
|
||||
Function un.onInit
|
||||
|
||||
ClearErrors
|
||||
UserInfo::GetName
|
||||
IfErrors noLM
|
||||
Pop $0
|
||||
UserInfo::GetAccountType
|
||||
Pop $1
|
||||
StrCmp $1 "Admin" 0 +3
|
||||
SetShellVarContext all
|
||||
;MessageBox MB_OK 'User "$0" is in the Admin group'
|
||||
Goto done
|
||||
StrCmp $1 "Power" 0 +3
|
||||
SetShellVarContext all
|
||||
;MessageBox MB_OK 'User "$0" is in the Power Users group'
|
||||
Goto done
|
||||
|
||||
noLM:
|
||||
;Get installation folder from registry if available
|
||||
|
||||
done:
|
||||
|
||||
FunctionEnd
|
||||
|
||||
;--- Add/Remove callback functions: ---
|
||||
!macro SectionList MacroName
|
||||
;This macro used to perform operation on multiple sections.
|
||||
;List all of your components in following manner here.
|
||||
@CPACK_NSIS_COMPONENT_SECTION_LIST@
|
||||
!macroend
|
||||
|
||||
Section -FinishComponents
|
||||
;Removes unselected components and writes component status to registry
|
||||
!insertmacro SectionList "FinishSection"
|
||||
|
||||
!ifdef CPACK_NSIS_ADD_REMOVE
|
||||
; Get the name of the installer executable
|
||||
System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'
|
||||
StrCpy $R3 $R0
|
||||
|
||||
; Strip off the last 13 characters, to see if we have AddRemove.exe
|
||||
StrLen $R1 $R0
|
||||
IntOp $R1 $R0 - 13
|
||||
StrCpy $R2 $R0 13 $R1
|
||||
StrCmp $R2 "AddRemove.exe" addremove_installed
|
||||
|
||||
; We're not running AddRemove.exe, so install it
|
||||
CopyFiles $R3 $INSTDIR\AddRemove.exe
|
||||
|
||||
addremove_installed:
|
||||
!endif
|
||||
SectionEnd
|
||||
;--- End of Add/Remove callback functions ---
|
||||
|
||||
;--------------------------------
|
||||
; Component dependencies
|
||||
Function .onSelChange
|
||||
!insertmacro SectionList MaybeSelectionChanged
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Uninstaller Section
|
||||
|
||||
Section "Uninstall"
|
||||
ReadRegStr $START_MENU SHCTX \
|
||||
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu"
|
||||
;MessageBox MB_OK "Start menu is in: $START_MENU"
|
||||
ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \
|
||||
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath"
|
||||
ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \
|
||||
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers"
|
||||
ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \
|
||||
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser"
|
||||
;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
|
||||
ReadRegStr $INSTALL_DESKTOP SHCTX \
|
||||
"Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop"
|
||||
;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "
|
||||
|
||||
@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@
|
||||
|
||||
;Remove files we installed.
|
||||
;Keep the list of directories here in sync with the File commands above.
|
||||
@CPACK_NSIS_DELETE_FILES@
|
||||
@CPACK_NSIS_DELETE_DIRECTORIES@
|
||||
|
||||
!ifdef CPACK_NSIS_ADD_REMOVE
|
||||
;Remove the add/remove program
|
||||
Delete "$INSTDIR\AddRemove.exe"
|
||||
!endif
|
||||
|
||||
;Remove the uninstaller itself.
|
||||
Delete "$INSTDIR\Uninstall.exe"
|
||||
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
|
||||
|
||||
;Remove the installation directory if it is empty.
|
||||
RMDir "$INSTDIR"
|
||||
|
||||
; Remove the registry entries.
|
||||
DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
|
||||
|
||||
; Removes all optional components
|
||||
!insertmacro SectionList "RemoveSection_CPack"
|
||||
|
||||
!insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP
|
||||
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
|
||||
@CPACK_NSIS_DELETE_ICONS@
|
||||
@CPACK_NSIS_DELETE_ICONS_EXTRA@
|
||||
|
||||
;Delete empty start menu parent diretories
|
||||
StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
|
||||
|
||||
startMenuDeleteLoop:
|
||||
ClearErrors
|
||||
RMDir $MUI_TEMP
|
||||
GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
|
||||
|
||||
IfErrors startMenuDeleteLoopDone
|
||||
|
||||
StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop
|
||||
startMenuDeleteLoopDone:
|
||||
|
||||
; If the user changed the shortcut, then untinstall may not work. This should
|
||||
; try to fix it.
|
||||
StrCpy $MUI_TEMP "$START_MENU"
|
||||
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
|
||||
@CPACK_NSIS_DELETE_ICONS_EXTRA@
|
||||
|
||||
;Delete empty start menu parent diretories
|
||||
StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP"
|
||||
|
||||
secondStartMenuDeleteLoop:
|
||||
ClearErrors
|
||||
RMDir $MUI_TEMP
|
||||
GetFullPathName $MUI_TEMP "$MUI_TEMP\.."
|
||||
|
||||
IfErrors secondStartMenuDeleteLoopDone
|
||||
|
||||
StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop
|
||||
secondStartMenuDeleteLoopDone:
|
||||
|
||||
DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@"
|
||||
|
||||
Push $INSTDIR\bin
|
||||
StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0
|
||||
Call un.RemoveFromPath
|
||||
doNotRemoveFromPath:
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
; determine admin versus local install
|
||||
; Is install for "AllUsers" or "JustMe"?
|
||||
; Default to "JustMe" - set to "AllUsers" if admin or on Win9x
|
||||
; This function is used for the very first "custom page" of the installer.
|
||||
; This custom page does not show up visibly, but it executes prior to the
|
||||
; first visible page and sets up $INSTDIR properly...
|
||||
; Choose different default installation folder based on SV_ALLUSERS...
|
||||
; "Program Files" for AllUsers, "My Documents" for JustMe...
|
||||
|
||||
Function .onInit
|
||||
StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst
|
||||
|
||||
ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString"
|
||||
StrCmp $0 "" inst
|
||||
|
||||
MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \
|
||||
"@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \
|
||||
IDYES uninst IDNO inst
|
||||
Abort
|
||||
|
||||
;Run the uninstaller
|
||||
uninst:
|
||||
ClearErrors
|
||||
StrLen $2 "\Uninstall.exe"
|
||||
StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path
|
||||
ExecWait '$0 _?=$3' ;Do not copy the uninstaller to a temp file
|
||||
|
||||
IfErrors uninst_failed inst
|
||||
uninst_failed:
|
||||
MessageBox MB_OK|MB_ICONSTOP "Uninstall failed."
|
||||
Abort
|
||||
|
||||
|
||||
inst:
|
||||
; Reads components status for registry
|
||||
!insertmacro SectionList "InitSection"
|
||||
|
||||
; check to see if /D has been used to change
|
||||
; the install directory by comparing it to the
|
||||
; install directory that is expected to be the
|
||||
; default
|
||||
StrCpy $IS_DEFAULT_INSTALLDIR 0
|
||||
StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2
|
||||
StrCpy $IS_DEFAULT_INSTALLDIR 1
|
||||
|
||||
StrCpy $SV_ALLUSERS "JustMe"
|
||||
; if default install dir then change the default
|
||||
; if it is installed for JustMe
|
||||
StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
|
||||
StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
||||
|
||||
ClearErrors
|
||||
UserInfo::GetName
|
||||
IfErrors noLM
|
||||
Pop $0
|
||||
UserInfo::GetAccountType
|
||||
Pop $1
|
||||
StrCmp $1 "Admin" 0 +4
|
||||
SetShellVarContext all
|
||||
;MessageBox MB_OK 'User "$0" is in the Admin group'
|
||||
StrCpy $SV_ALLUSERS "AllUsers"
|
||||
Goto done
|
||||
StrCmp $1 "Power" 0 +4
|
||||
SetShellVarContext all
|
||||
;MessageBox MB_OK 'User "$0" is in the Power Users group'
|
||||
StrCpy $SV_ALLUSERS "AllUsers"
|
||||
Goto done
|
||||
|
||||
noLM:
|
||||
StrCpy $SV_ALLUSERS "AllUsers"
|
||||
;Get installation folder from registry if available
|
||||
|
||||
done:
|
||||
StrCmp $SV_ALLUSERS "AllUsers" 0 +3
|
||||
StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2
|
||||
StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
||||
|
||||
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage
|
||||
!insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini"
|
||||
|
||||
noOptionsPage:
|
||||
FunctionEnd
|
||||
17
debian/changelog
vendored
17
debian/changelog
vendored
@@ -1,11 +1,12 @@
|
||||
i2pd (20140919-2) unstable; urgency=low
|
||||
i2pd (2.2.0-2) unstable; urgency=low
|
||||
|
||||
* updated to latest sources
|
||||
* updated to version 2.2.0
|
||||
|
||||
-- hagen <hagen@i2pmail.org> Wed, 23 Dec 2015 01:29:40 +0000
|
||||
|
||||
i2pd (2.1.0-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.1.0/0.9.23
|
||||
* updated deps
|
||||
|
||||
-- hagen <hagen@i2pmail.org> Fri, 19 Sep 2014 05:16:12 +0000
|
||||
|
||||
i2pd (20140919-1) unstable; urgency=low
|
||||
|
||||
* Initial release (Closes: #nnnn)
|
||||
|
||||
-- hagen <hagen@i2pmail.org> Mon, 19 Sep 2014 00:00:00 +0000
|
||||
|
||||
2
debian/compat
vendored
2
debian/compat
vendored
@@ -1 +1 @@
|
||||
8
|
||||
9
|
||||
|
||||
38
debian/control
vendored
38
debian/control
vendored
@@ -2,21 +2,43 @@ Source: i2pd
|
||||
Section: net
|
||||
Priority: extra
|
||||
Maintainer: hagen <hagen@i2pmail.org>
|
||||
Build-Depends: debhelper (>= 8.0.0), dpkg-dev (>= 1.16.1~),
|
||||
cmake (>= 2.8), gcc (>= 4.6) | clang (>= 3.3),
|
||||
Build-Depends: debhelper (>= 9.0.0), dpkg-dev (>= 1.16.1~),
|
||||
gcc (>= 4.6) | clang (>= 3.3),
|
||||
libboost-regex-dev,
|
||||
libboost-system-dev (>= 1.46),
|
||||
libboost-date-time-dev,
|
||||
libboost-filesystem-dev,
|
||||
libboost-program-options-dev,
|
||||
libcrypto++-dev
|
||||
libssl-dev
|
||||
Standards-Version: 3.9.3
|
||||
Homepage: https://github.com/PrivacySolutions/i2pd
|
||||
Vcs-Git: git://github.com/PrivacySolutions/i2pd.git
|
||||
Vcs-Browser: https://github.com/PrivacySolutions/i2pd.git
|
||||
Homepage: https://github.com/PurpleI2P/i2pd
|
||||
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
|
||||
Vcs-Browser: https://github.com/PurpleI2P/i2pd.git
|
||||
|
||||
Package: i2pd
|
||||
Architecture: any
|
||||
Pre-Depends: adduser
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: i2p router written in C++
|
||||
Mainly runs on linux, but also supports OSX, BSD and Windows
|
||||
Recommends: privoxy
|
||||
Suggests: tor
|
||||
Description: load-balanced unspoofable packet switching network - C++ port
|
||||
I2P is an anonymizing network, offering a simple layer that identity-sensitive
|
||||
applications can use to securely communicate. All data is wrapped with several
|
||||
layers of encryption, and the network is both distributed and dynamic, with no
|
||||
trusted parties.
|
||||
.
|
||||
This package contains the port of the I2P router to C++. Unless willing
|
||||
to test and report problems, you should install the 'i2p' package instead.
|
||||
|
||||
Package: i2pd-dbg
|
||||
Architecture: any
|
||||
Priority: extra
|
||||
Section: debug
|
||||
Depends: i2pd (= ${binary:Version}), ${misc:Depends}
|
||||
Description: i2pd debugging symbols
|
||||
I2P is an anonymizing network, offering a simple layer that identity-sensitive
|
||||
applications can use to securely communicate. All data is wrapped with several
|
||||
layers of encryption, and the network is both distributed and dynamic, with no
|
||||
trusted parties.
|
||||
.
|
||||
This package contains symbols required for debugging.
|
||||
|
||||
59
debian/copyright
vendored
59
debian/copyright
vendored
@@ -3,38 +3,39 @@ Upstream-Name: i2pd
|
||||
Source: https://github.com/PurpleI2P
|
||||
|
||||
Files: *
|
||||
Copyright: 2013-2014 PurpleI2P
|
||||
Copyright: 2013-2015 PurpleI2P
|
||||
License: BSD-3-clause
|
||||
Copyright (c) 2013-2015, The PurpleI2P Project
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Copyright (c) 2013-2015, The PurpleI2P Project
|
||||
.
|
||||
All rights reserved.
|
||||
.
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
.
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
conditions and the following disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
.
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific prior written
|
||||
permission.
|
||||
.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2014 hagen <hagen@i2pmail.org>
|
||||
Copyright: 2014-2015 hagen <hagen@i2pmail.org>
|
||||
2013-2015 Kill Your TV <killyourtv@i2pmail.org>
|
||||
License: GPL-2.0+
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
1
debian/docs
vendored
1
debian/docs
vendored
@@ -1 +1,2 @@
|
||||
README.md
|
||||
docs/configuration.md
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user