Merge pull request #1301 from PurpleI2P/openssl

recent changes
This commit is contained in:
orignal 2019-02-22 10:49:51 -05:00 committed by GitHub
commit cc48436794
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 901 additions and 489 deletions

View File

@ -50,7 +50,7 @@ namespace util
if (isDaemon) if (isDaemon)
{ {
LogPrint(eLogDebug, "Daemon: running as service"); LogPrint(eLogDebug, "Daemon: running as service");
I2PService service(SERVICE_NAME); I2PService service((PSTR)SERVICE_NAME);
if (!I2PService::Run(service)) if (!I2PService::Run(service))
{ {
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());

View File

@ -24,17 +24,22 @@
#define ID_GRACEFUL_SHUTDOWN 2004 #define ID_GRACEFUL_SHUTDOWN 2004
#define ID_STOP_GRACEFUL_SHUTDOWN 2005 #define ID_STOP_GRACEFUL_SHUTDOWN 2005
#define ID_RELOAD 2006 #define ID_RELOAD 2006
#define ID_ACCEPT_TRANSIT 2007
#define ID_DECLINE_TRANSIT 2008
#define ID_TRAY_ICON 2050 #define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1) #define WM_TRAYICON (WM_USER + 1)
#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100 #define IDT_GRACEFUL_SHUTDOWN_TIMER 2100
#define FRAME_UPDATE_TIMER 2101 #define FRAME_UPDATE_TIMER 2101
#define IDT_GRACEFUL_TUNNELCHECK_TIMER 2102
namespace i2p namespace i2p
{ {
namespace win32 namespace win32
{ {
static DWORD GracefulShutdownEndtime = 0;
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem) static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
{ {
HMENU hPopup = CreatePopupMenu(); HMENU hPopup = CreatePopupMenu();
@ -42,11 +47,17 @@ namespace win32
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
if(!i2p::context.AcceptsTunnels())
InsertMenu (hPopup, -1,
i2p::util::DaemonWin32::Instance ().isGraceful ? MF_BYPOSITION | MF_STRING | MF_GRAYED : MF_BYPOSITION | MF_STRING,
ID_ACCEPT_TRANSIT, "Accept &transit");
else
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs");
if (!i2p::util::DaemonWin32::Instance ().isGraceful) if (!i2p::util::DaemonWin32::Instance ().isGraceful)
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
else else
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "&Stop graceful shutdown"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "Stop &graceful shutdown");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
@ -148,7 +159,13 @@ namespace win32
s << "; "; s << "; ";
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n"; s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
s << "\n"; if (GracefulShutdownEndtime != 0)
{
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCount()) / 1000;
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
}
else
s << "\n";
s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; "; s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; ";
s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n"; s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n";
s << "Received: "; ShowTransfered (s, i2p::transport::transports.GetTotalReceivedBytes()); s << "Received: "; ShowTransfered (s, i2p::transport::transports.GetTotalReceivedBytes());
@ -166,10 +183,13 @@ namespace win32
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
static UINT s_uTaskbarRestart;
switch (uMsg) switch (uMsg)
{ {
case WM_CREATE: case WM_CREATE:
{ {
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
AddTrayIcon (hWnd); AddTrayIcon (hWnd);
break; break;
} }
@ -178,6 +198,7 @@ namespace win32
RemoveTrayIcon (hWnd); RemoveTrayIcon (hWnd);
KillTimer (hWnd, FRAME_UPDATE_TIMER); KillTimer (hWnd, FRAME_UPDATE_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
PostQuitMessage (0); PostQuitMessage (0);
break; break;
} }
@ -197,10 +218,28 @@ namespace win32
PostMessage (hWnd, WM_CLOSE, 0, 0); PostMessage (hWnd, WM_CLOSE, 0, 0);
return 0; return 0;
} }
case ID_ACCEPT_TRANSIT:
{
i2p::context.SetAcceptsTunnels (true);
std::stringstream text;
text << "I2Pd now accept transit tunnels";
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
return 0;
}
case ID_DECLINE_TRANSIT:
{
i2p::context.SetAcceptsTunnels (false);
std::stringstream text;
text << "I2Pd now decline new transit tunnels";
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
return 0;
}
case ID_GRACEFUL_SHUTDOWN: case ID_GRACEFUL_SHUTDOWN:
{ {
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
GracefulShutdownEndtime = GetTickCount() + 10*60*1000;
i2p::util::DaemonWin32::Instance ().isGraceful = true; i2p::util::DaemonWin32::Instance ().isGraceful = true;
return 0; return 0;
} }
@ -208,6 +247,8 @@ namespace win32
{ {
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
GracefulShutdownEndtime = 0;
i2p::util::DaemonWin32::Instance ().isGraceful = false; i2p::util::DaemonWin32::Instance ().isGraceful = false;
return 0; return 0;
} }
@ -223,7 +264,7 @@ namespace win32
{ {
char buf[30]; char buf[30];
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort); snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort);
ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL); ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL);
return 0; return 0;
@ -290,14 +331,27 @@ namespace win32
} }
case WM_TIMER: case WM_TIMER:
{ {
if (wParam == IDT_GRACEFUL_SHUTDOWN_TIMER) switch(wParam)
{ {
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit case IDT_GRACEFUL_SHUTDOWN_TIMER:
return 0; {
} GracefulShutdownEndtime = 0;
if (wParam == FRAME_UPDATE_TIMER) PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
{ return 0;
InvalidateRect(hWnd, NULL, TRUE); }
case FRAME_UPDATE_TIMER:
{
InvalidateRect(hWnd, NULL, TRUE);
return 0;
}
case IDT_GRACEFUL_TUNNELCHECK_TIMER:
{
if (i2p::tunnel::tunnels.CountTransitTunnels() == 0)
PostMessage (hWnd, WM_CLOSE, 0, 0);
else
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr);
return 0;
}
} }
break; break;
} }
@ -318,6 +372,12 @@ namespace win32
EndPaint(hWnd, &ps); EndPaint(hWnd, &ps);
break; break;
} }
default:
{
if (uMsg == s_uTaskbarRestart)
AddTrayIcon (hWnd);
break;
}
} }
return DefWindowProc( hWnd, uMsg, wParam, lParam); return DefWindowProc( hWnd, uMsg, wParam, lParam);
} }

View File

@ -297,7 +297,8 @@ void InstallService(PCSTR pszServiceName, PCSTR pszDisplayName, DWORD dwStartTyp
FreeHandles(schSCManager, schService); FreeHandles(schSCManager, schService);
return; return;
} }
strncat(szPath, " --daemon", MAX_PATH); char SvcOpt[] = " --daemon";
strncat(szPath, SvcOpt, strlen(SvcOpt));
// Open the local default service control manager database // Open the local default service control manager database
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);

View File

@ -777,6 +777,9 @@ namespace client
m_DatagramDestination (nullptr), m_RefCounter (0), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(GetService()) m_ReadyChecker(GetService())
{ {
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only
m_EncryptionKeyType = GetIdentity ()->GetCryptoKeyType (); m_EncryptionKeyType = GetIdentity ()->GetCryptoKeyType ();
// extract encryption type params for LS2 // extract encryption type params for LS2
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 && params) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 && params)
@ -1048,9 +1051,7 @@ namespace client
// standard LS2 (type 3) assumed for now. TODO: implement others // standard LS2 (type 3) assumed for now. TODO: implement others
auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256; auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
leaseSet = new i2p::data::LocalLeaseSet2 (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, leaseSet = new i2p::data::LocalLeaseSet2 (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
GetIdentity (), m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels); m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels);
// sign
Sign (leaseSet->GetBuffer () - 1, leaseSet->GetBufferLen () - leaseSet->GetSignatureLen () + 1, leaseSet->GetSignature ()); // + leading store type
} }
SetLeaseSet (leaseSet); SetLeaseSet (leaseSet);
} }

View File

@ -126,6 +126,7 @@ namespace client
void SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet); void SetLeaseSet (i2p::data::LocalLeaseSet * newLeaseSet);
int GetLeaseSetType () const { return m_LeaseSetType; }; int GetLeaseSetType () const { return m_LeaseSetType; };
void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; };
virtual void CleanupDestination () {}; // additional clean up in derived classes virtual void CleanupDestination () {}; // additional clean up in derived classes
// I2CP // I2CP
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0; virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;

View File

