Merge pull request #768 from PurpleI2P/openssl

recent changes
This commit is contained in:
orignal 2017-01-05 15:47:04 -05:00 committed by GitHub
commit b3ab85f3b5
12 changed files with 160 additions and 103 deletions

View File

@ -205,7 +205,7 @@ namespace client
}
/* append to json chunk of data from 1st request */
json.write(buf->data() + len, bytes_transferred - len);
remains = req.content_length() - len;
remains = req.content_length();
/* 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;
@ -216,15 +216,17 @@ namespace client
} else {
json.write(buf->data(), bytes_transferred);
}
LogPrint(eLogDebug, "I2PControl: json from request: ", json.str());
//LogPrint(eLogDebug, "I2PControl: json from request: ", json.str());
#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");
#else
/* now try to parse json itself */
std::string j_str = json.str();
std::stringstream _json(j_str);
try {
boost::property_tree::ptree pt;
boost::property_tree::read_json (json, pt);
boost::property_tree::read_json (_json, pt);
std::string id = pt.get<std::string>("id");
std::string method = pt.get<std::string>("method");
@ -342,10 +344,11 @@ namespace client
(this->*(it1->second))(it.second.data ());
InsertParam (results, it.first, "");
}
else
else {
LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first);
}
}
}
void I2PControlService::PasswordHandler (const std::string& value)
{
@ -361,16 +364,19 @@ namespace client
for (auto it = params.begin (); it != params.end (); ++it)
{
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
if (it != params.begin ()) results << ",";
auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ())
{
if (it != params.begin ()) results << ",";
(this->*(it1->second))(results);
}
else
{
InsertParam(results, it->first, "");
LogPrint (eLogError, "I2PControl: RouterInfo unknown request ", it->first);
}
}
}
void I2PControlService::UptimeHandler (std::ostringstream& results)
{
@ -439,12 +445,17 @@ namespace client
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
auto it1 = m_RouterManagerHandlers.find (it->first);
if (it1 != m_RouterManagerHandlers.end ()) {
if (it1 != m_RouterManagerHandlers.end ())
{
(this->*(it1->second))(results);
} else
}
else
{
InsertParam(results, it->first, "");
LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);
}
}
}
void I2PControlService::ShutdownHandler (std::ostringstream& results)
@ -488,12 +499,17 @@ namespace client
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: NetworkSetting request: ", it->first);
auto it1 = m_NetworkSettingHandlers.find (it->first);
if (it1 != m_NetworkSettingHandlers.end ()) {
if (it1 != m_NetworkSettingHandlers.end ())
{
(this->*(it1->second))(it->second.data (), results);
} else
}
else
{
InsertParam(results, it->first, "");
LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
}
}
}
void I2PControlService::InboundBandwidthLimit (const std::string& value, std::ostringstream& results)
{

View File

@ -178,7 +178,7 @@ namespace client
{
if (bytes_transferred > 0)
Write (m_StreamBuffer, bytes_transferred); // postpone termination
else if (ecode == boost::asio::error::timed_out && m_Stream->IsOpen ())
else if (ecode == boost::asio::error::timed_out && m_Stream && m_Stream->IsOpen ())
StreamReceive ();
else
Terminate ();

View File

@ -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,9 +508,7 @@ namespace transport
if (m_ReceiveBufferOffset >= 16)
{
int numReloads = 0;
do
{
// process received data
uint8_t * nextBlock = m_ReceiveBuffer;
while (m_ReceiveBufferOffset >= 16)
{
@ -523,32 +522,52 @@ namespace transport
}
if (m_ReceiveBufferOffset > 0)
memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset);
}
// try to read more
if (numReloads < 5)
{
// read and process more is available
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);
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_NumReceivedBytes += moreBytes;
m_ReceiveBufferOffset += moreBytes;
numReloads++;
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;
}
while (m_ReceiveBufferOffset >= 16);
m_Handler.Flush ();
}
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
Receive ();

View File

@ -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

View File

@ -267,7 +267,8 @@ namespace i2p
}
// delete previous introducers
for (auto& addr : addresses)
addr->introducers.clear ();
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 ();

View File

@ -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;
}
}

View File

@ -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
{

View File

@ -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)
{

View File

@ -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
{

View File

@ -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;
}
}

View File

@ -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);
@ -402,7 +402,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
@ -1075,7 +1075,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");
}
@ -1114,7 +1114,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 ()

View File

@ -76,6 +76,9 @@ All options below still possible in cmdline, but better write it in config file:
* --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