mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 00:00:29 +03:00
Merge remote-tracking branch 'purple/openssl' into websocks
This commit is contained in:
commit
43c1a87c48
@ -494,8 +494,9 @@ namespace http {
|
||||
auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
|
||||
if (ntcpServer)
|
||||
{
|
||||
s << "<b>NTCP</b><br>\r\n";
|
||||
for (const auto& it: ntcpServer->GetNTCPSessions ())
|
||||
auto sessions = ntcpServer->GetNTCPSessions ();
|
||||
s << "<b>NTCP</b> ( " << (int) sessions.size() << " )<br>\r\n";
|
||||
for (const auto& it: sessions )
|
||||
{
|
||||
if (it.second && it.second->IsEstablished ())
|
||||
{
|
||||
@ -512,8 +513,9 @@ namespace http {
|
||||
auto ssuServer = i2p::transport::transports.GetSSUServer ();
|
||||
if (ssuServer)
|
||||
{
|
||||
s << "<br>\r\n<b>SSU</b><br>\r\n";
|
||||
for (const auto& it: ssuServer->GetSessions ())
|
||||
auto sessions = ssuServer->GetSessions ();
|
||||
s << "<br>\r\n<b>SSU</b> ( " << (int) sessions.size() << " )<br>\r\n";
|
||||
for (const auto& it: sessions)
|
||||
{
|
||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
||||
@ -713,20 +715,22 @@ namespace http {
|
||||
}
|
||||
/* method #2: 'Authorization' header sent */
|
||||
if (req.headers.count("Authorization") > 0) {
|
||||
bool result = false;
|
||||
std::string provided = req.headers.find("Authorization")->second;
|
||||
std::string expected = user + ":" + pass;
|
||||
char b64_creds[64];
|
||||
size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1;
|
||||
char * b64_creds = new char[b64_sz];
|
||||
std::size_t len = 0;
|
||||
len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds));
|
||||
len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, b64_sz);
|
||||
/* if we decoded properly then check credentials */
|
||||
if(len) {
|
||||
b64_creds[len] = '\0';
|
||||
expected = "Basic ";
|
||||
expected += b64_creds;
|
||||
return expected == provided;
|
||||
result = expected == provided;
|
||||
}
|
||||
/** we decoded wrong so it's not a correct login credential */
|
||||
return false;
|
||||
delete [] b64_creds;
|
||||
return result;
|
||||
}
|
||||
|
||||
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ());
|
||||
|
163
I2PControl.cpp
163
I2PControl.cpp
@ -2,6 +2,8 @@
|
||||
#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>
|
||||
|
||||
@ -14,7 +16,6 @@
|
||||
#include "Crypto.h"
|
||||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "HTTP.h"
|
||||
#include "Config.h"
|
||||
#include "NetDb.h"
|
||||
#include "RouterContext.h"
|
||||
@ -189,64 +190,71 @@ namespace client
|
||||
if (ecode) {
|
||||
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
|
||||
return;
|
||||
}
|
||||
/* try to parse received data */
|
||||
std::stringstream json;
|
||||
std::string response;
|
||||
bool isHTTP = false;
|
||||
if (memcmp (buf->data (), "POST", 4) == 0) {
|
||||
long int remains = 0;
|
||||
isHTTP = true;
|
||||
i2p::http::HTTPReq req;
|
||||
std::size_t len = req.parse(buf->data(), bytes_transferred);
|
||||
if (len <= 0) {
|
||||
LogPrint(eLogError, "I2PControl: incomplete/malformed POST request");
|
||||
return;
|
||||
}
|
||||
/* append to json chunk of data from 1st request */
|
||||
json.write(buf->data() + len, bytes_transferred - len);
|
||||
remains = req.content_length() - len;
|
||||
/* if request has Content-Length header, fetch rest of data and store to json buffer */
|
||||
while (remains > 0) {
|
||||
len = ((long int) buf->size() < remains) ? buf->size() : remains;
|
||||
bytes_transferred = boost::asio::read (*socket, boost::asio::buffer (buf->data (), len));
|
||||
json.write(buf->data(), bytes_transferred);
|
||||
remains -= bytes_transferred;
|
||||
}
|
||||
} else {
|
||||
json.write(buf->data(), bytes_transferred);
|
||||
}
|
||||
LogPrint(eLogDebug, "I2PControl: json from request: ", json.str());
|
||||
try
|
||||
{
|
||||
bool isHtml = !memcmp (buf->data (), "POST", 4);
|
||||
std::stringstream ss;
|
||||
ss.write (buf->data (), bytes_transferred);
|
||||
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, "I2PControl: malformed 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);
|
||||
}
|
||||
}
|
||||
std::ostringstream response;
|
||||
#if GCC47_BOOST149
|
||||
LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7");
|
||||
BuildErrorResponse(response, 32603, "JSON requests is not supported with this version of boost");
|
||||
LogPrint (eLogError, "I2PControl: json_read is not supported due bug in boost 1.49 with gcc 4.7");
|
||||
response << "{\"id\":null,\"error\":";
|
||||
response << "{\"code\":-32603,\"message\":\"JSON requests is not supported with this version of boost\"},";
|
||||
response << "\"jsonrpc\":\"2.0\"}";
|
||||
#else
|
||||
/* now try to parse json itself */
|
||||
try {
|
||||
boost::property_tree::ptree pt;
|
||||
boost::property_tree::read_json (json, pt);
|
||||
boost::property_tree::ptree pt;
|
||||
boost::property_tree::read_json (ss, pt);
|
||||
|
||||
std::string id = pt.get<std::string>("id");
|
||||
std::string method = pt.get<std::string>("method");
|
||||
auto it = m_MethodHandlers.find (method);
|
||||
if (it != m_MethodHandlers.end ()) {
|
||||
std::ostringstream ss;
|
||||
ss << "{\"id\":" << id << ",\"result\":{";
|
||||
(this->*(it->second))(pt.get_child ("params"), ss);
|
||||
ss << "},\"jsonrpc\":\"2.0\"}";
|
||||
response = ss.str();
|
||||
} else {
|
||||
LogPrint (eLogWarning, "I2PControl: unknown method ", method);
|
||||
BuildErrorResponse(response, 32601, "Method not found");
|
||||
}
|
||||
} catch (std::exception& ex) {
|
||||
LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ());
|
||||
BuildErrorResponse(response, 32603, ex.what());
|
||||
} catch (...) {
|
||||
LogPrint (eLogError, "I2PControl: handle request unknown exception");
|
||||
}
|
||||
std::string id = pt.get<std::string>("id");
|
||||
std::string method = pt.get<std::string>("method");
|
||||
auto it = m_MethodHandlers.find (method);
|
||||
if (it != m_MethodHandlers.end ())
|
||||
{
|
||||
response << "{\"id\":" << id << ",\"result\":{";
|
||||
(this->*(it->second))(pt.get_child ("params"), response);
|
||||
response << "},\"jsonrpc\":\"2.0\"}";
|
||||
} else {
|
||||
LogPrint (eLogWarning, "I2PControl: unknown method ", method);
|
||||
response << "{\"id\":null,\"error\":";
|
||||
response << "{\"code\":-32601,\"message\":\"Method not found\"},";
|
||||
response << "\"jsonrpc\":\"2.0\"}";
|
||||
}
|
||||
#endif
|
||||
SendResponse (socket, buf, response, isHTTP);
|
||||
SendResponse (socket, buf, response, isHtml);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: handle request unknown exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, int value) const
|
||||
@ -268,28 +276,27 @@ namespace client
|
||||
ss << "\"" << name << "\":" << std::fixed << std::setprecision(2) << value;
|
||||
}
|
||||
|
||||
void I2PControlService::BuildErrorResponse (std::string & content, int code, const char *message) {
|
||||
std::stringstream ss;
|
||||
ss << "{\"id\":null,\"error\":";
|
||||
ss << "{\"code\":" << -code << ",\"message\":\"" << message << "\"},";
|
||||
ss << "\"jsonrpc\":\"2.0\"}";
|
||||
content = ss.str();
|
||||
}
|
||||
|
||||
void I2PControlService::SendResponse (std::shared_ptr<ssl_socket> socket,
|
||||
std::shared_ptr<I2PControlBuffer> buf, std::string& content, bool isHTTP)
|
||||
std::shared_ptr<I2PControlBuffer> buf, std::ostringstream& response, bool isHtml)
|
||||
{
|
||||
if (isHTTP) {
|
||||
i2p::http::HTTPRes res;
|
||||
res.code = 200;
|
||||
res.add_header("Content-Type", "application/json");
|
||||
res.add_header("Connection", "close");
|
||||
res.body = content;
|
||||
std::string tmp = res.to_string();
|
||||
content = tmp;
|
||||
size_t len = response.str ().length (), offset = 0;
|
||||
if (isHtml)
|
||||
{
|
||||
std::ostringstream header;
|
||||
header << "HTTP/1.1 200 OK\r\n";
|
||||
header << "Connection: close\r\n";
|
||||
header << "Content-Length: " << boost::lexical_cast<std::string>(len) << "\r\n";
|
||||
header << "Content-Type: application/json\r\n";
|
||||
header << "Date: ";
|
||||
auto facet = new boost::local_time::local_time_facet ("%a, %d %b %Y %H:%M:%S GMT");
|
||||
header.imbue(std::locale (header.getloc(), facet));
|
||||
header << boost::posix_time::second_clock::local_time() << "\r\n";
|
||||
header << "\r\n";
|
||||
offset = header.str ().size ();
|
||||
memcpy (buf->data (), header.str ().c_str (), offset);
|
||||
}
|
||||
std::copy(content.begin(), content.end(), buf->begin());
|
||||
boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), content.length()),
|
||||
memcpy (buf->data () + offset, response.str ().c_str (), len);
|
||||
boost::asio::async_write (*socket, boost::asio::buffer (buf->data (), offset + len),
|
||||
boost::asio::transfer_all (),
|
||||
std::bind(&I2PControlService::HandleResponseSent, this,
|
||||
std::placeholders::_1, std::placeholders::_2, socket, buf));
|
||||
@ -316,7 +323,7 @@ namespace client
|
||||
}
|
||||
InsertParam (results, "API", api);
|
||||
results << ",";
|
||||
std::string token = std::to_string(i2p::util::GetSecondsSinceEpoch ());
|
||||
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
|
||||
m_Tokens.insert (token);
|
||||
InsertParam (results, "Token", token);
|
||||
}
|
||||
@ -358,7 +365,7 @@ namespace client
|
||||
|
||||
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
for (auto it = params.begin (); it != params.end (); ++it)
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
{
|
||||
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
|
||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||
@ -434,7 +441,7 @@ namespace client
|
||||
|
||||
void I2PControlService::RouterManagerHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
for (auto it = params.begin (); it != params.end (); ++it)
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
{
|
||||
if (it != params.begin ()) results << ",";
|
||||
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
|
||||
@ -483,7 +490,7 @@ namespace client
|
||||
// network setting
|
||||
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
for (auto it = params.begin (); it != params.end (); ++it)
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
{
|
||||
if (it != params.begin ()) results << ",";
|
||||
LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
|
||||
@ -529,7 +536,7 @@ namespace client
|
||||
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, "C", MBSTRING_ASC, (unsigned char *)"A1", -1, -1, 0); // country (Anonymous proxy)
|
||||
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
|
||||
|
@ -45,9 +45,8 @@ namespace client
|
||||
void ReadRequest (std::shared_ptr<ssl_socket> socket);
|
||||
void HandleRequestReceived (const boost::system::error_code& ecode, size_t bytes_transferred,
|
||||
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||
void BuildErrorResponse (std::string & content, int code, const char *message);
|
||||
void SendResponse (std::shared_ptr<ssl_socket> socket,
|
||||
std::shared_ptr<I2PControlBuffer> buf, std::string& response, bool isHtml);
|
||||
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<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf);
|
||||
|
||||
@ -120,4 +119,3 @@ namespace client
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -493,7 +493,8 @@ namespace transport
|
||||
|
||||
void NTCPSession::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||
{
|
||||
if (ecode) {
|
||||
if (ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogDebug, "NTCP: Read error: ", ecode.message ());
|
||||
//if (ecode != boost::asio::error::operation_aborted)
|
||||
@ -507,48 +508,66 @@ namespace transport
|
||||
|
||||
if (m_ReceiveBufferOffset >= 16)
|
||||
{
|
||||
int numReloads = 0;
|
||||
do
|
||||
{
|
||||
uint8_t * nextBlock = m_ReceiveBuffer;
|
||||
while (m_ReceiveBufferOffset >= 16)
|
||||
// process received data
|
||||
uint8_t * nextBlock = m_ReceiveBuffer;
|
||||
while (m_ReceiveBufferOffset >= 16)
|
||||
{
|
||||
if (!DecryptNextBlock (nextBlock)) // 16 bytes
|
||||
{
|
||||
if (!DecryptNextBlock (nextBlock)) // 16 bytes
|
||||
{
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
nextBlock += 16;
|
||||
m_ReceiveBufferOffset -= 16;
|
||||
}
|
||||
if (m_ReceiveBufferOffset > 0)
|
||||
memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset);
|
||||
|
||||
// try to read more
|
||||
if (numReloads < 5)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = m_Socket.available(ec);
|
||||
if (moreBytes && !ec)
|
||||
{
|
||||
if (moreBytes > NTCP_BUFFER_SIZE - m_ReceiveBufferOffset)
|
||||
moreBytes = NTCP_BUFFER_SIZE - m_ReceiveBufferOffset;
|
||||
moreBytes = m_Socket.read_some (boost::asio::buffer (m_ReceiveBuffer + m_ReceiveBufferOffset, moreBytes), ec);
|
||||
if (ec)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ());
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
m_NumReceivedBytes += moreBytes;
|
||||
m_ReceiveBufferOffset += moreBytes;
|
||||
numReloads++;
|
||||
}
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
nextBlock += 16;
|
||||
m_ReceiveBufferOffset -= 16;
|
||||
}
|
||||
while (m_ReceiveBufferOffset >= 16);
|
||||
m_Handler.Flush ();
|
||||
}
|
||||
if (m_ReceiveBufferOffset > 0)
|
||||
memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset);
|
||||
}
|
||||
|
||||
// read and process more is available
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = m_Socket.available(ec);
|
||||
if (moreBytes && !ec)
|
||||
{
|
||||
uint8_t * buf = nullptr, * moreBuf = m_ReceiveBuffer;
|
||||
if (moreBytes + m_ReceiveBufferOffset > NTCP_BUFFER_SIZE)
|
||||
{
|
||||
buf = new uint8_t[moreBytes + m_ReceiveBufferOffset + 16];
|
||||
moreBuf = buf;
|
||||
uint8_t rem = ((size_t)buf) & 0x0f;
|
||||
if (rem) moreBuf += (16 - rem); // align 16
|
||||
if (m_ReceiveBufferOffset)
|
||||
memcpy (moreBuf, m_ReceiveBuffer, m_ReceiveBufferOffset);
|
||||
}
|
||||
moreBytes = m_Socket.read_some (boost::asio::buffer (moreBuf + m_ReceiveBufferOffset, moreBytes), ec);
|
||||
if (ec)
|
||||
{
|
||||
LogPrint (eLogInfo, "NTCP: Read more bytes error: ", ec.message ());
|
||||
delete[] buf;
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
m_ReceiveBufferOffset += moreBytes;
|
||||
m_NumReceivedBytes += moreBytes;
|
||||
i2p::transport::transports.UpdateReceivedBytes (moreBytes);
|
||||
// process more data
|
||||
uint8_t * nextBlock = moreBuf;
|
||||
while (m_ReceiveBufferOffset >= 16)
|
||||
{
|
||||
if (!DecryptNextBlock (nextBlock)) // 16 bytes
|
||||
{
|
||||
delete[] buf;
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
nextBlock += 16;
|
||||
m_ReceiveBufferOffset -= 16;
|
||||
}
|
||||
if (m_ReceiveBufferOffset > 0)
|
||||
memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); // nextBlock points to memory inside buf
|
||||
delete[] buf;
|
||||
}
|
||||
m_Handler.Flush ();
|
||||
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
Receive ();
|
||||
|
@ -35,12 +35,11 @@ namespace transport
|
||||
};
|
||||
|
||||
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
|
||||
const size_t NTCP_BUFFER_SIZE = 4160; // fits 4 tunnel messages (4*1028)
|
||||
const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message
|
||||
const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int NTCP_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||
const int NTCP_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
const size_t NTCP_DEFAULT_PHASE3_SIZE = 2/*size*/ + i2p::data::DEFAULT_IDENTITY_SIZE/*387*/ + 4/*ts*/ + 15/*padding*/ + 40/*signature*/; // 448
|
||||
const int NTCP_BAN_EXPIRATION_TIMEOUT = 70; // in second
|
||||
const int NTCP_CLOCK_SKEW = 60; // in seconds
|
||||
const int NTCP_MAX_OUTGOING_QUEUE_SIZE = 200; // how many messages we can queue up
|
||||
|
||||
|
@ -266,8 +266,9 @@ namespace i2p
|
||||
}
|
||||
}
|
||||
// delete previous introducers
|
||||
for (auto& addr : addresses)
|
||||
addr->introducers.clear ();
|
||||
for (auto& addr : addresses)
|
||||
if (addr->ssu)
|
||||
addr->ssu->introducers.clear ();
|
||||
|
||||
// update
|
||||
UpdateRouterInfo ();
|
||||
@ -298,7 +299,8 @@ namespace i2p
|
||||
}
|
||||
// delete previous introducers
|
||||
for (auto& addr : addresses)
|
||||
addr->introducers.clear ();
|
||||
if (addr->ssu)
|
||||
addr->ssu->introducers.clear ();
|
||||
|
||||
// update
|
||||
UpdateRouterInfo ();
|
||||
|
@ -175,11 +175,14 @@ namespace data
|
||||
if (!strcmp (transportStyle, "NTCP"))
|
||||
address->transportStyle = eTransportNTCP;
|
||||
else if (!strcmp (transportStyle, "SSU"))
|
||||
{
|
||||
address->transportStyle = eTransportSSU;
|
||||
address->ssu.reset (new SSUExt ());
|
||||
address->ssu->mtu = 0;
|
||||
}
|
||||
else
|
||||
address->transportStyle = eTransportUnknown;
|
||||
address->port = 0;
|
||||
address->mtu = 0;
|
||||
uint16_t size, r = 0;
|
||||
s.read ((char *)&size, sizeof (size)); if (!s) return;
|
||||
size = be16toh (size);
|
||||
@ -220,9 +223,19 @@ namespace data
|
||||
else if (!strcmp (key, "port"))
|
||||
address->port = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "mtu"))
|
||||
address->mtu = boost::lexical_cast<int>(value);
|
||||
{
|
||||
if (address->ssu)
|
||||
address->ssu->mtu = boost::lexical_cast<int>(value);
|
||||
else
|
||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
|
||||
}
|
||||
else if (!strcmp (key, "key"))
|
||||
Base64ToByteStream (value, strlen (value), address->key, 32);
|
||||
{
|
||||
if (address->ssu)
|
||||
Base64ToByteStream (value, strlen (value), address->ssu->key, 32);
|
||||
else
|
||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
|
||||
}
|
||||
else if (!strcmp (key, "caps"))
|
||||
ExtractCaps (value);
|
||||
else if (key[0] == 'i')
|
||||
@ -237,9 +250,9 @@ namespace data
|
||||
LogPrint (eLogError, "RouterInfo: Unexpected introducer's index ", index, " skipped");
|
||||
if (s) continue; else return;
|
||||
}
|
||||
if (index >= address->introducers.size ())
|
||||
address->introducers.resize (index + 1);
|
||||
Introducer& introducer = address->introducers.at (index);
|
||||
if (index >= address->ssu->introducers.size ())
|
||||
address->ssu->introducers.resize (index + 1);
|
||||
Introducer& introducer = address->ssu->introducers.at (index);
|
||||
if (!strcmp (key, "ihost"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
@ -417,10 +430,10 @@ namespace data
|
||||
if (address.transportStyle == eTransportSSU)
|
||||
{
|
||||
// write introducers if any
|
||||
if (address.introducers.size () > 0)
|
||||
if (address.ssu->introducers.size () > 0)
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto& introducer: address.introducers)
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
WriteString ("ihost" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
@ -429,7 +442,7 @@ namespace data
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.introducers)
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
WriteString ("ikey" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
@ -441,7 +454,7 @@ namespace data
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.introducers)
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
WriteString ("iport" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
@ -450,7 +463,7 @@ namespace data
|
||||
i++;
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.introducers)
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
@ -463,16 +476,16 @@ namespace data
|
||||
WriteString ("key", properties);
|
||||
properties << '=';
|
||||
char value[64];
|
||||
size_t l = ByteStreamToBase64 (address.key, 32, value, 64);
|
||||
size_t l = ByteStreamToBase64 (address.ssu->key, 32, value, 64);
|
||||
value[l] = 0;
|
||||
WriteString (value, properties);
|
||||
properties << ';';
|
||||
// write mtu
|
||||
if (address.mtu)
|
||||
if (address.ssu->mtu)
|
||||
{
|
||||
WriteString ("mtu", properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(address.mtu), properties);
|
||||
WriteString (boost::lexical_cast<std::string>(address.ssu->mtu), properties);
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
@ -589,7 +602,6 @@ namespace data
|
||||
addr->transportStyle = eTransportNTCP;
|
||||
addr->cost = 2;
|
||||
addr->date = 0;
|
||||
addr->mtu = 0;
|
||||
for (const auto& it: *m_Addresses) // don't insert same address twice
|
||||
if (*it == *addr) return;
|
||||
m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4;
|
||||
@ -604,8 +616,9 @@ namespace data
|
||||
addr->transportStyle = eTransportSSU;
|
||||
addr->cost = 10; // NTCP should have priority over SSU
|
||||
addr->date = 0;
|
||||
addr->mtu = mtu;
|
||||
memcpy (addr->key, key, 32);
|
||||
addr->ssu.reset (new SSUExt ());
|
||||
addr->ssu->mtu = mtu;
|
||||
memcpy (addr->ssu->key, key, 32);
|
||||
for (const auto& it: *m_Addresses) // don't insert same address twice
|
||||
if (*it == *addr) return;
|
||||
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
|
||||
@ -621,9 +634,9 @@ namespace data
|
||||
{
|
||||
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
|
||||
{
|
||||
for (auto& intro: addr->introducers)
|
||||
for (auto& intro: addr->ssu->introducers)
|
||||
if (intro.iTag == introducer.iTag) return false; // already presented
|
||||
addr->introducers.push_back (introducer);
|
||||
addr->ssu->introducers.push_back (introducer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -636,10 +649,10 @@ namespace data
|
||||
{
|
||||
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
|
||||
{
|
||||
for (auto it = addr->introducers.begin (); it != addr->introducers.end (); ++it)
|
||||
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
|
||||
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
|
||||
{
|
||||
addr->introducers.erase (it);
|
||||
addr->ssu->introducers.erase (it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
13
RouterInfo.h
13
RouterInfo.h
@ -79,17 +79,22 @@ namespace data
|
||||
uint32_t iTag;
|
||||
};
|
||||
|
||||
struct SSUExt
|
||||
{
|
||||
int mtu;
|
||||
IntroKey key; // intro key for SSU
|
||||
std::vector<Introducer> introducers;
|
||||
};
|
||||
|
||||
struct Address
|
||||
{
|
||||
TransportStyle transportStyle;
|
||||
boost::asio::ip::address host;
|
||||
std::string addressString;
|
||||
int port, mtu;
|
||||
int port;
|
||||
uint64_t date;
|
||||
uint8_t cost;
|
||||
// SSU only
|
||||
IntroKey key; // intro key for SSU
|
||||
std::vector<Introducer> introducers;
|
||||
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
||||
|
||||
bool IsCompatible (const boost::asio::ip::address& other) const
|
||||
{
|
||||
|
4
SAM.cpp
4
SAM.cpp
@ -693,9 +693,9 @@ namespace client
|
||||
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);
|
||||
size_t l = sprintf_s ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len);
|
||||
#else
|
||||
size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), len);
|
||||
size_t l = snprintf ((char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE, SAM_DATAGRAM_RECEIVED, base64.c_str (), (long unsigned int)len);
|
||||
#endif
|
||||
if (len < SAM_SOCKET_BUFFER_SIZE - l)
|
||||
{
|
||||
|
4
SSU.cpp
4
SSU.cpp
@ -417,7 +417,7 @@ namespace transport
|
||||
return;
|
||||
}
|
||||
// create new session
|
||||
int numIntroducers = address->introducers.size ();
|
||||
int numIntroducers = address->ssu->introducers.size ();
|
||||
if (numIntroducers > 0)
|
||||
{
|
||||
std::shared_ptr<SSUSession> introducerSession;
|
||||
@ -425,7 +425,7 @@ namespace transport
|
||||
// we might have a session to introducer already
|
||||
for (int i = 0; i < numIntroducers; i++)
|
||||
{
|
||||
auto intr = &(address->introducers[i]);
|
||||
auto intr = &(address->ssu->introducers[i]);
|
||||
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
|
||||
if (ep.address ().is_v4 ()) // ipv4 only
|
||||
{
|
||||
|
10
SSUData.cpp
10
SSUData.cpp
@ -54,23 +54,23 @@ namespace transport
|
||||
{
|
||||
if (remoteRouter) return;
|
||||
auto ssuAddress = remoteRouter->GetSSUAddress ();
|
||||
if (ssuAddress && ssuAddress->mtu)
|
||||
if (ssuAddress && ssuAddress->ssu->mtu)
|
||||
{
|
||||
if (m_Session.IsV6 ())
|
||||
m_PacketSize = ssuAddress->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||
m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||
else
|
||||
m_PacketSize = ssuAddress->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||
m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||
if (m_PacketSize > 0)
|
||||
{
|
||||
// make sure packet size multiple of 16
|
||||
m_PacketSize >>= 4;
|
||||
m_PacketSize <<= 4;
|
||||
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
|
||||
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->mtu, " packet size=", m_PacketSize);
|
||||
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->mtu);
|
||||
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
|
||||
m_PacketSize = m_MaxPacketSize;
|
||||
}
|
||||
}
|
||||
|
@ -22,14 +22,14 @@ namespace transport
|
||||
{
|
||||
// we are client
|
||||
auto address = router->GetSSUAddress (false);
|
||||
if (address) m_IntroKey = address->key;
|
||||
if (address) m_IntroKey = address->ssu->key;
|
||||
m_Data.AdjustPacketSize (router); // mtu
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are server
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
|
||||
if (address) m_IntroKey = address->key;
|
||||
if (address) m_IntroKey = address->ssu->key;
|
||||
}
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
@ -115,8 +115,8 @@ namespace transport
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
return;
|
||||
}
|
||||
if (Validate (buf, len, address->key))
|
||||
Decrypt (buf, len, address->key);
|
||||
if (Validate (buf, len, address->ssu->key))
|
||||
Decrypt (buf, len, address->ssu->key);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
|
||||
@ -403,7 +403,7 @@ namespace transport
|
||||
payload += 2;
|
||||
*payload = 0; // challenge
|
||||
payload++;
|
||||
memcpy (payload, (const uint8_t *)address->key, 32);
|
||||
memcpy (payload, (const uint8_t *)address->ssu->key, 32);
|
||||
payload += 32;
|
||||
htobe32buf (payload, nonce); // nonce
|
||||
|
||||
@ -1081,7 +1081,7 @@ namespace transport
|
||||
// send our intro key to address instead it's own
|
||||
auto addr = i2p::context.GetRouterInfo ().GetSSUAddress ();
|
||||
if (addr)
|
||||
memcpy (payload, addr->key, 32); // intro key
|
||||
memcpy (payload, addr->ssu->key, 32); // intro key
|
||||
else
|
||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||
}
|
||||
@ -1121,7 +1121,7 @@ namespace transport
|
||||
if (!nonce) nonce = 1;
|
||||
m_IsPeerTest = false;
|
||||
m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ());
|
||||
SendPeerTest (nonce, boost::asio::ip::address(), 0, address->key, false, false); // address and port always zero for Alice
|
||||
SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice
|
||||
}
|
||||
|
||||
void SSUSession::SendKeepAlive ()
|
||||
|
@ -384,7 +384,7 @@ namespace transport
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Transports: No NTCP or SSU addresses available");
|
||||
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
||||
peer.Done ();
|
||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||
m_Peers.erase (ident);
|
||||
|
31
Tunnel.cpp
31
Tunnel.cpp
@ -19,36 +19,11 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
|
||||
void TunnelLatency::AddSample(Sample s)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_access);
|
||||
m_samples.push_back(s);
|
||||
}
|
||||
|
||||
bool TunnelLatency::HasSamples() const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_access);
|
||||
return m_samples.size() > 0;
|
||||
}
|
||||
|
||||
TunnelLatency::Latency TunnelLatency::GetMeanLatency() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_access);
|
||||
if (m_samples.size() > 0) {
|
||||
Latency l = 0;
|
||||
for(auto s : m_samples)
|
||||
l += s;
|
||||
return l / m_samples.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
|
||||
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
|
||||
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false)
|
||||
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false),
|
||||
m_Latency (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
31
Tunnel.h
31
Tunnel.h
@ -78,21 +78,6 @@ namespace tunnel
|
||||
eTunnelStateFailed,
|
||||
eTunnelStateExpiring
|
||||
};
|
||||
|
||||
/** @brief for storing latency history */
|
||||
struct TunnelLatency
|
||||
{
|
||||
typedef uint64_t Sample;
|
||||
typedef uint64_t Latency;
|
||||
|
||||
|
||||
void AddSample(Sample s);
|
||||
bool HasSamples() const;
|
||||
Latency GetMeanLatency() const;
|
||||
|
||||
std::vector<Sample> m_samples;
|
||||
mutable std::mutex m_access;
|
||||
};
|
||||
|
||||
class OutboundTunnel;
|
||||
class InboundTunnel;
|
||||
@ -133,14 +118,14 @@ namespace tunnel
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||
|
||||
/** @brief add latency sample */
|
||||
void AddLatencySample(const uint64_t ms) { m_Latency.AddSample(ms); }
|
||||
/** @brief get this tunnel's estimated latency */
|
||||
uint64_t GetMeanLatency() const { return m_Latency.GetMeanLatency(); }
|
||||
/** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
|
||||
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
|
||||
/** @brief add latency sample */
|
||||
void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; }
|
||||
/** @brief get this tunnel's estimated latency */
|
||||
uint64_t GetMeanLatency() const { return m_Latency; }
|
||||
/** @breif return true if this tunnel's latency fits in range [lowerbound, upperbound] */
|
||||
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
|
||||
|
||||
bool LatencyIsKnown() const { return m_Latency.HasSamples(); }
|
||||
bool LatencyIsKnown() const { return m_Latency > 0; }
|
||||
protected:
|
||||
|
||||
void PrintHops (std::stringstream& s) const;
|
||||
@ -152,7 +137,7 @@ namespace tunnel
|
||||
std::shared_ptr<TunnelPool> m_Pool; // pool, tunnel belongs to, or null
|
||||
TunnelState m_State;
|
||||
bool m_IsRecreated;
|
||||
TunnelLatency m_Latency;
|
||||
uint64_t m_Latency; // in milliseconds
|
||||
};
|
||||
|
||||
class OutboundTunnel: public Tunnel
|
||||
|
@ -11,4 +11,4 @@
|
||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||
|
||||
# Project target.
|
||||
target=android-24
|
||||
target=android-25
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 36 KiB |
Binary file not shown.
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 36 KiB |
@ -73,9 +73,12 @@ All options below still possible in cmdline, but better write it in config file:
|
||||
* --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid
|
||||
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP
|
||||
|
||||
* --i2pcontrol.address= - The address to listen on (I2P control service)
|
||||
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
|
||||
* --i2pcontrol.enabled= - If I2P control is enabled. false by default
|
||||
* --i2pcontrol.address= - The address to listen on (I2P control service)
|
||||
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified
|
||||
* --i2pcontrol.enabled= - If I2P control is enabled. false by default
|
||||
* --i2pcontrol.password= - I2P control authentication password. itoopie by default
|
||||
* --i2pcontrol.cert= - I2P control HTTPS certificate file name. i2pcontrol.crt.pem by default
|
||||
* --i2pcontrol.key= - I2P control HTTPS certificate key file name. i2pcontrol.key.pem by default
|
||||
|
||||
* --upnp.enabled= - Enable or disable UPnP, false by default for CLI and true for GUI (Windows, Android)
|
||||
* --upnp.name= - Name i2pd appears in UPnP forwardings list. I2Pd by default
|
||||
|
3
qt/i2pd_qt/README.md
Normal file
3
qt/i2pd_qt/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Build Requirements
|
||||
|
||||
* Qt 5 is necessary (because Qt4 lacks QtWidgets/ folder)
|
Loading…
Reference in New Issue
Block a user