@ -11,6 +11,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include <shlobj.h> #include <shlobj.h>
#include <windows.h>
#endif #endif
#include "Base.h" #include "Base.h"
@ -20,187 +21,211 @@
namespace i2p { namespace i2p {
namespace fs { namespace fs {
std::string appName = "i2pd"; std::string appName = "i2pd";
std::string dataDir = ""; std::string dataDir = "";
#ifdef _WIN32 #ifdef _WIN32
std::string dirSep = "\\"; std::string dirSep = "\\";
#else #else
std::string dirSep = "/"; std::string dirSep = "/";
#endif #endif
const std::string & GetAppName () { const std::string & GetAppName () {
return appName; return appName;
} }
void SetAppName (const std::string& name) { void SetAppName (const std::string& name) {
appName = name; appName = name;
} }
const std::string & GetDataDir () { const std::string & GetDataDir () {
return dataDir; return dataDir;
} }
void DetectDataDir(const std::string & cmdline_param, bool isService) { void DetectDataDir(const std::string & cmdline_param, bool isService) {
if (cmdline_param != "") { if (cmdline_param != "") {
dataDir = cmdline_param; dataDir = cmdline_param;
return; return;
} }
#if defined(WIN32) || defined(_WIN32) #if defined(WIN32) || defined(_WIN32)
char localAppData[MAX_PATH]; char localAppData[MAX_PATH];
// check executable directory first
GetModuleFileName (NULL, localAppData, MAX_PATH); // check executable directory first
auto execPath = boost::filesystem::path(localAppData).parent_path(); if(!GetModuleFileName(NULL, localAppData, MAX_PATH))
// if config file exists in .exe's folder use it {
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string #if defined(WIN32_APP)
dataDir = execPath.string (); MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
else #else
{ fprintf(stderr, "Error: Unable to get application path!");
// otherwise %appdata% #endif
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData); exit(1);
dataDir = std::string(localAppData) + "\\" + appName; }
} else
return; {
auto execPath = boost::filesystem::path(localAppData).parent_path();
// if config file exists in .exe's folder use it
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
dataDir = execPath.string ();
else // otherwise %appdata%
{
if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK)
{
#if defined(WIN32_APP)
MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
#else
fprintf(stderr, "Error: Unable to get AppData path!");
#endif
exit(1);
}
else
dataDir = std::string(localAppData) + "\\" + appName;
}
}
return;
#elif defined(MAC_OSX) #elif defined(MAC_OSX)
char *home = getenv("HOME"); char *home = getenv("HOME");
dataDir = (home != NULL && strlen(home) > 0) ? home : ""; dataDir = (home != NULL && strlen(home) > 0) ? home : "";
dataDir += "/Library/Application Support/" + appName; dataDir += "/Library/Application Support/" + appName;
return; return;
#else /* other unix */ #else /* other unix */
#if defined(ANDROID) #if defined(ANDROID)
const char * ext = getenv("EXTERNAL_STORAGE"); const char * ext = getenv("EXTERNAL_STORAGE");
if (!ext) ext = "/sdcard"; if (!ext) ext = "/sdcard";
if (boost::filesystem::exists(ext)) if (boost::filesystem::exists(ext))
{ {
dataDir = std::string (ext) + "/" + appName; dataDir = std::string (ext) + "/" + appName;
return;
}
#endif
// otherwise use /data/files
char *home = getenv("HOME");
if (isService) {
dataDir = "/var/lib/" + appName;
} else if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/." + appName;
} else {
dataDir = "/tmp/" + appName;
}
return; return;
#endif
} }
// otherwise use /data/files
#endif
char *home = getenv("HOME");
if (isService) {
dataDir = "/var/lib/" + appName;
} else if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/." + appName;
} else {
dataDir = "/tmp/" + appName;
}
return;
#endif
}
bool Init() { bool Init() {
if (!boost::filesystem::exists(dataDir)) if (!boost::filesystem::exists(dataDir))
boost::filesystem::create_directory(dataDir); boost::filesystem::create_directory(dataDir);
std::string destinations = DataDirPath("destinations");
if (!boost::filesystem::exists(destinations))
boost::filesystem::create_directory(destinations);
std::string tags = DataDirPath("tags");
if (!boost::filesystem::exists(tags))
boost::filesystem::create_directory(tags);
else
i2p::garlic::CleanUpTagsFiles ();
return true; std::string destinations = DataDirPath("destinations");
} if (!boost::filesystem::exists(destinations))
boost::filesystem::create_directory(destinations);
bool ReadDir(const std::string & path, std::vector<std::string> & files) { std::string tags = DataDirPath("tags");
if (!boost::filesystem::exists(path)) if (!boost::filesystem::exists(tags))
return false; boost::filesystem::create_directory(tags);
boost::filesystem::directory_iterator it(path); else
boost::filesystem::directory_iterator end; i2p::garlic::CleanUpTagsFiles ();
for ( ; it != end; it++) { return true;
if (!boost::filesystem::is_regular_file(it->status())) }
continue;
files.push_back(it->path().string());
}
return true; bool ReadDir(const std::string & path, std::vector<std::string> & files) {
} if (!boost::filesystem::exists(path))
return false;
boost::filesystem::directory_iterator it(path);
boost::filesystem::directory_iterator end;
bool Exists(const std::string & path) { for ( ; it != end; it++) {
return boost::filesystem::exists(path); if (!boost::filesystem::is_regular_file(it->status()))
} continue;
files.push_back(it->path().string());
}
uint32_t GetLastUpdateTime (const std::string & path) return true;
{ }
if (!boost::filesystem::exists(path)) return 0;
boost::system::error_code ec;
auto t = boost::filesystem::last_write_time (path, ec);
return ec ? 0 : t;
}
bool Remove(const std::string & path) { bool Exists(const std::string & path) {
if (!boost::filesystem::exists(path)) return boost::filesystem::exists(path);
return false; }
return boost::filesystem::remove(path);
} uint32_t GetLastUpdateTime (const std::string & path)
{
if (!boost::filesystem::exists(path))
return 0;
boost::system::error_code ec;
auto t = boost::filesystem::last_write_time (path, ec);
return ec ? 0 : t;
}
bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path))
return false;
return boost::filesystem::remove(path);
}
bool CreateDirectory (const std::string& path) bool CreateDirectory (const std::string& path)
{ {
if (boost::filesystem::exists(path) && if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (path)))
boost::filesystem::is_directory (boost::filesystem::status (path))) return true; return true;
return boost::filesystem::create_directory(path); return boost::filesystem::create_directory(path);
} }
void HashedStorage::SetPlace(const std::string &path) { void HashedStorage::SetPlace(const std::string &path) {
root = path + i2p::fs::dirSep + name; root = path + i2p::fs::dirSep + name;
} }
bool HashedStorage::Init(const char * chars, size_t count) { bool HashedStorage::Init(const char * chars, size_t count) {
if (!boost::filesystem::exists(root)) { if (!boost::filesystem::exists(root)) {
boost::filesystem::create_directories(root); boost::filesystem::create_directories(root);
} }
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
auto p = root + i2p::fs::dirSep + prefix1 + chars[i]; auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
if (boost::filesystem::exists(p)) if (boost::filesystem::exists(p))
continue; continue;
if (boost::filesystem::create_directory(p)) if (boost::filesystem::create_directory(p))
continue; /* ^ throws exception on failure */ continue; /* ^ throws exception on failure */
return false; return false;
} }
return true; return true;
} }
std::string HashedStorage::Path(const std::string & ident) const { std::string HashedStorage::Path(const std::string & ident) const {
std::string safe_ident = ident; std::string safe_ident = ident;
std::replace(safe_ident.begin(), safe_ident.end(), '/', '-'); std::replace(safe_ident.begin(), safe_ident.end(), '/', '-');
std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-'); std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
std::stringstream t(""); std::stringstream t("");
t << this->root << i2p::fs::dirSep; t << this->root << i2p::fs::dirSep;
t << prefix1 << safe_ident[0] << i2p::fs::dirSep; t << prefix1 << safe_ident[0] << i2p::fs::dirSep;
t << prefix2 << safe_ident << "." << suffix; t << prefix2 << safe_ident << "." << suffix;
return t.str(); return t.str();
} }
void HashedStorage::Remove(const std::string & ident) { void HashedStorage::Remove(const std::string & ident) {
std::string path = Path(ident); std::string path = Path(ident);
if (!boost::filesystem::exists(path)) if (!boost::filesystem::exists(path))
return; return;
boost::filesystem::remove(path); boost::filesystem::remove(path);
} }
void HashedStorage::Traverse(std::vector<std::string> & files) { void HashedStorage::Traverse(std::vector<std::string> & files) {
Iterate([&files] (const std::string & fname) { Iterate([&files] (const std::string & fname) {
files.push_back(fname); files.push_back(fname);
}); });
} }
void HashedStorage::Iterate(FilenameVisitor v) void HashedStorage::Iterate(FilenameVisitor v)
{ {
boost::filesystem::path p(root); boost::filesystem::path p(root);
boost::filesystem::recursive_directory_iterator it(p); boost::filesystem::recursive_directory_iterator it(p);
boost::filesystem::recursive_directory_iterator end; boost::filesystem::recursive_directory_iterator end;
for ( ; it != end; it++) { for ( ; it != end; it++) {
if (!boost::filesystem::is_regular_file( it->status() )) if (!boost::filesystem::is_regular_file( it->status() ))
continue; continue;
const std::string & t = it->path().string(); const std::string & t = it->path().string();
v(t); v(t);
} }
} }
} // fs } // fs
} // i2p } // i2p

View File

@ -432,6 +432,9 @@ namespace data
m_Public = std::make_shared<IdentityEx>(Identity (keys)); m_Public = std::make_shared<IdentityEx>(Identity (keys));
memcpy (m_PrivateKey, keys.privateKey, 256); // 256 memcpy (m_PrivateKey, keys.privateKey, 256); // 256
memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ()); memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ());
m_OfflineSignature.resize (0);
m_TransientSignatureLen = 0;
m_TransientSigningPrivateKeyLen = 0;
m_Signer = nullptr; m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return *this; return *this;
@ -441,12 +444,23 @@ namespace data
{ {
m_Public = std::make_shared<IdentityEx>(*other.m_Public); m_Public = std::make_shared<IdentityEx>(*other.m_Public);
memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256 memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_Public->GetSigningPrivateKeyLen ()); m_OfflineSignature = other.m_OfflineSignature;
m_TransientSignatureLen = other.m_TransientSignatureLen;
m_TransientSigningPrivateKeyLen = other.m_TransientSigningPrivateKeyLen;
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_TransientSigningPrivateKeyLen > 0 ? m_TransientSigningPrivateKeyLen : m_Public->GetSigningPrivateKeyLen ());
m_Signer = nullptr; m_Signer = nullptr;
CreateSigner (); CreateSigner ();
return *this; return *this;
} }
size_t PrivateKeys::GetFullLen () const
{
size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen ();
if (IsOfflineSignature ())
ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen;
return ret;
}
size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len) size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len)
{ {
m_Public = std::make_shared<IdentityEx>(); m_Public = std::make_shared<IdentityEx>();
@ -455,11 +469,50 @@ namespace data
memcpy (m_PrivateKey, buf + ret, 256); // private key always 256 memcpy (m_PrivateKey, buf + ret, 256); // private key always 256
ret += 256; ret += 256;
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
if(signingPrivateKeySize + ret > len) return 0; // overflow if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
ret += signingPrivateKeySize; ret += signingPrivateKeySize;
m_Signer = nullptr; m_Signer = nullptr;
CreateSigner (); // check if signing private key is all zeros
bool allzeros = true;
for (size_t i = 0; i < signingPrivateKeySize; i++)
if (m_SigningPrivateKey[i])
{
allzeros = false;
break;
}
if (allzeros)
{
// offline information
const uint8_t * offlineInfo = buf + ret;
ret += 4; // expires timestamp
SigningKeyType keyType = bufbe16toh (buf + ret); ret += 2; // key type
std::unique_ptr<i2p::crypto::Verifier> transientVerifier (IdentityEx::CreateVerifier (keyType));
if (!transientVerifier) return 0;
auto keyLen = transientVerifier->GetPublicKeyLen ();
if (keyLen + ret > len) return 0;
transientVerifier->SetPublicKey (buf + ret); ret += keyLen;
if (m_Public->GetSignatureLen () + ret > len) return 0;
if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret))
{
LogPrint (eLogError, "Identity: offline signature verification failed");
return 0;
}
ret += m_Public->GetSignatureLen ();
m_TransientSignatureLen = transientVerifier->GetSignatureLen ();
// copy offline signature
size_t offlineInfoLen = buf + ret - offlineInfo;
m_OfflineSignature.resize (offlineInfoLen);
memcpy (m_OfflineSignature.data (), offlineInfo, offlineInfoLen);
// override signing private key
m_TransientSigningPrivateKeyLen = transientVerifier->GetPrivateKeyLen ();
if (m_TransientSigningPrivateKeyLen + ret > len || m_TransientSigningPrivateKeyLen > 128) return 0;
memcpy (m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen);
ret += m_TransientSigningPrivateKeyLen;
CreateSigner (keyType);
}
else
CreateSigner (m_Public->GetSigningKeyType ());
return ret; return ret;
} }
@ -470,8 +523,23 @@ namespace data
ret += 256; ret += 256;
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
if(ret + signingPrivateKeySize > len) return 0; // overflow if(ret + signingPrivateKeySize > len) return 0; // overflow
memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize); if (IsOfflineSignature ())
memset (buf + ret, 0, signingPrivateKeySize);
else
memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize);
ret += signingPrivateKeySize; ret += signingPrivateKeySize;
if (IsOfflineSignature ())
{
// offline signature
auto offlineSignatureLen = m_OfflineSignature.size ();
if (ret + offlineSignatureLen > len) return 0;
memcpy (buf + ret, m_OfflineSignature.data (), offlineSignatureLen);
ret += offlineSignatureLen;
// transient private key
if (ret + m_TransientSigningPrivateKeyLen > len) return 0;
memcpy (buf + ret, m_SigningPrivateKey, m_TransientSigningPrivateKeyLen);
ret += m_TransientSigningPrivateKeyLen;
}
return ret; return ret;
} }
@ -505,9 +573,17 @@ namespace data
} }
void PrivateKeys::CreateSigner () const void PrivateKeys::CreateSigner () const
{
if (IsOfflineSignature ())
CreateSigner (bufbe16toh (m_OfflineSignature.data () + 4)); // key type
else
CreateSigner (m_Public->GetSigningKeyType ());
}
void PrivateKeys::CreateSigner (SigningKeyType keyType) const
{ {
if (m_Signer) return; if (m_Signer) return;
switch (m_Public->GetSigningKeyType ()) switch (keyType)
{ {
case SIGNING_KEY_TYPE_DSA_SHA1: case SIGNING_KEY_TYPE_DSA_SHA1:
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey)); m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
@ -527,7 +603,7 @@ namespace data
LogPrint (eLogError, "Identity: RSA signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported"); LogPrint (eLogError, "Identity: RSA signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported");
break; break;
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, IsOfflineSignature () ? nullptr: m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
break; break;
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
m_Signer.reset (new i2p::crypto::GOSTR3410_256_Signer (i2p::crypto::eGOSTR3410CryptoProA, m_SigningPrivateKey)); m_Signer.reset (new i2p::crypto::GOSTR3410_256_Signer (i2p::crypto::eGOSTR3410CryptoProA, m_SigningPrivateKey));
@ -540,6 +616,11 @@ namespace data
} }
} }
size_t PrivateKeys::GetSignatureLen () const
{
return IsOfflineSignature () ? m_TransientSignatureLen : m_Public->GetSignatureLen ();
}
uint8_t * PrivateKeys::GetPadding() uint8_t * PrivateKeys::GetPadding()
{ {
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
@ -582,35 +663,7 @@ namespace data
PrivateKeys keys; PrivateKeys keys;
// signature // signature
uint8_t signingPublicKey[512]; // signing public key is 512 bytes max uint8_t signingPublicKey[512]; // signing public key is 512 bytes max
switch (type) GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey);
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
i2p::crypto::CreateECDSAP256RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
i2p::crypto::CreateECDSAP384RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
i2p::crypto::CreateECDSAP521RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
// no break here
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey);
break;
default:
LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
}
// encryption // encryption
uint8_t publicKey[256]; uint8_t publicKey[256];
GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey); GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey);
@ -623,6 +676,39 @@ namespace data
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1 return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
} }
void PrivateKeys::GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub)
{
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
i2p::crypto::CreateECDSAP256RandomKeys (priv, pub);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
i2p::crypto::CreateECDSAP384RandomKeys (priv, pub);
break;
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
i2p::crypto::CreateECDSAP521RandomKeys (priv, pub);
break;
case SIGNING_KEY_TYPE_RSA_SHA256_2048:
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
// no break here
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub);
break;
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, priv, pub);
break;
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, priv, pub);
break;
default:
LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1
}
}
void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub) void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub)
{ {
switch (type) switch (type)
@ -642,6 +728,27 @@ namespace data
} }
} }
PrivateKeys PrivateKeys::CreateOfflineKeys (SigningKeyType type, uint32_t expires) const
{
PrivateKeys keys (*this);
std::unique_ptr<i2p::crypto::Verifier> verifier (IdentityEx::CreateVerifier (type));
if (verifier)
{
size_t pubKeyLen = verifier->GetPublicKeyLen ();
keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen ();
keys.m_TransientSignatureLen = verifier->GetSignatureLen ();
keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6);
htobe32buf (keys.m_OfflineSignature.data (), expires); // expires
htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature
// recreate signer
keys.m_Signer = nullptr;
keys.CreateSigner (type);
}
return keys;
}
Keys CreateRandomKeys () Keys CreateRandomKeys ()
{ {
Keys keys; Keys keys;

View File

@ -6,6 +6,7 @@
#include <string> #include <string>
#include <memory> #include <memory>
#include <atomic> #include <atomic>
#include <vector>
#include "Base.h" #include "Base.h"
#include "Signature.h" #include "Signature.h"
#include "CryptoKey.h" #include "CryptoKey.h"
@ -142,11 +143,13 @@ namespace data
std::shared_ptr<const IdentityEx> GetPublic () const { return m_Public; }; std::shared_ptr<const IdentityEx> GetPublic () const { return m_Public; };
const uint8_t * GetPrivateKey () const { return m_PrivateKey; }; const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
uint8_t * GetPadding(); size_t GetSignatureLen () const; // might not match identity
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); } bool IsOfflineSignature () const { return m_TransientSignatureLen > 0; };
uint8_t * GetPadding();
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); }; size_t GetFullLen () const;
size_t FromBuffer (const uint8_t * buf, size_t len); size_t FromBuffer (const uint8_t * buf, size_t len);
size_t ToBuffer (uint8_t * buf, size_t len) const; size_t ToBuffer (uint8_t * buf, size_t len) const;
@ -157,18 +160,27 @@ namespace data
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key); static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub);
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
// offline keys
PrivateKeys CreateOfflineKeys (SigningKeyType type, uint32_t expires) const;
const std::vector<uint8_t>& GetOfflineSignature () const { return m_OfflineSignature; };
private: private:
void CreateSigner () const; void CreateSigner () const;
void CreateSigner (SigningKeyType keyType) const;
private: private:
std::shared_ptr<IdentityEx> m_Public; std::shared_ptr<IdentityEx> m_Public;
uint8_t m_PrivateKey[256]; uint8_t m_PrivateKey[256];
uint8_t m_SigningPrivateKey[1024]; // assume private key doesn't exceed 1024 bytes uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes
mutable std::unique_ptr<i2p::crypto::Signer> m_Signer; mutable std::unique_ptr<i2p::crypto::Signer> m_Signer;
std::vector<uint8_t> m_OfflineSignature; // non zero length, if applicable
size_t m_TransientSignatureLen = 0;
size_t m_TransientSigningPrivateKeyLen = 0;
}; };
// kademlia // kademlia

View File

@ -262,43 +262,38 @@ namespace data
void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature) void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature)
{ {
// shouldn't be called for now. Must be called from NetDb::AddLeaseSet later
SetBuffer (buf, len); SetBuffer (buf, len);
// TODO:verify signature if requested if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
ReadFromBuffer (buf, len, false, verifySignature);
// TODO: implement encrypted
} }
void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len) void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature)
{ {
// standard LS2 header // standard LS2 header
auto identity = std::make_shared<IdentityEx>(buf, len); std::shared_ptr<const IdentityEx> identity;
SetIdentity (identity); if (readIdentity)
{
identity = std::make_shared<IdentityEx>(buf, len);
SetIdentity (identity);
}
else
identity = GetIdentity ();
size_t offset = identity->GetFullLen (); size_t offset = identity->GetFullLen ();
if (offset + 8 >= len) return; if (offset + 8 >= len) return;
uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds) uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; // published timestamp (seconds)
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds) uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
std::unique_ptr<i2p::crypto::Verifier> transientVerifier; if (flags & LEASESET2_FLAG_OFFLINE_KEYS)
if (flags & 0x0001)
{ {
// transient key // transient key
if (offset + 6 >= len) return; m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset);
const uint8_t * signedData = buf + offset; if (!m_TransientVerifier)
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ())
{ {
LogPrint (eLogWarning, "LeaseSet2: transient key expired"); LogPrint (eLogError, "LeaseSet2: offline signature failed");
return; return;
} }
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
transientVerifier.reset (i2p::data::IdentityEx::CreateVerifier (keyType));
if (!transientVerifier) return;
auto keyLen = transientVerifier->GetPublicKeyLen ();
if (offset + keyLen >= len) return;
transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
if (offset + identity->GetSignatureLen () >= len) return;
if (!identity->Verify (signedData, keyLen + 6, buf + offset)) return;
offset += identity->GetSignatureLen ();
} }
// type specific part // type specific part
size_t s = 0; size_t s = 0;
@ -315,10 +310,13 @@ namespace data
} }
if (!s) return; if (!s) return;
offset += s; offset += s;
// verify signature if (verifySignature || m_TransientVerifier)
bool verified = transientVerifier ? VerifySignature (transientVerifier, buf, len, offset) : {
VerifySignature (identity, buf, len, offset); // verify signature
SetIsValid (verified); bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
VerifySignature (identity, buf, len, offset);
SetIsValid (verified);
}
} }
template<typename Verifier> template<typename Verifier>
@ -344,6 +342,7 @@ namespace data
offset += propertiesLen; // skip for now. TODO: implement properties offset += propertiesLen; // skip for now. TODO: implement properties
if (offset + 1 >= len) return 0; if (offset + 1 >= len) return 0;
// key sections // key sections
uint16_t currentKeyType = 0;
int numKeySections = buf[offset]; offset++; int numKeySections = buf[offset]; offset++;
for (int i = 0; i < numKeySections; i++) for (int i = 0; i < numKeySections; i++)
{ {
@ -351,10 +350,16 @@ namespace data
if (offset + 2 >= len) return 0; if (offset + 2 >= len) return 0;
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2; uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
if (offset + encryptionKeyLen >= len) return 0; if (offset + encryptionKeyLen >= len) return 0;
if (!m_Encryptor && IsStoreLeases ()) // create encryptor with leases only, first key if (IsStoreLeases ()) // create encryptor with leases only
{ {
// we pick first valid key, higher key type has higher priority 4-1-0
// if two keys with of the same type, pick first
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset); auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
m_Encryptor = encryptor; // TODO: atomic if (encryptor && (!m_Encryptor || keyType > currentKeyType))
{
m_Encryptor = encryptor; // TODO: atomic
currentKeyType = keyType;
}
} }
offset += encryptionKeyLen; offset += encryptionKeyLen;
} }
@ -426,33 +431,21 @@ namespace data
uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds) uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds)
SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds
uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags
std::unique_ptr<i2p::crypto::Verifier> transientVerifier; if (flags & LEASESET2_FLAG_OFFLINE_KEYS)
if (flags & 0x0001)
{ {
// transient key // transient key
if (offset + 6 >= len) return; m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset);
const uint8_t * signedData = buf + offset; if (!m_TransientVerifier)
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ())
{ {
LogPrint (eLogWarning, "LeaseSet2: transient key expired"); LogPrint (eLogError, "LeaseSet2: offline signature failed");
return; return;
} }
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
transientVerifier.reset (i2p::data::IdentityEx::CreateVerifier (keyType));
if (!transientVerifier) return;
auto keyLen = transientVerifier->GetPublicKeyLen ();
if (offset + keyLen >= len) return;
transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
if (offset + blindedVerifier->GetSignatureLen () >= len) return;
if (!blindedVerifier->Verify (signedData, keyLen + 6, buf + offset)) return;
offset += blindedVerifier->GetSignatureLen ();
} }
// outer ciphertext // outer ciphertext
if (offset + 2 > len) return; if (offset + 2 > len) return;
uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2 + lenOuterCiphertext; uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2 + lenOuterCiphertext;
// verify signature // verify signature
bool verified = transientVerifier ? VerifySignature (transientVerifier, buf, len, offset) : bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
VerifySignature (blindedVerifier, buf, len, offset); VerifySignature (blindedVerifier, buf, len, offset);
SetIsValid (verified); SetIsValid (verified);
} }
@ -586,16 +579,24 @@ namespace data
return ident.Verify(ptr, leases - ptr, leases); return ident.Verify(ptr, leases - ptr, leases);
} }
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey, uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels): std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
LocalLeaseSet (identity, nullptr, 0) LocalLeaseSet (keys.GetPublic (), nullptr, 0)
{ {
auto identity = keys.GetPublic ();
// assume standard LS2 // assume standard LS2
int num = tunnels.size (); int num = tunnels.size ();
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ + m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + identity->GetSignatureLen (); 1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
uint16_t flags = 0;
if (keys.IsOfflineSignature ())
{
flags |= LEASESET2_FLAG_OFFLINE_KEYS;
m_BufferLen += keys.GetOfflineSignature ().size ();
}
m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer = new uint8_t[m_BufferLen + 1];
m_Buffer[0] = storeType; m_Buffer[0] = storeType;
// LS2 header // LS2 header
@ -603,7 +604,14 @@ namespace data
auto timestamp = i2p::util::GetSecondsSinceEpoch (); auto timestamp = i2p::util::GetSecondsSinceEpoch ();
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds) htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later uint8_t * expiresBuf = m_Buffer + offset; offset += 2; // expires, fill later
htobe16buf (m_Buffer + offset, 0); offset += 2; // flags htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
if (keys.IsOfflineSignature ())
{
// offline signature
const auto& offlineSignature = keys.GetOfflineSignature ();
memcpy (m_Buffer + offset, offlineSignature.data (), offlineSignature.size ());
offset += offlineSignature.size ();
}
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
// keys // keys
m_Buffer[offset] = 1; offset++; // 1 key m_Buffer[offset] = 1; offset++; // 1 key
@ -628,7 +636,17 @@ namespace data
SetExpirationTime (expirationTime*1000LL); SetExpirationTime (expirationTime*1000LL);
auto expires = expirationTime - timestamp; auto expires = expirationTime - timestamp;
htobe16buf (expiresBuf, expires > 0 ? expires : 0); htobe16buf (expiresBuf, expires > 0 ? expires : 0);
// we don't sign it yet. must be signed later on // sign
keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
}
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
LocalLeaseSet (identity, nullptr, 0)
{
m_BufferLen = len;
m_Buffer = new uint8_t[m_BufferLen + 1];
memcpy (m_Buffer + 1, buf, len);
m_Buffer[0] = storeType;
} }
} }
} }

View File

@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include "Identity.h" #include "Identity.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "I2PEndian.h"
namespace i2p namespace i2p
{ {
@ -77,6 +78,7 @@ namespace data
bool operator== (const LeaseSet& other) const bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; { return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; }; virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
virtual std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return nullptr; };
// implements RoutingDestination // implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; }; std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
@ -122,12 +124,16 @@ namespace data
const uint8_t NETDB_STORE_TYPE_STANDARD_LEASESET2 = 3; const uint8_t NETDB_STORE_TYPE_STANDARD_LEASESET2 = 3;
const uint8_t NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 = 5; const uint8_t NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 = 5;
const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7; const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7;
const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001;
class LeaseSet2: public LeaseSet class LeaseSet2: public LeaseSet
{ {
public: public:
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true); LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true);
uint8_t GetStoreType () const { return m_StoreType; }; uint8_t GetStoreType () const { return m_StoreType; };
std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return m_TransientVerifier; };
void Update (const uint8_t * buf, size_t len, bool verifySignature); void Update (const uint8_t * buf, size_t len, bool verifySignature);
// implements RoutingDestination // implements RoutingDestination
@ -135,7 +141,7 @@ namespace data
private: private:
void ReadFromBuffer (const uint8_t * buf, size_t len); void ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity = true, bool verifySignature = true);
void ReadFromBufferEncrypted (const uint8_t * buf, size_t len); void ReadFromBufferEncrypted (const uint8_t * buf, size_t len);
size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len); size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len);
size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len); size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len);
@ -148,9 +154,31 @@ namespace data
private: private:
uint8_t m_StoreType; uint8_t m_StoreType;
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2 std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
}; };
// also called from Streaming.cpp
template<typename Verifier>
std::shared_ptr<i2p::crypto::Verifier> ProcessOfflineSignature (const Verifier& verifier, const uint8_t * buf, size_t len, size_t& offset)
{
if (offset + 6 >= len) return nullptr;
const uint8_t * signedData = buf + offset;
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ()) return nullptr;
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
std::shared_ptr<i2p::crypto::Verifier> transientVerifier (i2p::data::IdentityEx::CreateVerifier (keyType));
if (!transientVerifier) return nullptr;
auto keyLen = transientVerifier->GetPublicKeyLen ();
if (offset + keyLen >= len) return nullptr;
transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
if (offset + verifier->GetSignatureLen () >= len) return nullptr;
if (!verifier->Verify (signedData, keyLen + 6, buf + offset)) return nullptr;
offset += verifier->GetSignatureLen ();
return transientVerifier;
}
//------------------------------------------------------------------------------------
class LocalLeaseSet class LocalLeaseSet
{ {
public: public:
@ -186,9 +214,10 @@ namespace data
{ {
public: public:
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey, uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels); std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len);
virtual ~LocalLeaseSet2 () { delete[] m_Buffer; }; virtual ~LocalLeaseSet2 () { delete[] m_Buffer; };
uint8_t * GetBuffer () const { return m_Buffer + 1; }; uint8_t * GetBuffer () const { return m_Buffer + 1; };

View File

@ -217,59 +217,15 @@ namespace stream
void Stream::ProcessPacket (Packet * packet) void Stream::ProcessPacket (Packet * packet)
{ {
// process flags
uint32_t receivedSeqn = packet->GetSeqn (); uint32_t receivedSeqn = packet->GetSeqn ();
uint16_t flags = packet->GetFlags (); uint16_t flags = packet->GetFlags ();
LogPrint (eLogDebug, "Streaming: Process seqn=", receivedSeqn, ", flags=", flags); LogPrint (eLogDebug, "Streaming: Process seqn=", receivedSeqn, ", flags=", flags);
const uint8_t * optionData = packet->GetOptionData (); if (!ProcessOptions (flags, packet))
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 ()); m_LocalDestination.DeletePacket (packet);
if (m_RemoteIdentity->IsRSA ()) Terminate ();
{ return;
LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded");
m_LocalDestination.DeletePacket (packet);
Terminate ();
return;
}
optionData += m_RemoteIdentity->GetFullLen ();
if (!m_RemoteLeaseSet)
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
}
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
{
uint16_t maxPacketSize = bufbe16toh (optionData);
LogPrint (eLogDebug, "Streaming: Max packet size ", maxPacketSize);
optionData += 2;
}
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
{
uint8_t signature[256];
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
if(signatureLen <= sizeof(signature))
{
memcpy (signature, optionData, signatureLen);
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature))
{
LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
Close ();
flags |= PACKET_FLAG_CLOSE;
}
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
optionData += signatureLen;
}
else
{
LogPrint(eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
}
} }
packet->offset = packet->GetPayload () - packet->buf; packet->offset = packet->GetPayload () - packet->buf;
@ -298,6 +254,94 @@ namespace stream
} }
} }
bool Stream::ProcessOptions (uint16_t flags, Packet * packet)
{
const uint8_t * optionData = packet->GetOptionData ();
size_t optionSize = packet->GetOptionSize ();
if (flags & PACKET_FLAG_DELAY_REQUESTED)
optionData += 2;
if (flags & PACKET_FLAG_FROM_INCLUDED)
{
if (m_RemoteLeaseSet) m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity ();
if (!m_RemoteIdentity)
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, optionSize);
if (m_RemoteIdentity->IsRSA ())
{
LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded");
return false;
}
optionData += m_RemoteIdentity->GetFullLen ();
if (!m_RemoteLeaseSet)
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
}
if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED)
{
uint16_t maxPacketSize = bufbe16toh (optionData);
LogPrint (eLogDebug, "Streaming: Max packet size ", maxPacketSize);
optionData += 2;
}
if (flags & PACKET_FLAG_OFFLINE_SIGNATURE)
{
if (!m_RemoteIdentity)
{
LogPrint (eLogInfo, "Streaming: offline signature without identity");
return false;
}
// if we have it in LeaseSet already we don't neet parse it again
if (m_RemoteLeaseSet) m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier ();
if (m_TransientVerifier)
{
// skip option data
optionData += 6; // timestamp and key type
optionData += m_TransientVerifier->GetPublicKeyLen (); // public key
optionData += m_RemoteIdentity->GetSignatureLen (); // signature
}
else
{
// transient key
size_t offset = 0;
m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset);
optionData += offset;
if (!m_TransientVerifier)
{
LogPrint (eLogError, "Streaming: offline signature failed");
return false;
}
}
}
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
{
uint8_t signature[256];
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
if(signatureLen <= sizeof(signature))
{
memcpy (signature, optionData, signatureLen);
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
bool verified = m_TransientVerifier ?
m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) :
m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature);
if (!verified)
{
LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
Close ();
flags |= PACKET_FLAG_CLOSE;
}
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
optionData += signatureLen;
}
else
{
LogPrint (eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
return false;
}
}
return true;
}
void Stream::ProcessAck (Packet * packet) void Stream::ProcessAck (Packet * packet)
{ {
bool acknowledged = false; bool acknowledged = false;
@ -438,19 +482,28 @@ namespace stream
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED | uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED; PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
if (isNoAck) flags |= PACKET_FLAG_NO_ACK; if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
htobe16buf (packet + size, flags); htobe16buf (packet + size, flags);
size += 2; // flags size += 2; // flags
size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen (); size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
size_t signatureLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetSignatureLen (); size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
htobe16buf (packet + size, identityLen + signatureLen + 2); // identity + signature + packet size uint8_t * optionsSize = packet + size; // set options size later
size += 2; // options size size += 2; // options size
m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen); m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
size += identityLen; // from size += identityLen; // from
htobe16buf (packet + size, STREAMING_MTU); htobe16buf (packet + size, STREAMING_MTU);
size += 2; // max packet size size += 2; // max packet size
if (isOfflineSignature)
{
const auto& offlineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetOfflineSignature ();
memcpy (packet + size, offlineSignature.data (), offlineSignature.size ());
size += offlineSignature.size (); // offline signature
}
uint8_t * signature = packet + size; // set it later uint8_t * signature = packet + size; // set it later
memset (signature, 0, signatureLen); // zeroes for now memset (signature, 0, signatureLen); // zeroes for now
size += signatureLen; // signature size += signatureLen; // signature
htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
size += m_SendBuffer.Get (packet + size, STREAMING_MTU - size); // payload size += m_SendBuffer.Get (packet + size, STREAMING_MTU - size); // payload
m_LocalDestination.GetOwner ()->Sign (packet, size, signature); m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
} }
@ -849,6 +902,12 @@ namespace stream
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found"); LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // try to request for a next attempt
} }
else
{
// LeaseSet updated
m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity ();
m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier ();
}
} }
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet)
{ {

View File

@ -38,6 +38,7 @@ namespace stream
const uint16_t PACKET_FLAG_PROFILE_INTERACTIVE = 0x0100; const uint16_t PACKET_FLAG_PROFILE_INTERACTIVE = 0x0100;
const uint16_t PACKET_FLAG_ECHO = 0x0200; const uint16_t PACKET_FLAG_ECHO = 0x0200;
const uint16_t PACKET_FLAG_NO_ACK = 0x0400; const uint16_t PACKET_FLAG_NO_ACK = 0x0400;
const uint16_t PACKET_FLAG_OFFLINE_SIGNATURE = 0x0800;
const size_t STREAMING_MTU = 1730; const size_t STREAMING_MTU = 1730;
const size_t MAX_PACKET_SIZE = 4096; const size_t MAX_PACKET_SIZE = 4096;
@ -195,6 +196,7 @@ namespace stream
void SavePacket (Packet * packet); void SavePacket (Packet * packet);
void ProcessPacket (Packet * packet); void ProcessPacket (Packet * packet);
bool ProcessOptions (uint16_t flags, Packet * packet);
void ProcessAck (Packet * packet); void ProcessAck (Packet * packet);
size_t ConcatenatePackets (uint8_t * buf, size_t len); size_t ConcatenatePackets (uint8_t * buf, size_t len);
@ -216,6 +218,7 @@ namespace stream
bool m_IsAckSendScheduled; bool m_IsAckSendScheduled;
StreamingDestination& m_LocalDestination; StreamingDestination& m_LocalDestination;
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity; std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet; std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession; std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease; std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;

View File

@ -51,6 +51,19 @@ namespace tunnel
// create fragments // create fragments
const std::shared_ptr<I2NPMessage> & msg = block.data; const std::shared_ptr<I2NPMessage> & msg = block.data;
size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
if (!messageCreated && fullMsgLen > m_RemainingSize) // check if we should complete previous message
{
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
// length of bytes doesn't fit full tunnel message
// every follow-on fragment adds 7 bytes
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
if (!nonFit || nonFit > m_RemainingSize)
{
CompleteCurrentTunnelDataMessage ();
CreateCurrentTunnelDataMessage ();
}
}
if (fullMsgLen <= m_RemainingSize) if (fullMsgLen <= m_RemainingSize)
{ {
// message fits. First and last fragment // message fits. First and last fragment
@ -65,18 +78,6 @@ namespace tunnel
} }
else else
{ {
if (!messageCreated) // check if we should complete previous message
{
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
// length of bytes don't fit full tunnel message
// every follow-on fragment adds 7 bytes
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
if (!nonFit || nonFit > m_RemainingSize)
{
CompleteCurrentTunnelDataMessage ();
CreateCurrentTunnelDataMessage ();
}
}
if (diLen + 6 <= m_RemainingSize) if (diLen + 6 <= m_RemainingSize)
{ {
// delivery instructions fit // delivery instructions fit

View File

@ -9,6 +9,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <sysinfoapi.h>
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <iphlpapi.h> #include <iphlpapi.h>
@ -21,9 +22,10 @@
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
/* // No more needed. Exists in MinGW. // inet_pton exists Windows since Vista, but XP haven't that function!
int inet_pton(int af, const char *src, void *dst) // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
{ // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found int inet_pton_xp(int af, const char *src, void *dst)
{
struct sockaddr_storage ss; struct sockaddr_storage ss;
int size = sizeof (ss); int size = sizeof (ss);
char src_copy[INET6_ADDRSTRLEN + 1]; char src_copy[INET6_ADDRSTRLEN + 1];
@ -45,7 +47,7 @@ int inet_pton(int af, const char *src, void *dst)
} }
} }
return 0; return 0;
}*/ }
#else /* !WIN32 => UNIX */ #else /* !WIN32 => UNIX */
#include <sys/types.h> #include <sys/types.h>
#include <ifaddrs.h> #include <ifaddrs.h>
@ -58,204 +60,236 @@ namespace util
namespace net namespace net
{ {
#ifdef WIN32 #ifdef WIN32
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback) bool IsWindowsXPorLater()
{ {
ULONG outBufLen = 0; OSVERSIONINFO osvi;
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) if (osvi.dwMajorVersion <= 5)
== ERROR_BUFFER_OVERFLOW) { return true;
FREE(pAddresses); else
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen); return false;
} }
DWORD dwRetVal = GetAdaptersAddresses( int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen {
); ULONG outBufLen = 0;
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if(dwRetVal != NO_ERROR) { if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed"); == ERROR_BUFFER_OVERFLOW)
FREE(pAddresses); {
return fallback; FREE(pAddresses);
} pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
}
pCurrAddresses = pAddresses; DWORD dwRetVal = GetAdaptersAddresses(
while(pCurrAddresses) { AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; );
pUnicast = pCurrAddresses->FirstUnicastAddress; if(dwRetVal != NO_ERROR)
if(pUnicast == nullptr) { {
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv4 address, this is not supported"); LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed");
} FREE(pAddresses);
for(int i = 0; pUnicast != nullptr; ++i) { return fallback;
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; }
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) {
auto result = pAddresses->Mtu;
FREE(pAddresses);
return result;
}
pUnicast = pUnicast->Next;
}
pCurrAddresses = pCurrAddresses->Next;
}
LogPrint(eLogError, "NetIface: GetMTU(): no usable unicast ipv4 addresses found"); pCurrAddresses = pAddresses;
FREE(pAddresses); while(pCurrAddresses)
return fallback; {
} PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
int GetMTUWindowsIpv6(sockaddr_in6 inputAddress, int fallback) pUnicast = pCurrAddresses->FirstUnicastAddress;
{ if(pUnicast == nullptr)
ULONG outBufLen = 0; LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv4 address, this is not supported");
PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) for(int i = 0; pUnicast != nullptr; ++i)
== ERROR_BUFFER_OVERFLOW) { {
FREE(pAddresses); LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen); sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
} if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
{
auto result = pAddresses->Mtu;
FREE(pAddresses);
return result;
}
pUnicast = pUnicast->Next;
}
pCurrAddresses = pCurrAddresses->Next;
}
DWORD dwRetVal = GetAdaptersAddresses( LogPrint(eLogError, "NetIface: GetMTU(): no usable unicast ipv4 addresses found");
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen FREE(pAddresses);
); return fallback;
}
if(dwRetVal != NO_ERROR) { int GetMTUWindowsIpv6(sockaddr_in6 inputAddress, int fallback)
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed"); {
FREE(pAddresses); ULONG outBufLen = 0;
return fallback; PIP_ADAPTER_ADDRESSES pAddresses = nullptr;
} PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
bool found_address = false; if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
pCurrAddresses = pAddresses; == ERROR_BUFFER_OVERFLOW)
while(pCurrAddresses) { {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; FREE(pAddresses);
pUnicast = pCurrAddresses->FirstUnicastAddress; pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen);
if(pUnicast == nullptr) { }
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv6 address, this is not supported");
}
for(int i = 0; pUnicast != nullptr; ++i) {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
for (int j = 0; j != 8; ++j) { DWORD dwRetVal = GetAdaptersAddresses(
if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j]) { AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
break; );
} else {
found_address = true;
}
} if (found_address) {
auto result = pAddresses->Mtu;
FREE(pAddresses);
pAddresses = nullptr;
return result;
}
pUnicast = pUnicast->Next;
}
pCurrAddresses = pCurrAddresses->Next; if(dwRetVal != NO_ERROR)
} {
LogPrint(eLogError, "NetIface: GetMTU(): enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses);
return fallback;
}
LogPrint(eLogError, "NetIface: GetMTU(): no usable unicast ipv6 addresses found"); bool found_address = false;
FREE(pAddresses); pCurrAddresses = pAddresses;
return fallback; while(pCurrAddresses)
} {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress;
if(pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU(): not a unicast ipv6 address, this is not supported");
int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback) for(int i = 0; pUnicast != nullptr; ++i)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
for (int j = 0; j != 8; ++j)
{
if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j])
break;
else
found_address = true;
}
if (found_address)
{
auto result = pAddresses->Mtu;
FREE(pAddresses);
pAddresses = nullptr;
return result;
}
pUnicast = pUnicast->Next;
}
pCurrAddresses = pCurrAddresses->Next;
}
LogPrint(eLogError, "NetIface: GetMTU(): no usable unicast ipv6 addresses found");
FREE(pAddresses);
return fallback;
}
int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback)
{
#ifdef UNICODE #ifdef UNICODE
string localAddress_temporary = localAddress.to_string(); string localAddress_temporary = localAddress.to_string();
wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end()); wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end());
#else #else
std::string localAddressUniversal = localAddress.to_string(); std::string localAddressUniversal = localAddress.to_string();
#endif #endif
if(localAddress.is_v4()) { if (IsWindowsXPorLater())
sockaddr_in inputAddress; {
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr)); #define inet_pton inet_pton_xp
return GetMTUWindowsIpv4(inputAddress, fallback); }
} else if(localAddress.is_v6()) {
sockaddr_in6 inputAddress;
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
return GetMTUWindowsIpv6(inputAddress, fallback);
} else {
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
return fallback;
}
} if(localAddress.is_v4())
{
sockaddr_in inputAddress;
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
return GetMTUWindowsIpv4(inputAddress, fallback);
}
else if(localAddress.is_v6())
{
sockaddr_in6 inputAddress;
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
return GetMTUWindowsIpv6(inputAddress, fallback);
} else {
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
return fallback;
}
}
#else // assume unix #else // assume unix
int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback) int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback)
{ {
ifaddrs* ifaddr, *ifa = nullptr; ifaddrs* ifaddr, *ifa = nullptr;
if(getifaddrs(&ifaddr) == -1) if(getifaddrs(&ifaddr) == -1)
{ {
LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno)); LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno));
return fallback; return fallback;
} }
int family = 0; int family = 0;
// look for interface matching local address // look for interface matching local address
for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{ {
if(!ifa->ifa_addr) if(!ifa->ifa_addr)
continue; continue;
family = ifa->ifa_addr->sa_family; family = ifa->ifa_addr->sa_family;
if(family == AF_INET && localAddress.is_v4()) if(family == AF_INET && localAddress.is_v4())
{ {
sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr; sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr;
if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4)) if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
break; // address matches break; // address matches
} }
else if(family == AF_INET6 && localAddress.is_v6()) else if(family == AF_INET6 && localAddress.is_v6())
{ {
sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr; sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr;
if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16)) if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
break; // address matches break; // address matches
} }
} }
int mtu = fallback; int mtu = fallback;
if(ifa && family) if(ifa && family)
{ // interface found? { // interface found?
int fd = socket(family, SOCK_DGRAM, 0); int fd = socket(family, SOCK_DGRAM, 0);
if(fd > 0) if(fd > 0)
{ {
ifreq ifr; ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query
if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0) if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU mtu = ifr.ifr_mtu; // MTU
else else
LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno)); LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno));
close(fd); close(fd);
} }
else else
LogPrint(eLogError, "NetIface: Failed to create datagram socket"); LogPrint(eLogError, "NetIface: Failed to create datagram socket");
} }
else else
LogPrint(eLogWarning, "NetIface: interface for local address", localAddress.to_string(), " not found"); LogPrint(eLogWarning, "NetIface: interface for local address", localAddress.to_string(), " not found");
freeifaddrs(ifaddr); freeifaddrs(ifaddr);
return mtu; return mtu;
} }
#endif // WIN32 #endif // WIN32
int GetMTU(const boost::asio::ip::address& localAddress) int GetMTU(const boost::asio::ip::address& localAddress)
{ {
const int fallback = 576; // fallback MTU const int fallback = 576; // fallback MTU
#ifdef WIN32 #ifdef WIN32
return GetMTUWindows(localAddress, fallback); return GetMTUWindows(localAddress, fallback);
#else #else
return GetMTUUnix(localAddress, fallback); return GetMTUUnix(localAddress, fallback);
#endif #endif
return fallback; return fallback;
} }
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6) const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6)
{ {
@ -291,7 +325,8 @@ namespace net
} }
if(addrs) freeifaddrs(addrs); if(addrs) freeifaddrs(addrs);
std::string fallback; std::string fallback;
if(ipv6) { if(ipv6)
{
fallback = "::"; fallback = "::";
LogPrint(eLogWarning, "NetIface: cannot find ipv6 address for interface ", ifname); LogPrint(eLogWarning, "NetIface: cannot find ipv6 address for interface ", ifname);
} else { } else {

View File

@ -156,7 +156,7 @@ namespace proxy {
std::stringstream ss; std::stringstream ss;
ss << "<h1>Proxy error: Host not found</h1>\r\n" ss << "<h1>Proxy error: Host not found</h1>\r\n"
<< "<p>Remote host not found in router's addressbook</p>\r\n" << "<p>Remote host not found in router's addressbook</p>\r\n"
<< "<p>You may try to find this host on jumpservices below:</p>\r\n" << "<p>You may try to find this host on jump services below:</p>\r\n"
<< "<ul>\r\n"; << "<ul>\r\n";
for (const auto& js : jumpservices) { for (const auto& js : jumpservices) {
ss << " <li><a href=\"" << js.second << host << "\">" << js.first << "</a></li>\r\n"; ss << " <li><a href=\"" << js.second << host << "\">" << js.first << "</a></li>\r\n";
@ -219,7 +219,11 @@ namespace proxy {
/* replace headers */ /* replace headers */
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)"); req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
/* add headers */ /* add headers */
req.UpdateHeader("Connection", "close"); /* keep-alive conns not supported yet */ /* close connection, if not Connection: (U|u)pgrade (for websocket) */
auto h = req.GetHeader ("Connection");
auto x = h.find("pgrade");
if (!(x != std::string::npos && std::tolower(h[x - 1]) == 'u'))
req.UpdateHeader("Connection", "close");
} }
/** /**
@ -349,7 +353,7 @@ namespace proxy {
else else
GenericProxyError("Outproxy failure", "bad outproxy settings"); GenericProxyError("Outproxy failure", "bad outproxy settings");
} else { } else {
LogPrint (eLogWarning, "HTTPProxy: outproxy failure for ", dest_host, ": no outprxy enabled"); LogPrint (eLogWarning, "HTTPProxy: outproxy failure for ", dest_host, ": no outproxy enabled");
std::string message = "Host " + dest_host + " not inside I2P network, but outproxy is not enabled"; std::string message = "Host " + dest_host + " not inside I2P network, but outproxy is not enabled";
GenericProxyError("Outproxy failure", message.c_str()); GenericProxyError("Outproxy failure", message.c_str());
} }
@ -392,7 +396,7 @@ namespace proxy {
// update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections // update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections
if(m_ClientRequest.method != "CONNECT") if(m_ClientRequest.method != "CONNECT")
m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0"); m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0");
m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequest.write(m_ClientRequestBuffer);
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2016, The PurpleI2P Project * Copyright (c) 2013-2019, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -68,6 +68,13 @@ namespace client
SetLeaseSet (ls); SetLeaseSet (ls);
} }
void I2CPDestination::LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len)
{
auto ls = new i2p::data::LocalLeaseSet2 (storeType, m_Identity, buf, len);
ls->SetExpirationTime (m_LeaseSetExpirationTime);
SetLeaseSet (ls);
}
void I2CPDestination::SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce) void I2CPDestination::SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce)
{ {
auto msg = NewI2NPMessage (); auto msg = NewI2NPMessage ();
@ -512,6 +519,36 @@ namespace client
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID); LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
} }
void I2CPSession::CreateLeaseSet2MessageHandler (const uint8_t * buf, size_t len)
{
uint16_t sessionID = bufbe16toh (buf);
if (sessionID == m_SessionID)
{
size_t offset = 2;
if (m_Destination)
{
uint8_t storeType = buf[offset]; offset++; // store type
// TODO: parse LS2 and obtain correct private keys lengths
size_t signingPrivateKeyLength = 0, encryptionPrivateKeyLength = 0;
if (storeType != i2p::data::NETDB_STORE_TYPE_META_LEASESET2) // no private keys for meta
{
signingPrivateKeyLength = m_Destination->GetIdentity ()->GetSigningPrivateKeyLen (); // no offline keys
encryptionPrivateKeyLength = 256; // ElGamal only
if (len < offset + signingPrivateKeyLength + encryptionPrivateKeyLength)
{
LogPrint (eLogError, "I2CP: CreateLeaseSet2 message is too short ", len);
return;
}
m_Destination->SetEncryptionPrivateKey (buf + len - encryptionPrivateKeyLength);
// ignore signing private key
}
m_Destination->LeaseSet2Created (storeType, buf + offset, len - offset - signingPrivateKeyLength - encryptionPrivateKeyLength);
}
}
else
LogPrint (eLogError, "I2CP: unexpected sessionID ", sessionID);
}
void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len) void I2CPSession::SendMessageMessageHandler (const uint8_t * buf, size_t len)
{ {
uint16_t sessionID = bufbe16toh (buf); uint16_t sessionID = bufbe16toh (buf);
@ -704,6 +741,7 @@ namespace client
m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler; m_MessagesHandlers[I2CP_DESTROY_SESSION_MESSAGE] = &I2CPSession::DestroySessionMessageHandler;
m_MessagesHandlers[I2CP_RECONFIGURE_SESSION_MESSAGE] = &I2CPSession::ReconfigureSessionMessageHandler; m_MessagesHandlers[I2CP_RECONFIGURE_SESSION_MESSAGE] = &I2CPSession::ReconfigureSessionMessageHandler;
m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler; m_MessagesHandlers[I2CP_CREATE_LEASESET_MESSAGE] = &I2CPSession::CreateLeaseSetMessageHandler;
m_MessagesHandlers[I2CP_CREATE_LEASESET2_MESSAGE] = &I2CPSession::CreateLeaseSet2MessageHandler;
m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler; m_MessagesHandlers[I2CP_SEND_MESSAGE_MESSAGE] = &I2CPSession::SendMessageMessageHandler;
m_MessagesHandlers[I2CP_SEND_MESSAGE_EXPIRES_MESSAGE] = &I2CPSession::SendMessageExpiresMessageHandler; m_MessagesHandlers[I2CP_SEND_MESSAGE_EXPIRES_MESSAGE] = &I2CPSession::SendMessageExpiresMessageHandler;
m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler; m_MessagesHandlers[I2CP_HOST_LOOKUP_MESSAGE] = &I2CPSession::HostLookupMessageHandler;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2016, The PurpleI2P Project * Copyright (c) 2013-2019, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -36,6 +36,7 @@ namespace client
const uint8_t I2CP_DESTROY_SESSION_MESSAGE = 3; const uint8_t I2CP_DESTROY_SESSION_MESSAGE = 3;
const uint8_t I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE = 37; const uint8_t I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE = 37;
const uint8_t I2CP_CREATE_LEASESET_MESSAGE = 4; const uint8_t I2CP_CREATE_LEASESET_MESSAGE = 4;
const uint8_t I2CP_CREATE_LEASESET2_MESSAGE = 40;
const uint8_t I2CP_SEND_MESSAGE_MESSAGE = 5; const uint8_t I2CP_SEND_MESSAGE_MESSAGE = 5;
const uint8_t I2CP_SEND_MESSAGE_EXPIRES_MESSAGE = 36; const uint8_t I2CP_SEND_MESSAGE_EXPIRES_MESSAGE = 36;
const uint8_t I2CP_MESSAGE_PAYLOAD_MESSAGE = 31; const uint8_t I2CP_MESSAGE_PAYLOAD_MESSAGE = 31;
@ -68,6 +69,7 @@ namespace client
void SetEncryptionPrivateKey (const uint8_t * key); void SetEncryptionPrivateKey (const uint8_t * key);
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
// implements LocalDestination // implements LocalDestination
@ -126,6 +128,7 @@ namespace client
void DestroySessionMessageHandler (const uint8_t * buf, size_t len); void DestroySessionMessageHandler (const uint8_t * buf, size_t len);
void ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len); void ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len);
void CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len); void CreateLeaseSetMessageHandler (const uint8_t * buf, size_t len);
void CreateLeaseSet2MessageHandler (const uint8_t * buf, size_t len);
void SendMessageMessageHandler (const uint8_t * buf, size_t len); void SendMessageMessageHandler (const uint8_t * buf, size_t len);
void SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len); void SendMessageExpiresMessageHandler (const uint8_t * buf, size_t len);
void HostLookupMessageHandler (const uint8_t * buf, size_t len); void HostLookupMessageHandler (const uint8_t * buf, size_t len);

View File

@ -256,7 +256,13 @@ namespace client
{ {
if (!m_ConnectionSent && !line.compare(0, 10, "Connection")) if (!m_ConnectionSent && !line.compare(0, 10, "Connection"))
{ {
m_OutHeader << "Connection: close\r\n"; /* close connection, if not Connection: (U|u)pgrade (for websocket) */
auto x = line.find("pgrade");
if (x != std::string::npos && std::tolower(line[x - 1]) == 'u')
m_OutHeader << line << "\r\n";
else
m_OutHeader << "Connection: close\r\n";
m_ConnectionSent = true; m_ConnectionSent = true;
} }
else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection")) else if (!m_ProxyConnectionSent && !line.compare(0, 16, "Proxy-Connection"))

View File

@ -963,7 +963,16 @@ namespace client
void SAMBridge::Stop () void SAMBridge::Stop ()
{ {
m_IsRunning = false; m_IsRunning = false;
m_Acceptor.cancel ();
try
{
m_Acceptor.cancel ();
}
catch (const std::exception& ex)
{
LogPrint (eLogError, "SAM: runtime exception: ", ex.what ());
}
for (auto& it: m_Sessions) for (auto& it: m_Sessions)
it.second->CloseStreams (); it.second->CloseStreams ();
m_Sessions.clear (); m_Sessions.clear ();