From aac1141ca6884bd4693127f800cc911c81c5d359 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 11 Feb 2018 06:05:41 -0500 Subject: [PATCH 001/195] fix issue #1107 --- libi2pd/HTTP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/HTTP.cpp b/libi2pd/HTTP.cpp index 24e55457..9bca11d7 100644 --- a/libi2pd/HTTP.cpp +++ b/libi2pd/HTTP.cpp @@ -84,7 +84,7 @@ namespace http { pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */ if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) { std::size_t delim = url.find(':', pos_p); - if (delim != std::string::npos && delim < pos_c) { + if (delim && delim != std::string::npos && delim < pos_c) { user = url.substr(pos_p, delim - pos_p); delim += 1; pass = url.substr(delim, pos_c - delim); From f11266972e81a6db65aeecc3f77fe2b47418385c Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Fri, 30 Mar 2018 15:50:30 +0300 Subject: [PATCH 002/195] Change jni to build executable. Clone with minimal changes DaemonUnix into DaemonAndroid --- android/jni/Android.mk | 8 +- android/jni/Application.mk | 8 +- android/jni/DaemonAndroid.cpp | 356 +++++++++++----------- android/jni/DaemonAndroid.h | 113 +++---- android/jni/i2pd_android.cpp | 66 ---- android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 33 -- 6 files changed, 230 insertions(+), 354 deletions(-) delete mode 100755 android/jni/i2pd_android.cpp delete mode 100644 android/jni/org_purplei2p_i2pd_I2PD_JNI.h diff --git a/android/jni/Android.mk b/android/jni/Android.mk index d5a8f05f..90284995 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -12,15 +12,15 @@ LOCAL_STATIC_LIBRARIES := \ miniupnpc LOCAL_LDLIBS := -lz -LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp $(IFADDRS_PATH)/ifaddrs.c \ +LOCAL_SRC_FILES := DaemonAndroid.cpp $(IFADDRS_PATH)/ifaddrs.c \ $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/Daemon.cpp \ $(DAEMON_SRC_PATH)/UPnP.cpp \ $(DAEMON_SRC_PATH)/HTTPServer.cpp \ - $(DAEMON_SRC_PATH)/I2PControl.cpp - -include $(BUILD_SHARED_LIBRARY) + $(DAEMON_SRC_PATH)/I2PControl.cpp \ + $(DAEMON_SRC_PATH)/i2pd.cpp +include $(BUILD_EXECUTABLE) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 0fa116c2..acc6f895 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -9,12 +9,14 @@ APP_PLATFORM := android-14 # http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse NDK_TOOLCHAIN_VERSION := 4.9 # APP_STL := stlport_shared --> does not seem to contain C++11 features -APP_STL := gnustl_shared +#APP_STL := gnustl_shared +APP_STL := gnustl_static # Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 +APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif @@ -26,7 +28,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /path/to/libraries +I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 75584740..94c679be 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -1,193 +1,193 @@ #include "DaemonAndroid.h" -#include "Daemon.h" -#include -#include -#include -#include -//#include "mainwindow.h" + +#ifndef _WIN32 + +#include +#include +#include +#include +#include +#include +#include + +#include "Config.h" +#include "FS.h" +#include "Log.h" +#include "Tunnel.h" +#include "RouterContext.h" +#include "ClientContext.h" + +void handle_signal(int sig) +{ + switch (sig) + { + case SIGHUP: + LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening tunnel configuration..."); + i2p::client::context.ReloadConfig(); + break; + case SIGUSR1: + LogPrint(eLogInfo, "Daemon: Got SIGUSR1, reopening logs..."); + i2p::log::Logger().Reopen (); + break; + case SIGINT: + if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval) + { + i2p::context.SetAcceptsTunnels (false); + Daemon.gracefulShutdownInterval = 10*60; // 10 minutes + LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds"); + } + else + Daemon.running = 0; + break; + case SIGABRT: + case SIGTERM: + Daemon.running = 0; // Exit loop + break; + case SIGPIPE: + LogPrint(eLogInfo, "SIGPIPE received"); + break; + } +} namespace i2p { -namespace android -{ -/* Worker::Worker (DaemonAndroidImpl& daemon): - m_Daemon (daemon) + namespace util { - } - - void Worker::startDaemon() - { - Log.d(TAG"Performing daemon start..."); - m_Daemon.start(); - Log.d(TAG"Daemon started."); - emit resultReady(); - } - void Worker::restartDaemon() - { - Log.d(TAG"Performing daemon restart..."); - m_Daemon.restart(); - Log.d(TAG"Daemon restarted."); - emit resultReady(); - } - void Worker::stopDaemon() { - Log.d(TAG"Performing daemon stop..."); - m_Daemon.stop(); - Log.d(TAG"Daemon stopped."); - emit resultReady(); - } - - Controller::Controller(DaemonAndroidImpl& daemon): - m_Daemon (daemon) - { - Worker *worker = new Worker (m_Daemon); - worker->moveToThread(&workerThread); - connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); - connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); - connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); - connect(worker, &Worker::resultReady, this, &Controller::handleResults); - workerThread.start(); - } - Controller::~Controller() - { - Log.d(TAG"Closing and waiting for daemon worker thread..."); - workerThread.quit(); - workerThread.wait(); - Log.d(TAG"Waiting for daemon worker thread finished."); - if(m_Daemon.isRunning()) - { - Log.d(TAG"Stopping the daemon..."); - m_Daemon.stop(); - Log.d(TAG"Stopped the daemon."); - } - } -*/ - DaemonAndroidImpl::DaemonAndroidImpl () - //: - /*mutex(nullptr), */ - //m_IsRunning(false), - //m_RunningChangedCallback(nullptr) - { - } - - DaemonAndroidImpl::~DaemonAndroidImpl () - { - //delete mutex; - } - - bool DaemonAndroidImpl::init(int argc, char* argv[]) - { - //mutex=new QMutex(QMutex::Recursive); - //setRunningCallback(0); - //m_IsRunning=false; - return Daemon.init(argc,argv); - } - - void DaemonAndroidImpl::start() - { - //QMutexLocker locker(mutex); - //setRunning(true); - Daemon.start(); - } - - void DaemonAndroidImpl::stop() - { - //QMutexLocker locker(mutex); - Daemon.stop(); - //setRunning(false); - } - - void DaemonAndroidImpl::restart() - { - //QMutexLocker locker(mutex); - stop(); - start(); - } - /* - void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb) - { - m_RunningChangedCallback = cb; - } - - bool DaemonAndroidImpl::isRunning() - { - return m_IsRunning; - } - - void DaemonAndroidImpl::setRunning(bool newValue) - { - bool oldValue = m_IsRunning; - if(oldValue!=newValue) + bool DaemonAndroid::start() { - m_IsRunning = newValue; - if(m_RunningChangedCallback) - m_RunningChangedCallback(); - } - } -*/ - static DaemonAndroidImpl daemon; - static char* argv[1]={strdup("tmp")}; - /** - * returns error details if failed - * returns "ok" if daemon initialized and started okay - */ - std::string start(/*int argc, char* argv[]*/) - { - try - { - //int result; - + if (isDaemon) { - //Log.d(TAG"Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(1,argv); - if(!daemonInitSuccess) - { - //QMessageBox::critical(0, "Error", "Daemon init failed"); - return "Daemon init failed"; - } - //Log.d(TAG"Initialised, creating the main window..."); - //MainWindow w; - //Log.d(TAG"Before main window.show()..."); - //w.show (); + pid_t pid; + pid = fork(); + if (pid > 0) // parent + ::exit (EXIT_SUCCESS); + if (pid < 0) // error { - //i2p::qt::Controller daemonQtController(daemon); - //Log.d(TAG"Starting the daemon..."); - //emit daemonQtController.startDaemon(); - //daemon.start (); - //Log.d(TAG"Starting GUI event loop..."); - //result = app.exec(); - //daemon.stop (); - daemon.start(); + LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno)); + return false; + } + + // child + umask(S_IWGRP | S_IRWXO); // 0027 + int sid = setsid(); + if (sid < 0) + { + LogPrint(eLogError, "Daemon: could not create process group."); + return false; + } + std::string d = i2p::fs::GetDataDir(); + if (chdir(d.c_str()) != 0) + { + LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); + return false; + } + + // point std{in,out,err} descriptors to /dev/null + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stdout); + freopen("/dev/null", "w", stderr); + } + + // set proc limits + struct rlimit limit; + uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); + getrlimit(RLIMIT_NOFILE, &limit); + if (nfiles == 0) { + LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); + } else if (nfiles <= limit.rlim_max) { + limit.rlim_cur = nfiles; + if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { + LogPrint(eLogInfo, "Daemon: set max number of open files to ", + nfiles, " (system limit is ", limit.rlim_max, ")"); + } else { + LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); + } + } else { + LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); + } + uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize); + if (cfsize) // core file size set + { + cfsize *= 1024; + getrlimit(RLIMIT_CORE, &limit); + if (cfsize <= limit.rlim_max) { + limit.rlim_cur = cfsize; + if (setrlimit(RLIMIT_CORE, &limit) != 0) { + LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); + } else if (cfsize == 0) { + LogPrint(eLogInfo, "Daemon: coredumps disabled"); + } else { + LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); + } + } else { + LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); } } - //QMessageBox::information(&w, "Debug", "demon stopped"); - //Log.d(TAG"Exiting the application"); - //return result; - } - catch (boost::exception& ex) - { - std::stringstream ss; - ss << boost::diagnostic_information(ex); - return ss.str(); - } - catch (std::exception& ex) - { - std::stringstream ss; - ss << ex.what(); - return ss.str(); - } - catch(...) - { - return "unknown exception"; - } - return "ok"; - } + // Pidfile + // this code is c-styled and a bit ugly + std::string pidfile; i2p::config::GetOption("pidfile", pidfile); + if (pidfile == "") { + pidfile = i2p::fs::DataDirPath("i2pd.pid"); + } + if (pidfile != "") { + pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); + if (pidFH < 0) + { + LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); + return false; + } + char pid[10]; + sprintf(pid, "%d\n", getpid()); + ftruncate(pidFH, 0); + if (write(pidFH, pid, strlen(pid)) < 0) + { + LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno)); + return false; + } + } + gracefulShutdownInterval = 0; // not specified - void stop() - { - daemon.stop(); + // Signal handler + struct sigaction sa; + sa.sa_handler = handle_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGHUP, &sa, 0); + sigaction(SIGUSR1, &sa, 0); + sigaction(SIGABRT, &sa, 0); + sigaction(SIGTERM, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGPIPE, &sa, 0); + + return Daemon_Singleton::start(); + } + + bool DaemonAndroid::stop() + { + i2p::fs::Remove(pidfile); + + return Daemon_Singleton::stop(); + } + + void DaemonAndroid::run () + { + while (running) + { + std::this_thread::sleep_for (std::chrono::seconds(1)); + if (gracefulShutdownInterval) + { + gracefulShutdownInterval--; // - 1 second + if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0) + { + LogPrint(eLogInfo, "Graceful shutdown"); + return; + } + } + } + } } } -} + +#endif diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index 9cc8219b..c62d7c76 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -1,87 +1,60 @@ -#ifndef DAEMON_ANDROID_H -#define DAEMON_ANDROID_H +#ifndef DAEMON_H__ +#define DAEMON_H__ +#include #include namespace i2p { -namespace android +namespace util { - class DaemonAndroidImpl - { - public: + class Daemon_Singleton_Private; + class Daemon_Singleton + { + public: + virtual bool init(int argc, char* argv[]); + virtual bool start(); + virtual bool stop(); + virtual void run () {}; - DaemonAndroidImpl (); - ~DaemonAndroidImpl (); + bool isDaemon; + bool running; - //typedef void (*runningChangedCallback)(); + protected: + Daemon_Singleton(); + virtual ~Daemon_Singleton(); - /** - * @return success - */ - bool init(int argc, char* argv[]); - void start(); - void stop(); - void restart(); - //void setRunningCallback(runningChangedCallback cb); - //bool isRunning(); - private: - //void setRunning(bool running); - private: - //QMutex* mutex; - //bool m_IsRunning; - //runningChangedCallback m_RunningChangedCallback; - }; + bool IsService () const; - /** - * returns "ok" if daemon init failed - * returns errinfo if daemon initialized and started okay - */ - std::string start(); + // d-pointer for httpServer, httpProxy, etc. + class Daemon_Singleton_Private; + Daemon_Singleton_Private &d; + }; - // stops the daemon - void stop(); +#if defined(ANDROID) +#define Daemon i2p::util::DaemonAndroid::Instance() + class DaemonAndroid : public Daemon_Singleton + { + public: + static DaemonAndroid& Instance() + { + static DaemonAndroid instance; + return instance; + } - /* - class Worker : public QObject - { - Q_OBJECT - public: + bool start(); + bool stop(); + void run (); - Worker (DaemonAndroidImpl& daemon); + private: + std::string pidfile; + int pidFH; - private: - - DaemonAndroidImpl& m_Daemon; - - public slots: - void startDaemon(); - void restartDaemon(); - void stopDaemon(); - - signals: - void resultReady(); - }; - - class Controller : public QObject - { - Q_OBJECT - QThread workerThread; - public: - Controller(DaemonAndroidImpl& daemon); - ~Controller(); - private: - DaemonAndroidImpl& m_Daemon; - - public slots: - void handleResults(){} - signals: - void startDaemon(); - void stopDaemon(); - void restartDaemon(); - }; - */ + public: + int gracefulShutdownInterval; // in seconds + }; +#endif } } -#endif // DAEMON_ANDROID_H +#endif // DAEMON_H__ diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp deleted file mode 100755 index 8791c90b..00000000 --- a/android/jni/i2pd_android.cpp +++ /dev/null @@ -1,66 +0,0 @@ - -//#include -#include -#include "org_purplei2p_i2pd_I2PD_JNI.h" -#include "DaemonAndroid.h" -#include "RouterContext.h" -#include "Transports.h" - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith - (JNIEnv * env, jclass clazz) { -#if defined(__arm__) - #if defined(__ARM_ARCH_7A__) - #if defined(__ARM_NEON__) - #if defined(__ARM_PCS_VFP) - #define ABI "armeabi-v7a/NEON (hard-float)" - #else - #define ABI "armeabi-v7a/NEON" - #endif - #else - #if defined(__ARM_PCS_VFP) - #define ABI "armeabi-v7a (hard-float)" - #else - #define ABI "armeabi-v7a" - #endif - #endif - #else - #define ABI "armeabi" - #endif -#elif defined(__i386__) - #define ABI "x86" -#elif defined(__x86_64__) - #define ABI "x86_64" -#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ - #define ABI "mips64" -#elif defined(__mips__) - #define ABI "mips" -#elif defined(__aarch64__) - #define ABI "arm64-v8a" -#else - #define ABI "unknown" -#endif - - return env->NewStringUTF(ABI); -} - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv * env, jclass clazz) { - return env->NewStringUTF(i2p::android::start().c_str()); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon - (JNIEnv * env, jclass clazz) { - i2p::android::stop(); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels - (JNIEnv * env, jclass clazz) { - i2p::context.SetAcceptsTunnels (false); -} - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged - (JNIEnv * env, jclass clazz, jboolean isConnected) -{ - bool isConnectedBool = (bool) isConnected; - i2p::transport::transports.SetOnline (isConnectedBool); -} diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h deleted file mode 100644 index 04923d22..00000000 --- a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h +++ /dev/null @@ -1,33 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class org_purplei2p_i2pd_I2PD_JNI */ - -#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI -#define _Included_org_purplei2p_i2pd_I2PD_JNI -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: org_purplei2p_i2pd_I2PD_JNI - * Method: stringFromJNI - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith - (JNIEnv *, jclass); - -JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels - (JNIEnv *, jclass); - -JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged - (JNIEnv * env, jclass clazz, jboolean isConnected); - -#ifdef __cplusplus -} -#endif -#endif From ff4e254618a2724a23f316c1ad8c5257640cadc5 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 11 Apr 2018 10:30:13 -0400 Subject: [PATCH 003/195] 0.9.34 --- libi2pd/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/version.h b/libi2pd/version.h index 36e7eb6e..e0443415 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 33 +#define I2P_VERSION_MICRO 34 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From 82534eef1216510eea7e4e5ede9c27d2099953f0 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 11 Apr 2018 20:58:21 +0300 Subject: [PATCH 004/195] try fix appveyor build --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f663c86a..68b74529 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: - MSYSTEM: MINGW32 install: -- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc catgets" +- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu " - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" From 855cc9ed83b0cfb8a6efb844dc872d9a876cbbac Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Apr 2018 19:10:21 -0400 Subject: [PATCH 005/195] correct Proxy-Authroization --- libi2pd_client/HTTPProxy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 47f756d3..ffabb61d 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -282,6 +282,7 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { + m_ClientRequest.RemoveHeader("Proxy-"); std::string uri(m_ClientRequest.uri); auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) @@ -392,7 +393,7 @@ namespace proxy { if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) { // http proxy authorization - std::string s = "basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); + std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); m_ClientRequest.AddHeader("Proxy-Authorization", s); } From 387e030d83cabee89913386271534d1d1259a881 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Apr 2018 21:25:20 -0400 Subject: [PATCH 006/195] correct cleanup for CONNECT --- libi2pd_client/HTTPProxy.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index ffabb61d..2778f24a 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -219,7 +219,7 @@ namespace proxy { /* replace headers */ req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)"); /* add headers */ - req.AddHeader("Connection", "close"); /* keep-alive conns not supported yet */ + req.UpdateHeader("Connection", "close"); /* keep-alive conns not supported yet */ } /** @@ -282,7 +282,7 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { - m_ClientRequest.RemoveHeader("Proxy-"); + SanitizeHTTPRequest (m_ClientRequest); std::string uri(m_ClientRequest.uri); auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) @@ -399,7 +399,7 @@ namespace proxy { m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); - + // assume http if empty schema if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") { From a9b64893d83bffbe8e908e0932b6eab560b40811 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 12:47:53 -0400 Subject: [PATCH 007/195] replace Proxy-Authorization --- libi2pd_client/HTTPProxy.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 2778f24a..5f00ffdb 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -282,7 +282,6 @@ namespace proxy { bool useConnect = false; if(m_ClientRequest.method == "CONNECT") { - SanitizeHTTPRequest (m_ClientRequest); std::string uri(m_ClientRequest.uri); auto pos = uri.find(":"); if(pos == std::string::npos || pos == uri.size() - 1) @@ -392,7 +391,9 @@ namespace proxy { if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) { - // http proxy authorization + // remove existing authorization if any + m_ClientRequest.RemoveHeader("Proxy-"); + // add own http proxy authorization std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); m_ClientRequest.AddHeader("Proxy-Authorization", s); } From 48099a367e3fd967623f042d8f33d791e046cb09 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 15:13:50 -0400 Subject: [PATCH 008/195] send correct buffer to outproxy --- libi2pd_client/HTTPProxy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 5f00ffdb..805b3247 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -408,7 +408,7 @@ namespace proxy { if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { - m_send_buf = m_recv_buf; + m_send_buf = m_ClientRequestBuffer.str (); GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port); } From 17aa91803a0019dd2a557956ff044bcf729434f5 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 15:40:25 -0400 Subject: [PATCH 009/195] update outproxy header in right place --- libi2pd_client/HTTPProxy.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 805b3247..69cda97f 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -389,15 +389,6 @@ namespace proxy { m_ClientRequestURL.host = ""; m_ClientRequest.uri = m_ClientRequestURL.to_string(); - if (m_ProxyURL.schema == "http" && (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ())) - { - // remove existing authorization if any - m_ClientRequest.RemoveHeader("Proxy-"); - // add own http proxy authorization - std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); - m_ClientRequest.AddHeader("Proxy-Authorization", s); - } - m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); @@ -408,7 +399,17 @@ namespace proxy { if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { - m_send_buf = m_ClientRequestBuffer.str (); + if (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ()) + { + // remove existing authorization if any + m_ClientRequest.RemoveHeader("Proxy-"); + // add own http proxy authorization + std::string s = "Basic " + i2p::data::ToBase64Standard (m_ProxyURL.user + ":" + m_ProxyURL.pass); + m_ClientRequest.AddHeader("Proxy-Authorization", s); + } + m_send_buf = m_ClientRequest.to_string(); + m_recv_buf.erase(0, m_req_len); + m_send_buf.append(m_recv_buf); GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete, shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port); } From c175dc30f8b0fd4365f77e310eedbc44e2abcca9 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Apr 2018 16:29:49 -0400 Subject: [PATCH 010/195] correct uri for outproxy --- libi2pd_client/HTTPProxy.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index 69cda97f..ea95a6bd 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -387,6 +387,7 @@ namespace proxy { LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host); m_ClientRequestURL.schema = ""; m_ClientRequestURL.host = ""; + std::string origURI = m_ClientRequest.uri; // TODO: what do we need to chage uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); m_ClientRequest.write(m_ClientRequestBuffer); @@ -399,6 +400,7 @@ namespace proxy { if (!m_ProxyURL.port) m_ProxyURL.port = 80; if (m_ProxyURL.is_i2p()) { + m_ClientRequest.uri = origURI; if (!m_ProxyURL.user.empty () || !m_ProxyURL.pass.empty ()) { // remove existing authorization if any From 83932a6f0272a29e0128a77562f0543492221e75 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 16 Apr 2018 09:38:32 -0400 Subject: [PATCH 011/195] remove streaming bans --- libi2pd/Streaming.cpp | 76 +------------------------------- libi2pd/Streaming.h | 31 ------------- libi2pd_client/ClientContext.cpp | 4 +- libi2pd_client/I2PTunnel.h | 2 - 4 files changed, 3 insertions(+), 110 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 91acc9d0..afcda9ec 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -904,10 +904,7 @@ namespace stream m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_LastIncomingReceiveStreamID (0), m_PendingIncomingTimer (m_Owner->GetService ()), - m_ConnTrackTimer(m_Owner->GetService()), - m_ConnsPerMinute(DEFAULT_MAX_CONNS_PER_MIN), - m_LastBanClear(i2p::util::GetMillisecondsSinceEpoch()), - m_EnableDrop(false) + m_ConnTrackTimer(m_Owner->GetService()) { } @@ -923,7 +920,6 @@ namespace stream void StreamingDestination::Start () { - ScheduleConnTrack(); } void StreamingDestination::Stop () @@ -971,17 +967,7 @@ namespace stream auto incomingStream = CreateNewIncomingStream (); incomingStream->HandleNextPacket (packet); // SYN auto ident = incomingStream->GetRemoteIdentity(); - if(ident && m_EnableDrop) - { - auto ih = ident->GetIdentHash(); - if(DropNewStream(ih)) - { - // drop - LogPrint(eLogWarning, "Streaming: Dropping connection, too many inbound streams from ", ih.ToBase32()); - incomingStream->Terminate(); - return; - } - } + m_LastIncomingReceiveStreamID = receiveStreamID; // handle saved packets if any @@ -1176,63 +1162,5 @@ namespace stream return msg; } - void StreamingDestination::SetMaxConnsPerMinute(const uint32_t conns) - { - m_EnableDrop = conns > 0; - m_ConnsPerMinute = conns; - LogPrint(eLogDebug, "Streaming: Set max conns per minute per destination to ", conns); - } - - bool StreamingDestination::DropNewStream(const i2p::data::IdentHash & ih) - { - std::lock_guard lock(m_ConnsMutex); - if (m_Banned.size() > MAX_BANNED_CONNS) return true; // overload - auto end = std::end(m_Banned); - if ( std::find(std::begin(m_Banned), end, ih) != end) return true; // already banned - auto itr = m_Conns.find(ih); - if (itr == m_Conns.end()) - m_Conns[ih] = 0; - - m_Conns[ih] += 1; - - bool ban = m_Conns[ih] >= m_ConnsPerMinute; - if (ban) - { - m_Banned.push_back(ih); - m_Conns.erase(ih); - LogPrint(eLogWarning, "Streaming: ban ", ih.ToBase32()); - } - return ban; - } - - void StreamingDestination::HandleConnTrack(const boost::system::error_code& ecode) - { - if (ecode != boost::asio::error::operation_aborted) - { - { // acquire lock - std::lock_guard lock(m_ConnsMutex); - // clear conn tracking - m_Conns.clear(); - // check for ban clear - auto ts = i2p::util::GetMillisecondsSinceEpoch(); - if (ts - m_LastBanClear >= DEFAULT_BAN_INTERVAL) - { - // clear bans - m_Banned.clear(); - m_LastBanClear = ts; - } - } - // reschedule timer - ScheduleConnTrack(); - } - } - - void StreamingDestination::ScheduleConnTrack() - { - m_ConnTrackTimer.expires_from_now (boost::posix_time::seconds(60)); - m_ConnTrackTimer.async_wait ( - std::bind (&StreamingDestination::HandleConnTrack, - shared_from_this (), std::placeholders::_1)); - } } } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index a114844d..9ce7e210 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -53,22 +53,6 @@ namespace stream const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int MAX_RECEIVE_TIMEOUT = 30; // in seconds - /** i2cp option for limiting inbound stremaing connections */ - const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns"; - /** default maximum connections attempts per minute per destination */ - const uint32_t DEFAULT_MAX_CONNS_PER_MIN = 600; - - /** - * max banned destinations per local destination - * TODO: make configurable - */ - const uint16_t MAX_BANNED_CONNS = 9999; - /** - * length of a ban in ms - * TODO: make configurable - */ - const uint64_t DEFAULT_BAN_INTERVAL = 60 * 60 * 1000; - struct Packet { size_t len, offset; @@ -273,9 +257,6 @@ namespace stream void HandleDataMessagePayload (const uint8_t * buf, size_t len); std::shared_ptr CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort); - /** set max connections per minute per destination */ - void SetMaxConnsPerMinute(const uint32_t conns); - Packet * NewPacket () { return m_PacketsPool.Acquire(); } void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); } @@ -286,13 +267,6 @@ namespace stream std::shared_ptr CreateNewIncomingStream (); void HandlePendingIncomingTimer (const boost::system::error_code& ecode); - /** handle cleaning up connection tracking for ratelimits */ - void HandleConnTrack(const boost::system::error_code& ecode); - - bool DropNewStream(const i2p::data::IdentHash & ident); - - void ScheduleConnTrack(); - private: std::shared_ptr m_Owner; @@ -310,13 +284,8 @@ namespace stream /** how many connections per minute did each identity have */ std::map m_Conns; boost::asio::deadline_timer m_ConnTrackTimer; - uint32_t m_ConnsPerMinute; - /** banned identities */ - std::vector m_Banned; - uint64_t m_LastBanClear; i2p::util::MemoryPool m_PacketsPool; - bool m_EnableDrop; public: diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index fb8fff97..b04ab885 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -567,7 +567,7 @@ namespace client bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); - uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); + std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); @@ -618,8 +618,6 @@ namespace client else // regular server tunnel by default serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip); - LogPrint(eLogInfo, "Clients: Set Max Conns To ", maxConns); - serverTunnel->SetMaxConnsPerMinute(maxConns); if(!isUniqueLocal) { LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); diff --git a/libi2pd_client/I2PTunnel.h b/libi2pd_client/I2PTunnel.h index 1bdf8bb5..0cff9ad5 100644 --- a/libi2pd_client/I2PTunnel.h +++ b/libi2pd_client/I2PTunnel.h @@ -280,8 +280,6 @@ namespace client const char* GetName() { return m_Name.c_str (); } - void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); } - private: void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, std::shared_ptr resolver); From eefbbd4efed3db5300a7593eb12d3d7b32dafd66 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 16 Apr 2018 09:47:35 -0400 Subject: [PATCH 012/195] remove all related streaming limit members --- libi2pd/Streaming.cpp | 8 +------- libi2pd/Streaming.h | 5 ----- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index afcda9ec..dd8e3634 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -903,8 +903,7 @@ namespace stream StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort, bool gzip): m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip), m_LastIncomingReceiveStreamID (0), - m_PendingIncomingTimer (m_Owner->GetService ()), - m_ConnTrackTimer(m_Owner->GetService()) + m_PendingIncomingTimer (m_Owner->GetService ()) { } @@ -927,15 +926,10 @@ namespace stream ResetAcceptor (); m_PendingIncomingTimer.cancel (); m_PendingIncomingStreams.clear (); - m_ConnTrackTimer.cancel(); { std::unique_lock l(m_StreamsMutex); m_Streams.clear (); } - { - std::unique_lock l(m_ConnsMutex); - m_Conns.clear (); - } } void StreamingDestination::HandleNextPacket (Packet * packet) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 9ce7e210..47f99833 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -280,11 +280,6 @@ namespace stream boost::asio::deadline_timer m_PendingIncomingTimer; std::map > m_SavedPackets; // receiveStreamID->packets, arrived before SYN - std::mutex m_ConnsMutex; - /** how many connections per minute did each identity have */ - std::map m_Conns; - boost::asio::deadline_timer m_ConnTrackTimer; - i2p::util::MemoryPool m_PacketsPool; public: From 0c661e7373c4463cfce31f70fd9c574f7d9f12fb Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Apr 2018 15:08:06 -0400 Subject: [PATCH 013/195] save new local destination for failed insert --- libi2pd_client/ClientContext.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index b04ab885..6c3a9410 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -531,6 +531,7 @@ namespace client LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout); } + auto clientTunnelDest = clientTunnel->GetLocalDestination (); // make copy of destination for possible update auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr(clientTunnel))); if (ins.second) { @@ -540,10 +541,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) + if (ins.first->second->GetLocalDestination () != clientTunnelDest) { LogPrint (eLogInfo, "Clients: I2P client tunnel destination updated"); - ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); + ins.first->second->SetLocalDestination (clientTunnelDest); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, " already exists"); @@ -639,6 +640,7 @@ namespace client while (comma != std::string::npos); serverTunnel->SetAccessList (idents); } + auto serverTunnelDest = serverTunnel->GetLocalDestination (); auto ins = m_ServerTunnels.insert (std::make_pair ( std::make_pair (localDestination->GetIdentHash (), inPort), std::unique_ptr(serverTunnel))); @@ -650,10 +652,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ()) + if (ins.first->second->GetLocalDestination () != serverTunnelDest) { LogPrint (eLogInfo, "Clients: I2P server tunnel destination updated"); - ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); + ins.first->second->SetLocalDestination (serverTunnelDest); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); From e2da16e9c32d2d7be8a1ec24fb03938653abbc61 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 19 Apr 2018 19:46:00 +0300 Subject: [PATCH 014/195] moved reseed out --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index d9cc6dec..126de7fc 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -191,7 +191,7 @@ namespace config { // "https://uk.reseed.i2p2.no:444/," // mamoth's shit "https://i2p-0.manas.ca:8443/," "https://download.xxlspeed.com/," - "https://reseed-ru.lngserv.ru/," + "https://reseed-fr.i2pd.xyz/," "https://reseed.atomike.ninja/," "https://reseed.memcpy.io/," "https://reseed.onion.im/," From 6916147dda4a4b46a1049d38bf81b5c6c9abb264 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sat, 21 Apr 2018 21:48:42 +0300 Subject: [PATCH 015/195] Few cents to get fullly console i2pd under Android --- android/i2pd/Android.mk | 74 +++++++++++++++++++++++++++++++++++++ android/i2pd/Application.mk | 42 +++++++++++++++++++++ daemon/Daemon.h | 13 ------- daemon/UnixDaemon.cpp | 3 ++ 4 files changed, 119 insertions(+), 13 deletions(-) create mode 100755 android/i2pd/Android.mk create mode 100755 android/i2pd/Application.mk diff --git a/android/i2pd/Android.mk b/android/i2pd/Android.mk new file mode 100755 index 00000000..ae56110c --- /dev/null +++ b/android/i2pd/Android.mk @@ -0,0 +1,74 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := i2pd +LOCAL_CPP_FEATURES := rtti exceptions +LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(DAEMON_SRC_PATH) +LOCAL_STATIC_LIBRARIES := \ + boost_system \ + boost_date_time \ + boost_filesystem \ + boost_program_options \ + crypto ssl \ + miniupnpc +LOCAL_LDLIBS := -lz + +LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \ + $(wildcard $(LIB_SRC_PATH)/*.cpp)\ + $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ + $(DAEMON_SRC_PATH)/UnixDaemon.cpp \ + $(DAEMON_SRC_PATH)/Daemon.cpp \ + $(DAEMON_SRC_PATH)/UPnP.cpp \ + $(DAEMON_SRC_PATH)/HTTPServer.cpp \ + $(DAEMON_SRC_PATH)/I2PControl.cpp \ + $(DAEMON_SRC_PATH)/i2pd.cpp +include $(BUILD_EXECUTABLE) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_system +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_62_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_date_time +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_62_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_filesystem +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_62_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_program_options +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_62_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_62_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := crypto +LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.0e/$(TARGET_ARCH_ABI)/lib/libcrypto.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.0e/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := ssl +LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.0e/$(TARGET_ARCH_ABI)/lib/libssl.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.0e/include +LOCAL_STATIC_LIBRARIES := crypto +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := miniupnpc +LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a +LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include +include $(PREBUILT_STATIC_LIBRARY) diff --git a/android/i2pd/Application.mk b/android/i2pd/Application.mk new file mode 100755 index 00000000..acc6f895 --- /dev/null +++ b/android/i2pd/Application.mk @@ -0,0 +1,42 @@ +#APP_ABI := all +#APP_ABI := armeabi-v7a x86 +#APP_ABI := x86 +#APP_ABI := x86_64 +APP_ABI := armeabi-v7a +#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there. +APP_PLATFORM := android-14 + +# http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse +NDK_TOOLCHAIN_VERSION := 4.9 +# APP_STL := stlport_shared --> does not seem to contain C++11 features +#APP_STL := gnustl_shared +APP_STL := gnustl_static + +# Enable c++11 extensions in source code +APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE + +APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_LDFLAGS += -rdynamic -fPIE -pie +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +APP_CPPFLAGS += -DANDROID_ARM7A +endif + +APP_OPTIM := debug + +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/android-ifaddrs.git +# change to your own +I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs +BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt +OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt +MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt +IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs + +# don't change me +I2PD_SRC_PATH = $(PWD)/.. + +LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd +LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client +DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 48301e73..f3e72904 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -44,19 +44,6 @@ namespace util } }; -#elif defined(ANDROID) -#define Daemon i2p::util::DaemonAndroid::Instance() - // dummy, invoked from android/jni/DaemonAndroid.* - class DaemonAndroid: public i2p::util::Daemon_Singleton - { - public: - static DaemonAndroid& Instance() - { - static DaemonAndroid instance; - return instance; - } - }; - #elif defined(_WIN32) #define Daemon i2p::util::DaemonWin32::Instance() class DaemonWin32 : public Daemon_Singleton diff --git a/daemon/UnixDaemon.cpp b/daemon/UnixDaemon.cpp index a9c48fee..3dd38fba 100644 --- a/daemon/UnixDaemon.cpp +++ b/daemon/UnixDaemon.cpp @@ -138,11 +138,14 @@ namespace i2p LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); return false; } + +#ifndef ANDROID if (lockf(pidFH, F_TLOCK, 0) != 0) { LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno)); return false; } +#endif char pid[10]; sprintf(pid, "%d\n", getpid()); ftruncate(pidFH, 0); From faac35cd1e868d888bba722164b7b3037af0ce46 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sat, 21 Apr 2018 21:55:45 +0300 Subject: [PATCH 016/195] Revert "Change jni to build executable. Clone with minimal changes DaemonUnix into DaemonAndroid" This reverts commit f11266972e81a6db65aeecc3f77fe2b47418385c. --- android/jni/Android.mk | 8 +- android/jni/Application.mk | 8 +- android/jni/DaemonAndroid.cpp | 366 +++++++++++----------- android/jni/DaemonAndroid.h | 113 ++++--- android/jni/i2pd_android.cpp | 66 ++++ android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 33 ++ 6 files changed, 359 insertions(+), 235 deletions(-) create mode 100755 android/jni/i2pd_android.cpp create mode 100644 android/jni/org_purplei2p_i2pd_I2PD_JNI.h diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 90284995..d5a8f05f 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -12,15 +12,15 @@ LOCAL_STATIC_LIBRARIES := \ miniupnpc LOCAL_LDLIBS := -lz -LOCAL_SRC_FILES := DaemonAndroid.cpp $(IFADDRS_PATH)/ifaddrs.c \ +LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp $(IFADDRS_PATH)/ifaddrs.c \ $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/Daemon.cpp \ $(DAEMON_SRC_PATH)/UPnP.cpp \ $(DAEMON_SRC_PATH)/HTTPServer.cpp \ - $(DAEMON_SRC_PATH)/I2PControl.cpp \ - $(DAEMON_SRC_PATH)/i2pd.cpp -include $(BUILD_EXECUTABLE) + $(DAEMON_SRC_PATH)/I2PControl.cpp + +include $(BUILD_SHARED_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index acc6f895..0fa116c2 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -9,14 +9,12 @@ APP_PLATFORM := android-14 # http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse NDK_TOOLCHAIN_VERSION := 4.9 # APP_STL := stlport_shared --> does not seem to contain C++11 features -#APP_STL := gnustl_shared -APP_STL := gnustl_static +APP_STL := gnustl_shared # Enable c++11 extensions in source code -APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE +APP_CPPFLAGS += -std=c++11 APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP -APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif @@ -28,7 +26,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs +I2PD_LIBS_PATH = /path/to/libraries BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 94c679be..75584740 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -1,193 +1,193 @@ #include "DaemonAndroid.h" - -#ifndef _WIN32 - -#include -#include -#include -#include -#include -#include -#include - -#include "Config.h" -#include "FS.h" -#include "Log.h" -#include "Tunnel.h" -#include "RouterContext.h" -#include "ClientContext.h" - -void handle_signal(int sig) -{ - switch (sig) - { - case SIGHUP: - LogPrint(eLogInfo, "Daemon: Got SIGHUP, reopening tunnel configuration..."); - i2p::client::context.ReloadConfig(); - break; - case SIGUSR1: - LogPrint(eLogInfo, "Daemon: Got SIGUSR1, reopening logs..."); - i2p::log::Logger().Reopen (); - break; - case SIGINT: - if (i2p::context.AcceptsTunnels () && !Daemon.gracefulShutdownInterval) - { - i2p::context.SetAcceptsTunnels (false); - Daemon.gracefulShutdownInterval = 10*60; // 10 minutes - LogPrint(eLogInfo, "Graceful shutdown after ", Daemon.gracefulShutdownInterval, " seconds"); - } - else - Daemon.running = 0; - break; - case SIGABRT: - case SIGTERM: - Daemon.running = 0; // Exit loop - break; - case SIGPIPE: - LogPrint(eLogInfo, "SIGPIPE received"); - break; - } -} +#include "Daemon.h" +#include +#include +#include +#include +//#include "mainwindow.h" namespace i2p { - namespace util +namespace android +{ +/* Worker::Worker (DaemonAndroidImpl& daemon): + m_Daemon (daemon) { - bool DaemonAndroid::start() - { - if (isDaemon) - { - pid_t pid; - pid = fork(); - if (pid > 0) // parent - ::exit (EXIT_SUCCESS); + } - if (pid < 0) // error - { - LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno)); - return false; - } + void Worker::startDaemon() + { + Log.d(TAG"Performing daemon start..."); + m_Daemon.start(); + Log.d(TAG"Daemon started."); + emit resultReady(); + } + void Worker::restartDaemon() + { + Log.d(TAG"Performing daemon restart..."); + m_Daemon.restart(); + Log.d(TAG"Daemon restarted."); + emit resultReady(); + } + void Worker::stopDaemon() { + Log.d(TAG"Performing daemon stop..."); + m_Daemon.stop(); + Log.d(TAG"Daemon stopped."); + emit resultReady(); + } - // child - umask(S_IWGRP | S_IRWXO); // 0027 - int sid = setsid(); - if (sid < 0) - { - LogPrint(eLogError, "Daemon: could not create process group."); - return false; - } - std::string d = i2p::fs::GetDataDir(); - if (chdir(d.c_str()) != 0) - { - LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); - return false; - } - - // point std{in,out,err} descriptors to /dev/null - freopen("/dev/null", "r", stdin); - freopen("/dev/null", "w", stdout); - freopen("/dev/null", "w", stderr); - } - - // set proc limits - struct rlimit limit; - uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); - getrlimit(RLIMIT_NOFILE, &limit); - if (nfiles == 0) { - LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); - } else if (nfiles <= limit.rlim_max) { - limit.rlim_cur = nfiles; - if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { - LogPrint(eLogInfo, "Daemon: set max number of open files to ", - nfiles, " (system limit is ", limit.rlim_max, ")"); - } else { - LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); - } - } else { - LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); - } - uint32_t cfsize; i2p::config::GetOption("limits.coresize", cfsize); - if (cfsize) // core file size set - { - cfsize *= 1024; - getrlimit(RLIMIT_CORE, &limit); - if (cfsize <= limit.rlim_max) { - limit.rlim_cur = cfsize; - if (setrlimit(RLIMIT_CORE, &limit) != 0) { - LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); - } else if (cfsize == 0) { - LogPrint(eLogInfo, "Daemon: coredumps disabled"); - } else { - LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); - } - } else { - LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); - } - } - - // Pidfile - // this code is c-styled and a bit ugly - std::string pidfile; i2p::config::GetOption("pidfile", pidfile); - if (pidfile == "") { - pidfile = i2p::fs::DataDirPath("i2pd.pid"); - } - if (pidfile != "") { - pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); - if (pidFH < 0) - { - LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); - return false; - } - char pid[10]; - sprintf(pid, "%d\n", getpid()); - ftruncate(pidFH, 0); - if (write(pidFH, pid, strlen(pid)) < 0) - { - LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno)); - return false; - } - } - gracefulShutdownInterval = 0; // not specified - - // Signal handler - struct sigaction sa; - sa.sa_handler = handle_signal; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGHUP, &sa, 0); - sigaction(SIGUSR1, &sa, 0); - sigaction(SIGABRT, &sa, 0); - sigaction(SIGTERM, &sa, 0); - sigaction(SIGINT, &sa, 0); - sigaction(SIGPIPE, &sa, 0); - - return Daemon_Singleton::start(); - } - - bool DaemonAndroid::stop() - { - i2p::fs::Remove(pidfile); - - return Daemon_Singleton::stop(); - } - - void DaemonAndroid::run () - { - while (running) - { - std::this_thread::sleep_for (std::chrono::seconds(1)); - if (gracefulShutdownInterval) - { - gracefulShutdownInterval--; // - 1 second - if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0) - { - LogPrint(eLogInfo, "Graceful shutdown"); - return; - } - } - } + Controller::Controller(DaemonAndroidImpl& daemon): + m_Daemon (daemon) + { + Worker *worker = new Worker (m_Daemon); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); + connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); + connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); + connect(worker, &Worker::resultReady, this, &Controller::handleResults); + workerThread.start(); + } + Controller::~Controller() + { + Log.d(TAG"Closing and waiting for daemon worker thread..."); + workerThread.quit(); + workerThread.wait(); + Log.d(TAG"Waiting for daemon worker thread finished."); + if(m_Daemon.isRunning()) + { + Log.d(TAG"Stopping the daemon..."); + m_Daemon.stop(); + Log.d(TAG"Stopped the daemon."); } } -} +*/ + DaemonAndroidImpl::DaemonAndroidImpl () + //: + /*mutex(nullptr), */ + //m_IsRunning(false), + //m_RunningChangedCallback(nullptr) + { + } -#endif + DaemonAndroidImpl::~DaemonAndroidImpl () + { + //delete mutex; + } + + bool DaemonAndroidImpl::init(int argc, char* argv[]) + { + //mutex=new QMutex(QMutex::Recursive); + //setRunningCallback(0); + //m_IsRunning=false; + return Daemon.init(argc,argv); + } + + void DaemonAndroidImpl::start() + { + //QMutexLocker locker(mutex); + //setRunning(true); + Daemon.start(); + } + + void DaemonAndroidImpl::stop() + { + //QMutexLocker locker(mutex); + Daemon.stop(); + //setRunning(false); + } + + void DaemonAndroidImpl::restart() + { + //QMutexLocker locker(mutex); + stop(); + start(); + } + /* + void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb) + { + m_RunningChangedCallback = cb; + } + + bool DaemonAndroidImpl::isRunning() + { + return m_IsRunning; + } + + void DaemonAndroidImpl::setRunning(bool newValue) + { + bool oldValue = m_IsRunning; + if(oldValue!=newValue) + { + m_IsRunning = newValue; + if(m_RunningChangedCallback) + m_RunningChangedCallback(); + } + } +*/ + static DaemonAndroidImpl daemon; + static char* argv[1]={strdup("tmp")}; + /** + * returns error details if failed + * returns "ok" if daemon initialized and started okay + */ + std::string start(/*int argc, char* argv[]*/) + { + try + { + //int result; + + { + //Log.d(TAG"Initialising the daemon..."); + bool daemonInitSuccess = daemon.init(1,argv); + if(!daemonInitSuccess) + { + //QMessageBox::critical(0, "Error", "Daemon init failed"); + return "Daemon init failed"; + } + //Log.d(TAG"Initialised, creating the main window..."); + //MainWindow w; + //Log.d(TAG"Before main window.show()..."); + //w.show (); + + { + //i2p::qt::Controller daemonQtController(daemon); + //Log.d(TAG"Starting the daemon..."); + //emit daemonQtController.startDaemon(); + //daemon.start (); + //Log.d(TAG"Starting GUI event loop..."); + //result = app.exec(); + //daemon.stop (); + daemon.start(); + } + } + + //QMessageBox::information(&w, "Debug", "demon stopped"); + //Log.d(TAG"Exiting the application"); + //return result; + } + catch (boost::exception& ex) + { + std::stringstream ss; + ss << boost::diagnostic_information(ex); + return ss.str(); + } + catch (std::exception& ex) + { + std::stringstream ss; + ss << ex.what(); + return ss.str(); + } + catch(...) + { + return "unknown exception"; + } + return "ok"; + } + + void stop() + { + daemon.stop(); + } +} +} diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index c62d7c76..9cc8219b 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -1,60 +1,87 @@ -#ifndef DAEMON_H__ -#define DAEMON_H__ +#ifndef DAEMON_ANDROID_H +#define DAEMON_ANDROID_H -#include #include namespace i2p { -namespace util +namespace android { - class Daemon_Singleton_Private; - class Daemon_Singleton - { - public: - virtual bool init(int argc, char* argv[]); - virtual bool start(); - virtual bool stop(); - virtual void run () {}; + class DaemonAndroidImpl + { + public: - bool isDaemon; - bool running; + DaemonAndroidImpl (); + ~DaemonAndroidImpl (); - protected: - Daemon_Singleton(); - virtual ~Daemon_Singleton(); + //typedef void (*runningChangedCallback)(); - bool IsService () const; + /** + * @return success + */ + bool init(int argc, char* argv[]); + void start(); + void stop(); + void restart(); + //void setRunningCallback(runningChangedCallback cb); + //bool isRunning(); + private: + //void setRunning(bool running); + private: + //QMutex* mutex; + //bool m_IsRunning; + //runningChangedCallback m_RunningChangedCallback; + }; - // d-pointer for httpServer, httpProxy, etc. - class Daemon_Singleton_Private; - Daemon_Singleton_Private &d; - }; + /** + * returns "ok" if daemon init failed + * returns errinfo if daemon initialized and started okay + */ + std::string start(); -#if defined(ANDROID) -#define Daemon i2p::util::DaemonAndroid::Instance() - class DaemonAndroid : public Daemon_Singleton - { - public: - static DaemonAndroid& Instance() - { - static DaemonAndroid instance; - return instance; - } + // stops the daemon + void stop(); - bool start(); - bool stop(); - void run (); + /* + class Worker : public QObject + { + Q_OBJECT + public: - private: - std::string pidfile; - int pidFH; + Worker (DaemonAndroidImpl& daemon); - public: - int gracefulShutdownInterval; // in seconds - }; -#endif + private: + + DaemonAndroidImpl& m_Daemon; + + public slots: + void startDaemon(); + void restartDaemon(); + void stopDaemon(); + + signals: + void resultReady(); + }; + + class Controller : public QObject + { + Q_OBJECT + QThread workerThread; + public: + Controller(DaemonAndroidImpl& daemon); + ~Controller(); + private: + DaemonAndroidImpl& m_Daemon; + + public slots: + void handleResults(){} + signals: + void startDaemon(); + void stopDaemon(); + void restartDaemon(); + }; + */ } } -#endif // DAEMON_H__ +#endif // DAEMON_ANDROID_H diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp new file mode 100755 index 00000000..8791c90b --- /dev/null +++ b/android/jni/i2pd_android.cpp @@ -0,0 +1,66 @@ + +//#include +#include +#include "org_purplei2p_i2pd_I2PD_JNI.h" +#include "DaemonAndroid.h" +#include "RouterContext.h" +#include "Transports.h" + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv * env, jclass clazz) { +#if defined(__arm__) + #if defined(__ARM_ARCH_7A__) + #if defined(__ARM_NEON__) + #if defined(__ARM_PCS_VFP) + #define ABI "armeabi-v7a/NEON (hard-float)" + #else + #define ABI "armeabi-v7a/NEON" + #endif + #else + #if defined(__ARM_PCS_VFP) + #define ABI "armeabi-v7a (hard-float)" + #else + #define ABI "armeabi-v7a" + #endif + #endif + #else + #define ABI "armeabi" + #endif +#elif defined(__i386__) + #define ABI "x86" +#elif defined(__x86_64__) + #define ABI "x86_64" +#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ + #define ABI "mips64" +#elif defined(__mips__) + #define ABI "mips" +#elif defined(__aarch64__) + #define ABI "arm64-v8a" +#else + #define ABI "unknown" +#endif + + return env->NewStringUTF(ABI); +} + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv * env, jclass clazz) { + return env->NewStringUTF(i2p::android::start().c_str()); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv * env, jclass clazz) { + i2p::android::stop(); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels + (JNIEnv * env, jclass clazz) { + i2p::context.SetAcceptsTunnels (false); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged + (JNIEnv * env, jclass clazz, jboolean isConnected) +{ + bool isConnectedBool = (bool) isConnected; + i2p::transport::transports.SetOnline (isConnectedBool); +} diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h new file mode 100644 index 00000000..04923d22 --- /dev/null +++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -0,0 +1,33 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_purplei2p_i2pd_I2PD_JNI */ + +#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI +#define _Included_org_purplei2p_i2pd_I2PD_JNI +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_purplei2p_i2pd_I2PD_JNI + * Method: stringFromJNI + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv *, jclass); + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged + (JNIEnv * env, jclass clazz, jboolean isConnected); + +#ifdef __cplusplus +} +#endif +#endif From c8de7aa23c5a17c35520e7606459da4e9e770111 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Tue, 24 Apr 2018 01:40:12 +0800 Subject: [PATCH 017/195] qt now statically compiles for win32 --- qt/i2pd_qt/ServerTunnelPane.cpp | 18 ------------------ qt/i2pd_qt/ServerTunnelPane.h | 13 ------------- qt/i2pd_qt/TunnelConfig.cpp | 3 +-- qt/i2pd_qt/TunnelConfig.h | 6 ------ qt/i2pd_qt/i2pd_qt.pro | 23 ++++++++++++++++++++--- qt/i2pd_qt/mainwindow.h | 4 ---- 6 files changed, 21 insertions(+), 46 deletions(-) diff --git a/qt/i2pd_qt/ServerTunnelPane.cpp b/qt/i2pd_qt/ServerTunnelPane.cpp index 029a3ea2..bc6389a9 100644 --- a/qt/i2pd_qt/ServerTunnelPane.cpp +++ b/qt/i2pd_qt/ServerTunnelPane.cpp @@ -204,24 +204,6 @@ int ServerTunnelPane::appendServerTunnelForm( horizontalLayout_2->addItem(horizontalSpacer); tunnelGridLayout->addLayout(horizontalLayout_2); } - { - uint32_t maxConns = tunnelConfig->getmaxConns(); - QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); - horizontalLayout_2->setObjectName(QStringLiteral("horizontalLayout_2")); - ui.maxConnsLabel = new QLabel(gridLayoutWidget_2); - maxConnsLabel->setObjectName(QStringLiteral("maxConnsLabel")); - horizontalLayout_2->addWidget(maxConnsLabel); - ui.maxConnsLineEdit = new QLineEdit(gridLayoutWidget_2); - maxConnsLineEdit->setObjectName(QStringLiteral("maxConnsLineEdit")); - maxConnsLineEdit->setText(QString::number(maxConns)); - maxConnsLineEdit->setMaximumWidth(80); - QObject::connect(maxConnsLineEdit, SIGNAL(textChanged(const QString &)), - this, SLOT(updated())); - horizontalLayout_2->addWidget(maxConnsLineEdit); - QSpacerItem * horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); - horizontalLayout_2->addItem(horizontalSpacer); - tunnelGridLayout->addLayout(horizontalLayout_2); - } { std::string address = tunnelConfig->getaddress(); QHBoxLayout *horizontalLayout_2 = new QHBoxLayout(); diff --git a/qt/i2pd_qt/ServerTunnelPane.h b/qt/i2pd_qt/ServerTunnelPane.h index 556c8473..0a07267b 100644 --- a/qt/i2pd_qt/ServerTunnelPane.h +++ b/qt/i2pd_qt/ServerTunnelPane.h @@ -81,10 +81,6 @@ private: QLabel * addressLabel; QLineEdit * addressLineEdit; - //maxConns - QLabel * maxConnsLabel; - QLineEdit * maxConnsLineEdit; - //gzip QCheckBox * gzipCheckBox; @@ -109,7 +105,6 @@ private: hostOverrideLabel->setText(QApplication::translate("srvTunForm", "Host override:", 0)); webIRCPassLabel->setText(QApplication::translate("srvTunForm", "WebIRC password:", 0)); addressLabel->setText(QApplication::translate("srvTunForm", "Address:", 0)); - maxConnsLabel->setText(QApplication::translate("srvTunForm", "Max connections:", 0)); gzipCheckBox->setText(QApplication::translate("srvTunForm", "GZip", 0)); isUniqueLocalCheckBox->setText(QApplication::translate("srvTunForm", "Is unique local", 0)); @@ -152,14 +147,6 @@ protected: stc->setaddress(addressLineEdit->text().toStdString()); - auto mcStr=maxConnsLineEdit->text(); - uint32_t mcInt=(uint32_t)mcStr.toInt(&ok); - if(!ok){ - highlightWrongInput(QApplication::tr("Bad maxConns, must be int.")+" "+cannotSaveSettings,maxConnsLineEdit); - return false; - } - stc->setmaxConns(mcInt); - stc->setgzip(gzipCheckBox->isChecked()); stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked()); diff --git a/qt/i2pd_qt/TunnelConfig.cpp b/qt/i2pd_qt/TunnelConfig.cpp index 81216c0b..e4354b62 100644 --- a/qt/i2pd_qt/TunnelConfig.cpp +++ b/qt/i2pd_qt/TunnelConfig.cpp @@ -48,7 +48,6 @@ void ServerTunnelConfig::saveToStringStream(std::stringstream& out) { << "enableuniquelocal=" << (isUniqueLocal?"true":"false") << "\n" << "address=" << address << "\n" << "hostoverride=" << hostOverride << "\n" - << "webircpassword=" << webircpass << "\n" - << "maxconns=" << maxConns << "\n"; + << "webircpassword=" << webircpass << "\n"; } diff --git a/qt/i2pd_qt/TunnelConfig.h b/qt/i2pd_qt/TunnelConfig.h index c714a4f5..58a1fa0b 100644 --- a/qt/i2pd_qt/TunnelConfig.h +++ b/qt/i2pd_qt/TunnelConfig.h @@ -148,7 +148,6 @@ public: std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); - uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); # * inport -- optional, i2p service port, if unset - the same as 'port' @@ -170,7 +169,6 @@ class ServerTunnelConfig : public TunnelConfig { std::string webircpass; bool gzip; i2p::data::SigningKeyType sigType; - uint32_t maxConns; std::string address; bool isUniqueLocal; public: @@ -184,7 +182,6 @@ public: std::string webircpass_, bool gzip_, i2p::data::SigningKeyType sigType_, - uint32_t maxConns_, std::string address_, bool isUniqueLocal_): TunnelConfig(name_, type_, i2cpParameters_), host(host_), @@ -196,7 +193,6 @@ public: webircpass(webircpass_), gzip(gzip_), sigType(sigType_), - maxConns(maxConns_), address(address_), isUniqueLocal(isUniqueLocal_) {} std::string& gethost(){return host;} @@ -208,7 +204,6 @@ public: std::string& getwebircpass(){return webircpass;} bool getgzip(){return gzip;} i2p::data::SigningKeyType getsigType(){return sigType;} - uint32_t getmaxConns(){return maxConns;} std::string& getaddress(){return address;} bool getisUniqueLocal(){return isUniqueLocal;} void sethost(const std::string& host_){host=host_;} @@ -220,7 +215,6 @@ public: void setwebircpass(const std::string& webircpass_){webircpass=webircpass_;} void setgzip(bool gzip_){gzip=gzip_;} void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;} - void setmaxConns(uint32_t maxConns_){maxConns=maxConns_;} void setaddress(const std::string& address_){address=address_;} void setisUniqueLocal(bool isUniqueLocal_){isUniqueLocal=isUniqueLocal_;} virtual void saveToStringStream(std::stringstream& out); diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 941dfff3..b46cfa38 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -272,10 +272,27 @@ linux:!android { LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc } -windows:!android { +windows { message("Using Windows settings") - DEFINES += BOOST_USE_WINDOWS_H WINDOWS - LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc + DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB + DEFINES -= UNICODE _UNICODE + BOOST_SUFFIX = -mt + QMAKE_LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + LIBS = -lminiupnpc \ + -lboost_system$$BOOST_SUFFIX \ + -lboost_date_time$$BOOST_SUFFIX \ + -lboost_filesystem$$BOOST_SUFFIX \ + -lboost_program_options$$BOOST_SUFFIX \ + -lssl \ + -lcrypto \ + -lz \ + -lwsock32 \ + -lws2_32 \ + -lgdi32 \ + -liphlpapi \ + -lstdc++ \ + -lpthread } !android:!symbian:!maemo5:!simulator { diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index cac97a1f..c5f0c902 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -628,7 +628,6 @@ private: std::string webircpass = ""; bool gzip = true; i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256; - uint32_t maxConns = i2p::stream::DEFAULT_MAX_CONNS_PER_MIN; std::string address = "127.0.0.1"; bool isUniqueLocal = true; @@ -646,7 +645,6 @@ private: webircpass, gzip, sigType, - maxConns, address, isUniqueLocal); @@ -734,7 +732,6 @@ private: std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); - uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); @@ -769,7 +766,6 @@ private: webircpass, gzip, sigType, - maxConns, address, isUniqueLocal); } From a2b3ee53e085bf40b35d49629efe38ab1e349daa Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Apr 2018 14:39:46 -0400 Subject: [PATCH 018/195] fixed build error --- daemon/Daemon.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/daemon/Daemon.h b/daemon/Daemon.h index f3e72904..4491d303 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -64,7 +64,18 @@ namespace util DaemonWin32 ():isGraceful(false) {} }; - +#elif defined(ANDROID) +#define Daemon i2p::util::DaemonAndroid::Instance() + // dummy, invoked from android/jni/DaemonAndroid.* + class DaemonAndroid: public i2p::util::Daemon_Singleton + { + public: + static DaemonAndroid& Instance() + { + static DaemonAndroid instance; + return instance; + } + }; #else #define Daemon i2p::util::DaemonLinux::Instance() class DaemonLinux : public Daemon_Singleton From 396cba7339b9dda8f9f13c4743bdfc216c0b4658 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 24 Apr 2018 03:19:02 +0300 Subject: [PATCH 019/195] fix static building on windows, add resource files (closes #1163) --- qt/i2pd_qt/i2pd.qrc | 7 +++-- qt/i2pd_qt/i2pd.rc | 32 +++++++++++++++++++++ qt/i2pd_qt/i2pd_qt.pro | 4 ++- qt/i2pd_qt/mainwindow.cpp | 2 +- qt/i2pd_qt/resources/icons/mask.ico | Bin 0 -> 156564 bytes qt/i2pd_qt/{ => resources}/images/icon.png | Bin 6 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 qt/i2pd_qt/i2pd.rc create mode 100644 qt/i2pd_qt/resources/icons/mask.ico rename qt/i2pd_qt/{ => resources}/images/icon.png (100%) diff --git a/qt/i2pd_qt/i2pd.qrc b/qt/i2pd_qt/i2pd.qrc index 2abdeb05..4e5523e9 100644 --- a/qt/i2pd_qt/i2pd.qrc +++ b/qt/i2pd_qt/i2pd.qrc @@ -1,5 +1,6 @@ - - images/icon.png - + + resources/icons/mask.ico + resources/images/icon.png + diff --git a/qt/i2pd_qt/i2pd.rc b/qt/i2pd_qt/i2pd.rc new file mode 100644 index 00000000..bebdf1d6 --- /dev/null +++ b/qt/i2pd_qt/i2pd.rc @@ -0,0 +1,32 @@ +IDI_ICON1 ICON DISCARDABLE "resources/icons/mask.ico" + +#include // needed for VERSIONINFO +#include "../../libi2pd/version.h" + +VS_VERSION_INFO VERSIONINFO +FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH +PRODUCTVERSION I2P_VERSION_MAJOR,I2P_VERSION_MINOR,I2P_VERSION_MICRO,I2P_VERSION_PATCH +FILEOS VOS_NT_WINDOWS32 +FILETYPE VFT_APP +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // U.S. English - multilingual (hex) + BEGIN + VALUE "CompanyName", "PurpleI2P" + VALUE "FileDescription", "I2Pd Qt" + VALUE "FileVersion", I2PD_VERSION + VALUE "InternalName", "i2pd-qt" + VALUE "LegalCopyright", "Copyright (C) 2013-2018, The PurpleI2P Project" + VALUE "LegalTrademarks1", "Distributed under the BSD 3-Clause software license, see the accompanying file COPYING or https://opensource.org/licenses/BSD-3-Clause." + VALUE "OriginalFilename", "i2pd_qt.exe" + VALUE "ProductName", "i2pd-qt" + VALUE "ProductVersion", I2P_VERSION + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal) + END +END diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index b46cfa38..21ef6358 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -274,10 +274,12 @@ linux:!android { windows { message("Using Windows settings") + RC_FILE = i2pd.rc DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB DEFINES -= UNICODE _UNICODE BOOST_SUFFIX = -mt - QMAKE_LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + QMAKE_CXXFLAGS = -Os + QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows LIBS = -lminiupnpc \ -lboost_system$$BOOST_SUFFIX \ diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index fc1e5985..c3761764 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -449,7 +449,7 @@ void MainWindow::createTrayIcon() { } void MainWindow::setIcon() { - QIcon icon(":/images/icon.png"); + QIcon icon(":icons/mask"); trayIcon->setIcon(icon); setWindowIcon(icon); diff --git a/qt/i2pd_qt/resources/icons/mask.ico b/qt/i2pd_qt/resources/icons/mask.ico new file mode 100644 index 0000000000000000000000000000000000000000..f5807de5ccae7dae7b7234badc651a7a57b62367 GIT binary patch literal 156564 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%0AO>91EHxccO^29Yysmoh8MthpVdk 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%0A2cpAh53rB_uKqdNWrzK_ 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 K0(OBOy!U^N3-aIq literal 0 HcmV?d00001 diff --git a/qt/i2pd_qt/images/icon.png b/qt/i2pd_qt/resources/images/icon.png similarity index 100% rename from qt/i2pd_qt/images/icon.png rename to qt/i2pd_qt/resources/images/icon.png From 4643c92d33a1d43861b0aac74dec2f01689d01bf Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 09:45:16 -0400 Subject: [PATCH 020/195] Initial SAM cleanup --- daemon/HTTPServer.cpp | 2 +- daemon/I2PControl.cpp | 2 +- libi2pd/Streaming.cpp | 4 +- libi2pd/Streaming.h | 3 + libi2pd_client/SAM.cpp | 208 ++++++++++++++++++----------------------- libi2pd_client/SAM.h | 52 ++++------- 6 files changed, 118 insertions(+), 153 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 6f884a9b..554ba45d 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -649,7 +649,7 @@ namespace http { s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n"; s << "
\r\n"; s << "Streams:
\r\n"; - for (const auto& it: session->ListSockets()) + for (const auto& it: sam->ListSockets(id)) { switch (it->GetSocketType ()) { diff --git a/daemon/I2PControl.cpp b/daemon/I2PControl.cpp index fcff78cd..6ac87cbb 100644 --- a/daemon/I2PControl.cpp +++ b/daemon/I2PControl.cpp @@ -727,7 +727,7 @@ namespace client sam_session.put("name", name); sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident)); - for (const auto& socket: it.second->ListSockets()) + for (const auto& socket: sam->ListSockets(it.first)) { boost::property_tree::ptree stream; stream.put("type", socket->GetSocketType ()); diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index dd8e3634..e8386b61 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -578,9 +578,7 @@ namespace stream if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) // nothing to send { m_Status = eStreamStatusClosed; - // close could be called from another thread so do SendClose from the destination thread - // this is so m_LocalDestination.NewPacket () does not trigger a race condition - m_Service.post(std::bind(&Stream::SendClose, shared_from_this())); + SendClose(); } break; case eStreamStatusClosed: diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 47f99833..7f2598c0 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -165,6 +165,9 @@ namespace stream void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; + void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; + + /** only call close from destination thread, use Stream::AsyncClose for other threads */ void Close (); void Cancel () { m_ReceiveTimer.cancel (); }; diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 05943981..b8a72f0c 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -15,8 +15,8 @@ namespace i2p { namespace client { - SAMSocket::SAMSocket (SAMBridge& owner, std::shared_ptr socket): - m_Owner (owner), m_Socket(socket), m_Timer (m_Owner.GetService ()), + SAMSocket::SAMSocket (SAMBridge& owner): + m_Owner (owner), m_Socket(owner.GetService()), m_Timer (m_Owner.GetService ()), m_BufferOffset (0), m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false), m_IsAccepting (false), m_Stream (nullptr) @@ -25,51 +25,18 @@ namespace client SAMSocket::~SAMSocket () { - if(m_Stream) - { - m_Stream->Close (); - m_Stream.reset (); - } - auto Session = m_Owner.FindSession(m_ID); - - switch (m_SocketType) - { - case eSAMSocketTypeSession: - m_Owner.CloseSession (m_ID); - break; - case eSAMSocketTypeStream: - { - if (Session) - Session->DelSocket (this); - break; - } - case eSAMSocketTypeAcceptor: - { - if (Session) - { - Session->DelSocket (this); - if (m_IsAccepting && Session->localDestination) - Session->localDestination->StopAcceptingStreams (); - } - break; - } - default: - ; - } - m_SocketType = eSAMSocketTypeTerminated; - if (m_Socket && m_Socket->is_open()) m_Socket->close (); - m_Socket.reset (); + m_Stream.reset (); + if (m_Socket.is_open()) m_Socket.close (); } void SAMSocket::Terminate (const char* reason) { if(m_Stream) { - m_Stream->Close (); + m_Stream->AsyncClose (); m_Stream.reset (); } auto Session = m_Owner.FindSession(m_ID); - switch (m_SocketType) { case eSAMSocketTypeSession: @@ -77,15 +44,12 @@ namespace client break; case eSAMSocketTypeStream: { - if (Session) - Session->DelSocket (this); break; } case eSAMSocketTypeAcceptor: { if (Session) { - Session->DelSocket (this); if (m_IsAccepting && Session->localDestination) Session->localDestination->StopAcceptingStreams (); } @@ -95,16 +59,15 @@ namespace client ; } m_SocketType = eSAMSocketTypeTerminated; - if (m_Socket && m_Socket->is_open()) m_Socket->close (); - m_Socket.reset (); + if (m_Socket.is_open()) m_Socket.close (); + m_Owner.RemoveSocket(this); } void SAMSocket::ReceiveHandshake () - { - if(m_Socket) - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), - std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); + { + m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), + std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); } static bool SAMVersionAcceptable(const std::string & ver) @@ -125,7 +88,7 @@ namespace client void SAMSocket::HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) - { + { LogPrint (eLogError, "SAM: handshake read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: handshake read error"); @@ -184,7 +147,7 @@ namespace client #else size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ()); #endif - boost::asio::async_write (*m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Buffer, l), boost::asio::transfer_all (), std::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -199,17 +162,22 @@ namespace client } } + bool SAMSocket::IsSession(const std::string & id) const + { + return id == m_ID; + } + void SAMSocket::HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) - { + { LogPrint (eLogError, "SAM: handshake reply send error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: handshake reply send error"); } - else if(m_Socket) + else { - m_Socket->async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), + m_Socket.async_read_some (boost::asio::buffer(m_Buffer, SAM_SOCKET_BUFFER_SIZE), std::bind(&SAMSocket::HandleMessage, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -220,7 +188,7 @@ namespace client LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg); if (!m_IsSilent) - boost::asio::async_write (*m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, close)); else @@ -501,7 +469,6 @@ namespace client if(session) { m_SocketType = eSAMSocketTypeStream; - session->AddSocket (shared_from_this ()); m_Stream = session->localDestination->CreateStream (remote); m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send m_BufferOffset = 0; @@ -534,7 +501,6 @@ namespace client if (session) { m_SocketType = eSAMSocketTypeAcceptor; - session->AddSocket (shared_from_this ()); if (!session->localDestination->IsAcceptingStreams ()) { m_IsAccepting = true; @@ -704,17 +670,9 @@ namespace client void SAMSocket::Receive () { - if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE) - { - LogPrint (eLogError, "SAM: Buffer is full, terminate"); - Terminate ("Buffer is full"); - return; - } else if (m_Socket) - m_Socket->async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), - std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage, - shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - else - LogPrint(eLogError, "SAM: receive with no native socket"); + m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset), + std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage, + shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -731,15 +689,12 @@ namespace client { bytes_transferred += m_BufferOffset; m_BufferOffset = 0; - auto s = shared_from_this (); m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred, - [s](const boost::system::error_code& ecode) - { - if (!ecode) - s->m_Owner.GetService ().post ([s] { s->Receive (); }); - else - s->m_Owner.GetService ().post ([s] { s->Terminate ("AsyncSend failed"); }); - }); + std::bind(&SAMSocket::HandleStreamSend, shared_from_this(), std::placeholders::_1)); + } + else + { + Terminate("No Stream Remaining"); } } } @@ -773,14 +728,11 @@ namespace client void SAMSocket::WriteI2PDataImmediate(uint8_t * buff, size_t sz) { - if(m_Socket) - boost::asio::async_write ( - *m_Socket, - boost::asio::buffer (buff, sz), - boost::asio::transfer_all(), - std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination - else - LogPrint(eLogError, "SAM: no native socket"); + boost::asio::async_write ( + m_Socket, + boost::asio::buffer (buff, sz), + boost::asio::transfer_all(), + std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination } void SAMSocket::HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff) @@ -858,7 +810,7 @@ namespace client if (session) { // find more pending acceptors - for (auto it: session->ListSockets ()) + for (auto it: m_Owner.ListSockets (m_ID)) if (it->m_SocketType == eSAMSocketTypeAcceptor) { it->m_IsAccepting = true; @@ -930,12 +882,19 @@ namespace client } } - SAMSession::SAMSession (std::shared_ptr dest): + void SAMSocket::HandleStreamSend(const boost::system::error_code & ec) + { + m_Owner.GetService ().post (std::bind( !ec ? &SAMSocket::Receive : &SAMSocket::TerminateClose, shared_from_this())); + } + + SAMSession::SAMSession (SAMBridge & parent, const std::string & id, std::shared_ptr dest): + m_Bridge(parent), localDestination (dest), - UDPEndpoint(nullptr) + UDPEndpoint(nullptr), + Name(id) { } - + SAMSession::~SAMSession () { CloseStreams(); @@ -944,15 +903,10 @@ namespace client void SAMSession::CloseStreams () { - std::vector > socks; + for(const auto & itr : m_Bridge.ListSockets(Name)) { - std::lock_guard lock(m_SocketsMutex); - for (const auto& sock : m_Sockets) { - socks.push_back(sock); - } + itr->Terminate(nullptr); } - for (auto & sock : socks ) sock->Terminate("SAMSession::CloseStreams()"); - m_Sockets.clear(); } SAMBridge::SAMBridge (const std::string& address, int port): @@ -1009,12 +963,16 @@ namespace client void SAMBridge::Accept () { - auto native = std::make_shared(m_Service); - auto newSocket = std::make_shared (*this, native); - m_Acceptor.async_accept (*native, std::bind (&SAMBridge::HandleAccept, this, + auto newSocket = std::make_shared(*this); + m_Acceptor.async_accept (newSocket->GetSocket(), std::bind (&SAMBridge::HandleAccept, this, std::placeholders::_1, newSocket)); } + void SAMBridge::RemoveSocket(const SAMSocket * socket) + { + m_OpenSockets.remove_if([socket](const std::shared_ptr & item) -> bool { return item.get() == socket; }); + } + void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) { if (!ecode) @@ -1024,6 +982,7 @@ namespace client if (!ec) { LogPrint (eLogDebug, "SAM: new connection from ", ep); + m_OpenSockets.push_back(socket); socket->ReceiveHandshake (); } else @@ -1066,7 +1025,7 @@ namespace client if (localDestination) { localDestination->Acquire (); - auto session = std::make_shared(localDestination); + auto session = std::make_shared(*this, id, localDestination); std::unique_lock l(m_SessionsMutex); auto ret = m_Sessions.insert (std::make_pair(id, session)); if (!ret.second) @@ -1105,6 +1064,18 @@ namespace client return nullptr; } + std::list > SAMBridge::ListSockets(const std::string & id) const + { + std::list > list; + { + std::unique_lock l(m_SessionsMutex); + for (const auto & itr : m_OpenSockets) + if (itr->IsSession(id)) + list.push_back(itr); + } + return list; + } + void SAMBridge::SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote) { if(remote) @@ -1127,33 +1098,38 @@ namespace client { m_DatagramReceiveBuffer[bytes_transferred] = 0; char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n'); - *eol = 0; eol++; - size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer); - LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen); - char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' '); - if (sessionID) + if(eol) { - sessionID++; - char * destination = strchr (sessionID, ' '); - if (destination) + *eol = 0; eol++; + size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer); + LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen); + char * sessionID = strchr ((char *)m_DatagramReceiveBuffer, ' '); + if (sessionID) { - *destination = 0; destination++; - auto session = FindSession (sessionID); - if (session) + sessionID++; + char * destination = strchr (sessionID, ' '); + if (destination) { - i2p::data::IdentityEx dest; - dest.FromBase64 (destination); - session->localDestination->GetDatagramDestination ()-> - SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + *destination = 0; destination++; + auto session = FindSession (sessionID); + if (session) + { + i2p::data::IdentityEx dest; + dest.FromBase64 (destination); + session->localDestination->GetDatagramDestination ()-> + SendDatagramTo ((uint8_t *)eol, payloadLen, dest.GetIdentHash ()); + } + else + LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); } else - LogPrint (eLogError, "SAM: Session ", sessionID, " not found"); + LogPrint (eLogError, "SAM: Missing destination key"); } else - LogPrint (eLogError, "SAM: Missing destination key"); + LogPrint (eLogError, "SAM: Missing sessionID"); } else - LogPrint (eLogError, "SAM: Missing sessionID"); + LogPrint(eLogError, "SAM: invalid datagram"); ReceiveDatagram (); } else diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 6ecd14a4..d14e5e39 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -77,24 +77,27 @@ namespace client class SAMBridge; struct SAMSession; - class SAMSocket: public std::enable_shared_from_this + class SAMSocket :public std::enable_shared_from_this { public: typedef boost::asio::ip::tcp::socket Socket_t; - SAMSocket (SAMBridge& owner, std::shared_ptr socket); + SAMSocket (SAMBridge& owner); ~SAMSocket (); - boost::asio::ip::tcp::socket& GetSocket () { return *m_Socket; }; + Socket_t& GetSocket () { return m_Socket; }; void ReceiveHandshake (); void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; }; SAMSocketType GetSocketType () const { return m_SocketType; }; void Terminate (const char* reason); + bool IsSession(const std::string & id) const; + private: - - void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void TerminateClose() { Terminate(nullptr); } + + void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendMessageReply (const char * msg, size_t len, bool close); @@ -128,10 +131,12 @@ namespace client void WriteI2PDataImmediate(uint8_t * ptr, size_t sz); void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff); + void HandleStreamSend(const boost::system::error_code & ec); + private: SAMBridge& m_Owner; - std::shared_ptr m_Socket; + Socket_t m_Socket; boost::asio::deadline_timer m_Timer; char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1]; size_t m_BufferOffset; @@ -145,34 +150,12 @@ namespace client struct SAMSession { + SAMBridge & m_Bridge; std::shared_ptr localDestination; - std::list > m_Sockets; std::shared_ptr UDPEndpoint; - std::mutex m_SocketsMutex; + std::string Name; - /** safely add a socket to this session */ - void AddSocket(std::shared_ptr sock) { - std::lock_guard lock(m_SocketsMutex); - m_Sockets.push_back(sock); - } - - /** safely remove a socket from this session */ - void DelSocket(SAMSocket * sock) { - std::lock_guard lock(m_SocketsMutex); - m_Sockets.remove_if([sock](const std::shared_ptr s) -> bool { return s.get() == sock; }); - } - - /** get a list holding a copy of all sam sockets from this session */ - std::list > ListSockets() { - std::list > l; - { - std::lock_guard lock(m_SocketsMutex); - for(const auto& sock : m_Sockets ) l.push_back(sock); - } - return l; - } - - SAMSession (std::shared_ptr dest); + SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest); ~SAMSession (); void CloseStreams (); @@ -194,15 +177,19 @@ namespace client void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const; + std::list > ListSockets(const std::string & id) const; + /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); + void RemoveSocket(const SAMSocket * socket); + private: void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); void ReceiveDatagram (); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -217,6 +204,7 @@ namespace client boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; std::map > m_Sessions; + std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; public: From b7a67b4b03c319fd9fc4432e2ac8751c75d5ff39 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 09:56:24 -0400 Subject: [PATCH 021/195] use refernce not copy --- libi2pd_client/SAM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index b8a72f0c..71b5bea1 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -810,7 +810,7 @@ namespace client if (session) { // find more pending acceptors - for (auto it: m_Owner.ListSockets (m_ID)) + for (auto & it: m_Owner.ListSockets (m_ID)) if (it->m_SocketType == eSAMSocketTypeAcceptor) { it->m_IsAccepting = true; From 60463fdafa97ba68f41430c78bb946ff41bbc1d7 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:11:48 -0400 Subject: [PATCH 022/195] shut down socket and don't allocate buffer for each write in WriteI2PData --- libi2pd_client/SAM.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 71b5bea1..b0ffda51 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -25,8 +25,7 @@ namespace client SAMSocket::~SAMSocket () { - m_Stream.reset (); - if (m_Socket.is_open()) m_Socket.close (); + m_Stream.reset (); } void SAMSocket::Terminate (const char* reason) @@ -59,7 +58,11 @@ namespace client ; } m_SocketType = eSAMSocketTypeTerminated; - if (m_Socket.is_open()) m_Socket.close (); + if (m_Socket.is_open ()) + { + m_Socket.shutdown (); + m_Socket.close (); + } m_Owner.RemoveSocket(this); } @@ -742,9 +745,11 @@ namespace client void SAMSocket::WriteI2PData(size_t sz) { - uint8_t * sendbuff = new uint8_t[sz]; - memcpy(sendbuff, m_StreamBuffer, sz); - WriteI2PDataImmediate(sendbuff, sz); + boost::asio::async_write ( + m_Socket, + boost::asio::buffer (m_StreamBuffer, sz), + boost::asio::transfer_all(), + std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1)); } void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -778,7 +783,8 @@ namespace client { WriteI2PData(bytes_transferred); } - I2PReceive(); + else + I2PReceive(); } } } @@ -897,7 +903,6 @@ namespace client SAMSession::~SAMSession () { - CloseStreams(); i2p::client::context.DeleteLocalDestination (localDestination); } From 5f525d0e4344bb5d062bb22be285d62aa58d4e52 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:16:15 -0400 Subject: [PATCH 023/195] fix previous commit --- libi2pd_client/SAM.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index b0ffda51..6511d8ba 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -60,7 +60,8 @@ namespace client m_SocketType = eSAMSocketTypeTerminated; if (m_Socket.is_open ()) { - m_Socket.shutdown (); + boost::system::error_code ec; + m_Socket.shutdown (boost::asio::ip::tcp::socket::shutdown_both, ec); m_Socket.close (); } m_Owner.RemoveSocket(this); @@ -749,7 +750,7 @@ namespace client m_Socket, boost::asio::buffer (m_StreamBuffer, sz), boost::asio::transfer_all(), - std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1)); + std::bind(&SAMSocket::HandleWriteI2PData, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) From 73b3fbc2daefc3258d3d1bd1c16f9fd17d528866 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:42:37 -0400 Subject: [PATCH 024/195] wrap m_OpenSockets with mutex --- libi2pd_client/SAM.cpp | 16 ++++++++++------ libi2pd_client/SAM.h | 3 ++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 6511d8ba..0edc8252 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -33,7 +33,7 @@ namespace client if(m_Stream) { m_Stream->AsyncClose (); - m_Stream.reset (); + m_Stream = nullptr; } auto Session = m_Owner.FindSession(m_ID); switch (m_SocketType) @@ -64,7 +64,7 @@ namespace client m_Socket.shutdown (boost::asio::ip::tcp::socket::shutdown_both, ec); m_Socket.close (); } - m_Owner.RemoveSocket(this); + m_Owner.RemoveSocket(shared_from_this()); } void SAMSocket::ReceiveHandshake () @@ -974,9 +974,10 @@ namespace client std::placeholders::_1, newSocket)); } - void SAMBridge::RemoveSocket(const SAMSocket * socket) + void SAMBridge::RemoveSocket(const std::shared_ptr & socket) { - m_OpenSockets.remove_if([socket](const std::shared_ptr & item) -> bool { return item.get() == socket; }); + std::unique_lock lock(m_OpenSocketsMutex); + m_OpenSockets.remove_if([socket](const std::shared_ptr & item) -> bool { return item == socket; }); } void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket) @@ -988,7 +989,10 @@ namespace client if (!ec) { LogPrint (eLogDebug, "SAM: new connection from ", ep); - m_OpenSockets.push_back(socket); + { + std::unique_lock l(m_OpenSocketsMutex); + m_OpenSockets.push_back(socket); + } socket->ReceiveHandshake (); } else @@ -1074,7 +1078,7 @@ namespace client { std::list > list; { - std::unique_lock l(m_SessionsMutex); + std::unique_lock l(m_OpenSocketsMutex); for (const auto & itr : m_OpenSockets) if (itr->IsSession(id)) list.push_back(itr); diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index d14e5e39..23cdf170 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -182,7 +182,7 @@ namespace client /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); - void RemoveSocket(const SAMSocket * socket); + void RemoveSocket(const std::shared_ptr & socket); private: @@ -204,6 +204,7 @@ namespace client boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; std::map > m_Sessions; + mutable std::mutex m_OpenSocketsMutex; std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; From 623433099b2bd8456adad3f40abeda4ce8dee26d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 11:50:51 -0400 Subject: [PATCH 025/195] don't use reset --- libi2pd_client/SAM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 0edc8252..41db644d 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -25,7 +25,7 @@ namespace client SAMSocket::~SAMSocket () { - m_Stream.reset (); + m_Stream = nullptr; } void SAMSocket::Terminate (const char* reason) From 1e1e4da14471b190be0997b9be3948183fb7fbd7 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 24 Apr 2018 14:02:48 -0400 Subject: [PATCH 026/195] delete buffer --- libi2pd_client/SAM.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 41db644d..d228e317 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -725,7 +725,10 @@ namespace client WriteI2PDataImmediate(buff, len); } else // no more data + { + delete [] buff; Terminate ("no more data"); + } } } } From 66de7ad0491264f4a0c179dac7e46dfbbd7ce7a1 Mon Sep 17 00:00:00 2001 From: Arm64 plaz Date: Tue, 24 Apr 2018 18:23:40 +0000 Subject: [PATCH 027/195] for first time disable aesenc for arm64 --- Makefile.linux | 7 ++++++- libi2pd/Crypto.cpp | 7 +++++++ libi2pd/Crypto.h | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Makefile.linux b/Makefile.linux index 4a82591a..2c30bbb0 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -60,7 +60,12 @@ endif ifeq ($(USE_AESNI),yes) #check if AES-NI is supported by CPU ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) - CPU_FLAGS += -maes -DAESNI + machine := $(shell uname -m) + ifeq ($(machine), aarch64) + CXXFLAGS += -DARM64AES + else + CPU_FLAGS += -maes -DAESNI + endif endif endif diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 5ba3334d..b0473410 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -594,6 +594,13 @@ namespace crypto // AES #ifdef AESNI + #ifdef ARM64AES + void init_aesenc(void) __attribute__((constructor)){ + + } + + #endif + #define KeyExpansion256(round0,round1) \ "pshufd $0xff, %%xmm2, %%xmm2 \n" \ "movaps %%xmm1, %%xmm4 \n" \ diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 6e4ddb3d..859f2d97 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -124,6 +124,9 @@ namespace crypto #ifdef AESNI + #ifdef ARM64AES + void init_aesenc(void) __attribute__((constructor)); + #endif class ECBCryptoAESNI { public: From 97127e86dc1d600f667f7c0c0b205371f74eb8a0 Mon Sep 17 00:00:00 2001 From: Sammael <36346388+borned-mind@users.noreply.github.com> Date: Wed, 25 Apr 2018 01:59:11 +0700 Subject: [PATCH 028/195] Delete some for correct compilation --- libi2pd/Crypto.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index b0473410..8ba99a15 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -595,8 +595,8 @@ namespace crypto // AES #ifdef AESNI #ifdef ARM64AES - void init_aesenc(void) __attribute__((constructor)){ - + void init_aesenc(void){ + // TODO: Implementation } #endif From 72252318142076f5ed0486ee12dc6737ccfa3fd2 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Wed, 25 Apr 2018 16:15:40 +0800 Subject: [PATCH 029/195] perfecting qt status page --- daemon/HTTPServer.cpp | 43 ++- daemon/HTTPServer.h | 3 +- qt/i2pd_qt/i2pd_qt.pro | 618 +++++++++++++++++++------------------- qt/i2pd_qt/mainwindow.cpp | 4 +- 4 files changed, 342 insertions(+), 326 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 6f884a9b..12edf276 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -198,7 +198,10 @@ namespace http { s << "ERROR: " << string << "
\r\n"; } - void ShowStatus (std::stringstream& s, bool includeHiddenContent) + void ShowStatus ( + std::stringstream& s, + bool includeHiddenContent, + i2p::http::OutputFormatEnum outputFormat) { s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); @@ -245,9 +248,12 @@ namespace http { ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ()); s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)
\r\n"; s << "Data path: " << i2p::fs::GetDataDir() << "
\r\n"; - s << "

\r\n\r\n

\r\n"; - if(includeHiddenContent) { - s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; + s << "

"; + if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) { + s << "\r\n\r\n

\r\n"; + } + if(includeHiddenContent) { + s << "Router Ident: " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "
\r\n"; s << "Router Family: " << i2p::context.GetRouterInfo().GetProperty("family") << "
\r\n"; s << "Router Caps: " << i2p::context.GetRouterInfo().GetProperty("caps") << "
\r\n"; s << "Our external address:" << "
\r\n" ; @@ -272,9 +278,12 @@ namespace http { } s << address->host.to_string() << ":" << address->port << "
\r\n"; } - } + } s << "

\r\n
\r\n"; - s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; + if(outputFormat==OutputFormatEnum::forQtUi) { + s << "
"; + } + s << "Routers: " << i2p::data::netdb.GetNumRouters () << " "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " "; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "
\r\n"; @@ -285,15 +294,17 @@ namespace http { s << "Client Tunnels: " << std::to_string(clientTunnelCount) << " "; s << "Transit Tunnels: " << std::to_string(transitTunnelCount) << "
\r\n
\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - s << "\r\n"; - bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); - s << "\r\n"; - s << "
Services
ServiceState
" << "HTTP Proxy" << "
" << "SOCKS Proxy" << "
" << "BOB" << "
" << "SAM" << "
" << "I2CP" << "
" << "I2PControl" << "
\r\n"; + if(outputFormat==OutputFormatEnum::forWebConsole) { + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + s << "\r\n"; + bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol); + s << "\r\n"; + s << "
Services
ServiceState
" << "HTTP Proxy" << "
" << "SOCKS Proxy" << "
" << "BOB" << "
" << "SAM" << "
" << "I2CP" << "
" << "I2PControl" << "
\r\n"; + } } void ShowLocalDestinations (std::stringstream& s) @@ -863,7 +874,7 @@ namespace http { } else if (req.uri.find("cmd=") != std::string::npos) { HandleCommand (req, res, s); } else { - ShowStatus (s, true); + ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole); res.add_header("Refresh", "10"); } ShowPageTail (s); diff --git a/daemon/HTTPServer.h b/daemon/HTTPServer.h index 46477dae..a1b82875 100644 --- a/daemon/HTTPServer.h +++ b/daemon/HTTPServer.h @@ -80,7 +80,8 @@ namespace http }; //all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml - void ShowStatus (std::stringstream& s, bool includeHiddenContent); + enum OutputFormatEnum { forWebConsole, forQtUi }; + void ShowStatus (std::stringstream& s, bool includeHiddenContent, OutputFormatEnum outputFormat); void ShowLocalDestinations (std::stringstream& s); void ShowLeasesSets(std::stringstream& s); void ShowTunnels (std::stringstream& s); diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 21ef6358..12d13a17 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -1,308 +1,310 @@ -QT += core gui - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets - -TARGET = i2pd_qt -TEMPLATE = app -QMAKE_CXXFLAGS *= -std=c++11 -DEFINES += USE_UPNP - -# change to your own path, where you will store all needed libraries with 'git clone' commands below. -MAIN_PATH = /path/to/libraries - -# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git -# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git -# git clone https://github.com/PurpleI2P/android-ifaddrs.git -BOOST_PATH = $$MAIN_PATH/Boost-for-Android-Prebuilt -OPENSSL_PATH = $$MAIN_PATH/OpenSSL-for-Android-Prebuilt -MINIUPNP_PATH = $$MAIN_PATH/MiniUPnP-for-Android-Prebuilt -IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs - -# Steps in Android SDK manager: -# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html -# 2) Check API 11 -# Finally, click Install. - -SOURCES += DaemonQT.cpp mainwindow.cpp \ - ../../libi2pd/api.cpp \ - ../../libi2pd/Base.cpp \ - ../../libi2pd/BloomFilter.cpp \ - ../../libi2pd/Config.cpp \ - ../../libi2pd/CPU.cpp \ - ../../libi2pd/Crypto.cpp \ - ../../libi2pd/CryptoKey.cpp \ - ../../libi2pd/Datagram.cpp \ - ../../libi2pd/Destination.cpp \ - ../../libi2pd/Event.cpp \ - ../../libi2pd/Family.cpp \ - ../../libi2pd/FS.cpp \ - ../../libi2pd/Garlic.cpp \ - ../../libi2pd/Gost.cpp \ - ../../libi2pd/Gzip.cpp \ - ../../libi2pd/HTTP.cpp \ - ../../libi2pd/I2NPProtocol.cpp \ - ../../libi2pd/I2PEndian.cpp \ - ../../libi2pd/Identity.cpp \ - ../../libi2pd/LeaseSet.cpp \ - ../../libi2pd/Log.cpp \ - ../../libi2pd/NetDb.cpp \ - ../../libi2pd/NetDbRequests.cpp \ - ../../libi2pd/NTCPSession.cpp \ - ../../libi2pd/Profiling.cpp \ - ../../libi2pd/Reseed.cpp \ - ../../libi2pd/RouterContext.cpp \ - ../../libi2pd/RouterInfo.cpp \ - ../../libi2pd/Signature.cpp \ - ../../libi2pd/SSU.cpp \ - ../../libi2pd/SSUData.cpp \ - ../../libi2pd/SSUSession.cpp \ - ../../libi2pd/Streaming.cpp \ - ../../libi2pd/Timestamp.cpp \ - ../../libi2pd/TransitTunnel.cpp \ - ../../libi2pd/Transports.cpp \ - ../../libi2pd/Tunnel.cpp \ - ../../libi2pd/TunnelEndpoint.cpp \ - ../../libi2pd/TunnelGateway.cpp \ - ../../libi2pd/TunnelPool.cpp \ - ../../libi2pd/util.cpp \ - ../../libi2pd_client/AddressBook.cpp \ - ../../libi2pd_client/BOB.cpp \ - ../../libi2pd_client/ClientContext.cpp \ - ../../libi2pd_client/HTTPProxy.cpp \ - ../../libi2pd_client/I2CP.cpp \ - ../../libi2pd_client/I2PService.cpp \ - ../../libi2pd_client/I2PTunnel.cpp \ - ../../libi2pd_client/MatchedDestination.cpp \ - ../../libi2pd_client/SAM.cpp \ - ../../libi2pd_client/SOCKS.cpp \ - ../../libi2pd_client/Websocket.cpp \ - ../../libi2pd_client/WebSocks.cpp \ - ClientTunnelPane.cpp \ - MainWindowItems.cpp \ - ServerTunnelPane.cpp \ - SignatureTypeComboboxFactory.cpp \ - TunnelConfig.cpp \ - TunnelPane.cpp \ - ../../daemon/Daemon.cpp \ - ../../daemon/HTTPServer.cpp \ - ../../daemon/i2pd.cpp \ - ../../daemon/I2PControl.cpp \ - ../../daemon/UnixDaemon.cpp \ - ../../daemon/UPnP.cpp \ - textbrowsertweaked1.cpp \ - pagewithbackbutton.cpp \ - widgetlock.cpp \ - widgetlockregistry.cpp - -#qt creator does not handle this well -#SOURCES += $$files(../../libi2pd/*.cpp) -#SOURCES += $$files(../../libi2pd_client/*.cpp) -#SOURCES += $$files(../../daemon/*.cpp) -#SOURCES += $$files(./*.cpp) - -SOURCES -= ../../daemon/UnixDaemon.cpp - -HEADERS += DaemonQT.h mainwindow.h \ - ../../libi2pd/api.h \ - ../../libi2pd/Base.h \ - ../../libi2pd/BloomFilter.h \ - ../../libi2pd/Config.h \ - ../../libi2pd/Crypto.h \ - ../../libi2pd/CryptoKey.h \ - ../../libi2pd/Datagram.h \ - ../../libi2pd/Destination.h \ - ../../libi2pd/Event.h \ - ../../libi2pd/Family.h \ - ../../libi2pd/FS.h \ - ../../libi2pd/Garlic.h \ - ../../libi2pd/Gost.h \ - ../../libi2pd/Gzip.h \ - ../../libi2pd/HTTP.h \ - ../../libi2pd/I2NPProtocol.h \ - ../../libi2pd/I2PEndian.h \ - ../../libi2pd/Identity.h \ - ../../libi2pd/LeaseSet.h \ - ../../libi2pd/LittleBigEndian.h \ - ../../libi2pd/Log.h \ - ../../libi2pd/NetDb.hpp \ - ../../libi2pd/NetDbRequests.h \ - ../../libi2pd/NTCPSession.h \ - ../../libi2pd/Profiling.h \ - ../../libi2pd/Queue.h \ - ../../libi2pd/Reseed.h \ - ../../libi2pd/RouterContext.h \ - ../../libi2pd/RouterInfo.h \ - ../../libi2pd/Signature.h \ - ../../libi2pd/SSU.h \ - ../../libi2pd/SSUData.h \ - ../../libi2pd/SSUSession.h \ - ../../libi2pd/Streaming.h \ - ../../libi2pd/Tag.h \ - ../../libi2pd/Timestamp.h \ - ../../libi2pd/TransitTunnel.h \ - ../../libi2pd/Transports.h \ - ../../libi2pd/TransportSession.h \ - ../../libi2pd/Tunnel.h \ - ../../libi2pd/TunnelBase.h \ - ../../libi2pd/TunnelConfig.h \ - ../../libi2pd/TunnelEndpoint.h \ - ../../libi2pd/TunnelGateway.h \ - ../../libi2pd/TunnelPool.h \ - ../../libi2pd/util.h \ - ../../libi2pd/version.h \ - ../../libi2pd_client/AddressBook.h \ - ../../libi2pd_client/BOB.h \ - ../../libi2pd_client/ClientContext.h \ - ../../libi2pd_client/HTTPProxy.h \ - ../../libi2pd_client/I2CP.h \ - ../../libi2pd_client/I2PService.h \ - ../../libi2pd_client/I2PTunnel.h \ - ../../libi2pd_client/MatchedDestination.h \ - ../../libi2pd_client/SAM.h \ - ../../libi2pd_client/SOCKS.h \ - ../../libi2pd_client/Websocket.h \ - ../../libi2pd_client/WebSocks.h \ - ClientTunnelPane.h \ - MainWindowItems.h \ - ServerTunnelPane.h \ - SignatureTypeComboboxFactory.h \ - TunnelConfig.h \ - TunnelPane.h \ - TunnelsPageUpdateListener.h \ - ../../daemon/Daemon.h \ - ../../daemon/HTTPServer.h \ - ../../daemon/I2PControl.h \ - ../../daemon/UPnP.h \ - textbrowsertweaked1.h \ - pagewithbackbutton.h \ - widgetlock.h \ - widgetlockregistry.h - -INCLUDEPATH += ../../libi2pd -INCLUDEPATH += ../../libi2pd_client -INCLUDEPATH += ../../daemon -INCLUDEPATH += . - -FORMS += mainwindow.ui \ - tunnelform.ui \ - statusbuttons.ui \ - routercommandswidget.ui \ - generalsettingswidget.ui - -LIBS += -lz - -macx { - message("using mac os x target") - BREWROOT=/usr/local - BOOSTROOT=$$BREWROOT/opt/boost - SSLROOT=$$BREWROOT/opt/libressl - UPNPROOT=$$BREWROOT/opt/miniupnpc - INCLUDEPATH += $$BOOSTROOT/include - INCLUDEPATH += $$SSLROOT/include - INCLUDEPATH += $$UPNPROOT/include - LIBS += $$SSLROOT/lib/libcrypto.a - LIBS += $$SSLROOT/lib/libssl.a - LIBS += $$BOOSTROOT/lib/libboost_system.a - LIBS += $$BOOSTROOT/lib/libboost_date_time.a - LIBS += $$BOOSTROOT/lib/libboost_filesystem.a - LIBS += $$BOOSTROOT/lib/libboost_program_options.a - LIBS += $$UPNPROOT/lib/libminiupnpc.a -} - -android { - message("Using Android settings") - DEFINES += ANDROID=1 - DEFINES += __ANDROID__ - - CONFIG += mobility - - MOBILITY = - - INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ - $$OPENSSL_PATH/openssl-1.0.2/include \ - $$MINIUPNP_PATH/miniupnp-2.0/include \ - $$IFADDRS_PATH - DISTFILES += android/AndroidManifest.xml - - ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android - - SOURCES += $$IFADDRS_PATH/ifaddrs.c - HEADERS += $$IFADDRS_PATH/ifaddrs.h - - equals(ANDROID_TARGET_ARCH, armeabi-v7a){ - DEFINES += ANDROID_ARM7A - # http://stackoverflow.com/a/30235934/529442 - LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ - -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ - -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ - -L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \ - -L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc - - PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ - $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a - DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include - - ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \ - $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \ - $$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so - } - - equals(ANDROID_TARGET_ARCH, x86){ - # http://stackoverflow.com/a/30235934/529442 - LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \ - -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ - -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ - -L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \ - -L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc - - PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ - $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a - - DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include - - ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \ - $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \ - $$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so - } -} - -linux:!android { - message("Using Linux settings") - LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc -} - -windows { - message("Using Windows settings") - RC_FILE = i2pd.rc - DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB - DEFINES -= UNICODE _UNICODE - BOOST_SUFFIX = -mt - QMAKE_CXXFLAGS = -Os - QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows - - LIBS = -lminiupnpc \ - -lboost_system$$BOOST_SUFFIX \ - -lboost_date_time$$BOOST_SUFFIX \ - -lboost_filesystem$$BOOST_SUFFIX \ - -lboost_program_options$$BOOST_SUFFIX \ - -lssl \ - -lcrypto \ - -lz \ - -lwsock32 \ - -lws2_32 \ - -lgdi32 \ - -liphlpapi \ - -lstdc++ \ - -lpthread -} - -!android:!symbian:!maemo5:!simulator { - message("Build with a system tray icon") - # see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince* - #sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images - RESOURCES = i2pd.qrc - QT += xml - #INSTALLS += sources -} - +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = i2pd_qt +TEMPLATE = app +QMAKE_CXXFLAGS *= -std=c++11 +DEFINES += USE_UPNP + +# change to your own path, where you will store all needed libraries with 'git clone' commands below. +MAIN_PATH = /path/to/libraries + +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/android-ifaddrs.git +BOOST_PATH = $$MAIN_PATH/Boost-for-Android-Prebuilt +OPENSSL_PATH = $$MAIN_PATH/OpenSSL-for-Android-Prebuilt +MINIUPNP_PATH = $$MAIN_PATH/MiniUPnP-for-Android-Prebuilt +IFADDRS_PATH = $$MAIN_PATH/android-ifaddrs + +# Steps in Android SDK manager: +# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html +# 2) Check API 11 +# Finally, click Install. + +SOURCES += DaemonQT.cpp mainwindow.cpp \ + ../../libi2pd/api.cpp \ + ../../libi2pd/Base.cpp \ + ../../libi2pd/BloomFilter.cpp \ + ../../libi2pd/Config.cpp \ + ../../libi2pd/CPU.cpp \ + ../../libi2pd/Crypto.cpp \ + ../../libi2pd/CryptoKey.cpp \ + ../../libi2pd/Datagram.cpp \ + ../../libi2pd/Destination.cpp \ + ../../libi2pd/Event.cpp \ + ../../libi2pd/Family.cpp \ + ../../libi2pd/FS.cpp \ + ../../libi2pd/Garlic.cpp \ + ../../libi2pd/Gost.cpp \ + ../../libi2pd/Gzip.cpp \ + ../../libi2pd/HTTP.cpp \ + ../../libi2pd/I2NPProtocol.cpp \ + ../../libi2pd/I2PEndian.cpp \ + ../../libi2pd/Identity.cpp \ + ../../libi2pd/LeaseSet.cpp \ + ../../libi2pd/Log.cpp \ + ../../libi2pd/NetDb.cpp \ + ../../libi2pd/NetDbRequests.cpp \ + ../../libi2pd/NTCPSession.cpp \ + ../../libi2pd/Profiling.cpp \ + ../../libi2pd/Reseed.cpp \ + ../../libi2pd/RouterContext.cpp \ + ../../libi2pd/RouterInfo.cpp \ + ../../libi2pd/Signature.cpp \ + ../../libi2pd/SSU.cpp \ + ../../libi2pd/SSUData.cpp \ + ../../libi2pd/SSUSession.cpp \ + ../../libi2pd/Streaming.cpp \ + ../../libi2pd/Timestamp.cpp \ + ../../libi2pd/TransitTunnel.cpp \ + ../../libi2pd/Transports.cpp \ + ../../libi2pd/Tunnel.cpp \ + ../../libi2pd/TunnelEndpoint.cpp \ + ../../libi2pd/TunnelGateway.cpp \ + ../../libi2pd/TunnelPool.cpp \ + ../../libi2pd/util.cpp \ + ../../libi2pd_client/AddressBook.cpp \ + ../../libi2pd_client/BOB.cpp \ + ../../libi2pd_client/ClientContext.cpp \ + ../../libi2pd_client/HTTPProxy.cpp \ + ../../libi2pd_client/I2CP.cpp \ + ../../libi2pd_client/I2PService.cpp \ + ../../libi2pd_client/I2PTunnel.cpp \ + ../../libi2pd_client/MatchedDestination.cpp \ + ../../libi2pd_client/SAM.cpp \ + ../../libi2pd_client/SOCKS.cpp \ + ../../libi2pd_client/Websocket.cpp \ + ../../libi2pd_client/WebSocks.cpp \ + ClientTunnelPane.cpp \ + MainWindowItems.cpp \ + ServerTunnelPane.cpp \ + SignatureTypeComboboxFactory.cpp \ + TunnelConfig.cpp \ + TunnelPane.cpp \ + ../../daemon/Daemon.cpp \ + ../../daemon/HTTPServer.cpp \ + ../../daemon/i2pd.cpp \ + ../../daemon/I2PControl.cpp \ + ../../daemon/UnixDaemon.cpp \ + ../../daemon/UPnP.cpp \ + textbrowsertweaked1.cpp \ + pagewithbackbutton.cpp \ + widgetlock.cpp \ + widgetlockregistry.cpp + +#qt creator does not handle this well +#SOURCES += $$files(../../libi2pd/*.cpp) +#SOURCES += $$files(../../libi2pd_client/*.cpp) +#SOURCES += $$files(../../daemon/*.cpp) +#SOURCES += $$files(./*.cpp) + +SOURCES -= ../../daemon/UnixDaemon.cpp + +HEADERS += DaemonQT.h mainwindow.h \ + ../../libi2pd/api.h \ + ../../libi2pd/Base.h \ + ../../libi2pd/BloomFilter.h \ + ../../libi2pd/Config.h \ + ../../libi2pd/Crypto.h \ + ../../libi2pd/CryptoKey.h \ + ../../libi2pd/Datagram.h \ + ../../libi2pd/Destination.h \ + ../../libi2pd/Event.h \ + ../../libi2pd/Family.h \ + ../../libi2pd/FS.h \ + ../../libi2pd/Garlic.h \ + ../../libi2pd/Gost.h \ + ../../libi2pd/Gzip.h \ + ../../libi2pd/HTTP.h \ + ../../libi2pd/I2NPProtocol.h \ + ../../libi2pd/I2PEndian.h \ + ../../libi2pd/Identity.h \ + ../../libi2pd/LeaseSet.h \ + ../../libi2pd/LittleBigEndian.h \ + ../../libi2pd/Log.h \ + ../../libi2pd/NetDb.hpp \ + ../../libi2pd/NetDbRequests.h \ + ../../libi2pd/NTCPSession.h \ + ../../libi2pd/Profiling.h \ + ../../libi2pd/Queue.h \ + ../../libi2pd/Reseed.h \ + ../../libi2pd/RouterContext.h \ + ../../libi2pd/RouterInfo.h \ + ../../libi2pd/Signature.h \ + ../../libi2pd/SSU.h \ + ../../libi2pd/SSUData.h \ + ../../libi2pd/SSUSession.h \ + ../../libi2pd/Streaming.h \ + ../../libi2pd/Tag.h \ + ../../libi2pd/Timestamp.h \ + ../../libi2pd/TransitTunnel.h \ + ../../libi2pd/Transports.h \ + ../../libi2pd/TransportSession.h \ + ../../libi2pd/Tunnel.h \ + ../../libi2pd/TunnelBase.h \ + ../../libi2pd/TunnelConfig.h \ + ../../libi2pd/TunnelEndpoint.h \ + ../../libi2pd/TunnelGateway.h \ + ../../libi2pd/TunnelPool.h \ + ../../libi2pd/util.h \ + ../../libi2pd/version.h \ + ../../libi2pd_client/AddressBook.h \ + ../../libi2pd_client/BOB.h \ + ../../libi2pd_client/ClientContext.h \ + ../../libi2pd_client/HTTPProxy.h \ + ../../libi2pd_client/I2CP.h \ + ../../libi2pd_client/I2PService.h \ + ../../libi2pd_client/I2PTunnel.h \ + ../../libi2pd_client/MatchedDestination.h \ + ../../libi2pd_client/SAM.h \ + ../../libi2pd_client/SOCKS.h \ + ../../libi2pd_client/Websocket.h \ + ../../libi2pd_client/WebSocks.h \ + ClientTunnelPane.h \ + MainWindowItems.h \ + ServerTunnelPane.h \ + SignatureTypeComboboxFactory.h \ + TunnelConfig.h \ + TunnelPane.h \ + TunnelsPageUpdateListener.h \ + ../../daemon/Daemon.h \ + ../../daemon/HTTPServer.h \ + ../../daemon/I2PControl.h \ + ../../daemon/UPnP.h \ + textbrowsertweaked1.h \ + pagewithbackbutton.h \ + widgetlock.h \ + widgetlockregistry.h \ + i2pd.rc \ + i2pd.rc + +INCLUDEPATH += ../../libi2pd +INCLUDEPATH += ../../libi2pd_client +INCLUDEPATH += ../../daemon +INCLUDEPATH += . + +FORMS += mainwindow.ui \ + tunnelform.ui \ + statusbuttons.ui \ + routercommandswidget.ui \ + generalsettingswidget.ui + +LIBS += -lz + +macx { + message("using mac os x target") + BREWROOT=/usr/local + BOOSTROOT=$$BREWROOT/opt/boost + SSLROOT=$$BREWROOT/opt/libressl + UPNPROOT=$$BREWROOT/opt/miniupnpc + INCLUDEPATH += $$BOOSTROOT/include + INCLUDEPATH += $$SSLROOT/include + INCLUDEPATH += $$UPNPROOT/include + LIBS += $$SSLROOT/lib/libcrypto.a + LIBS += $$SSLROOT/lib/libssl.a + LIBS += $$BOOSTROOT/lib/libboost_system.a + LIBS += $$BOOSTROOT/lib/libboost_date_time.a + LIBS += $$BOOSTROOT/lib/libboost_filesystem.a + LIBS += $$BOOSTROOT/lib/libboost_program_options.a + LIBS += $$UPNPROOT/lib/libminiupnpc.a +} + +android { + message("Using Android settings") + DEFINES += ANDROID=1 + DEFINES += __ANDROID__ + + CONFIG += mobility + + MOBILITY = + + INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ + $$OPENSSL_PATH/openssl-1.0.2/include \ + $$MINIUPNP_PATH/miniupnp-2.0/include \ + $$IFADDRS_PATH + DISTFILES += android/AndroidManifest.xml + + ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android + + SOURCES += $$IFADDRS_PATH/ifaddrs.c + HEADERS += $$IFADDRS_PATH/ifaddrs.h + + equals(ANDROID_TARGET_ARCH, armeabi-v7a){ + DEFINES += ANDROID_ARM7A + # http://stackoverflow.com/a/30235934/529442 + LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \ + -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ + -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ + -L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \ + -L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc + + PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ + $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a + DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include + + ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \ + $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \ + $$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so + } + + equals(ANDROID_TARGET_ARCH, x86){ + # http://stackoverflow.com/a/30235934/529442 + LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \ + -lboost_system-gcc-mt-1_53 -lboost_date_time-gcc-mt-1_53 \ + -lboost_filesystem-gcc-mt-1_53 -lboost_program_options-gcc-mt-1_53 \ + -L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \ + -L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc + + PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ + $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a + + DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include + + ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \ + $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \ + $$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so + } +} + +linux:!android { + message("Using Linux settings") + LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc +} + +windows { + message("Using Windows settings") + RC_FILE = i2pd.rc + DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB + DEFINES -= UNICODE _UNICODE + BOOST_SUFFIX = -mt + QMAKE_CXXFLAGS = -Os + QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + LIBS = -lminiupnpc \ + -lboost_system$$BOOST_SUFFIX \ + -lboost_date_time$$BOOST_SUFFIX \ + -lboost_filesystem$$BOOST_SUFFIX \ + -lboost_program_options$$BOOST_SUFFIX \ + -lssl \ + -lcrypto \ + -lz \ + -lwsock32 \ + -lws2_32 \ + -lgdi32 \ + -liphlpapi \ + -lstdc++ \ + -lpthread +} + +!android:!symbian:!maemo5:!simulator { + message("Build with a system tray icon") + # see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince* + #sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images + RESOURCES = i2pd.qrc + QT += xml + #INSTALLS += sources +} + diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index c3761764..a095f78c 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -349,7 +349,9 @@ QString MainWindow::getStatusPageHtml(bool showHiddenInfo) { s << ""; switch (statusPage) { - case main_page: i2p::http::ShowStatus(s, showHiddenInfo);break; + case main_page: + i2p::http::ShowStatus(s, showHiddenInfo, i2p::http::OutputFormatEnum::forQtUi); + break; case commands: break; case local_destinations: i2p::http::ShowLocalDestinations(s);break; case leasesets: i2p::http::ShowLeasesSets(s); break; From b046c45a9e7db86906684441818cc7153f269314 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 25 Apr 2018 11:25:49 -0400 Subject: [PATCH 030/195] tabify --- libi2pd_client/SAM.cpp | 6 +++--- libi2pd_client/SAM.h | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index d228e317..ac2dd853 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -207,7 +207,7 @@ namespace client void SAMSocket::HandleMessageReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred, bool close) { if (ecode) - { + { LogPrint (eLogError, "SAM: reply send error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: reply send error"); @@ -224,7 +224,7 @@ namespace client void SAMSocket::HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) - { + { LogPrint (eLogError, "SAM: read error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) Terminate ("SAM: read error"); @@ -569,7 +569,7 @@ namespace client keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); #else size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, - keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); + keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); #endif SendMessageReply (m_Buffer, l, false); } diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 23cdf170..0c70758f 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -92,12 +92,12 @@ namespace client void Terminate (const char* reason); - bool IsSession(const std::string & id) const; - + bool IsSession(const std::string & id) const; + private: - void TerminateClose() { Terminate(nullptr); } - - void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void TerminateClose() { Terminate(nullptr); } + + void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendMessageReply (const char * msg, size_t len, bool close); @@ -131,8 +131,8 @@ namespace client void WriteI2PDataImmediate(uint8_t * ptr, size_t sz); void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff); - void HandleStreamSend(const boost::system::error_code & ec); - + void HandleStreamSend(const boost::system::error_code & ec); + private: SAMBridge& m_Owner; @@ -150,10 +150,10 @@ namespace client struct SAMSession { - SAMBridge & m_Bridge; + SAMBridge & m_Bridge; std::shared_ptr localDestination; std::shared_ptr UDPEndpoint; - std::string Name; + std::string Name; SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr dest); ~SAMSession (); @@ -172,24 +172,24 @@ namespace client void Stop (); boost::asio::io_service& GetService () { return m_Service; }; - std::shared_ptr CreateSession (const std::string& id, const std::string& destination, // empty string means transient + std::shared_ptr CreateSession (const std::string& id, const std::string& destination, // empty string means transient const std::map * params); void CloseSession (const std::string& id); std::shared_ptr FindSession (const std::string& id) const; - std::list > ListSockets(const std::string & id) const; + std::list > ListSockets(const std::string & id) const; /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); - void RemoveSocket(const std::shared_ptr & socket); - + void RemoveSocket(const std::shared_ptr & socket); + private: void Run (); void Accept (); - void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); + void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr socket); void ReceiveDatagram (); void HandleReceivedDatagram (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -204,8 +204,8 @@ namespace client boost::asio::ip::udp::socket m_DatagramSocket; mutable std::mutex m_SessionsMutex; std::map > m_Sessions; - mutable std::mutex m_OpenSocketsMutex; - std::list > m_OpenSockets; + mutable std::mutex m_OpenSocketsMutex; + std::list > m_OpenSockets; uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1]; public: From 0ced38cdcbcae6f6bfe1ab653d85f201f194c247 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 25 Apr 2018 11:27:56 -0400 Subject: [PATCH 031/195] tabify --- libi2pd/Streaming.h | 4 ++-- libi2pd_client/SAM.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index 7f2598c0..3db8d760 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -165,9 +165,9 @@ namespace stream void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; - void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; + void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; - /** only call close from destination thread, use Stream::AsyncClose for other threads */ + /** only call close from destination thread, use Stream::AsyncClose for other threads */ void Close (); void Cancel () { m_ReceiveTimer.cancel (); }; diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 0c70758f..953af1cd 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -77,7 +77,7 @@ namespace client class SAMBridge; struct SAMSession; - class SAMSocket :public std::enable_shared_from_this + class SAMSocket: public std::enable_shared_from_this { public: From 2fbbbf298bf272009618332bed2d2e58977fdc21 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 Apr 2018 16:18:07 -0400 Subject: [PATCH 032/195] use shared pointers for tunnel reload --- libi2pd_client/ClientContext.cpp | 54 +++++++++++++++++--------------- libi2pd_client/ClientContext.h | 8 ++--- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 6c3a9410..99f34b73 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -488,8 +488,8 @@ namespace client { localDestination = m_SharedLocalDestination; } - auto clientTunnel = new I2PUDPClientTunnel(name, dest, end, localDestination, destinationPort); - if(m_ClientForwards.insert(std::make_pair(end, std::unique_ptr(clientTunnel))).second) + auto clientTunnel = std::make_shared(name, dest, end, localDestination, destinationPort); + if(m_ClientForwards.insert(std::make_pair(end, clientTunnel)).second) { clientTunnel->Start(); } @@ -498,31 +498,35 @@ namespace client } else { boost::asio::ip::tcp::endpoint clientEndpoint; - I2PService * clientTunnel = nullptr; + std::shared_ptr clientTunnel; if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS) { // socks proxy - clientTunnel = new i2p::proxy::SOCKSProxy(name, address, port, false, "", destinationPort, localDestination); - clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint (); + auto tun = std::make_shared(name, address, port, false, "", destinationPort, localDestination); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint (); } else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY) { // http proxy std::string outproxy = section.second.get("outproxy", ""); - clientTunnel = new i2p::proxy::HTTPProxy(name, address, port, outproxy, localDestination); - clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint (); + auto tun = std::make_shared(name, address, port, outproxy, localDestination); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint (); } else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS) { // websocks proxy - clientTunnel = new WebSocks(address, port, localDestination);; - clientEndpoint = ((WebSocks*)clientTunnel)->GetLocalEndpoint(); + auto tun = std::make_shared(address, port, localDestination); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint(); } else { // tcp client - clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort); - clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint (); + auto tun = std::make_shared (name, dest, address, port, localDestination, destinationPort); + clientTunnel = tun; + clientEndpoint = tun->GetLocalEndpoint (); } uint32_t timeout = section.second.get(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0); if(timeout) @@ -531,8 +535,7 @@ namespace client LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout); } - auto clientTunnelDest = clientTunnel->GetLocalDestination (); // make copy of destination for possible update - auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr(clientTunnel))); + auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, clientTunnel)); if (ins.second) { clientTunnel->Start (); @@ -541,10 +544,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != clientTunnelDest) + if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) { LogPrint (eLogInfo, "Clients: I2P client tunnel destination updated"); - ins.first->second->SetLocalDestination (clientTunnelDest); + ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, " already exists"); @@ -589,7 +592,7 @@ namespace client // TODO: hostnames auto localAddress = boost::asio::ip::address::from_string(address); boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); - I2PUDPServerTunnel * serverTunnel = new I2PUDPServerTunnel(name, localDestination, localAddress, endpoint, port); + auto serverTunnel = std::make_shared(name, localDestination, localAddress, endpoint, port); if(!isUniqueLocal) { LogPrint(eLogInfo, "Clients: disabling loopback address mapping"); @@ -600,7 +603,7 @@ namespace client std::make_pair( std::make_pair( localDestination->GetIdentHash(), port), - std::unique_ptr(serverTunnel))).second) + serverTunnel)).second) { serverTunnel->Start(); LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32()); @@ -611,13 +614,13 @@ namespace client continue; } - I2PServerTunnel * serverTunnel; + std::shared_ptr serverTunnel; if (type == I2P_TUNNELS_SECTION_TYPE_HTTP) - serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip); + serverTunnel = std::make_shared (name, host, port, localDestination, hostOverride, inPort, gzip); else if (type == I2P_TUNNELS_SECTION_TYPE_IRC) - serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, webircpass, inPort, gzip); + serverTunnel = std::make_shared (name, host, port, localDestination, webircpass, inPort, gzip); else // regular server tunnel by default - serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip); + serverTunnel = std::make_shared (name, host, port, localDestination, inPort, gzip); if(!isUniqueLocal) { @@ -640,10 +643,9 @@ namespace client while (comma != std::string::npos); serverTunnel->SetAccessList (idents); } - auto serverTunnelDest = serverTunnel->GetLocalDestination (); auto ins = m_ServerTunnels.insert (std::make_pair ( - std::make_pair (localDestination->GetIdentHash (), inPort), - std::unique_ptr(serverTunnel))); + std::make_pair (localDestination->GetIdentHash (), inPort), + serverTunnel)); if (ins.second) { serverTunnel->Start (); @@ -652,10 +654,10 @@ namespace client else { // TODO: update - if (ins.first->second->GetLocalDestination () != serverTunnelDest) + if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ()) { LogPrint (eLogInfo, "Clients: I2P server tunnel destination updated"); - ins.first->second->SetLocalDestination (serverTunnelDest); + ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); } ins.first->second->isUpdated = true; LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index 922d7acc..06aab3b1 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -113,12 +113,12 @@ namespace client i2p::proxy::HTTPProxy * m_HttpProxy; i2p::proxy::SOCKSProxy * m_SocksProxy; - std::map > m_ClientTunnels; // local endpoint->tunnel - std::map, std::unique_ptr > m_ServerTunnels; // ->tunnel + std::map > m_ClientTunnels; // local endpoint->tunnel + std::map, std::shared_ptr > m_ServerTunnels; // ->tunnel std::mutex m_ForwardsMutex; - std::map > m_ClientForwards; // local endpoint -> udp tunnel - std::map, std::unique_ptr > m_ServerForwards; // -> udp tunnel + std::map > m_ClientForwards; // local endpoint -> udp tunnel + std::map, std::shared_ptr > m_ServerForwards; // -> udp tunnel SAMBridge * m_SamBridge; BOBCommandChannel * m_BOBCommandChannel; From ad23ccb2191c8478da2ade1f565d32c6b70f9e39 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:28:30 +0300 Subject: [PATCH 033/195] separating android binary build --- {android/i2pd => android_binary/jni}/Android.mk | 2 +- {android/i2pd => android_binary/jni}/Application.mk | 2 +- daemon/Daemon.h | 2 +- daemon/HTTPServer.cpp | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) rename {android/i2pd => android_binary/jni}/Android.mk (98%) rename {android/i2pd => android_binary/jni}/Application.mk (95%) diff --git a/android/i2pd/Android.mk b/android_binary/jni/Android.mk similarity index 98% rename from android/i2pd/Android.mk rename to android_binary/jni/Android.mk index ae56110c..1c7cd92e 100755 --- a/android/i2pd/Android.mk +++ b/android_binary/jni/Android.mk @@ -13,7 +13,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_LDLIBS := -lz LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \ - $(wildcard $(LIB_SRC_PATH)/*.cpp)\ + $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/UnixDaemon.cpp \ $(DAEMON_SRC_PATH)/Daemon.cpp \ diff --git a/android/i2pd/Application.mk b/android_binary/jni/Application.mk similarity index 95% rename from android/i2pd/Application.mk rename to android_binary/jni/Application.mk index acc6f895..c2112d54 100755 --- a/android/i2pd/Application.mk +++ b/android_binary/jni/Application.mk @@ -15,7 +15,7 @@ APP_STL := gnustl_static # Enable c++11 extensions in source code APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE -APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP +APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP APP_LDFLAGS += -rdynamic -fPIE -pie ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 4491d303..00baf7b9 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -64,7 +64,7 @@ namespace util DaemonWin32 ():isGraceful(false) {} }; -#elif defined(ANDROID) +#elif (defined(ANDROID) && !defined(ANDROID_BINARY)) #define Daemon i2p::util::DaemonAndroid::Instance() // dummy, invoked from android/jni/DaemonAndroid.* class DaemonAndroid: public i2p::util::Daemon_Singleton diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 657e6d43..faf386d8 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -227,7 +227,7 @@ namespace http { default: s << "Unknown"; } s << "
\r\n"; -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (auto remains = Daemon.gracefulShutdownInterval) { s << "Stopping in: "; s << remains << " seconds"; @@ -504,7 +504,7 @@ namespace http { s << " Decline transit tunnels
\r\n"; else s << " Accept transit tunnels
\r\n"; -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (Daemon.gracefulShutdownInterval) s << " Cancel graceful shutdown
"; else @@ -964,14 +964,14 @@ namespace http { i2p::context.SetAcceptsTunnels (false); else if (cmd == HTTP_COMMAND_SHUTDOWN_START) { i2p::context.SetAcceptsTunnels (false); -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) Daemon.gracefulShutdownInterval = 10*60; #elif defined(WIN32_APP) i2p::win32::GracefulShutdown (); #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { i2p::context.SetAcceptsTunnels (true); -#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) +#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) Daemon.gracefulShutdownInterval = 0; #elif defined(WIN32_APP) i2p::win32::StopGracefulShutdown (); From c7b796ff313d007f6bfd1e0ab4830234b4d8cbd6 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:40:13 +0300 Subject: [PATCH 034/195] separate Android binary build based on DaemonLinux --- {android_binary => android_binary_only}/jni/Android.mk | 0 {android_binary => android_binary_only}/jni/Application.mk | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {android_binary => android_binary_only}/jni/Android.mk (100%) rename {android_binary => android_binary_only}/jni/Application.mk (100%) diff --git a/android_binary/jni/Android.mk b/android_binary_only/jni/Android.mk similarity index 100% rename from android_binary/jni/Android.mk rename to android_binary_only/jni/Android.mk diff --git a/android_binary/jni/Application.mk b/android_binary_only/jni/Application.mk similarity index 100% rename from android_binary/jni/Application.mk rename to android_binary_only/jni/Application.mk From 08a8ab98926797a2b9d9e3af6d8ead289227b25c Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:42:12 +0300 Subject: [PATCH 035/195] format --- android_binary_only/jni/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android_binary_only/jni/Android.mk b/android_binary_only/jni/Android.mk index 1c7cd92e..ae56110c 100755 --- a/android_binary_only/jni/Android.mk +++ b/android_binary_only/jni/Android.mk @@ -13,7 +13,7 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_LDLIBS := -lz LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \ - $(wildcard $(LIB_SRC_PATH)/*.cpp)\ + $(wildcard $(LIB_SRC_PATH)/*.cpp)\ $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\ $(DAEMON_SRC_PATH)/UnixDaemon.cpp \ $(DAEMON_SRC_PATH)/Daemon.cpp \ From 6e95318cba0ce810ce7e7a1c2e72b4882afbfff3 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 26 Apr 2018 22:44:32 +0300 Subject: [PATCH 036/195] I2PD_LIBS_PATH = /path/to/libraries to be same as in android normal build --- android_binary_only/jni/Application.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android_binary_only/jni/Application.mk b/android_binary_only/jni/Application.mk index c2112d54..7cd5c813 100755 --- a/android_binary_only/jni/Application.mk +++ b/android_binary_only/jni/Application.mk @@ -28,7 +28,7 @@ APP_OPTIM := debug # git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git # change to your own -I2PD_LIBS_PATH = /home/u/build/i2p/daemon/static.libs +I2PD_LIBS_PATH = /path/to/libraries BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt From db8a546b8fa2d23accbdf41de3ddc69e66df10d7 Mon Sep 17 00:00:00 2001 From: Al Date: Thu, 26 Apr 2018 20:07:51 +0000 Subject: [PATCH 037/195] android i2pd executable build instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 8fc8393a..9b7e42d4 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,12 @@ Build instructions: * [windows](https://i2pd.readthedocs.io/en/latest/devs/building/windows/) * [iOS](https://i2pd.readthedocs.io/en/latest/devs/building/ios/) * [android](https://i2pd.readthedocs.io/en/latest/devs/building/android/) +* android executable binary build: + - clone https://github.com/unlnown542a/i2pd.git or download https://github.com/unlnown542a/i2pd/archive/openssl.zip + - change to i2pd/android_binary_only + - edit jni/Application.mk - define path to static libs I2PD_LIBS_PATH + - in the directory i2pd/android_binary_only run: ndk-build -j4 + - find compiled binary - libs/armeabi-v7a/i2pd **Supported systems:** From 6265d452e9f464aebdd140429e87028d3705fb33 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 29 Apr 2018 10:53:04 -0400 Subject: [PATCH 038/195] more bounds checking --- libi2pd/Destination.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index b7c2ee32..4e758c92 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -329,17 +329,17 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); + HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); + HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET)); + HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); @@ -859,6 +859,11 @@ namespace client void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) { uint32_t length = bufbe32toh (buf); + if(length > len - 4) + { + LogPrint(eLogError, "Destination: Data message length ", length, " exceeds buffer length ", len); + return; + } buf += 4; // we assume I2CP payload uint16_t fromPort = bufbe16toh (buf + 4), // source From a63bc1cdca9b338c3c672aee4c79399e8087617c Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 29 Apr 2018 11:41:03 -0400 Subject: [PATCH 039/195] correct sizes --- libi2pd/Destination.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 4e758c92..e565d6c0 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -329,17 +329,17 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); + HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); + HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len)); + HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); From db035954732dadc5f8a8f09c944159ba56592504 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Apr 2018 18:05:28 -0400 Subject: [PATCH 040/195] correct message size --- libi2pd/Destination.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index e565d6c0..d3632881 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -329,17 +329,17 @@ namespace client switch (typeID) { case eI2NPData: - HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); + HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); break; case eI2NPDeliveryStatus: // we assume tunnel tests non-encrypted HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); break; case eI2NPDatabaseStore: - HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); + HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); break; case eI2NPDatabaseSearchReply: - HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len - I2NP_HEADER_SIZE)); + HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE); break; default: i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from)); From a22e9a2ca7f117daf6b17b11fb51e1549d87c621 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Apr 2018 13:34:16 -0400 Subject: [PATCH 041/195] don't start shared local destination twice --- libi2pd_client/ClientContext.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index 99f34b73..b40c2832 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -362,8 +362,6 @@ namespace client { m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA m_SharedLocalDestination->Acquire (); - m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination; - m_SharedLocalDestination->Start (); } std::shared_ptr ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const From 53a1a097a61e7a59af10a1166546c8e1b9387445 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Fri, 18 May 2018 15:45:35 -0400 Subject: [PATCH 042/195] Restore reseed certificate hottuna_at_mail.i2p.crt --- .../reseed/hottuna_at_mail.i2p.crt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 contrib/certificates/reseed/hottuna_at_mail.i2p.crt diff --git a/contrib/certificates/reseed/hottuna_at_mail.i2p.crt b/contrib/certificates/reseed/hottuna_at_mail.i2p.crt new file mode 100644 index 00000000..d0ff7c33 --- /dev/null +++ b/contrib/certificates/reseed/hottuna_at_mail.i2p.crt @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +MIIFxzCCA6+gAwIBAgIQZfqn0yiJL3dGgCjeOeWS6DANBgkqhkiG9w0BAQsFADBw +MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK +ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQ +aG90dHVuYUBtYWlsLmkycDAeFw0xNjExMDkwMzE1MzJaFw0yNjExMDkwMzE1MzJa +MHAxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNV +BAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQD +DBBob3R0dW5hQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEA21Bfgcc9VVH4l2u1YvYlTw2OPUyQb16X2IOW0PzdsUO5W78Loueu974BkiKi +84lQZanLr0OwEopdfutGc6gegSLmwaWx5YCG5uwpLOPkDiObfX+nptH6As/B1cn+ +mzejYdVKRnWd7EtHW0iseSsILBK1YbGw4AGpXJ8k18DJSzUt2+spOkpBW6XqectN +8y2JDSTns8yiNxietVeRN/clolDXT9ZwWHkd+QMHTKhgl3Uz1knOffU0L9l4ij4E +oFgPfQo8NL63kLM24hF1hM/At7XvE4iOlObFwPXE+H5EGZpT5+A7Oezepvd/VMzM +tCJ49hM0OlR393tKFONye5GCYeSDJGdPEB6+rBptpRrlch63tG9ktpCRrg2wQWgC +e3aOE1xVRrmwiTZ+jpfsOCbZrrSA/C4Bmp6AfGchyHuDGGkRU/FJwa1YLJe0dkWG +ITLWeh4zeVuAS5mctdv9NQ5wflSGz9S8HjsPBS5+CDOFHh4cexXRG3ITfk6aLhuY +KTMlkIO4SHKmnwAvy1sFlsqj6PbfVjpHPLg625fdNxBpe57TLxtIdBB3C7ccQSRW ++UG6Cmbcmh80PbsSR132NLMlzLhbaOjxeCWWJRo6cLuHBptAFMNwqsXt8xVf9M0N +NdJoKUmblyvjnq0N8aMEqtQ1uGMTaCB39cutHQq+reD/uzsCAwEAAaNdMFswDgYD +VR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNV +HRMBAf8EBTADAQH/MBkGA1UdDgQSBBBob3R0dW5hQG1haWwuaTJwMA0GCSqGSIb3 +DQEBCwUAA4ICAQCibFV8t4pajP176u3jx31x1kgqX6Nd+0YFARPZQjq99kUyoZer +GyHGsMWgM281RxiZkveHxR7Hm7pEd1nkhG3rm+d7GdJ2p2hujr9xUvl0zEqAAqtm +lkYI6uJ13WBjFc9/QuRIdeIeSUN+eazSXNg2nJhoV4pF9n2Q2xDc9dH4GWO93cMX +JPKVGujT3s0b7LWsEguZBPdaPW7wwZd902Cg/M5fE1hZQ8/SIAGUtylb/ZilVeTS +spxWP1gX3NT1SSvv0s6oL7eADCgtggWaMxEjZhi6WMnPUeeFY8X+6trkTlnF9+r/ +HiVvvzQKrPPtB3j1xfQCAF6gUKN4iY+2AOExv4rl/l+JJbPhpd/FuvD8AVkLMZ8X +uPe0Ew2xv30cc8JjGDzQvoSpBmVTra4f+xqH+w8UEmxnx97Ye2aUCtnPykACnFte +oT97K5052B1zq+4fu4xaHZnEzPYVK5POzOufNLPgciJsWrR5GDWtHd+ht/ZD37+b ++j1BXpeBWUBQgluFv+lNMVNPJxc2OMELR1EtEwXD7mTuuUEtF5Pi63IerQ5LzD3G +KBvXhMB0XhpE6WG6pBwAvkGf5zVv/CxClJH4BQbdZwj9HYddfEQlPl0z/XFR2M0+ +9/8nBfGSPYIt6KeHBCeyQWTdE9gqSzMwTMFsennXmaT8gyc7eKqKF6adqw== +-----END CERTIFICATE----- From d8b4765f23952ad6ae5c816cfd30ef88facd2d89 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Fri, 18 May 2018 15:54:39 -0400 Subject: [PATCH 043/195] Add /etc/resolv.conf to apparmor profile and k flag for pidfile --- contrib/apparmor/usr.sbin.i2pd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/apparmor/usr.sbin.i2pd b/contrib/apparmor/usr.sbin.i2pd index 4349e07b..168070da 100644 --- a/contrib/apparmor/usr.sbin.i2pd +++ b/contrib/apparmor/usr.sbin.i2pd @@ -17,14 +17,15 @@ /etc/host.conf r, /etc/hosts r, /etc/nsswitch.conf r, + /etc/resolv.conf r, /run/resolvconf/resolv.conf r, # path specific (feel free to modify if you have another paths) /etc/i2pd/** r, - /run/i2pd/i2pd.pid rw, + /run/i2pd/i2pd.pid rwk, /var/lib/i2pd/** rw, /var/log/i2pd/i2pd.log w, - /var/run/i2pd/i2pd.pid rw, + /var/run/i2pd/i2pd.pid rwk, /usr/sbin/i2pd mr, /usr/share/i2pd/** r, From 5ec11c53e9fd79aeace80512c50f584978bb22f2 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Sun, 6 May 2018 12:26:59 +0800 Subject: [PATCH 044/195] differentiation between windows release and debug build into i2pd_qt.pro --- qt/i2pd_qt/i2pd_qt.pro | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 12d13a17..8ae9f581 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -4,7 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = i2pd_qt TEMPLATE = app -QMAKE_CXXFLAGS *= -std=c++11 +QMAKE_CXXFLAGS *= -std=c++11 -ggdb DEFINES += USE_UPNP # change to your own path, where you will store all needed libraries with 'git clone' commands below. @@ -280,8 +280,11 @@ windows { DEFINES += BOOST_USE_WINDOWS_H WINDOWS _WINDOWS WIN32_LEAN_AND_MEAN MINIUPNP_STATICLIB DEFINES -= UNICODE _UNICODE BOOST_SUFFIX = -mt - QMAKE_CXXFLAGS = -Os - QMAKE_LFLAGS = -s -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + QMAKE_CXXFLAGS_RELEASE = -Os + QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows + + #strip + QMAKE_LFLAGS_RELEASE += -s LIBS = -lminiupnpc \ -lboost_system$$BOOST_SUFFIX \ From f8fe124428df31cc7942417b9f4e74a31d1ecb14 Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Sun, 6 May 2018 12:30:09 +0800 Subject: [PATCH 045/195] improved comment at qt.pro file --- qt/i2pd_qt/i2pd_qt.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 8ae9f581..86cf579e 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -283,7 +283,7 @@ windows { QMAKE_CXXFLAGS_RELEASE = -Os QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows - #strip + #linker's -s means "strip" QMAKE_LFLAGS_RELEASE += -s LIBS = -lminiupnpc \ From ed2818eaa24dd7f0e883e05e97544986858db9af Mon Sep 17 00:00:00 2001 From: "mewmew@i2p" Date: Sat, 19 May 2018 23:03:49 +0800 Subject: [PATCH 046/195] qt log viewer now works --- daemon/Daemon.cpp | 13 ++- daemon/Daemon.h | 6 +- libi2pd/Log.cpp | 16 ++- qt/i2pd_qt/DaemonQT.cpp | 27 +++-- qt/i2pd_qt/DaemonQT.h | 2 +- qt/i2pd_qt/SignatureTypeComboboxFactory.h | 2 +- qt/i2pd_qt/i2pd_qt.pro | 6 +- qt/i2pd_qt/logviewermanager.cpp | 45 ++++++++ qt/i2pd_qt/logviewermanager.h | 130 ++++++++++++++++++++++ qt/i2pd_qt/mainwindow.cpp | 24 +++- qt/i2pd_qt/mainwindow.h | 24 ++-- qt/i2pd_qt/mainwindow.ui | 80 ++++++++++++- 12 files changed, 335 insertions(+), 40 deletions(-) create mode 100644 qt/i2pd_qt/logviewermanager.cpp create mode 100644 qt/i2pd_qt/logviewermanager.h diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index d077644d..ee56a1c7 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -60,8 +60,12 @@ namespace i2p return service; } - bool Daemon_Singleton::init(int argc, char* argv[]) - { + bool Daemon_Singleton::init(int argc, char* argv[]) { + return init(argc, argv, nullptr); + } + + bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr logstream) + { i2p::config::Init(); i2p::config::ParseCmdline(argc, argv); @@ -104,7 +108,10 @@ namespace i2p logs = "file"; i2p::log::Logger().SetLogLevel(loglevel); - if (logs == "file") { + if (logstream) { + LogPrint(eLogInfo, "Log: will send messages to std::ostream"); + i2p::log::Logger().SendTo (logstream); + } else if (logs == "file") { if (logfile == "") logfile = i2p::fs::DataDirPath("i2pd.log"); LogPrint(eLogInfo, "Log: will send messages to ", logfile); diff --git a/daemon/Daemon.h b/daemon/Daemon.h index 00baf7b9..1745b980 100644 --- a/daemon/Daemon.h +++ b/daemon/Daemon.h @@ -3,6 +3,7 @@ #include #include +#include namespace i2p { @@ -12,8 +13,9 @@ namespace util class Daemon_Singleton { public: - virtual bool init(int argc, char* argv[]); - virtual bool start(); + virtual bool init(int argc, char* argv[], std::shared_ptr logstream); + virtual bool init(int argc, char* argv[]); + virtual bool start(); virtual bool stop(); virtual void run () {}; diff --git a/libi2pd/Log.cpp b/libi2pd/Log.cpp index b664a5d9..79b4a511 100644 --- a/libi2pd/Log.cpp +++ b/libi2pd/Log.cpp @@ -8,6 +8,9 @@ #include "Log.h" +//for std::transform +#include + namespace i2p { namespace log { static Log logger; @@ -107,7 +110,18 @@ namespace log { } } - void Log::SetLogLevel (const std::string& level) { + std::string str_tolower(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + // static_cast(std::tolower) // wrong + // [](int c){ return std::tolower(c); } // wrong + // [](char c){ return std::tolower(c); } // wrong + [](unsigned char c){ return std::tolower(c); } // correct + ); + return s; + } + + void Log::SetLogLevel (const std::string& level_) { + std::string level=str_tolower(level_); if (level == "none") { m_MinLevel = eLogNone; } else if (level == "error") { m_MinLevel = eLogError; } else if (level == "warn") { m_MinLevel = eLogWarning; } diff --git a/qt/i2pd_qt/DaemonQT.cpp b/qt/i2pd_qt/DaemonQT.cpp index dd7c892d..f5e6d62b 100644 --- a/qt/i2pd_qt/DaemonQT.cpp +++ b/qt/i2pd_qt/DaemonQT.cpp @@ -1,6 +1,11 @@ +#include + #include "DaemonQT.h" #include "Daemon.h" #include "mainwindow.h" + +#include "Log.h" + #include #include #include @@ -90,12 +95,12 @@ namespace qt delete mutex; } - bool DaemonQTImpl::init(int argc, char* argv[]) + bool DaemonQTImpl::init(int argc, char* argv[], std::shared_ptr logstream) { mutex=new QMutex(QMutex::Recursive); setRunningCallback(0); m_IsRunning=false; - return Daemon.init(argc,argv); + return Daemon.init(argc,argv,logstream); } void DaemonQTImpl::start() @@ -146,33 +151,35 @@ namespace qt int result; { + std::shared_ptr logstreamptr=std::make_shared(); + //TODO move daemon init deinit to a bg thread DaemonQTImpl daemon; - qDebug("Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(argc, argv); + (*logstreamptr) << "Initialising the daemon..." << std::endl; + bool daemonInitSuccess = daemon.init(argc, argv, logstreamptr); if(!daemonInitSuccess) { QMessageBox::critical(0, "Error", "Daemon init failed"); return 1; } - qDebug("Initialised, creating the main window..."); - MainWindow w; - qDebug("Before main window.show()..."); + LogPrint(eLogDebug, "Initialised, creating the main window..."); + MainWindow w(logstreamptr); + LogPrint(eLogDebug, "Before main window.show()..."); w.show (); { i2p::qt::Controller daemonQtController(daemon); w.setI2PController(&daemonQtController); - qDebug("Starting the daemon..."); + LogPrint(eLogDebug, "Starting the daemon..."); emit daemonQtController.startDaemon(); //daemon.start (); - qDebug("Starting GUI event loop..."); + LogPrint(eLogDebug, "Starting GUI event loop..."); result = app.exec(); //daemon.stop (); } } //QMessageBox::information(&w, "Debug", "demon stopped"); - qDebug("Exiting the application"); + LogPrint(eLogDebug, "Exiting the application"); return result; } } diff --git a/qt/i2pd_qt/DaemonQT.h b/qt/i2pd_qt/DaemonQT.h index d0add0e3..780d2f73 100644 --- a/qt/i2pd_qt/DaemonQT.h +++ b/qt/i2pd_qt/DaemonQT.h @@ -25,7 +25,7 @@ namespace qt * @param argv * @return success */ - bool init(int argc, char* argv[]); + bool init(int argc, char* argv[], std::shared_ptr logstream); void start(); void stop(); void restart(); diff --git a/qt/i2pd_qt/SignatureTypeComboboxFactory.h b/qt/i2pd_qt/SignatureTypeComboboxFactory.h index 41245dac..f7cac658 100644 --- a/qt/i2pd_qt/SignatureTypeComboboxFactory.h +++ b/qt/i2pd_qt/SignatureTypeComboboxFactory.h @@ -18,7 +18,7 @@ class SignatureTypeComboBoxFactory } public: - static const uint16_t getSigType(const QVariant& var) { + static uint16_t getSigType(const QVariant& var) { return (uint16_t)var.toInt(); } diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 86cf579e..6c0464ab 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -93,7 +93,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ textbrowsertweaked1.cpp \ pagewithbackbutton.cpp \ widgetlock.cpp \ - widgetlockregistry.cpp + widgetlockregistry.cpp \ + logviewermanager.cpp #qt creator does not handle this well #SOURCES += $$files(../../libi2pd/*.cpp) @@ -179,7 +180,8 @@ HEADERS += DaemonQT.h mainwindow.h \ widgetlock.h \ widgetlockregistry.h \ i2pd.rc \ - i2pd.rc + i2pd.rc \ + logviewermanager.h INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client diff --git a/qt/i2pd_qt/logviewermanager.cpp b/qt/i2pd_qt/logviewermanager.cpp new file mode 100644 index 00000000..30fc904a --- /dev/null +++ b/qt/i2pd_qt/logviewermanager.cpp @@ -0,0 +1,45 @@ +#include "logviewermanager.h" + +LogViewerManager::LogViewerManager(std::shared_ptr logStream_, + QPlainTextEdit* logTextEdit_, + QObject *parent) : + QObject(parent), + logStream(logStream_), + logTextEdit(logTextEdit_), + controllerForBgThread(nullptr) +{ + assert(logTextEdit!=nullptr); + controllerForBgThread=new i2pd::qt::logviewer::Controller(*this); +} + +namespace i2pd { +namespace qt { +namespace logviewer { + +QString Worker::pollAndShootATimerForInfiniteRetries() { + std::shared_ptr logStream=logViewerManager.getLogStream(); + assert(logStream!=nullptr); + std::streamsize MAX_SZ=64*1024; + char*buf=(char*)malloc(MAX_SZ*sizeof(char)); + if(buf==nullptr)return ""; + std::streamsize read=logStream->readsome(buf, MAX_SZ); + if(read<0)read=0; + QString ret=QString::fromUtf8(buf, read); + free(buf); + return ret; +} + +Controller::Controller(LogViewerManager ¶meter1):logViewerManager(parameter1) { + Worker *worker = new Worker(parameter1); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::operate1, worker, &Worker::doWork1); + connect(worker, &Worker::resultReady, + ¶meter1, &LogViewerManager::appendPlainText_atGuiThread); + workerThread.start(); + timerId=startTimer(100/*millis*/); +} + +} +} +} diff --git a/qt/i2pd_qt/logviewermanager.h b/qt/i2pd_qt/logviewermanager.h new file mode 100644 index 00000000..e9ede79f --- /dev/null +++ b/qt/i2pd_qt/logviewermanager.h @@ -0,0 +1,130 @@ +#ifndef LOGVIEWERMANAGER_H +#define LOGVIEWERMANAGER_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "FS.h" +#include "Log.h" + +class LogViewerManager; + +namespace i2pd { +namespace qt { +namespace logviewer { + +class Worker : public QObject +{ + Q_OBJECT +private: + LogViewerManager &logViewerManager; +public: + Worker(LogViewerManager ¶meter1):logViewerManager(parameter1){} +private: + QString pollAndShootATimerForInfiniteRetries(); + +public slots: + void doWork1() { + /* ... here is the expensive or blocking operation ... */ + QString read=pollAndShootATimerForInfiniteRetries(); + emit resultReady(read); + } + +signals: + void resultReady(QString read); +}; + +class Controller : public QObject +{ + Q_OBJECT + QThread workerThread; + LogViewerManager& logViewerManager; + int timerId; +public: + Controller(LogViewerManager ¶meter1); + ~Controller() { + if(timerId!=0)killTimer(timerId); + workerThread.quit(); + workerThread.wait(); + } +signals: + void operate1(); +protected: + void timerEvent(QTimerEvent */*event*/) { + emit operate1(); + } +}; + +} +} +} + +class LogViewerManager : public QObject +{ + Q_OBJECT +private: + std::shared_ptr logStream; + QPlainTextEdit* logTextEdit; + i2pd::qt::logviewer::Controller* controllerForBgThread; +public: + //also starts a bg thread (QTimer) polling logStream->readsome(buf, n) + explicit LogViewerManager(std::shared_ptr logStream_, + QPlainTextEdit* logTextEdit_, + QObject *parent); + //also deallocs the bg thread (QTimer) + virtual ~LogViewerManager(){} + const i2pd::qt::logviewer::Controller& getControllerForBgThread() { + assert(controllerForBgThread!=nullptr); + return *controllerForBgThread; + } + const QPlainTextEdit* getLogTextEdit(){ return logTextEdit; } + const std::shared_ptr getLogStream(){ return logStream; } +signals: + +public slots: + //void appendFromNonGuiThread(std::string read) { + //} +public slots: + void appendPlainText_atGuiThread(QString plainText) { + if(plainText.length()==0)return; + assert(logTextEdit!=nullptr); + int scrollPosVert =logTextEdit->verticalScrollBar()->value(); + int scrollPosHoriz=logTextEdit->horizontalScrollBar()->value(); + int scrollPosVertMax =logTextEdit->verticalScrollBar()->maximum(); + const int MAX_LINES=10*1024; + logTextEdit->setMaximumBlockCount(MAX_LINES); + //logTextEdit->appendPlainText(plainText); + //navigate the window to the end + //QTextCursor cursor = logTextEdit->textCursor(); + //cursor.movePosition(QTextCursor::MoveOperation::End); + //logTextEdit->setTextCursor(cursor); + //QTextCursor prev_cursor = logTextEdit->textCursor(); + logTextEdit->moveCursor(QTextCursor::End); + logTextEdit->insertPlainText(plainText); + if(/*prev_cursor.atEnd()*/scrollPosVert==scrollPosVertMax){ + //logTextEdit->moveCursor(QTextCursor::End); + scrollPosVert =logTextEdit->verticalScrollBar()->maximum(); + scrollPosHoriz=logTextEdit->horizontalScrollBar()->minimum(); + } + //else + // logTextEdit->setTextCursor(prev_cursor); + logTextEdit->verticalScrollBar()->setValue(scrollPosVert); + logTextEdit->horizontalScrollBar()->setValue(scrollPosHoriz); + } + /* + void replaceText_atGuiThread() { + assert(logTextEdit!=nullptr); + logTextEdit->setText(QString::fromStdString(nav.getContent())); + } + */ +}; + +#endif // LOGVIEWERMANAGER_H diff --git a/qt/i2pd_qt/mainwindow.cpp b/qt/i2pd_qt/mainwindow.cpp index a095f78c..e4c9f2a7 100644 --- a/qt/i2pd_qt/mainwindow.cpp +++ b/qt/i2pd_qt/mainwindow.cpp @@ -27,15 +27,19 @@ #include "DaemonQT.h" #include "SignatureTypeComboboxFactory.h" +#include "logviewermanager.h" + std::string programOptionsWriterCurrentSection; -MainWindow::MainWindow(QWidget *parent) : +MainWindow::MainWindow(std::shared_ptr logStream_, QWidget *parent) : QMainWindow(parent) + ,logStream(logStream_) #ifndef ANDROID ,quitting(false) #endif ,wasSelectingAtStatusMainPage(false) ,showHiddenInfoStatusMainPage(false) + ,logViewerManagerPtr(nullptr) ,ui(new Ui::MainWindow) ,statusButtonsUI(new Ui::StatusButtonsForm) ,routerCommandsUI(new Ui::routerCommandsWidget) @@ -132,6 +136,8 @@ MainWindow::MainWindow(QWidget *parent) : QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit())); QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit())); + QObject::connect(ui->logViewerPushButton, SIGNAL(released()), this, SLOT(showLogViewerPage())); + QObject::connect(ui->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage())); QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage())); @@ -299,6 +305,9 @@ MainWindow::MainWindow(QWidget *parent) : trayIcon->show(); #endif + logViewerManagerPtr=new LogViewerManager(logStream_,ui->logViewerTextEdit,this); + assert(logViewerManagerPtr!=nullptr); + onLoggingOptionsChange(); //QMetaObject::connectSlotsByName(this); } @@ -333,10 +342,11 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){ } wasSelectingAtStatusMainPage=false; } -void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} -void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} -void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} -void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);} +void MainWindow::showLogViewerPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);} +void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);} +void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);} +void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(4);setStatusButtonsVisible(false);} +void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(5);setStatusButtonsVisible(false);} void MainWindow::setStatusButtonsVisible(bool visible) { ui->statusButtonsPane->setVisible(visible); @@ -631,6 +641,8 @@ void MainWindow::loadAllConfigs(){ } ReadTunnelsConfig(); + + onLoggingOptionsChange(); } /** returns false iff not valid items present and save was aborted */ bool MainWindow::saveAllConfigs(){ @@ -668,6 +680,8 @@ bool MainWindow::saveAllConfigs(){ SaveTunnelsConfig(); + onLoggingOptionsChange(); + return true; } diff --git a/qt/i2pd_qt/mainwindow.h b/qt/i2pd_qt/mainwindow.h index c5f0c902..51384f51 100644 --- a/qt/i2pd_qt/mainwindow.h +++ b/qt/i2pd_qt/mainwindow.h @@ -62,6 +62,8 @@ #include "widgetlockregistry.h" #include "widgetlock.h" +class LogViewerManager; + template bool isType(boost::any& a) { return @@ -215,7 +217,8 @@ public: }; class LogDestinationComboBoxItem : public ComboBoxItem { public: - LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {}; + LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : + ComboBoxItem(option_, comboBox_) {} virtual ~LogDestinationComboBoxItem(){} virtual void loadFromConfigOption(){ MainWindowItem::loadFromConfigOption(); @@ -228,6 +231,8 @@ public: MainWindowItem::saveToStringStream(out); } virtual bool isValid() { return true; } + + Q_OBJECT }; class LogLevelComboBoxItem : public ComboBoxItem { public: @@ -370,9 +375,10 @@ class Controller; class MainWindow : public QMainWindow { Q_OBJECT - +private: + std::shared_ptr logStream; public: - explicit MainWindow(QWidget *parent=0); + explicit MainWindow(std::shared_ptr logStream_, QWidget *parent=nullptr); ~MainWindow(); void setI2PController(i2p::qt::Controller* controller_); @@ -419,6 +425,7 @@ public slots: void showStatus_i2p_tunnels_Page(); void showStatus_sam_sessions_Page(); + void showLogViewerPage(); void showSettingsPage(); void showTunnelsPage(); void showRestartPage(); @@ -430,6 +437,8 @@ private: bool wasSelectingAtStatusMainPage; bool showHiddenInfoStatusMainPage; + LogViewerManager *logViewerManagerPtr; + void showStatusPage(StatusPage newStatusPage); #ifndef ANDROID void createActions(); @@ -522,13 +531,6 @@ private: void appendTunnelForms(std::string tunnelNameToFocus); void deleteTunnelForms(); - - /* - - TODO signaturetype - - */ - template std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const { @@ -790,6 +792,8 @@ private: }; TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener; + + void onLoggingOptionsChange() {} }; #endif // MAINWINDOW_H diff --git a/qt/i2pd_qt/mainwindow.ui b/qt/i2pd_qt/mainwindow.ui index 9b463f44..dcdf88bd 100644 --- a/qt/i2pd_qt/mainwindow.ui +++ b/qt/i2pd_qt/mainwindow.ui @@ -58,7 +58,7 @@ QLayout::SetMaximumSize - + QLayout::SetMinimumSize @@ -96,6 +96,13 @@ + + + + Log + + + @@ -596,7 +603,7 @@ - TextLabel + wrongInputMessageLabel true @@ -627,7 +634,7 @@ - 2 + 1 @@ -671,6 +678,69 @@ + + + + 0 + 0 + + + + + + 0 + 0 + 711 + 531 + + + + + QLayout::SetMinAndMaxSize + + + + + + 15 + + + + Log + + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAsNeeded + + + QAbstractScrollArea::AdjustIgnored + + + 10000 + + + false + + + true + + + + + + @@ -728,8 +798,8 @@ 0 0 - 689 - 496 + 81 + 28 From 5d86c1c9a65819aaa89ba32f5f77990362885a2f Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 May 2018 14:27:26 -0400 Subject: [PATCH 047/195] ntcp2 crypto added --- libi2pd/ChaCha20.cpp | 147 +++++++++++++++++++++ libi2pd/ChaCha20.h | 26 ++++ libi2pd/Poly1305.cpp | 303 +++++++++++++++++++++++++++++++++++++++++++ libi2pd/Poly1305.h | 28 ++++ libi2pd/Siphash.h | 152 ++++++++++++++++++++++ 5 files changed, 656 insertions(+) create mode 100644 libi2pd/ChaCha20.cpp create mode 100644 libi2pd/ChaCha20.h create mode 100644 libi2pd/Poly1305.cpp create mode 100644 libi2pd/Poly1305.h create mode 100644 libi2pd/Siphash.h diff --git a/libi2pd/ChaCha20.cpp b/libi2pd/ChaCha20.cpp new file mode 100644 index 00000000..e43f1514 --- /dev/null +++ b/libi2pd/ChaCha20.cpp @@ -0,0 +1,147 @@ +#include "ChaCha20.h" + +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +namespace i2p +{ +namespace crypto +{ +namespace chacha +{ +constexpr int rounds = 20; +constexpr std::size_t blocksize = 64; + +void u32t8le(uint32_t v, uint8_t * p) +{ + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +uint32_t u8t32le(const uint8_t * p) +{ + uint32_t value = p[3]; + + value = (value << 8) | p[2]; + value = (value << 8) | p[1]; + value = (value << 8) | p[0]; + + return value; +} + +uint32_t rotl32(uint32_t x, int n) +{ + return x << n | (x >> (-n & 31)); +} + +void quarterround(uint32_t *x, int a, int b, int c, int d) +{ + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); +} + + struct State_t + { + State_t() {}; + State_t(State_t &&) = delete; + + State_t & operator += (const State_t & other) + { + for(int i = 0; i < 16; i++) + data[i] += other.data[i]; + return *this; + } + + void Copy(const State_t & other) + { + memcpy(data, other.data, sizeof(uint32_t) * 16); + } + uint32_t data[16]; + }; + + struct Block_t + { + Block_t() {}; + Block_t(Block_t &&) = delete; + + uint8_t data[blocksize]; + + void operator << (const State_t & st) + { + int i; + for (i = 0; i < 16; i++) + u32t8le(st.data[i], data + (i << 2)); + } + }; + +void block(const State_t &input, Block_t & block, int rounds) +{ + int i; + State_t x; + x.Copy(input); + + for (i = rounds; i > 0; i -= 2) + { + quarterround(x.data, 0, 4, 8, 12); + quarterround(x.data, 1, 5, 9, 13); + quarterround(x.data, 2, 6, 10, 14); + quarterround(x.data, 3, 7, 11, 15); + quarterround(x.data, 0, 5, 10, 15); + quarterround(x.data, 1, 6, 11, 12); + quarterround(x.data, 2, 7, 8, 13); + quarterround(x.data, 3, 4, 9, 14); + } + x += input; + block << x; + +} +} // namespace chacha + + + + + +void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter) +{ + chacha::State_t state; + chacha::Block_t block; + size_t i, j; + + state.data[0] = 0x61707865; + state.data[1] = 0x3320646e; + state.data[2] = 0x79622d32; + state.data[3] = 0x6b206574; + + for (i = 0; i < 8; i++) + state.data[4 + i] = chacha::u8t32le(key + i * 4); + + + state.data[12] = counter; + + for (i = 0; i < 3; i++) + state.data[13 + i] = chacha::u8t32le(nonce + i * 4); + + + for (i = 0; i < sz; i += chacha::blocksize) + { + chacha::block(state, block, chacha::rounds); + state.data[12]++; + for (j = i; j < i + chacha::blocksize; j++) + { + if (j >= sz) break; + buf[j] ^= block.data[j - i]; + } + } + +} + +} +} \ No newline at end of file diff --git a/libi2pd/ChaCha20.h b/libi2pd/ChaCha20.h new file mode 100644 index 00000000..c88325d5 --- /dev/null +++ b/libi2pd/ChaCha20.h @@ -0,0 +1,26 @@ +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +#ifndef LIBI2PD_CHACHA20_H +#define LIBI2PD_CHACHA20_H +#include +#include + +namespace i2p +{ +namespace crypto +{ + const std::size_t CHACHA20_KEY_BYTES = 32; + const std::size_t CHACHA20_NOUNCE_BYTES = 12; + + /** encrypt buf in place with chacha20 */ + void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter=1); + +} +} + +#endif diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp new file mode 100644 index 00000000..355555c6 --- /dev/null +++ b/libi2pd/Poly1305.cpp @@ -0,0 +1,303 @@ +#include "Poly1305.h" +#include "CPU.h" +#include +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +namespace i2p +{ +namespace crypto +{ +#if 0 +#ifdef __AVX2__ + struct Poly1305_AVX2 + { + Poly1305_AVX2(const uint32_t *& k) + { + __asm__ + ( + "VMOVNTDQA %[key0], %%ymm0 \n" + "VMOVNTDQA 32%[key0], %%ymm1 \n" + : + : + [key0]"m"(k) + ); + }; + + ~Poly1305_AVX2() + { + // clear out registers + __asm__ + ( + "VZEROALL\n" + ); + } + + void Update(const uint8_t * buf, size_t sz) + { + + } + + void Finish(uint32_t *& out) + { + + } + + + + size_t leftover; + + }; +#endif +#endif + namespace poly1305 + { + + struct LongBlock + { + unsigned long data[17]; + operator unsigned long * () + { + return data; + } + }; + + struct Block + { + unsigned char data[17]; + + operator uint8_t * () + { + return data; + } + + Block & operator += (const Block & other) + { + unsigned short u; + unsigned int i; + for(u = 0, i = 0; i < 17; i++) + { + u += (unsigned short) data[i] + (unsigned short) other.data[i]; + data[i] = (unsigned char) u & 0xff; + u >>= 8; + } + return *this; + } + + Block & operator %=(const LongBlock & other) + { + unsigned long u; + unsigned int i; + u = 0; + for (i = 0; i < 16; i++) { + u += other.data[i]; + data[i] = (unsigned char)u & 0xff; + u >>= 8; + } + u += other.data[16]; + data[16] = (unsigned char)u & 0x03; + u >>= 2; + u += (u << 2); + for (i = 0; i < 16; i++) { + u += data[i]; + data[i] = (unsigned char)u & 0xff; + u >>= 8; + } + data[16] += (unsigned char)u; + return *this; + } + + Block & operator = (const Block & other) + { + memcpy(data, other.data, sizeof(data)); + return *this; + } + + Block & operator ~ () + { + static const Block minusp = { + 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfc + }; + Block orig; + unsigned char neg; + unsigned int i; + orig = *this; + *this += minusp; + neg = -(data[16] >> 7); + for(i = 0; i < 17; i++) + data[i] ^= neg & (orig.data[i] ^ data[i]); + + return *this; + } + + void PutKey(const uint8_t * key) + { + data[0] = key[0] & 0xff; + data[1] = key[1] & 0xff; + data[2] = key[2] & 0xff; + data[3] = key[3] & 0x0f; + data[4] = key[4] & 0xfc; + data[5] = key[5] & 0xff; + data[6] = key[6] & 0xff; + data[7] = key[7] & 0x0f; + data[8] = key[8] & 0xfc; + data[9] = key[9] & 0xff; + data[10] = key[10] & 0xff; + data[11] = key[11] & 0x0f; + data[12] = key[12] & 0xfc; + data[13] = key[13] & 0xff; + data[14] = key[14] & 0xff; + data[15] = key[15] & 0x0f; + data[16] = 0; + } + + void Put(const uint8_t * d, uint8_t last=0) + { + memcpy(data, d, 17); + data[16] = last; + } + }; + + struct Buffer + { + uint8_t data[POLY1305_BLOCK_BYTES]; + + operator uint8_t * () + { + return data; + } + }; + } + + struct Poly1305 + { + + Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) + { + m_R.PutKey(key); + m_Pad.Put(key + 16); + } + + void Update(const uint8_t * buf, size_t sz) + { + // process leftover + if(m_Leftover) + { + size_t want = POLY1305_BLOCK_BYTES - m_Leftover; + if(want > sz) want = sz; + memcpy(m_Buffer + m_Leftover, buf, want); + sz -= want; + buf += want; + m_Leftover += want; + if(m_Leftover < POLY1305_BLOCK_BYTES) return; + Blocks(m_Buffer, POLY1305_BLOCK_BYTES); + m_Leftover = 0; + } + // process blocks + if(sz >= POLY1305_BLOCK_BYTES) + { + size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1)); + Blocks(buf, want); + buf += want; + sz -= want; + } + // leftover + if(sz) + { + memcpy(m_Buffer+m_Leftover, buf, sz); + m_Leftover += sz; + } + } + + void Blocks(const uint8_t * buf, size_t sz) + { + const unsigned char hi = m_Final ^ 1; + while (sz >= POLY1305_BLOCK_BYTES) { + + unsigned long u; + + unsigned int i, j; + m_Msg.Put(buf, hi); + /* h += m */ + m_H += m_Msg; + + /* h *= r */ + for (i = 0; i < 17; i++) { + u = 0; + for (j = 0; j <= i ; j++) { + u += (unsigned short)m_H.data[j] * m_R.data[i - j]; + } + for (j = i + 1; j < 17; j++) { + unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j]; + v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */ + u += v; + } + m_HR[i] = u; + } + /* (partial) h %= p */ + m_H %= m_HR; + buf += POLY1305_BLOCK_BYTES; + sz -= POLY1305_BLOCK_BYTES; + } + } + + void Finish(uint32_t *& out) + { + // process leftovers + if(m_Leftover) + { + size_t idx = m_Leftover; + m_Buffer[idx++] = 1; + for(; idx < POLY1305_BLOCK_BYTES; idx++) + m_Buffer[idx] = 0; + m_Final = 1; + Blocks(m_Buffer, POLY1305_BLOCK_BYTES); + } + + // freeze H + ~m_H; + // add pad + m_H += m_Pad; + // copy digest + memcpy(out, m_H, 16); + } + + size_t m_Leftover; + poly1305::Buffer m_Buffer; + poly1305::Block m_H; + poly1305::Block m_R; + poly1305::Block m_Pad; + poly1305::Block m_Msg; + poly1305::LongBlock m_HR; + uint8_t m_Final; + + }; + + void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz) + { + #if 0 + #ifdef __AVX2__ + if(i2p::cpu::avx2) + { + Poly1305_AVX2 p(key); + p.Update(buf, sz); + p.Finish(out); + } + else + #endif + #endif + { + const uint8_t * k = (const uint8_t *) key; + Poly1305 p(k); + p.Update(buf, sz); + p.Finish(out); + } + } +} +} diff --git a/libi2pd/Poly1305.h b/libi2pd/Poly1305.h new file mode 100644 index 00000000..2c62c5aa --- /dev/null +++ b/libi2pd/Poly1305.h @@ -0,0 +1,28 @@ +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +#ifndef LIBI2PD_POLY1305_H +#define LIBI2PD_POLY1305_H +#include +#include + +namespace i2p +{ +namespace crypto +{ + const std::size_t POLY1305_DIGEST_BYTES = 16; + const std::size_t POLY1305_DIGEST_DWORDS = 4; + const std::size_t POLY1305_KEY_BYTES = 32; + const std::size_t POLY1305_KEY_DWORDS = 8; + const std::size_t POLY1305_BLOCK_BYTES = 16; + + void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz); + +} +} + +#endif diff --git a/libi2pd/Siphash.h b/libi2pd/Siphash.h new file mode 100644 index 00000000..3e74c6e9 --- /dev/null +++ b/libi2pd/Siphash.h @@ -0,0 +1,152 @@ +/** + This code is licensed under the MCGSI Public License + Copyright 2018 Jeff Becker + + Kovri go write your own code + + */ +#ifndef SIPHASH_H +#define SIPHASH_H + +#include + +namespace i2p +{ +namespace crypto +{ + namespace siphash + { + constexpr int crounds = 2; + constexpr int drounds = 4; + + uint64_t rotl(const uint64_t & x, int b) + { + uint64_t ret = x << b; + ret |= x >> (64 - b); + return ret; + } + + void u32to8le(const uint32_t & v, uint8_t * p) + { + p[0] = (uint8_t) v; + p[1] = (uint8_t) (v >> 8); + p[2] = (uint8_t) (v >> 16); + p[3] = (uint8_t) (v >> 24); + } + + void u64to8le(const uint64_t & v, uint8_t * p) + { + p[0] = v & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; + p[4] = (v >> 32) & 0xff; + p[5] = (v >> 40) & 0xff; + p[6] = (v >> 48) & 0xff; + p[7] = (v >> 56) & 0xff; + } + + uint64_t u8to64le(const uint8_t * p) + { + uint64_t i = 0; + int idx = 0; + while(idx < 8) + { + i |= ((uint64_t) p[idx]) << (idx * 8); + ++idx; + } + return i; + } + + void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) + { + _v0 += _v1; + _v1 = rotl(_v1, 13); + _v1 ^= _v0; + _v0 = rotl(_v0, 32); + _v2 += _v3; + _v3 = rotl(_v3, 16); + _v3 ^= _v2; + _v0 += _v3; + _v3 = rotl(_v3, 21); + _v3 ^= _v0; + _v2 += _v1; + _v1 = rotl(_v1, 17); + _v1 ^= _v2; + _v2 = rotl(_v2, 32); + } + } + + /** hashsz must be 8 or 16 */ + template + void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) + { + uint64_t v0 = 0x736f6d6570736575ULL; + uint64_t v1 = 0x646f72616e646f6dULL; + uint64_t v2 = 0x6c7967656e657261ULL; + uint64_t v3 = 0x7465646279746573ULL; + const uint64_t k0 = siphash::u8to64le(key); + const uint64_t k1 = siphash::u8to64le(key + 8); + uint64_t msg; + int i; + const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t)); + auto left = bufsz & 7; + uint64_t b = ((uint64_t)bufsz) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if(hashsz == 16) v1 ^= 0xee; + + while(buf != end) + { + msg = siphash::u8to64le(buf); + v3 ^= msg; + for(i = 0; i < siphash::crounds; ++i) + siphash::round(v0, v1, v2, v3); + + v0 ^= msg; + buf += 8; + } + + while(left) + { + --left; + b |= ((uint64_t)(buf[left])) << (left * 8); + } + + v3 ^= b; + + for(i = 0; i < siphash::crounds; ++i) + siphash::round(v0, v1, v2, v3); + + v0 ^= b; + + + if(hashsz == 16) + v2 ^= 0xee; + else + v2 ^= 0xff; + + for(i = 0; i < siphash::drounds; ++i) + siphash::round(v0, v1, v2, v3); + + b = v0 ^ v1 ^ v2 ^ v3; + + siphash::u64to8le(b, h); + + if(hashsz == 8) return; + + v1 ^= 0xdd; + + for (i = 0; i < siphash::drounds; ++i) + siphash::round(v0, v1, v2, v3); + + b = v0 ^ v1 ^ v2 ^ v3; + siphash::u64to8le(b, h + 8); + } +} +} + +#endif \ No newline at end of file From 516f140bef4cafa9fea860dd2e5f34021d30f237 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 24 May 2018 14:32:14 -0400 Subject: [PATCH 048/195] ntcp2 crypto added --- build/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index fc9ca417..8ea4bfcc 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -77,6 +77,8 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/api.cpp" "${LIBI2PD_SRC_DIR}/Event.cpp" "${LIBI2PD_SRC_DIR}/Gost.cpp" + "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" + "${LIBI2PD_SRC_DIR}/Poly1305.cpp" ) if (WITH_WEBSOCKETS) From 4cedaa9e807ec5bcd104c546994d24089a6b60b5 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 28 May 2018 09:49:59 -0400 Subject: [PATCH 049/195] fixed android build --- libi2pd/Poly1305.cpp | 65 +++----------------------------------------- 1 file changed, 4 insertions(+), 61 deletions(-) diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index 355555c6..5378d3cb 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -1,6 +1,4 @@ #include "Poly1305.h" -#include "CPU.h" -#include /** This code is licensed under the MCGSI Public License Copyright 2018 Jeff Becker @@ -12,48 +10,6 @@ namespace i2p { namespace crypto { -#if 0 -#ifdef __AVX2__ - struct Poly1305_AVX2 - { - Poly1305_AVX2(const uint32_t *& k) - { - __asm__ - ( - "VMOVNTDQA %[key0], %%ymm0 \n" - "VMOVNTDQA 32%[key0], %%ymm1 \n" - : - : - [key0]"m"(k) - ); - }; - - ~Poly1305_AVX2() - { - // clear out registers - __asm__ - ( - "VZEROALL\n" - ); - } - - void Update(const uint8_t * buf, size_t sz) - { - - } - - void Finish(uint32_t *& out) - { - - } - - - - size_t leftover; - - }; -#endif -#endif namespace poly1305 { @@ -281,23 +237,10 @@ namespace crypto void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz) { - #if 0 - #ifdef __AVX2__ - if(i2p::cpu::avx2) - { - Poly1305_AVX2 p(key); - p.Update(buf, sz); - p.Finish(out); - } - else - #endif - #endif - { - const uint8_t * k = (const uint8_t *) key; - Poly1305 p(k); - p.Update(buf, sz); - p.Finish(out); - } + const uint8_t * k = (const uint8_t *) key; + Poly1305 p(k); + p.Update(buf, sz); + p.Finish(out); } } } From 56e76ec59fe7456e67182d4317099dfc26dec7ed Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 28 May 2018 19:41:23 +0300 Subject: [PATCH 050/195] fix using debug library compilation in release mode --- android/build.gradle | 4 ++-- android/jni/Application.mk | 3 ++- android_binary_only/jni/Application.mk | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 4fe17d88..d58e098f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -19,7 +19,7 @@ repositories { android { compileSdkVersion 25 - buildToolsVersion "25.0.2" + buildToolsVersion "25.0.3" defaultConfig { applicationId "org.purplei2p.i2pd" targetSdkVersion 25 @@ -49,7 +49,7 @@ android { } buildTypes { release { - minifyEnabled false + minifyEnabled true signingConfig signingConfigs.orignal proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' } diff --git a/android/jni/Application.mk b/android/jni/Application.mk index 0fa116c2..b5b920fa 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -19,7 +19,8 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif -APP_OPTIM := debug +# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead. +#APP_OPTIM := debug # git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git diff --git a/android_binary_only/jni/Application.mk b/android_binary_only/jni/Application.mk index 7cd5c813..b8cdc2ab 100755 --- a/android_binary_only/jni/Application.mk +++ b/android_binary_only/jni/Application.mk @@ -21,7 +21,8 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) APP_CPPFLAGS += -DANDROID_ARM7A endif -APP_OPTIM := debug +# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead. +#APP_OPTIM := debug # git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git From 46283dc0eaeae24026456c92c3f7d2ef31640f1b Mon Sep 17 00:00:00 2001 From: Veggie Monster Date: Mon, 28 May 2018 17:00:47 -0400 Subject: [PATCH 051/195] fixes #1124 and calls the ready callbacks if the tunnel gets ready and no timeout is set --- libi2pd_client/I2PService.cpp | 23 +++++++++++------------ libi2pd_client/I2PService.h | 3 +++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/libi2pd_client/I2PService.cpp b/libi2pd_client/I2PService.cpp index 21e1fdfa..da8dd65a 100644 --- a/libi2pd_client/I2PService.cpp +++ b/libi2pd_client/I2PService.cpp @@ -14,6 +14,7 @@ namespace client m_LocalDestination (localDestination ? localDestination : i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)), m_ReadyTimer(m_LocalDestination->GetService()), + m_ReadyTimerTriggered(false), m_ConnectTimeout(0), isUpdated (true) { @@ -47,29 +48,25 @@ namespace client void I2PService::SetConnectTimeout(uint32_t timeout) { - if(timeout && !m_ConnectTimeout) - { - TriggerReadyCheckTimer(); - } - else if (m_ConnectTimeout && !timeout) - { - m_ReadyTimer.cancel(); - } m_ConnectTimeout = timeout; } void I2PService::AddReadyCallback(ReadyCallback cb) { uint32_t now = i2p::util::GetSecondsSinceEpoch(); - uint32_t tm = now + m_ConnectTimeout; + uint32_t tm = (m_ConnectTimeout) ? now + m_ConnectTimeout : NEVER_TIMES_OUT; + LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now); m_ReadyCallbacks.push_back({cb, tm}); + if (!m_ReadyTimerTriggered) TriggerReadyCheckTimer(); } void I2PService::TriggerReadyCheckTimer() { m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1)); m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, this, std::placeholders::_1)); + m_ReadyTimerTriggered = true; + } void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec) @@ -87,7 +84,7 @@ namespace client auto itr = m_ReadyCallbacks.begin(); while(itr != m_ReadyCallbacks.end()) { - if(itr->second >= now) + if(itr->second != NEVER_TIMES_OUT && now >= itr->second) { itr->first(boost::asio::error::timed_out); itr = m_ReadyCallbacks.erase(itr); @@ -96,8 +93,10 @@ namespace client ++itr; } } - if(!ec) - TriggerReadyCheckTimer(); + if(!ec && m_ReadyCallbacks.size()) + TriggerReadyCheckTimer(); + else + m_ReadyTimerTriggered = false; } void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) { diff --git a/libi2pd_client/I2PService.h b/libi2pd_client/I2PService.h index ecfd5bc5..55921898 100644 --- a/libi2pd_client/I2PService.h +++ b/libi2pd_client/I2PService.h @@ -67,8 +67,11 @@ namespace client std::mutex m_HandlersMutex; std::vector > m_ReadyCallbacks; boost::asio::deadline_timer m_ReadyTimer; + bool m_ReadyTimerTriggered; uint32_t m_ConnectTimeout; + const size_t NEVER_TIMES_OUT = 0; + public: bool isUpdated; // transient, used during reload only }; From cd0f75106a4d8f51b02b85c1b230617467517892 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 4 Jun 2018 16:06:38 -0400 Subject: [PATCH 052/195] moved Ed25519 away from signature --- build/CMakeLists.txt | 3 +- libi2pd/Ed25519.cpp | 429 +++++++++++++++++++++++++++++++++++++++++ libi2pd/Ed25519.h | 117 ++++++++++++ libi2pd/Signature.cpp | 436 ------------------------------------------ libi2pd/Signature.h | 57 +----- 5 files changed, 549 insertions(+), 493 deletions(-) create mode 100644 libi2pd/Ed25519.cpp create mode 100644 libi2pd/Ed25519.h diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 8ea4bfcc..299ca438 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -78,7 +78,8 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/Event.cpp" "${LIBI2PD_SRC_DIR}/Gost.cpp" "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" - "${LIBI2PD_SRC_DIR}/Poly1305.cpp" + "${LIBI2PD_SRC_DIR}/Poly1305.cpp" + "${LIBI2PD_SRC_DIR}/Ed25519.cpp" ) if (WITH_WEBSOCKETS) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp new file mode 100644 index 00000000..956f52fc --- /dev/null +++ b/libi2pd/Ed25519.cpp @@ -0,0 +1,429 @@ +#include +#include "Log.h" +#include "Crypto.h" +#include "Ed25519.h" + +namespace i2p +{ +namespace crypto +{ + Ed25519::Ed25519 () + { + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * tmp = BN_new (); + + q = BN_new (); + // 2^255-19 + BN_set_bit (q, 255); // 2^255 + BN_sub_word (q, 19); + + l = BN_new (); + // 2^252 + 27742317777372353535851937790883648493 + BN_set_bit (l, 252); + two_252_2 = BN_dup (l); + BN_dec2bn (&tmp, "27742317777372353535851937790883648493"); + BN_add (l, l, tmp); + BN_sub_word (two_252_2, 2); // 2^252 - 2 + + // -121665*inv(121666) + d = BN_new (); + BN_set_word (tmp, 121666); + BN_mod_inverse (tmp, tmp, q, ctx); + BN_set_word (d, 121665); + BN_set_negative (d, 1); + BN_mul (d, d, tmp, ctx); + + // 2^((q-1)/4) + I = BN_new (); + BN_free (tmp); + tmp = BN_dup (q); + BN_sub_word (tmp, 1); + BN_div_word (tmp, 4); + BN_set_word (I, 2); + BN_mod_exp (I, I, tmp, q, ctx); + BN_free (tmp); + + // 4*inv(5) + BIGNUM * By = BN_new (); + BN_set_word (By, 5); + BN_mod_inverse (By, By, q, ctx); + BN_mul_word (By, 4); + BIGNUM * Bx = RecoverX (By, ctx); + BN_mod (Bx, Bx, q, ctx); // % q + BN_mod (By, By, q, ctx); // % q + + // precalculate Bi256 table + Bi256Carry = { Bx, By }; // B + for (int i = 0; i < 32; i++) + { + Bi256[i][0] = Bi256Carry; // first point + for (int j = 1; j < 128; j++) + Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B + Bi256Carry = Bi256[i][127]; + for (int j = 0; j < 128; j++) // add first point 128 more times + Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx); + } + + BN_CTX_free (ctx); + } + + Ed25519::Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)), + d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)), + Bi256Carry (other.Bi256Carry) + { + for (int i = 0; i < 32; i++) + for (int j = 0; j < 128; j++) + Bi256[i][j] = other.Bi256[i][j]; + } + + Ed25519::~Ed25519 () + { + BN_free (q); + BN_free (l); + BN_free (d); + BN_free (I); + BN_free (two_252_2); + } + + + EDDSAPoint Ed25519::GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const + { + return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian + } + + EDDSAPoint Ed25519::DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const + { + return DecodePoint (buf, ctx); + } + + void Ed25519::EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const + { + EncodePoint (Normalize (publicKey, ctx), buf); + } + + bool Ed25519::Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const + { + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * h = DecodeBN<64> (digest); + // signature 0..31 - R, 32..63 - S + // B*S = R + PK*h => R = B*S - PK*h + // we don't decode R, but encode (B*S - PK*h) + auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S; + BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0 + auto PKh = Mul (publicKey, h, ctx); // PK*h + uint8_t diff[32]; + EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded + bool passed = !memcmp (signature, diff, 32); // R + BN_free (h); + BN_CTX_free (ctx); + if (!passed) + LogPrint (eLogError, "25519 signature verification failed"); + return passed; + } + + void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, + uint8_t * signature) const + { + BN_CTX * bnCtx = BN_CTX_new (); + // calculate r + SHA512_CTX ctx; + SHA512_Init (&ctx); + SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key + SHA512_Update (&ctx, buf, len); // data + uint8_t digest[64]; + SHA512_Final (digest, &ctx); + BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors + // calculate R + uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf + EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors + // calculate S + SHA512_Init (&ctx); + SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + SHA512_Update (&ctx, buf, len); // data + SHA512_Final (digest, &ctx); + BIGNUM * h = DecodeBN<64> (digest); + // S = (r + h*a) % l + BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key + BN_mod_mul (h, h, a, l, bnCtx); // %l + BN_mod_add (h, h, r, l, bnCtx); // %l + memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); + EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S + BN_free (r); BN_free (h); BN_free (a); + BN_CTX_free (bnCtx); + } + + EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const + { + // x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2) + // y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2) + // z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2) + // t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2) + BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new (); + + BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2 + BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2 + + BN_CTX_start (ctx); + BIGNUM * t1 = p1.t, * t2 = p2.t; + if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); } + if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); } + BN_mul (t3, t1, t2, ctx); + BN_mul (t3, t3, d, ctx); // C = d*t1*t2 + + if (p1.z) + { + if (p2.z) + BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2 + else + BN_copy (z3, p1.z); // D = z1 + } + else + { + if (p2.z) + BN_copy (z3, p2.z); // D = z2 + else + BN_one (z3); // D = 1 + } + + BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); + BN_add (E, p1.x, p1.y); + BN_add (F, p2.x, p2.y); + BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2) + BN_sub (E, E, x3); + BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B + BN_sub (F, z3, t3); // F = D - C + BN_add (G, z3, t3); // G = D + C + BN_add (H, y3, x3); // H = B + A + + BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F + BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H + BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G + BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H + + BN_CTX_end (ctx); + + return EDDSAPoint {x3, y3, z3, t3}; + } + + void Ed25519::Double (EDDSAPoint& p, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx); + + BN_sqr (x2, p.x, ctx); // x2 = A = x^2 + BN_sqr (y2, p.y, ctx); // y2 = B = y^2 + if (p.t) + BN_sqr (t2, p.t, ctx); // t2 = t^2 + else + { + BN_mul (t2, p.x, p.y, ctx); // t = x*y + BN_sqr (t2, t2, ctx); // t2 = t^2 + } + BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2 + if (p.z) + BN_sqr (z2, p.z, ctx); // z2 = D = z^2 + else + BN_one (z2); // z2 = 1 + + BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); + // E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy + BN_mul (E, p.x, p.y, ctx); + BN_lshift1 (E, E); // E =2*x*y + BN_sub (F, z2, t2); // F = D - C + BN_add (G, z2, t2); // G = D + C + BN_add (H, y2, x2); // H = B + A + + BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F + BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H + if (!p.z) p.z = BN_new (); + BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G + if (!p.t) p.t = BN_new (); + BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H + + BN_CTX_end (ctx); + } + + EDDSAPoint Ed25519::Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const + { + BIGNUM * zero = BN_new (), * one = BN_new (); + BN_zero (zero); BN_one (one); + EDDSAPoint res {zero, one}; + if (!BN_is_zero (e)) + { + int bitCount = BN_num_bits (e); + for (int i = bitCount - 1; i >= 0; i--) + { + Double (res, ctx); + if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); + } + } + return res; + } + + EDDSAPoint Ed25519::MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian + { + BIGNUM * zero = BN_new (), * one = BN_new (); + BN_zero (zero); BN_one (one); + EDDSAPoint res {zero, one}; + bool carry = false; + for (int i = 0; i < 32; i++) + { + uint8_t x = e[i]; + if (carry) + { + if (x < 255) + { + x++; + carry = false; + } + else + x = 0; + } + if (x > 0) + { + if (x <= 128) + res = Sum (res, Bi256[i][x-1], ctx); + else + { + res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x] + carry = true; + } + } + } + if (carry) res = Sum (res, Bi256Carry, ctx); + return res; + } + + EDDSAPoint Ed25519::Normalize (const EDDSAPoint& p, BN_CTX * ctx) const + { + if (p.z) + { + BIGNUM * x = BN_new (), * y = BN_new (); + BN_mod_inverse (y, p.z, q, ctx); + BN_mod_mul (x, p.x, y, q, ctx); // x = x/z + BN_mod_mul (y, p.y, y, q, ctx); // y = y/z + return EDDSAPoint{x, y}; + } + else + return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)}; + } + + bool Ed25519::IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx); + BN_sqr (x2, p.x, ctx); // x^2 + BN_sqr (y2, p.y, ctx); // y^2 + // y^2 - x^2 - 1 - d*x^2*y^2 + BN_mul (tmp, d, x2, ctx); + BN_mul (tmp, tmp, y2, ctx); + BN_sub (tmp, y2, tmp); + BN_sub (tmp, tmp, x2); + BN_sub_word (tmp, 1); + BN_mod (tmp, tmp, q, ctx); // % q + bool ret = BN_is_zero (tmp); + BN_CTX_end (ctx); + return ret; + } + + BIGNUM * Ed25519::RecoverX (const BIGNUM * y, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx); + BN_sqr (y2, y, ctx); // y^2 + // xx = (y^2 -1)*inv(d*y^2 +1) + BN_mul (xx, d, y2, ctx); + BN_add_word (xx, 1); + BN_mod_inverse (xx, xx, q, ctx); + BN_sub_word (y2, 1); + BN_mul (xx, y2, xx, ctx); + // x = srqt(xx) = xx^(2^252-2) + BIGNUM * x = BN_new (); + BN_mod_exp (x, xx, two_252_2, q, ctx); + // check (x^2 -xx) % q + BN_sqr (y2, x, ctx); + BN_mod_sub (y2, y2, xx, q, ctx); + if (!BN_is_zero (y2)) + BN_mod_mul (x, x, I, q, ctx); + if (BN_is_odd (x)) + BN_sub (x, q, x); + BN_CTX_end (ctx); + return x; + } + + EDDSAPoint Ed25519::DecodePoint (const uint8_t * buf, BN_CTX * ctx) const + { + // buf is 32 bytes Little Endian, convert it to Big Endian + uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH]; + for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH/2; i++) // invert bytes + { + buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i]; + buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i]; + } + bool isHighestBitSet = buf1[0] & 0x80; + if (isHighestBitSet) + buf1[0] &= 0x7f; // clear highest bit + BIGNUM * y = BN_new (); + BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); + BIGNUM * x = RecoverX (y, ctx); + if (BN_is_bit_set (x, 0) != isHighestBitSet) + BN_sub (x, q, x); // x = q - x + BIGNUM * z = BN_new (), * t = BN_new (); + BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t + EDDSAPoint p {x, y, z, t}; + if (!IsOnCurve (p, ctx)) + LogPrint (eLogError, "Decoded point is not on 25519"); + return p; + } + + void Ed25519::EncodePoint (const EDDSAPoint& p, uint8_t * buf) const + { + EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH); + if (BN_is_bit_set (p.x, 0)) // highest bit + buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit + } + + template + BIGNUM * Ed25519::DecodeBN (const uint8_t * buf) const + { + // buf is Little Endian convert it to Big Endian + uint8_t buf1[len]; + for (size_t i = 0; i < len/2; i++) // invert bytes + { + buf1[i] = buf[len -1 - i]; + buf1[len -1 - i] = buf[i]; + } + BIGNUM * res = BN_new (); + BN_bin2bn (buf1, len, res); + return res; + } + + void Ed25519::EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const + { + bn2buf (bn, buf, len); + // To Little Endian + for (size_t i = 0; i < len/2; i++) // invert bytes + { + uint8_t tmp = buf[i]; + buf[i] = buf[len -1 - i]; + buf[len -1 - i] = tmp; + } + } + + static std::unique_ptr g_Ed25519; + std::unique_ptr& GetEd25519 () + { + if (!g_Ed25519) + { + auto c = new Ed25519(); + if (!g_Ed25519) // make sure it was not created already + g_Ed25519.reset (c); + else + delete c; + } + return g_Ed25519; + } +} +} + diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h new file mode 100644 index 00000000..9222edb4 --- /dev/null +++ b/libi2pd/Ed25519.h @@ -0,0 +1,117 @@ +#ifndef ED25519_H__ +#define ED25519_H__ + +#include +#include + +namespace i2p +{ +namespace crypto +{ + struct EDDSAPoint + { + BIGNUM * x {nullptr}; + BIGNUM * y {nullptr}; + BIGNUM * z {nullptr}; + BIGNUM * t {nullptr}; // projective coordinates + + EDDSAPoint () {} + EDDSAPoint (const EDDSAPoint& other) { *this = other; } + EDDSAPoint (EDDSAPoint&& other) { *this = std::move (other); } + EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr) + : x(x1) + , y(y1) + , z(z1) + , t(t1) + {} + ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } + + EDDSAPoint& operator=(EDDSAPoint&& other) + { + if (this != &other) + { + BN_free (x); x = other.x; other.x = nullptr; + BN_free (y); y = other.y; other.y = nullptr; + BN_free (z); z = other.z; other.z = nullptr; + BN_free (t); t = other.t; other.t = nullptr; + } + return *this; + } + + EDDSAPoint& operator=(const EDDSAPoint& other) + { + if (this != &other) + { + BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; + BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; + BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; + BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; + } + return *this; + } + + EDDSAPoint operator-() const + { + BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL; + if (x) { x1 = BN_dup (x); BN_set_negative (x1, !BN_is_negative (x)); }; + if (y) y1 = BN_dup (y); + if (z) z1 = BN_dup (z); + if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; + return EDDSAPoint {x1, y1, z1, t1}; + } + }; + + const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; + const size_t EDDSA25519_SIGNATURE_LENGTH = 64; + const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; + class Ed25519 + { + public: + + Ed25519 (); + Ed25519 (const Ed25519& other); + ~Ed25519 (); + + EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; + EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; + void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; + + bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; + void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; + + private: + + EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; + void Double (EDDSAPoint& p, BN_CTX * ctx) const; + EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const; + EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const; // B*e, e is 32 bytes Little Endian + EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const; + + bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const; + BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const; + EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const; + void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const; + + template + BIGNUM * DecodeBN (const uint8_t * buf) const; + void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; + + private: + + BIGNUM * q, * l, * d, * I; + // transient values + BIGNUM * two_252_2; // 2^252-2 + EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes + // if j > 128 we use 256 - j and carry 1 to next byte + // Bi256[0][0] = B, base point + EDDSAPoint Bi256Carry; // Bi256[32][0] + }; + + std::unique_ptr& GetEd25519 (); + +} +} + + +#endif + diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index aded9bc8..f9b7aebd 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -6,442 +6,6 @@ namespace i2p { namespace crypto { - class Ed25519 - { - public: - - Ed25519 () - { - BN_CTX * ctx = BN_CTX_new (); - BIGNUM * tmp = BN_new (); - - q = BN_new (); - // 2^255-19 - BN_set_bit (q, 255); // 2^255 - BN_sub_word (q, 19); - - l = BN_new (); - // 2^252 + 27742317777372353535851937790883648493 - BN_set_bit (l, 252); - two_252_2 = BN_dup (l); - BN_dec2bn (&tmp, "27742317777372353535851937790883648493"); - BN_add (l, l, tmp); - BN_sub_word (two_252_2, 2); // 2^252 - 2 - - // -121665*inv(121666) - d = BN_new (); - BN_set_word (tmp, 121666); - BN_mod_inverse (tmp, tmp, q, ctx); - BN_set_word (d, 121665); - BN_set_negative (d, 1); - BN_mul (d, d, tmp, ctx); - - // 2^((q-1)/4) - I = BN_new (); - BN_free (tmp); - tmp = BN_dup (q); - BN_sub_word (tmp, 1); - BN_div_word (tmp, 4); - BN_set_word (I, 2); - BN_mod_exp (I, I, tmp, q, ctx); - BN_free (tmp); - - // 4*inv(5) - BIGNUM * By = BN_new (); - BN_set_word (By, 5); - BN_mod_inverse (By, By, q, ctx); - BN_mul_word (By, 4); - BIGNUM * Bx = RecoverX (By, ctx); - BN_mod (Bx, Bx, q, ctx); // % q - BN_mod (By, By, q, ctx); // % q - - // precalculate Bi256 table - Bi256Carry = { Bx, By }; // B - for (int i = 0; i < 32; i++) - { - Bi256[i][0] = Bi256Carry; // first point - for (int j = 1; j < 128; j++) - Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B - Bi256Carry = Bi256[i][127]; - for (int j = 0; j < 128; j++) // add first point 128 more times - Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx); - } - - BN_CTX_free (ctx); - } - - Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)), - d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)), - Bi256Carry (other.Bi256Carry) - { - for (int i = 0; i < 32; i++) - for (int j = 0; j < 128; j++) - Bi256[i][j] = other.Bi256[i][j]; - } - - ~Ed25519 () - { - BN_free (q); - BN_free (l); - BN_free (d); - BN_free (I); - BN_free (two_252_2); - } - - - EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const - { - return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian - } - - EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const - { - return DecodePoint (buf, ctx); - } - - void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const - { - EncodePoint (Normalize (publicKey, ctx), buf); - } - - bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const - { - BN_CTX * ctx = BN_CTX_new (); - BIGNUM * h = DecodeBN<64> (digest); - // signature 0..31 - R, 32..63 - S - // B*S = R + PK*h => R = B*S - PK*h - // we don't decode R, but encode (B*S - PK*h) - auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S; - BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0 - auto PKh = Mul (publicKey, h, ctx); // PK*h - uint8_t diff[32]; - EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded - bool passed = !memcmp (signature, diff, 32); // R - BN_free (h); - BN_CTX_free (ctx); - if (!passed) - LogPrint (eLogError, "25519 signature verification failed"); - return passed; - } - - void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, - uint8_t * signature) const - { - BN_CTX * bnCtx = BN_CTX_new (); - // calculate r - SHA512_CTX ctx; - SHA512_Init (&ctx); - SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key - SHA512_Update (&ctx, buf, len); // data - uint8_t digest[64]; - SHA512_Final (digest, &ctx); - BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors - // calculate R - uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf - EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors - // calculate S - SHA512_Init (&ctx); - SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R - SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key - SHA512_Update (&ctx, buf, len); // data - SHA512_Final (digest, &ctx); - BIGNUM * h = DecodeBN<64> (digest); - // S = (r + h*a) % l - BIGNUM * a = DecodeBN (expandedPrivateKey); // left half of expanded key - BN_mod_mul (h, h, a, l, bnCtx); // %l - BN_mod_add (h, h, r, l, bnCtx); // %l - memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); - EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S - BN_free (r); BN_free (h); BN_free (a); - BN_CTX_free (bnCtx); - } - - private: - - EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const - { - // x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2) - // y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2) - // z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2) - // t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2) - BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new (); - - BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2 - BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2 - - BN_CTX_start (ctx); - BIGNUM * t1 = p1.t, * t2 = p2.t; - if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); } - if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); } - BN_mul (t3, t1, t2, ctx); - BN_mul (t3, t3, d, ctx); // C = d*t1*t2 - - if (p1.z) - { - if (p2.z) - BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2 - else - BN_copy (z3, p1.z); // D = z1 - } - else - { - if (p2.z) - BN_copy (z3, p2.z); // D = z2 - else - BN_one (z3); // D = 1 - } - - BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); - BN_add (E, p1.x, p1.y); - BN_add (F, p2.x, p2.y); - BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2) - BN_sub (E, E, x3); - BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B - BN_sub (F, z3, t3); // F = D - C - BN_add (G, z3, t3); // G = D + C - BN_add (H, y3, x3); // H = B + A - - BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F - BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H - BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G - BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H - - BN_CTX_end (ctx); - - return EDDSAPoint {x3, y3, z3, t3}; - } - - void Double (EDDSAPoint& p, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx); - - BN_sqr (x2, p.x, ctx); // x2 = A = x^2 - BN_sqr (y2, p.y, ctx); // y2 = B = y^2 - if (p.t) - BN_sqr (t2, p.t, ctx); // t2 = t^2 - else - { - BN_mul (t2, p.x, p.y, ctx); // t = x*y - BN_sqr (t2, t2, ctx); // t2 = t^2 - } - BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2 - if (p.z) - BN_sqr (z2, p.z, ctx); // z2 = D = z^2 - else - BN_one (z2); // z2 = 1 - - BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); - // E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy - BN_mul (E, p.x, p.y, ctx); - BN_lshift1 (E, E); // E =2*x*y - BN_sub (F, z2, t2); // F = D - C - BN_add (G, z2, t2); // G = D + C - BN_add (H, y2, x2); // H = B + A - - BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F - BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H - if (!p.z) p.z = BN_new (); - BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G - if (!p.t) p.t = BN_new (); - BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H - - BN_CTX_end (ctx); - } - - EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const - { - BIGNUM * zero = BN_new (), * one = BN_new (); - BN_zero (zero); BN_one (one); - EDDSAPoint res {zero, one}; - if (!BN_is_zero (e)) - { - int bitCount = BN_num_bits (e); - for (int i = bitCount - 1; i >= 0; i--) - { - Double (res, ctx); - if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); - } - } - return res; - } - - EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian - { - BIGNUM * zero = BN_new (), * one = BN_new (); - BN_zero (zero); BN_one (one); - EDDSAPoint res {zero, one}; - bool carry = false; - for (int i = 0; i < 32; i++) - { - uint8_t x = e[i]; - if (carry) - { - if (x < 255) - { - x++; - carry = false; - } - else - x = 0; - } - if (x > 0) - { - if (x <= 128) - res = Sum (res, Bi256[i][x-1], ctx); - else - { - res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x] - carry = true; - } - } - } - if (carry) res = Sum (res, Bi256Carry, ctx); - return res; - } - - EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const - { - if (p.z) - { - BIGNUM * x = BN_new (), * y = BN_new (); - BN_mod_inverse (y, p.z, q, ctx); - BN_mod_mul (x, p.x, y, q, ctx); // x = x/z - BN_mod_mul (y, p.y, y, q, ctx); // y = y/z - return EDDSAPoint{x, y}; - } - else - return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)}; - } - - bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx); - BN_sqr (x2, p.x, ctx); // x^2 - BN_sqr (y2, p.y, ctx); // y^2 - // y^2 - x^2 - 1 - d*x^2*y^2 - BN_mul (tmp, d, x2, ctx); - BN_mul (tmp, tmp, y2, ctx); - BN_sub (tmp, y2, tmp); - BN_sub (tmp, tmp, x2); - BN_sub_word (tmp, 1); - BN_mod (tmp, tmp, q, ctx); // % q - bool ret = BN_is_zero (tmp); - BN_CTX_end (ctx); - return ret; - } - - BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const - { - BN_CTX_start (ctx); - BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx); - BN_sqr (y2, y, ctx); // y^2 - // xx = (y^2 -1)*inv(d*y^2 +1) - BN_mul (xx, d, y2, ctx); - BN_add_word (xx, 1); - BN_mod_inverse (xx, xx, q, ctx); - BN_sub_word (y2, 1); - BN_mul (xx, y2, xx, ctx); - // x = srqt(xx) = xx^(2^252-2) - BIGNUM * x = BN_new (); - BN_mod_exp (x, xx, two_252_2, q, ctx); - // check (x^2 -xx) % q - BN_sqr (y2, x, ctx); - BN_mod_sub (y2, y2, xx, q, ctx); - if (!BN_is_zero (y2)) - BN_mod_mul (x, x, I, q, ctx); - if (BN_is_odd (x)) - BN_sub (x, q, x); - BN_CTX_end (ctx); - return x; - } - - EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const - { - // buf is 32 bytes Little Endian, convert it to Big Endian - uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH]; - for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH/2; i++) // invert bytes - { - buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i]; - buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i]; - } - bool isHighestBitSet = buf1[0] & 0x80; - if (isHighestBitSet) - buf1[0] &= 0x7f; // clear highest bit - BIGNUM * y = BN_new (); - BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); - BIGNUM * x = RecoverX (y, ctx); - if (BN_is_bit_set (x, 0) != isHighestBitSet) - BN_sub (x, q, x); // x = q - x - BIGNUM * z = BN_new (), * t = BN_new (); - BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t - EDDSAPoint p {x, y, z, t}; - if (!IsOnCurve (p, ctx)) - LogPrint (eLogError, "Decoded point is not on 25519"); - return p; - } - - void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const - { - EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH); - if (BN_is_bit_set (p.x, 0)) // highest bit - buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit - } - - template - BIGNUM * DecodeBN (const uint8_t * buf) const - { - // buf is Little Endian convert it to Big Endian - uint8_t buf1[len]; - for (size_t i = 0; i < len/2; i++) // invert bytes - { - buf1[i] = buf[len -1 - i]; - buf1[len -1 - i] = buf[i]; - } - BIGNUM * res = BN_new (); - BN_bin2bn (buf1, len, res); - return res; - } - - void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const - { - bn2buf (bn, buf, len); - // To Little Endian - for (size_t i = 0; i < len/2; i++) // invert bytes - { - uint8_t tmp = buf[i]; - buf[i] = buf[len -1 - i]; - buf[len -1 - i] = tmp; - } - } - - private: - - BIGNUM * q, * l, * d, * I; - // transient values - BIGNUM * two_252_2; // 2^252-2 - EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes - // if j > 128 we use 256 - j and carry 1 to next byte - // Bi256[0][0] = B, base point - EDDSAPoint Bi256Carry; // Bi256[32][0] - }; - - static std::unique_ptr g_Ed25519; - std::unique_ptr& GetEd25519 () - { - if (!g_Ed25519) - { - auto c = new Ed25519(); - if (!g_Ed25519) // make sure it was not created already - g_Ed25519.reset (c); - else - delete c; - } - return g_Ed25519; - } - - EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey) { memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 1e7db9f7..8b30a8e8 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -9,6 +9,7 @@ #include #include #include "Crypto.h" +#include "Ed25519.h" #include "Gost.h" namespace i2p @@ -361,62 +362,6 @@ namespace crypto typedef RSASigner RSASHA5124096Signer; // EdDSA - struct EDDSAPoint - { - BIGNUM * x {nullptr}; - BIGNUM * y {nullptr}; - BIGNUM * z {nullptr}; - BIGNUM * t {nullptr}; // projective coordinates - - EDDSAPoint () {} - EDDSAPoint (const EDDSAPoint& other) { *this = other; } - EDDSAPoint (EDDSAPoint&& other) { *this = std::move (other); } - EDDSAPoint (BIGNUM * x1, BIGNUM * y1, BIGNUM * z1 = nullptr, BIGNUM * t1 = nullptr) - : x(x1) - , y(y1) - , z(z1) - , t(t1) - {} - ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } - - EDDSAPoint& operator=(EDDSAPoint&& other) - { - if (this != &other) - { - BN_free (x); x = other.x; other.x = nullptr; - BN_free (y); y = other.y; other.y = nullptr; - BN_free (z); z = other.z; other.z = nullptr; - BN_free (t); t = other.t; other.t = nullptr; - } - return *this; - } - - EDDSAPoint& operator=(const EDDSAPoint& other) - { - if (this != &other) - { - BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; - BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; - BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; - BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; - } - return *this; - } - - EDDSAPoint operator-() const - { - BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL; - if (x) { x1 = BN_dup (x); BN_set_negative (x1, !BN_is_negative (x)); }; - if (y) y1 = BN_dup (y); - if (z) z1 = BN_dup (z); - if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; - return EDDSAPoint {x1, y1, z1, t1}; - } - }; - - const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; - const size_t EDDSA25519_SIGNATURE_LENGTH = 64; - const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; class EDDSA25519Verifier: public Verifier { public: From 86c19849820713366b82cc4995cb58f95095ca15 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jun 2018 12:53:13 -0400 Subject: [PATCH 053/195] NTCP2 added --- build/CMakeLists.txt | 3 ++- libi2pd/Ed25519.cpp | 8 ++++++++ libi2pd/Ed25519.h | 2 ++ libi2pd/NTCP2.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 32 +++++++++++++++++++++++++++++++ libi2pd/Signature.cpp | 6 +----- 6 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 libi2pd/NTCP2.cpp create mode 100644 libi2pd/NTCP2.h diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 299ca438..632edc03 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -79,7 +79,8 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/Gost.cpp" "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" "${LIBI2PD_SRC_DIR}/Poly1305.cpp" - "${LIBI2PD_SRC_DIR}/Ed25519.cpp" + "${LIBI2PD_SRC_DIR}/Ed25519.cpp" + "${LIBI2PD_SRC_DIR}/NTCP2.cpp" ) if (WITH_WEBSOCKETS) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 956f52fc..e921bada 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,6 +411,14 @@ namespace crypto } } + void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) + { + SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey); + expandedKey[0] &= 0xF8; // drop last 3 bits + expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits + expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit + } + static std::unique_ptr g_Ed25519; std::unique_ptr& GetEd25519 () { diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index 9222edb4..c3b162a7 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -79,6 +79,8 @@ namespace crypto bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; + static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes + private: EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp new file mode 100644 index 00000000..907e1fd8 --- /dev/null +++ b/libi2pd/NTCP2.cpp @@ -0,0 +1,44 @@ +#include +#include "Crypto.h" +#include "Ed25519.h" +#include "ChaCha20.h" +#include "Poly1305.h" +#include "NTCP2.h" + +namespace i2p +{ +namespace transport +{ + NTCP2Session::NTCP2Session (std::shared_ptr in_RemoteRouter): + TransportSession (in_RemoteRouter, 30) + { + } + + NTCP2Session::~NTCP2Session () + { + } + + void NTCP2Session::CreateEphemeralKey (uint8_t * pub) + { + uint8_t key[32]; + RAND_bytes (key, 32); + i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey); + BN_CTX * ctx = BN_CTX_new (); + auto publicKey = i2p::crypto::GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); + i2p::crypto::GetEd25519 ()->EncodePublicKey (publicKey, pub, ctx); + BN_CTX_free (ctx); + } + + void NTCP2Session::SendSessionRequest (const uint8_t * iv) + { + i2p::crypto::AESAlignedBuffer<32> x; + CreateEphemeralKey (x); + // encrypt X + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); + encryption.SetIV (iv); + encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + } +} +} + diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h new file mode 100644 index 00000000..6dfea8ae --- /dev/null +++ b/libi2pd/NTCP2.h @@ -0,0 +1,32 @@ +#ifndef NTCP2_H__ +#define NTCP2_H__ + +#include +#include +#include "RouterInfo.h" +#include "TransportSession.h" + +namespace i2p +{ +namespace transport +{ + class NTCP2Session: public TransportSession, public std::enable_shared_from_this + { + public: + + NTCP2Session (std::shared_ptr in_RemoteRouter = nullptr); // TODO + ~NTCP2Session (); + + private: + + void CreateEphemeralKey (uint8_t * pub); + void SendSessionRequest (const uint8_t * iv); + + private: + + uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key + }; +} +} + +#endif diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index f9b7aebd..baa265bc 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -30,11 +30,7 @@ namespace crypto EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) { // expand key - SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey); - m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits - m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits - m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit - + Ed25519::ExpandPrivateKey (signingPrivateKey, m_ExpandedPrivateKey); // generate and encode public key BN_CTX * ctx = BN_CTX_new (); auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); From 8c9eaccc11e573fa821d3b02efcb4b9f925d214b Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jun 2018 15:37:08 -0400 Subject: [PATCH 054/195] KeyDerivationFunction for NTCP2 --- libi2pd/Ed25519.cpp | 8 ++++++++ libi2pd/Ed25519.h | 1 + libi2pd/NTCP2.cpp | 31 +++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 1 + 4 files changed, 41 insertions(+) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index e921bada..8258d33c 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,6 +411,14 @@ namespace crypto } } + void Ed25519::Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + auto P = DecodePublicKey (p, ctx); + BIGNUM * e1 = DecodeBN<32> (e); + EncodePublicKey (Mul (P, e1, ctx), buf, ctx); + BN_free (e1); + } + void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) { SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey); diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index c3b162a7..cbf14bfd 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -75,6 +75,7 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; + void Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 907e1fd8..e6072207 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "Crypto.h" #include "Ed25519.h" #include "ChaCha20.h" @@ -18,6 +20,35 @@ namespace transport { } + bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + { + static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes + uint8_t h[64], ck[33]; + SHA256 ((const uint8_t *)protocolName, 32, h); + memcpy (ck, h, 32); + // h = SHA256(h || rs) + memcpy (h + 32, rs, 32); + SHA256 (h, 64, h); + // h = SHA256(h || pub) + memcpy (h + 32, pub, 32); + SHA256 (h, 64, h); + // x25519 between rs and priv + uint8_t inputKeyMaterial[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->Mul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv + BN_CTX_free (ctx); + // temp_key = HMAC-SHA256(ck, input_key_material) + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), ck, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) + inputKeyMaterial[0] = 1; + HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, ck, &len); + // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) + ck[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, ck, 33, derived, &len); + return true; + } + void NTCP2Session::CreateEphemeralKey (uint8_t * pub) { uint8_t key[32]; diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 6dfea8ae..11bb2674 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -19,6 +19,7 @@ namespace transport private: + bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (const uint8_t * iv); From a70d0edf2e8b80f7553c709c07aa93f96e36082a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 5 Jun 2018 16:15:33 -0400 Subject: [PATCH 055/195] encrypt SessionRequest options block --- libi2pd/NTCP2.cpp | 16 ++++++++++++---- libi2pd/NTCP2.h | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e6072207..8b33eb0d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -24,8 +24,8 @@ namespace transport { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; - SHA256 ((const uint8_t *)protocolName, 32, h); - memcpy (ck, h, 32); + memcpy (ck, protocolName, 32); + SHA256 ((const uint8_t *)protocolName, 32, h); // h = SHA256(h || rs) memcpy (h + 32, rs, 32); SHA256 (h, 64, h); @@ -60,7 +60,7 @@ namespace transport BN_CTX_free (ctx); } - void NTCP2Session::SendSessionRequest (const uint8_t * iv) + void NTCP2Session::SendSessionRequest (const uint8_t * iv, const uint8_t * rs) { i2p::crypto::AESAlignedBuffer<32> x; CreateEphemeralKey (x); @@ -68,7 +68,15 @@ namespace transport i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (iv); - encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + // encryption key for next block + uint8_t key[32]; + KeyDerivationFunction (rs, x, key); + // options + uint8_t options[32]; + // TODO: fill 16 bytes options + i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first + i2p::crypto::chacha20 (options, 16, 0, key); // then encrypt } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 11bb2674..52319db3 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -21,7 +21,7 @@ namespace transport bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); - void SendSessionRequest (const uint8_t * iv); + void SendSessionRequest (const uint8_t * iv, const uint8_t * rs); private: From 4f23d7b7df6b62b85c780e57cf4aad1fa138edb3 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jun 2018 11:51:34 -0400 Subject: [PATCH 056/195] recognize routers with NTCP2 --- libi2pd/RouterInfo.cpp | 30 +++++++++++++++++++++++++----- libi2pd/RouterInfo.h | 12 +++++++++++- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index e3f4d2d4..87f16346 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -244,6 +244,18 @@ namespace data } else if (!strcmp (key, "caps")) ExtractCaps (value); + else if (!strcmp (key, "s")) // ntcp2 static key + { + if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); + supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; + Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32); + } + else if (!strcmp (key, "i")) // ntcp2 iv + { + if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); + supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; + Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); + } else if (key[0] == 'i') { // introducers @@ -735,6 +747,14 @@ namespace data return m_SupportedTransports & (eSSUV4 | eSSUV6); } + bool RouterInfo::IsNTCP2 (bool v4only) const + { + if (v4only) + return m_SupportedTransports & eNTCP2V4; + else + return m_SupportedTransports & (eNTCP2V4 | eNTCP2V6); + } + bool RouterInfo::IsV6 () const { return m_SupportedTransports & (eNTCPV6 | eSSUV6); @@ -742,19 +762,19 @@ namespace data bool RouterInfo::IsV4 () const { - return m_SupportedTransports & (eNTCPV4 | eSSUV4); + return m_SupportedTransports & (eNTCPV4 | eSSUV4 | eNTCP2V4); } void RouterInfo::EnableV6 () { if (!IsV6 ()) - m_SupportedTransports |= eNTCPV6 | eSSUV6; + m_SupportedTransports |= eNTCPV6 | eSSUV6 | eNTCP2V6; } void RouterInfo::EnableV4 () { if (!IsV4 ()) - m_SupportedTransports |= eNTCPV4 | eSSUV4; + m_SupportedTransports |= eNTCPV4 | eSSUV4 | eNTCP2V4; } @@ -762,7 +782,7 @@ namespace data { if (IsV6 ()) { - m_SupportedTransports &= ~(eNTCPV6 | eSSUV6); + m_SupportedTransports &= ~(eNTCPV6 | eSSUV6 | eNTCP2V6); for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) { auto addr = *it; @@ -778,7 +798,7 @@ namespace data { if (IsV4 ()) { - m_SupportedTransports &= ~(eNTCPV4 | eSSUV4); + m_SupportedTransports &= ~(eNTCPV4 | eSSUV4 | eNTCP2V4); for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) { auto addr = *it; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 09e2c015..1125bdef 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -48,7 +48,9 @@ namespace data eNTCPV4 = 0x01, eNTCPV6 = 0x02, eSSUV4 = 0x04, - eSSUV6 = 0x08 + eSSUV6 = 0x08, + eNTCP2V4 = 0x10, + eNTCP2V6 = 0x20 }; enum Caps @@ -88,6 +90,12 @@ namespace data std::vector introducers; }; + struct NTCP2Ext + { + uint8_t staticKey[32]; + uint8_t iv[16]; + }; + struct Address { TransportStyle transportStyle; @@ -97,6 +105,7 @@ namespace data uint64_t date; uint8_t cost; std::unique_ptr ssu; // not null for SSU + std::unique_ptr ntcp2; // not null for NTCP2 bool IsCompatible (const boost::asio::ip::address& other) const { @@ -144,6 +153,7 @@ namespace data bool IsReachable () const { return m_Caps & Caps::eReachable; }; bool IsNTCP (bool v4only = true) const; bool IsSSU (bool v4only = true) const; + bool IsNTCP2 (bool v4only = true) const; bool IsV6 () const; bool IsV4 () const; void EnableV6 (); From 5cb81f8532b840da3ebf2b9c7c9b3d21ebc81169 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 6 Jun 2018 15:38:18 -0400 Subject: [PATCH 057/195] send SessionRequest message --- libi2pd/NTCP2.cpp | 60 ++++++++++++++++++++++++++++++++++++++++------- libi2pd/NTCP2.h | 29 +++++++++++++++++++++-- 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8b33eb0d..ac2805e0 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include "Log.h" +#include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" #include "ChaCha20.h" @@ -11,13 +14,23 @@ namespace i2p { namespace transport { - NTCP2Session::NTCP2Session (std::shared_ptr in_RemoteRouter): - TransportSession (in_RemoteRouter, 30) + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): + TransportSession (in_RemoteRouter, 30), + m_Server (server), m_Socket (m_Server.GetService ()), m_SessionRequestBuffer (nullptr) { + auto addr = in_RemoteRouter->GetNTCPAddress (); + if (addr->ntcp2) + { + memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32); + memcpy (m_RemoteIV, addr->ntcp2->iv, 16); + } + else + LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } NTCP2Session::~NTCP2Session () { + delete[] m_SessionRequestBuffer; } bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) @@ -60,24 +73,55 @@ namespace transport BN_CTX_free (ctx); } - void NTCP2Session::SendSessionRequest (const uint8_t * iv, const uint8_t * rs) + void NTCP2Session::SendSessionRequest () { i2p::crypto::AESAlignedBuffer<32> x; CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (iv); + encryption.SetIV (m_RemoteIV); encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); // encryption key for next block uint8_t key[32]; - KeyDerivationFunction (rs, x, key); - // options - uint8_t options[32]; - // TODO: fill 16 bytes options + KeyDerivationFunction (m_RemoteStaticKey, x, key); + // fill options + uint8_t options[32]; // actual options size is 16 bytes + memset (options, 0, 16); + htobe16buf (options, 2); // ver + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + htobe16buf (options + 2, paddingLength); // padLen + htobe16buf (options + 4, 0); // m3p2Len TODO: + // 2 bytes reserved + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA + // 4 bytes reserved + // sign and encrypt options i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first i2p::crypto::chacha20 (options, 16, 0, key); // then encrypt + // create buffer + m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; + memcpy (m_SessionRequestBuffer, x, 32); + memcpy (m_SessionRequestBuffer + 32, options, 32); + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } + + void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + delete[] m_SessionRequestBuffer; m_SessionRequestBuffer = nullptr; + if (ecode) + { + LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + } + } + + void NTCP2Session::ClientLogin () + { + SendSessionRequest (); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 52319db3..059f46c5 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -3,6 +3,7 @@ #include #include +#include #include "RouterInfo.h" #include "TransportSession.h" @@ -10,22 +11,46 @@ namespace i2p { namespace transport { + class NTCP2Server; class NTCP2Session: public TransportSession, public std::enable_shared_from_this { public: - NTCP2Session (std::shared_ptr in_RemoteRouter = nullptr); // TODO + NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO ~NTCP2Session (); + boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; + + void ClientLogin (); // Alice + private: bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); - void SendSessionRequest (const uint8_t * iv, const uint8_t * rs); + void SendSessionRequest (); + + void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: + NTCP2Server& m_Server; + boost::asio::ip::tcp::socket m_Socket; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key + uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; + uint8_t * m_SessionRequestBuffer; + }; + + class NTCP2Server + { + public: + + NTCP2Server () {}; + ~NTCP2Server () {} ; + boost::asio::io_service& GetService () { return m_Service; }; + + private: + + boost::asio::io_service m_Service; }; } } From 74c0b729c22b181c42b5e38ab342d99f51e528ac Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 12:29:30 -0400 Subject: [PATCH 058/195] connect to NTCP2 --- libi2pd/NTCP2.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++-- libi2pd/NTCP2.h | 28 +++++++++--- 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ac2805e0..6b21e900 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -16,7 +16,9 @@ namespace transport { NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, 30), - m_Server (server), m_Socket (m_Server.GetService ()), m_SessionRequestBuffer (nullptr) + m_Server (server), m_Socket (m_Server.GetService ()), + m_IsEstablished (false), m_IsTerminated (false), + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -31,9 +33,21 @@ namespace transport NTCP2Session::~NTCP2Session () { delete[] m_SessionRequestBuffer; + delete[] m_SessionCreatedBuffer; } - bool NTCP2Session::KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::Terminate () + { + if (!m_IsTerminated) + { + m_IsTerminated = true; + m_IsEstablished = false; + m_Socket.close (); + LogPrint (eLogDebug, "NTCP2: session terminated"); + } + } + + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -84,7 +98,7 @@ namespace transport encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); // encryption key for next block uint8_t key[32]; - KeyDerivationFunction (m_RemoteStaticKey, x, key); + KeyDerivationFunction1 (m_RemoteStaticKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -115,13 +129,102 @@ namespace transport if (ecode) { LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + Terminate (); } + else + { + m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, sizeof (56)), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + } + + void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; + if (ecode) + LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message ()); + Terminate (); // TODO: continue } void NTCP2Session::ClientLogin () { SendSessionRequest (); } + + NTCP2Server::NTCP2Server (): + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) + { + } + + NTCP2Server::~NTCP2Server () + { + Stop (); + } + + void NTCP2Server::Start () + { + if (!m_IsRunning) + { + m_IsRunning = true; + m_Thread = new std::thread (std::bind (&NTCP2Server::Run, this)); + } + } + + void NTCP2Server::Stop () + { + if (m_IsRunning) + { + m_IsRunning = false; + m_Service.stop (); + if (m_Thread) + { + m_Thread->join (); + delete m_Thread; + m_Thread = nullptr; + } + } + } + + void NTCP2Server::Run () + { + while (m_IsRunning) + { + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "NTCP2: runtime exception: ", ex.what ()); + } + } + } + + void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) + { + LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port); + m_Service.post([this, address, port, conn]() + { + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + }); + } + + void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn) + { + if (ecode) + { + LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ()); + conn->Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ()); + conn->ClientLogin (); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 059f46c5..a4f30920 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -18,6 +18,7 @@ namespace transport NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO ~NTCP2Session (); + void Terminate (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; @@ -25,32 +26,49 @@ namespace transport private: - bool KeyDerivationFunction (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: NTCP2Server& m_Server; boost::asio::ip::tcp::socket m_Socket; + bool m_IsEstablished, m_IsTerminated; + uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; - uint8_t * m_SessionRequestBuffer; + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; }; class NTCP2Server { public: - NTCP2Server () {}; - ~NTCP2Server () {} ; + NTCP2Server (); + ~NTCP2Server (); + + void Start (); + void Stop (); + boost::asio::io_service& GetService () { return m_Service; }; - + + void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); + private: + void Run (); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); + + private: + + bool m_IsRunning; + std::thread * m_Thread; boost::asio::io_service m_Service; + boost::asio::io_service::work m_Work; }; } } From 7cdb021a1fb3e54e4526981399bfa7db9fb103a0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 14:05:30 -0400 Subject: [PATCH 059/195] pass correct nonce to chacha20 --- libi2pd/NTCP2.cpp | 13 ++++++++++--- libi2pd/NTCP2.h | 5 ++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6b21e900..f3baa06c 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -47,6 +47,11 @@ namespace transport } } + void NTCP2Session::Done () + { + m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); + } + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes @@ -111,7 +116,9 @@ namespace transport // 4 bytes reserved // sign and encrypt options i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first - i2p::crypto::chacha20 (options, 16, 0, key); // then encrypt + uint8_t nonce[12]; + memset (nonce, 0, 12); + i2p::crypto::chacha20 (options, 16, nonce, key); // then encrypt // create buffer m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; memcpy (m_SessionRequestBuffer, x, 32); @@ -145,7 +152,7 @@ namespace transport (void) bytes_transferred; delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; if (ecode) - LogPrint (eLogInfo, "NTCP: Phase 2 read error: ", ecode.message ()); + LogPrint (eLogInfo, "NTCP2: SessionCreated read error: ", ecode.message ()); Terminate (); // TODO: continue } @@ -205,7 +212,7 @@ namespace transport void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) { - LogPrint (eLogDebug, "NTCP: Connecting to ", address ,":", port); + LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); m_Service.post([this, address, port, conn]() { conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index a4f30920..ca36d37b 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -3,6 +3,7 @@ #include #include +#include #include #include "RouterInfo.h" #include "TransportSession.h" @@ -16,13 +17,15 @@ namespace transport { public: - NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); // TODO + NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); ~NTCP2Session (); void Terminate (); + void Done (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; void ClientLogin (); // Alice + void SendI2NPMessages (const std::vector >& msgs) {}; // TODO private: From 7f3127ac893406a2a09fce63d8dca41e18de9f72 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 14:32:15 -0400 Subject: [PATCH 060/195] pass unencrypted X to KDF --- libi2pd/NTCP2.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f3baa06c..44c32324 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -94,13 +94,18 @@ namespace transport void NTCP2Session::SendSessionRequest () { - i2p::crypto::AESAlignedBuffer<32> x; + // create buffer and fill padding + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // generate key pair (X) + uint8_t x[32]; CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (m_RemoteIV); - encryption.Encrypt (2, x.GetChipherBlock (), x.GetChipherBlock ()); + encryption.Encrypt (x, 32, m_SessionRequestBuffer); // encryption key for next block uint8_t key[32]; KeyDerivationFunction1 (m_RemoteStaticKey, x, key); @@ -108,7 +113,6 @@ namespace transport uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); htobe16buf (options, 2); // ver - auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 4, 0); // m3p2Len TODO: // 2 bytes reserved @@ -117,13 +121,9 @@ namespace transport // sign and encrypt options i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first uint8_t nonce[12]; - memset (nonce, 0, 12); + memset (nonce, 0, 12); // set nonce to zero i2p::crypto::chacha20 (options, 16, nonce, key); // then encrypt - // create buffer - m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; - memcpy (m_SessionRequestBuffer, x, 32); memcpy (m_SessionRequestBuffer + 32, options, 32); - RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); From a8278fc78bba272518aaffe573a7cd4870e0091b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 11 Jun 2018 15:33:48 -0400 Subject: [PATCH 061/195] router's NTCP2 private keys --- libi2pd/Config.cpp | 1 + libi2pd/RouterContext.cpp | 31 +++++++++++++++++++++++++++++++ libi2pd/RouterContext.h | 11 +++++++++++ 3 files changed, 43 insertions(+) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 126de7fc..a7bc305c 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -59,6 +59,7 @@ namespace config { ("ntcp", value()->default_value(true), "Enable NTCP transport") ("ssu", value()->default_value(true), "Enable SSU transport") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") + ("ntcp2", value()->zero_tokens()->default_value(false), "Enable NTCP2 (experimental)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a82ace85..b0f1aa51 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -1,4 +1,5 @@ #include +#include #include "Config.h" #include "Crypto.h" #include "Timestamp.h" @@ -98,6 +99,16 @@ namespace i2p m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); } + void RouterContext::NewNTCP2Keys () + { + m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); + RAND_bytes (m_NTCP2Keys->staticKey, 32); + RAND_bytes (m_NTCP2Keys->iv, 16); + // save + std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out); + fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + } + void RouterContext::SetStatus (RouterStatus status) { if (status != m_Status) @@ -429,6 +440,26 @@ namespace i2p if (IsUnreachable ()) SetReachable (); // we assume reachable until we discover firewall through peer tests + // read NTCP2 + bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + if (ntcp2) + { + std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); + if (n2k) + { + n2k.seekg (0, std::ios::end); + len = fk.tellg(); + n2k.seekg (0, std::ios::beg); + if (len == sizeof (NTCP2PrivateKeys)) + { + m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); + n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + } + } + if (!m_NTCP2Keys) + NewNTCP2Keys (); + } + return true; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 4bd324f5..02c0156b 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -14,6 +14,7 @@ namespace i2p { const char ROUTER_INFO[] = "router.info"; const char ROUTER_KEYS[] = "router.keys"; + const char NTCP2_KEYS[] = "ntcp2.keys"; const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes enum RouterStatus @@ -32,6 +33,14 @@ namespace i2p class RouterContext: public i2p::garlic::GarlicDestination { + private: + + struct NTCP2PrivateKeys + { + uint8_t staticKey[32]; + uint8_t iv[16]; + }; + public: RouterContext (); @@ -108,6 +117,7 @@ namespace i2p void CreateNewRouter (); void NewRouterInfo (); void UpdateRouterInfo (); + void NewNTCP2Keys (); bool Load (); void SaveKeys (); @@ -125,6 +135,7 @@ namespace i2p RouterError m_Error; int m_NetID; std::mutex m_GarlicMutex; + std::unique_ptr m_NTCP2Keys; }; extern RouterContext context; From 046a80cfe4d35b0ab8a4e17753812ef555429ba6 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jun 2018 12:42:20 -0400 Subject: [PATCH 062/195] scalar multiplication for x25519 --- libi2pd/Ed25519.cpp | 101 +++++++++++++++++++++++++++++++++++++++++--- libi2pd/Ed25519.h | 6 ++- libi2pd/NTCP2.cpp | 5 +-- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 8258d33c..f8fdaae1 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,12 +411,103 @@ namespace crypto } } - void Ed25519::Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + BIGNUM * Ed25519::ScalarMul (const BIGNUM * p, const BIGNUM * n, BN_CTX * ctx) const { - auto P = DecodePublicKey (p, ctx); - BIGNUM * e1 = DecodeBN<32> (e); - EncodePublicKey (Mul (P, e1, ctx), buf, ctx); - BN_free (e1); + BN_CTX_start (ctx); + auto x1 = BN_CTX_get (ctx); BN_copy (x1, p); + auto x2 = BN_CTX_get (ctx); BN_one (x2); + auto z2 = BN_CTX_get (ctx); BN_zero (z2); + auto x3 = BN_CTX_get (ctx); BN_copy (x1, p); + auto z3 = BN_CTX_get (ctx); BN_one (z3); + auto a24 = BN_CTX_get (ctx); BN_set_word (a24, 121665); + auto a = BN_CTX_get (ctx); auto aa = BN_CTX_get (ctx); + auto b = BN_CTX_get (ctx); auto bb = BN_CTX_get (ctx); + auto e = BN_CTX_get (ctx); auto c = BN_CTX_get (ctx); + auto d = BN_CTX_get (ctx); + auto da = BN_CTX_get (ctx); auto cb = BN_CTX_get (ctx); + auto tmp1 = BN_CTX_get (ctx); auto tmp2 = BN_CTX_get (ctx); + unsigned int swap = 0; + auto bits = BN_num_bits (n); + while(bits) + { + --bits; + auto k_t = BN_is_bit_set(n, bits) ? 1 : 0; + swap ^= k_t; + if (swap) + { + std::swap (x2, x3); + std::swap (z2, z3); + } + swap = k_t; + // a = x2 + z2 + BN_mod_add(a, x2, z2, q, ctx); + // aa = a^2 + BN_mod_sqr(aa, a, q, ctx); + // b = x2 - z2 + BN_mod_sub(b, x2, z2, q, ctx); + // bb = b^2 + BN_mod_sqr(bb, b, q, ctx); + // e = aa - bb + BN_mod_sub(e, aa, bb, q, ctx); + // c = x3 + z3 + BN_mod_add(c, x3, z3, q, ctx); + // d = x3 - z3 + BN_mod_sub(d, x3, z3, q, ctx); + // da = d * a + BN_mod_mul(da, d, a, q, ctx); + // cb = c * b + BN_mod_mul(cb, c, b, q, ctx); + // x3 = ( da + cb )^2 + BN_mod_add(tmp1, da, cb, q, ctx); + BN_mod_sqr(x3, tmp1, q, ctx); + // z3 == x1 * (da - cb)^2 + BN_mod_sub(tmp1, da, cb, q, ctx); + BN_mod_sqr(tmp2, tmp1, q, ctx); + BN_mod_mul(z3, x1, tmp2, q, ctx); + // x2 = aa * bb + BN_mod_mul(x2, aa, bb, q, ctx); + // z2 = e * (aa + a24 * e) + BN_mod_mul(tmp1, a24, e, q, ctx); + BN_mod_add(tmp2, aa, tmp1, q, ctx); + BN_mod_mul(z2, e, tmp2, q, ctx); + } + if (swap) + { + std::swap (x2, x3); + std::swap (z2, z3); + } + // x2 * (z2 ^ (q - 2)) + BN_set_word(tmp1, 2); + BN_sub(tmp2, q, tmp1); + BN_mod_exp(tmp1, z2, tmp2, q, ctx); + BIGNUM * res = BN_new (); // not from ctx + BN_mod_mul(res, x2, tmp1, q, ctx); + BN_CTX_end (ctx); + return res; + } + + void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + BIGNUM * p1 = DecodeBN<32> (p); + uint8_t k[32]; + memcpy (k, e, 32); + k[0] &= 248; k[31] &= 127; k[31] |= 64; + BIGNUM * n = DecodeBN<32> (k); + BIGNUM * q1 = ScalarMul (p1, n, ctx); + EncodeBN (q1, buf, 32); + BN_free (p1); BN_free (n); BN_free (q1); + } + + void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + BIGNUM *p1 = BN_new (); BN_set_word (p1, 9); + uint8_t k[32]; + memcpy (k, e, 32); + k[0] &= 248; k[31] &= 127; k[31] |= 64; + BIGNUM * n = DecodeBN<32> (k); + BIGNUM * q1 = ScalarMul (p1, n, ctx); + EncodeBN (q1, buf, 32); + BN_free (p1); BN_free (n); BN_free (q1); } void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index cbf14bfd..fc23a457 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -75,7 +75,8 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; - void Mul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number + void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 + void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; @@ -99,6 +100,9 @@ namespace crypto BIGNUM * DecodeBN (const uint8_t * buf) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; + // for x25519 + BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; + private: BIGNUM * q, * l, * d, * I; diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 44c32324..43ccc2dd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -67,7 +67,7 @@ namespace transport // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->Mul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv + i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv BN_CTX_free (ctx); // temp_key = HMAC-SHA256(ck, input_key_material) uint8_t tempKey[32]; unsigned int len; @@ -87,8 +87,7 @@ namespace transport RAND_bytes (key, 32); i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey); BN_CTX * ctx = BN_CTX_new (); - auto publicKey = i2p::crypto::GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); - i2p::crypto::GetEd25519 ()->EncodePublicKey (publicKey, pub, ctx); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_ExpandedPrivateKey, pub, ctx); BN_CTX_free (ctx); } From 3b46e9f3510f0579ac37eca299bb7937eb587cb3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jun 2018 14:55:40 -0400 Subject: [PATCH 063/195] fixed typo --- libi2pd/Ed25519.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index f8fdaae1..05721d80 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,13 +411,13 @@ namespace crypto } } - BIGNUM * Ed25519::ScalarMul (const BIGNUM * p, const BIGNUM * n, BN_CTX * ctx) const + BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const { BN_CTX_start (ctx); - auto x1 = BN_CTX_get (ctx); BN_copy (x1, p); + auto x1 = BN_CTX_get (ctx); BN_copy (x1, u); auto x2 = BN_CTX_get (ctx); BN_one (x2); auto z2 = BN_CTX_get (ctx); BN_zero (z2); - auto x3 = BN_CTX_get (ctx); BN_copy (x1, p); + auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); auto z3 = BN_CTX_get (ctx); BN_one (z3); auto a24 = BN_CTX_get (ctx); BN_set_word (a24, 121665); auto a = BN_CTX_get (ctx); auto aa = BN_CTX_get (ctx); @@ -427,11 +427,11 @@ namespace crypto auto da = BN_CTX_get (ctx); auto cb = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); auto tmp2 = BN_CTX_get (ctx); unsigned int swap = 0; - auto bits = BN_num_bits (n); + auto bits = BN_num_bits (k); while(bits) { --bits; - auto k_t = BN_is_bit_set(n, bits) ? 1 : 0; + auto k_t = BN_is_bit_set(k, bits) ? 1 : 0; swap ^= k_t; if (swap) { From 7fa5b06359ac30c2006af2e67ce54e1680c4c244 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 12 Jun 2018 18:29:06 -0400 Subject: [PATCH 064/195] x25519 unti test --- tests/Makefile | 7 +++++-- tests/test-x25519.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 tests/test-x25519.cpp diff --git a/tests/Makefile b/tests/Makefile index f769ad35..4f4c895c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -TESTS = test-gost test-gost-sig test-base-64 +TESTS = test-gost test-gost-sig test-base-64 test-x25519 all: $(TESTS) run @@ -13,7 +13,10 @@ test-base-%: ../libi2pd/Base.cpp test-base-%.cpp test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Signature.cpp ../libi2pd/Crypto.cpp ../libi2pd/Log.cpp test-gost-sig.cpp +test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp ../libi2pd/Log.cpp test-gost-sig.cpp + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system + +test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp test-x25519.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system run: $(TESTS) diff --git a/tests/test-x25519.cpp b/tests/test-x25519.cpp new file mode 100644 index 00000000..9f249dbd --- /dev/null +++ b/tests/test-x25519.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +#include "Ed25519.h" + +const uint8_t k[32] = +{ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, + 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, + 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 +}; + +const uint8_t u[32] = +{ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, + 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, + 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c +}; + +uint8_t p[32] = +{ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, + 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, + 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 +}; + +int main () +{ + uint8_t buf[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMul (u, k, buf, ctx); + BN_CTX_free (ctx); + assert(memcmp (buf, p, 32) == 0); +} + From bf1e1ad457259db4148065305b95101c7cdfce96 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 10:49:14 -0400 Subject: [PATCH 065/195] eliminate extra dependencies --- tests/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index 4f4c895c..38080a32 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,4 +1,4 @@ -CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread +CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -Wl,--unresolved-symbols=ignore-in-object-files TESTS = test-gost test-gost-sig test-base-64 test-x25519 @@ -13,10 +13,10 @@ test-base-%: ../libi2pd/Base.cpp test-base-%.cpp test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp ../libi2pd/Log.cpp test-gost-sig.cpp +test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/Log.cpp test-gost-sig.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system -test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp ../libi2pd/CPU.cpp test-x25519.cpp +test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp test-x25519.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system run: $(TESTS) From df60e787661c07ad92144c72c0da872e78b556e4 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 11:41:46 -0400 Subject: [PATCH 066/195] AEAD/Chacha20/Poly1305 encryption --- libi2pd/Crypto.cpp | 29 +++++++++++++++++++++++++++++ libi2pd/Crypto.h | 4 ++++ libi2pd/I2PEndian.h | 13 +++++++++++++ libi2pd/NTCP2.cpp | 14 +++++--------- libi2pd/NTCP2.h | 2 +- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 8ba99a15..5e8ba855 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -8,6 +8,9 @@ #include #include "TunnelBase.h" #include +#include "I2PEndian.h" +#include "ChaCha20.h" +#include "Poly1305.h" #include "Log.h" #include "Crypto.h" @@ -1057,6 +1060,32 @@ namespace crypto } } +// AEAD/ChaCha20/Poly1305 + + size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + { + if (msgLen + 16 < len) return 0; + // generate one time poly key + uint8_t polyKey[64]; + memset(polyKey, 0, sizeof(polyKey)); + chacha20 (polyKey, 64, nonce, key, 0); + // encrypt data + memcpy (buf, msg, msgLen); + chacha20 (buf, msgLen, nonce, key, 1); + // create Poly1305 message + std::vector polyMsg(adLen + msgLen + 16); + size_t offset = 0; + memcpy (polyMsg.data (), ad, adLen); offset += adLen; + memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data + htole64buf (polyMsg.data () + offset, adLen); offset += 8; + htole64buf (polyMsg.data () + offset, msgLen); offset += 8; + // calculate Poly1305 tag and write in after encrypted data + Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)key, polyMsg.data (), offset); + return msgLen + 16; + } + +// init and terminate + /* std::vector > m_OpenSSLMutexes; static void OpensslLockingCallback(int mode, int type, const char * file, int line) { diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 859f2d97..0600c48c 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -252,6 +252,10 @@ namespace crypto CBCDecryption m_LayerDecryption; }; +// AEAD/ChaCha20/Poly1305 + size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + +// init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); } diff --git a/libi2pd/I2PEndian.h b/libi2pd/I2PEndian.h index d2250768..0798f688 100644 --- a/libi2pd/I2PEndian.h +++ b/libi2pd/I2PEndian.h @@ -113,7 +113,20 @@ inline void htobe64buf(void *buf, uint64_t big64) htobuf64(buf, htobe64(big64)); } +inline void htole16buf(void *buf, uint16_t big16) +{ + htobuf16(buf, htole16(big16)); +} +inline void htole32buf(void *buf, uint32_t big32) +{ + htobuf32(buf, htole32(big32)); +} + +inline void htole64buf(void *buf, uint64_t big64) +{ + htobuf64(buf, htole64(big64)); +} #endif // I2PENDIAN_H__ diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 43ccc2dd..b3794354 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -6,8 +6,6 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" -#include "ChaCha20.h" -#include "Poly1305.h" #include "NTCP2.h" namespace i2p @@ -52,7 +50,7 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -63,7 +61,7 @@ namespace transport SHA256 (h, 64, h); // h = SHA256(h || pub) memcpy (h + 32, pub, 32); - SHA256 (h, 64, h); + SHA256 (h, 64, ad); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); @@ -106,8 +104,8 @@ namespace transport encryption.SetIV (m_RemoteIV); encryption.Encrypt (x, 32, m_SessionRequestBuffer); // encryption key for next block - uint8_t key[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, x, key); + uint8_t key[32], ad[32]; + KeyDerivationFunction1 (m_RemoteStaticKey, x, key, ad); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -118,11 +116,9 @@ namespace transport htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved // sign and encrypt options - i2p::crypto::Poly1305HMAC (((uint32_t *)options) + 4, (uint32_t *)key, options, 16); // calculate MAC first uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::chacha20 (options, 16, nonce, key); // then encrypt - memcpy (m_SessionRequestBuffer + 32, options, 32); + i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, ad, 32, key, nonce, m_SessionRequestBuffer + 32, 32); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index ca36d37b..8cdf6073 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,7 +29,7 @@ namespace transport private: - bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); From 6b9061515fcc0da9c0e24fd770bf215331a576e2 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 12:25:32 -0400 Subject: [PATCH 067/195] AEAD/ChaCha20/Poly1305 test added --- libi2pd/Crypto.cpp | 17 ++++++++-- tests/Makefile | 5 ++- tests/test-aeadchacha20poly1305.cpp | 49 +++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 tests/test-aeadchacha20poly1305.cpp diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 5e8ba855..6d52a6c1 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1073,10 +1073,23 @@ namespace crypto memcpy (buf, msg, msgLen); chacha20 (buf, msgLen, nonce, key, 1); // create Poly1305 message - std::vector polyMsg(adLen + msgLen + 16); + std::vector polyMsg(adLen + msgLen + 3*16); size_t offset = 0; - memcpy (polyMsg.data (), ad, adLen); offset += adLen; + uint8_t padding[16]; memset (padding, 0, 16); + memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data + auto rem = adLen & 0x0F; // %16 + if (rem) + { + // padding1 + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + } memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data + rem = msgLen & 0x0F; // %16 + if (rem) + { + // padding2 + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + } htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; // calculate Poly1305 tag and write in after encrypted data diff --git a/tests/Makefile b/tests/Makefile index 38080a32..498cff17 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,6 +1,6 @@ CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -Wl,--unresolved-symbols=ignore-in-object-files -TESTS = test-gost test-gost-sig test-base-64 test-x25519 +TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 all: $(TESTS) run @@ -19,6 +19,9 @@ test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cp test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp test-x25519.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system +test-aeadchacha20poly1305: ../libi2pd/Crypto.cpp ../libi2pd/ChaCha20.cpp ../libi2pd/Poly1305.cpp test-aeadchacha20poly1305.cpp + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system + run: $(TESTS) @for TEST in $(TESTS); do ./$$TEST ; done diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp new file mode 100644 index 00000000..cb9ed5c3 --- /dev/null +++ b/tests/test-aeadchacha20poly1305.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +#include "Crypto.h" + +char text[] = "Ladies and Gentlemen of the class of '99: If I could offer you " +"only one tip for the future, sunscreen would be it."; // 114 bytes + +uint8_t key[32] = +{ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f +}; + +uint8_t ad[12] = +{ + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 +}; + +uint8_t nonce[12] = +{ + 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 +}; + +uint8_t tag[16] = +{ + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 +}; + +uint8_t encrypted[114] = +{ + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16 +}; + +int main () +{ + uint8_t buf[114+16]; + i2p::crypto::AEADChaCha20Poly1305Encrypt ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16); + assert (memcmp (buf, encrypted, 114) == 0); + assert(memcmp (buf + 114, tag, 16) == 0); +} From 966256ac325d500b04e1e746414aa89a66b2e0ac Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 12:58:32 -0400 Subject: [PATCH 068/195] correct Poly1305 calculation --- libi2pd/Crypto.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 6d52a6c1..0073faee 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1081,6 +1081,7 @@ namespace crypto if (rem) { // padding1 + rem = 16 - rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data @@ -1088,12 +1089,14 @@ namespace crypto if (rem) { // padding2 + rem = 16 - rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; + // calculate Poly1305 tag and write in after encrypted data - Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)key, polyMsg.data (), offset); + Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); return msgLen + 16; } From ee0ae0b74bca554fe15b8e9d8c231e6f8f991758 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 14:56:51 -0400 Subject: [PATCH 069/195] decrypt Y for NTCP2 --- libi2pd/Crypto.h | 2 ++ libi2pd/NTCP2.cpp | 42 ++++++++++++++++++++++++++---------------- libi2pd/NTCP2.h | 4 ++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 0600c48c..c124a200 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -181,6 +181,7 @@ namespace crypto void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_LastBlock, iv, 16); }; // 16 bytes + void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_LastBlock, 16); }; void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); @@ -203,6 +204,7 @@ namespace crypto void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_IV, iv, 16); }; // 16 bytes + void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_IV, 16); }; void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index b3794354..474ad67d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -22,7 +22,7 @@ namespace transport if (addr->ntcp2) { memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32); - memcpy (m_RemoteIV, addr->ntcp2->iv, 16); + memcpy (m_IV, addr->ntcp2->iv, 16); } else LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); @@ -50,7 +50,7 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad) + bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64], ck[33]; @@ -61,7 +61,7 @@ namespace transport SHA256 (h, 64, h); // h = SHA256(h || pub) memcpy (h + 32, pub, 32); - SHA256 (h, 64, ad); + SHA256 (h, 64, m_H); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); @@ -101,24 +101,25 @@ namespace transport // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_RemoteIV); + encryption.SetIV (m_IV); encryption.Encrypt (x, 32, m_SessionRequestBuffer); + encryption.GetIV (m_IV); // save IV for SessionCreated // encryption key for next block - uint8_t key[32], ad[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, x, key, ad); + uint8_t key[32]; + KeyDerivationFunction1 (m_RemoteStaticKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); htobe16buf (options, 2); // ver htobe16buf (options + 2, paddingLength); // padLen - htobe16buf (options + 4, 0); // m3p2Len TODO: + htobe16buf (options + 4, 550); // m3p2Len TODO: // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved - // sign and encrypt options + // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, ad, 32, key, nonce, m_SessionRequestBuffer + 32, 32); + i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -127,28 +128,37 @@ namespace transport void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { (void) bytes_transferred; - delete[] m_SessionRequestBuffer; m_SessionRequestBuffer = nullptr; if (ecode) { - LogPrint (eLogInfo, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); + LogPrint (eLogWarning, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); Terminate (); } else { m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, sizeof (56)), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 56), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - (void) bytes_transferred; - delete[] m_SessionCreatedBuffer; m_SessionCreatedBuffer = nullptr; if (ecode) - LogPrint (eLogInfo, "NTCP2: SessionCreated read error: ", ecode.message ()); - Terminate (); // TODO: continue + { + LogPrint (eLogWarning, "NTCP2: SessionCreated read error: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated received ", bytes_transferred); + uint8_t y[32]; + // decrypt Y + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); + decryption.SetIV (m_IV); + decryption.Decrypt (m_SessionCreatedBuffer, 32, y); + } } void NTCP2Session::ClientLogin () diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 8cdf6073..456f9d3e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,7 +29,7 @@ namespace transport private: - bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived, uint8_t * ad); // for SessionRequest + bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); @@ -43,7 +43,7 @@ namespace transport bool m_IsEstablished, m_IsTerminated; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_RemoteIV[16]; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32]; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; }; From 5447259e1a2cc7b29c4fc4993a85be3bb145b1fd Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 13 Jun 2018 16:16:23 -0400 Subject: [PATCH 070/195] AEAD/ChaCha20/Poly1305 decryption and SessionCreate prcessing --- libi2pd/Crypto.cpp | 23 ++++++--- libi2pd/Crypto.h | 2 +- libi2pd/NTCP2.cpp | 73 ++++++++++++++++++++++++----- libi2pd/NTCP2.h | 7 ++- tests/test-aeadchacha20poly1305.cpp | 9 +++- 5 files changed, 90 insertions(+), 24 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 0073faee..bdcf5acd 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1062,9 +1062,9 @@ namespace crypto // AEAD/ChaCha20/Poly1305 - size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) { - if (msgLen + 16 < len) return 0; + if (encrypt && msgLen + 16 < len) return 0; // generate one time poly key uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); @@ -1072,6 +1072,7 @@ namespace crypto // encrypt data memcpy (buf, msg, msgLen); chacha20 (buf, msgLen, nonce, key, 1); + // create Poly1305 message std::vector polyMsg(adLen + msgLen + 3*16); size_t offset = 0; @@ -1084,7 +1085,7 @@ namespace crypto rem = 16 - rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } - memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data + memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data rem = msgLen & 0x0F; // %16 if (rem) { @@ -1095,9 +1096,19 @@ namespace crypto htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; - // calculate Poly1305 tag and write in after encrypted data - Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); - return msgLen + 16; + if (encrypt) + { + // calculate Poly1305 tag and write in after encrypted data + Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); + } + else + { + uint32_t tag[8]; + // calculate Poly1305 tag + Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); + if (memcmp (tag, msg + msgLen, 16)) return false; // compare with provided + } + return true; } // init and terminate diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index c124a200..af4ec1f8 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -255,7 +255,7 @@ namespace crypto }; // AEAD/ChaCha20/Poly1305 - size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag // init and terminate void InitCrypto (bool precomputation); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 474ad67d..64636433 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "Log.h" #include "I2PEndian.h" #include "Crypto.h" @@ -50,11 +51,11 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes - uint8_t h[64], ck[33]; - memcpy (ck, protocolName, 32); + uint8_t h[64]; + memcpy (m_CK, protocolName, 32); SHA256 ((const uint8_t *)protocolName, 32, h); // h = SHA256(h || rs) memcpy (h + 32, rs, 32); @@ -69,14 +70,43 @@ namespace transport BN_CTX_free (ctx); // temp_key = HMAC-SHA256(ck, input_key_material) uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), ck, 32, inputKeyMaterial, 32, tempKey, &len); - // ck = HMAC-SHA256(temp_key, byte(0x01)) + HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) inputKeyMaterial[0] = 1; - HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, ck, &len); + HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - ck[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, ck, 33, derived, &len); - return true; + m_CK[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + } + + void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + { + uint8_t h[64]; + memcpy (h, m_H, 32); + memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload + SHA256 (h, 64, m_H); + int paddingLength = sessionRequestLen - 64; + if (paddingLength > 0) + { + std::vector h1(paddingLength + 32); + memcpy (h1.data (), m_H, 32); + memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); + SHA256 (h1.data (), paddingLength + 32, m_H); + } + // x25519 between remote pub and priv + uint8_t inputKeyMaterial[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx); + BN_CTX_free (ctx); + // temp_key = HMAC-SHA256(ck, input_key_material) + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) + inputKeyMaterial[0] = 1; + HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); + // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) + m_CK[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -93,7 +123,8 @@ namespace transport { // create buffer and fill padding auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; + m_SessionRequestBufferLen = paddingLength + 64; + m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // generate key pair (X) uint8_t x[32]; @@ -119,9 +150,9 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32); + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -151,13 +182,29 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: SessionCreated received ", bytes_transferred); + LogPrint (eLogInfo, "NTCP2: SessionCreated received ", bytes_transferred); uint8_t y[32]; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, y); + // decryption key for next block + uint8_t key[32]; + KeyDerivationFunction2 (y, m_SessionRequestBuffer, m_SessionRequestBufferLen, key); + // decrypt and verify MAC + uint8_t payload[8]; + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, key, nonce, payload, 8, false)) // decrypt + { + // TODO: + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed "); + Terminate (); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 456f9d3e..b7e83f26 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,7 +29,9 @@ namespace transport private: - bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); @@ -43,8 +45,9 @@ namespace transport bool m_IsEstablished, m_IsTerminated; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32]; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; + size_t m_SessionRequestBufferLen; }; class NTCP2Server diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp index cb9ed5c3..dcd4b4d6 100644 --- a/tests/test-aeadchacha20poly1305.cpp +++ b/tests/test-aeadchacha20poly1305.cpp @@ -43,7 +43,12 @@ uint8_t encrypted[114] = int main () { uint8_t buf[114+16]; - i2p::crypto::AEADChaCha20Poly1305Encrypt ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16); + // test encryption + i2p::crypto::AEADChaCha20Poly1305 ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16, true); assert (memcmp (buf, encrypted, 114) == 0); - assert(memcmp (buf + 114, tag, 16) == 0); + assert (memcmp (buf + 114, tag, 16) == 0); + // test decryption + uint8_t buf1[114]; + assert (i2p::crypto::AEADChaCha20Poly1305 (buf, 114, ad, 12, key, nonce, buf1, 114, false)); + assert (memcmp (buf1, text, 114) == 0); } From 6b37a41e007fa81be0ce00cdcc6b50e921630e4c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jun 2018 10:45:25 -0400 Subject: [PATCH 071/195] correct ad calculation for SessionCreated --- libi2pd/NTCP2.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 64636433..f2675276 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -84,15 +84,18 @@ namespace transport uint8_t h[64]; memcpy (h, m_H, 32); memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload - SHA256 (h, 64, m_H); + SHA256 (h, 64, h); int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) { std::vector h1(paddingLength + 32); - memcpy (h1.data (), m_H, 32); + memcpy (h1.data (), h, 32); memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, m_H); + SHA256 (h1.data (), paddingLength + 32, h); } + memcpy (h + 32, pub, 32); + SHA256 (h, 64, m_H); + // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); From 2bd7a92d20306a5ff99ebc069a634eb18f40b042 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 14 Jun 2018 15:29:36 -0400 Subject: [PATCH 072/195] send SessionConfirmed --- libi2pd/NTCP2.cpp | 128 ++++++++++++++++++++++++++++++++++++---------- libi2pd/NTCP2.h | 11 ++-- 2 files changed, 109 insertions(+), 30 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f2675276..2dd18960 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -17,7 +17,7 @@ namespace transport TransportSession (in_RemoteRouter, 30), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr) + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -33,6 +33,7 @@ namespace transport { delete[] m_SessionRequestBuffer; delete[] m_SessionCreatedBuffer; + delete[] m_SessionConfirmedBuffer; } void NTCP2Session::Terminate () @@ -51,6 +52,19 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } + void NTCP2Session::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) + { + // temp_key = HMAC-SHA256(ck, input_key_material) + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) + static uint8_t one[1] = { 1 }; + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_CK, &len); + // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) + m_CK[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + } + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes @@ -68,15 +82,7 @@ namespace transport BN_CTX * ctx = BN_CTX_new (); i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv BN_CTX_free (ctx); - // temp_key = HMAC-SHA256(ck, input_key_material) - uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); - // ck = HMAC-SHA256(temp_key, byte(0x01)) - inputKeyMaterial[0] = 1; - HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); - // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - m_CK[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + MixKey (inputKeyMaterial, derived); } void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) @@ -101,15 +107,16 @@ namespace transport BN_CTX * ctx = BN_CTX_new (); i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx); BN_CTX_free (ctx); - // temp_key = HMAC-SHA256(ck, input_key_material) - uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); - // ck = HMAC-SHA256(temp_key, byte(0x01)) - inputKeyMaterial[0] = 1; - HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len); - // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - m_CK[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + MixKey (inputKeyMaterial, derived); + } + + void NTCP2Session::KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived) + { + uint8_t inputKeyMaterial[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMul (m_Y, staticPrivKey, inputKeyMaterial, ctx); + BN_CTX_free (ctx); + MixKey (inputKeyMaterial, derived); } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -185,23 +192,30 @@ namespace transport } else { - LogPrint (eLogInfo, "NTCP2: SessionCreated received ", bytes_transferred); - uint8_t y[32]; + LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); + m_SessionCreatedBufferLen = 56; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, y); - // decryption key for next block - uint8_t key[32]; - KeyDerivationFunction2 (y, m_SessionRequestBuffer, m_SessionRequestBufferLen, key); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y); + // decryption key for next block (m_K) + KeyDerivationFunction2 (m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); // decrypt and verify MAC uint8_t payload[8]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, key, nonce, payload, 8, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, m_K, nonce, payload, 8, false)) // decrypt { - // TODO: + uint16_t paddingLen = bufbe16toh(payload); + LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); + if (paddingLen > 0) + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 56, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + SendSessionConfirmed (); } else { @@ -211,6 +225,66 @@ namespace transport } } + void NTCP2Session::HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionCreated padding read error: ", ecode.message ()); + Terminate (); + } + else + { + m_SessionCreatedBufferLen += bytes_transferred; + SendSessionConfirmed (); + } + } + + void NTCP2Session::SendSessionConfirmed () + { + // update AD + uint8_t h[80]; + memcpy (h, m_H, 32); + memcpy (h + 32, m_SessionCreatedBuffer + 32, 24); // encrypted payload + SHA256 (h, 56, h); + int paddingLength = m_SessionCreatedBufferLen - 56; + if (paddingLength > 0) + { + std::vector h1(paddingLength + 32); + memcpy (h1.data (), h, 32); + memcpy (h1.data () + 32, m_SessionCreatedBuffer + 56, paddingLength); + SHA256 (h1.data (), paddingLength + 32, h); + } + // part1 48 bytes + uint8_t s[32]; // public static + CreateEphemeralKey (s); // TODO: take it from RouterContext + m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size + uint8_t nonce[12]; + memset (nonce, 0, 4); htole64buf (nonce + 4, 1); // set nonce to 1 + i2p::crypto::AEADChaCha20Poly1305 (s, 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + // part 2 + // update AD again + memcpy (h + 32, m_SessionConfirmedBuffer, 48); + SHA256 (h, 80, m_H); + + size_t m3p2Len = 550; // TODO: actual size + uint8_t buf[550]; + memset (buf, 0, m3p2Len - 16); // TODO: fill + uint8_t key[32]; + KeyDerivationFunction3 (m_ExpandedPrivateKey, key); // TODO: take it from RouterContext + memset (nonce, 0, 12); // set nonce to 0 again + i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); + Terminate (); // TODO + } + void NTCP2Session::ClientLogin () { SendSessionRequest (); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index b7e83f26..e9a170bd 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -29,14 +29,19 @@ namespace transport private: + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); + void SendSessionConfirmed (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); private: @@ -45,9 +50,9 @@ namespace transport bool m_IsEstablished, m_IsTerminated; uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/; - uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; - size_t m_SessionRequestBufferLen; + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32]; + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; + size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; }; class NTCP2Server From 706b976a28c01ba00e147ce5a3dfbe59baa112e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Jun 2018 12:52:43 -0400 Subject: [PATCH 073/195] handle and publish NTCP2 address --- libi2pd/RouterContext.cpp | 24 +++++++++++---- libi2pd/RouterContext.h | 6 +++- libi2pd/RouterInfo.cpp | 61 ++++++++++++++++++++++++++++++--------- libi2pd/RouterInfo.h | 7 +++-- 4 files changed, 77 insertions(+), 21 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index b0f1aa51..862352ba 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -2,6 +2,7 @@ #include #include "Config.h" #include "Crypto.h" +#include "Ed25519.h" #include "Timestamp.h" #include "I2NPProtocol.h" #include "NetDb.hpp" @@ -36,7 +37,7 @@ namespace i2p void RouterContext::CreateNewRouter () { m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); - SaveKeys (); + SaveKeys (); NewRouterInfo (); } @@ -49,7 +50,8 @@ namespace i2p port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv6; i2p::config::GetOption("ipv6", ipv6); - bool nat; i2p::config::GetOption("nat", nat); + bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool nat; i2p::config::GetOption("nat", nat); std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname4; i2p::config::GetOption("ifname4", ifname4); std::string ifname6; i2p::config::GetOption("ifname6", ifname6); @@ -82,6 +84,11 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } + if (ntcp2) + { + NewNTCP2Keys (); + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC @@ -102,11 +109,14 @@ namespace i2p void RouterContext::NewNTCP2Keys () { m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); - RAND_bytes (m_NTCP2Keys->staticKey, 32); + RAND_bytes (m_NTCP2Keys->staticPrivateKey, 32); RAND_bytes (m_NTCP2Keys->iv, 16); + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_NTCP2Keys->staticPrivateKey, m_NTCP2Keys->staticPublicKey, ctx); + BN_CTX_free (ctx); // save std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out); - fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); } void RouterContext::SetStatus (RouterStatus status) @@ -455,9 +465,13 @@ namespace i2p m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); } + n2k.close (); } - if (!m_NTCP2Keys) + if (!m_NTCP2Keys) + { NewNTCP2Keys (); + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } } return true; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 02c0156b..ae4aa17e 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -37,7 +37,8 @@ namespace i2p struct NTCP2PrivateKeys { - uint8_t staticKey[32]; + uint8_t staticPublicKey[32]; + uint8_t staticPrivateKey[32]; uint8_t iv[16]; }; @@ -58,6 +59,9 @@ namespace i2p return std::shared_ptr (this, [](i2p::garlic::GarlicDestination *) {}); } + const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; }; + const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; }; + const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; }; uint32_t GetUptime () const; uint32_t GetStartupTime () const { return m_StartupTime; }; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 87f16346..088ba154 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -176,10 +176,14 @@ namespace data auto address = std::make_shared
(); s.read ((char *)&address->cost, sizeof (address->cost)); s.read ((char *)&address->date, sizeof (address->date)); - char transportStyle[5]; - ReadString (transportStyle, 5, s); - if (!strcmp (transportStyle, "NTCP")) + bool isNtcp2 = false; + char transportStyle[6]; + auto transportStyleLen = ReadString (transportStyle, 6, s) - 1; + if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2 + { address->transportStyle = eTransportNTCP; + if (transportStyleLen > 4 || transportStyle[4] == '2') isNtcp2= true; + } else if (!strcmp (transportStyle, "SSU")) { address->transportStyle = eTransportSSU; @@ -288,7 +292,7 @@ namespace data if (!s) return; } if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented - if (supportedTransports) + if (supportedTransports && !isNtcp2) // we ignore NTCP2 addresses for now. TODO: { addresses->push_back(address); m_SupportedTransports |= supportedTransports; @@ -435,7 +439,7 @@ namespace data s.write ((const char *)&address.date, sizeof (address.date)); std::stringstream properties; if (address.transportStyle == eTransportNTCP) - WriteString ("NTCP", s); + WriteString (address.IsNTCP2 () ? "NTCP2" : "NTCP", s); else if (address.transportStyle == eTransportSSU) { WriteString ("SSU", s); @@ -451,10 +455,13 @@ namespace data else WriteString ("", s); - WriteString ("host", properties); - properties << '='; - WriteString (address.host.to_string (), properties); - properties << ';'; + if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + { + WriteString ("host", properties); + properties << '='; + WriteString (address.host.to_string (), properties); + properties << ';'; + } if (address.transportStyle == eTransportSSU) { // write introducers if any @@ -529,10 +536,23 @@ namespace data properties << ';'; } } - WriteString ("port", properties); - properties << '='; - WriteString (boost::lexical_cast(address.port), properties); - properties << ';'; + + if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + { + WriteString ("port", properties); + properties << '='; + WriteString (boost::lexical_cast(address.port), properties); + properties << ';'; + } + if (address.IsNTCP2 ()) + { + // publish s and v for NTCP2 + WriteString ("s", properties); properties << '='; + WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; + WriteString ("v", properties); properties << '='; + WriteString ("2", properties); properties << ';'; + // TODO: publish "i" + } uint16_t size = htobe16 (properties.str ().size ()); s.write ((char *)&size, sizeof (size)); @@ -668,6 +688,21 @@ namespace data m_Caps |= eSSUIntroducer; } + void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv) + { + for (const auto& it: *m_Addresses) // don't insert one more NTCP2 + if (it->ntcp2) return; + auto addr = std::make_shared
(); + addr->port = 0; + addr->transportStyle = eTransportNTCP; + addr->cost = 14; + addr->date = 0; + addr->ntcp2.reset (new NTCP2Ext ()); + memcpy (addr->ntcp2->staticKey, staticKey, 32); + memcpy (addr->ntcp2->iv, iv, 32); + m_Addresses->push_back(std::move(addr)); + } + bool RouterInfo::AddIntroducer (const Introducer& introducer) { for (auto& addr : *m_Addresses) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 1125bdef..a12b23e3 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -92,8 +92,8 @@ namespace data struct NTCP2Ext { - uint8_t staticKey[32]; - uint8_t iv[16]; + Tag<32> staticKey; + Tag<16> iv; }; struct Address @@ -122,6 +122,8 @@ namespace data { return !(*this == other); } + + bool IsNTCP2 () const { return (bool)ntcp2; }; }; typedef std::list > Addresses; @@ -143,6 +145,7 @@ namespace data void AddNTCPAddress (const char * host, int port); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); + void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv); bool AddIntroducer (const Introducer& introducer); bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only From e05110ff444cee2bbd3d61c09c03580bb98e1ca2 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 15 Jun 2018 14:56:03 -0400 Subject: [PATCH 074/195] send RouterInfo in SessionConfirmed --- libi2pd/NTCP2.cpp | 20 +++++++++++--------- libi2pd/RouterContext.cpp | 11 ++++++----- libi2pd/RouterInfo.cpp | 2 +- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 2dd18960..71af855c 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -7,6 +7,7 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" +#include "RouterContext.h" #include "NTCP2.h" namespace i2p @@ -153,7 +154,7 @@ namespace transport memset (options, 0, 16); htobe16buf (options, 2); // ver htobe16buf (options + 2, paddingLength); // padLen - htobe16buf (options + 4, 550); // m3p2Len TODO: + htobe16buf (options + 4, i2p::context.GetRouterInfo ().GetBufferLen () + 20); // m3p2Len (RI header + RI + MAC for now) TODO: implement options // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved @@ -255,24 +256,25 @@ namespace transport SHA256 (h1.data (), paddingLength + 32, h); } // part1 48 bytes - uint8_t s[32]; // public static - CreateEphemeralKey (s); // TODO: take it from RouterContext m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; memset (nonce, 0, 4); htole64buf (nonce + 4, 1); // set nonce to 1 - i2p::crypto::AEADChaCha20Poly1305 (s, 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again memcpy (h + 32, m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_H); - size_t m3p2Len = 550; // TODO: actual size - uint8_t buf[550]; - memset (buf, 0, m3p2Len - 16); // TODO: fill + size_t m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; + std::vector buf(m3p2Len - 16); + buf[0] = 2; // block + htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI + buf[3] = 0; // flag + memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); uint8_t key[32]; - KeyDerivationFunction3 (m_ExpandedPrivateKey, key); // TODO: take it from RouterContext + KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey (), key); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 862352ba..9bd6da9f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -84,11 +84,6 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } - if (ntcp2) - { - NewNTCP2Keys (); - routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC @@ -97,6 +92,12 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); + + if (ntcp2) + { + NewNTCP2Keys (); + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } } void RouterContext::UpdateRouterInfo () diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 088ba154..a0b818fb 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -699,7 +699,7 @@ namespace data addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); memcpy (addr->ntcp2->staticKey, staticKey, 32); - memcpy (addr->ntcp2->iv, iv, 32); + memcpy (addr->ntcp2->iv, iv, 16); m_Addresses->push_back(std::move(addr)); } From d5214099c5f3c43b2282ca4c0d1cf33b67a98660 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 10:53:25 +0300 Subject: [PATCH 075/195] move out android binary build info from README little change in MSYS build script --- README.md | 6 ------ build/build_mingw.cmd | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9b7e42d4..8fc8393a 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,6 @@ Build instructions: * [windows](https://i2pd.readthedocs.io/en/latest/devs/building/windows/) * [iOS](https://i2pd.readthedocs.io/en/latest/devs/building/ios/) * [android](https://i2pd.readthedocs.io/en/latest/devs/building/android/) -* android executable binary build: - - clone https://github.com/unlnown542a/i2pd.git or download https://github.com/unlnown542a/i2pd/archive/openssl.zip - - change to i2pd/android_binary_only - - edit jni/Application.mk - define path to static libs I2PD_LIBS_PATH - - in the directory i2pd/android_binary_only run: ndk-build -j4 - - find compiled binary - libs/armeabi-v7a/i2pd **Supported systems:** diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index cc6a15fa..e7811b0b 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -16,7 +16,8 @@ REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\m set "WD=C:\msys64\usr\bin\" set MSYS2_PATH_TYPE=inherit set CHERE_INVOKING=enabled_from_arguments -set MSYSTEM=MSYS +REM set MSYSTEM=MSYS +set MSYSTEM=MINGW32 set "xSH=%WD%bash -lc" From e1bfa786fc203806e8fb176340c8f0786e7e5e05 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 11:59:54 +0300 Subject: [PATCH 076/195] fix #1192 --- contrib/apparmor/usr.sbin.i2pd | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/apparmor/usr.sbin.i2pd b/contrib/apparmor/usr.sbin.i2pd index 168070da..afa59563 100644 --- a/contrib/apparmor/usr.sbin.i2pd +++ b/contrib/apparmor/usr.sbin.i2pd @@ -19,6 +19,7 @@ /etc/nsswitch.conf r, /etc/resolv.conf r, /run/resolvconf/resolv.conf r, + /run/systemd/resolve/stub-resolv.conf r, # path specific (feel free to modify if you have another paths) /etc/i2pd/** r, From a59cdcc9e0cc0ff630e12c980e90f1f3fd490ebb Mon Sep 17 00:00:00 2001 From: l-n-s Date: Sat, 16 Jun 2018 08:05:43 -0400 Subject: [PATCH 077/195] Update contrib/i2pd.conf file with more options --- contrib/i2pd.conf | 130 +++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 41 deletions(-) diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index c87a2c0b..123df754 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -26,15 +26,11 @@ ## Log messages above this level (debug, *info, warn, error, none) ## If you set it to none, logging will be disabled # loglevel = info - -## Path to storage of i2pd data (RI, keys, peer profiles, ...) -## Default: ~/.i2pd or /var/lib/i2pd -# datadir = /var/lib/i2pd +## Write full CLF-formatted date and time to log (default: write only time) +# logclftime = true ## Daemon mode. Router will go to background after start # daemon = true -## Run as a service. Router will use system folders like ‘/var/lib/i2pd’ -# service = true ## Specify a family, router belongs to (default - none) # family = @@ -55,9 +51,15 @@ ipv6 = false ## Network interface to bind to # ifname = +## You can specify different interfaces for IPv4 and IPv6 +# ifname4 = +# ifname6 = ## Enable NTCP transport (default = true) # ntcp = true +## If you run i2pd behind a proxy server, you can only use NTCP transport with ntcpproxy option +## Should be http://address:port or socks://address:port +# ntcpproxy = http://127.0.0.1:8118 ## Enable SSU transport (default = true) # ssu = true @@ -69,6 +71,8 @@ ipv6 = false ## X - unlimited ## Default is X for floodfill, L for regular node # bandwidth = L +## Max % of bandwidth limit for transit. 0-100. 100 by default +# share = 100 ## Router will not accept transit tunnels, disabling transit traffic completely ## (default = false) @@ -77,46 +81,17 @@ ipv6 = false ## Router will be floodfill # floodfill = true -[limits] -## Maximum active transit sessions (default:2500) -# transittunnels = 2500 - -[precomputation] -## Enable or disable elgamal precomputation table -## By default, enabled on i386 hosts -# elgamal = true - -[upnp] -## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) -# enabled = false - -## Name i2pd appears in UPnP forwardings list (default = I2Pd) -# name = I2Pd - -[reseed] -## Enable or disable reseed data verification. -verify = true -## URLs to request reseed data from, separated by comma -## Default: "mainline" I2P Network reseeds -# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ -## Path to local reseed data file (.su3) for manual reseeding -# file = /path/to/i2pseeds.su3 -## or HTTPS URL to reseed from -# file = https://legit-website.com/i2pseeds.su3 - -[addressbook] -## AddressBook subscription URL for initial setup -## Default: inr.i2p at "mainline" I2P Network -# defaulturl = http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt -## Optional subscriptions URLs, separated by comma -# subscriptions = http://inr.i2p/export/alive-hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt - [http] +## Web Console settings ## Uncomment and set to 'false' to disable Web Console # enabled = true ## Address and port service will listen on address = 127.0.0.1 port = 7070 +## Uncomment following lines to enable Web Console authentication +# auth = true +# user = i2pd +# pass = changeme [httpproxy] ## Uncomment and set to 'false' to disable HTTP Proxy @@ -126,6 +101,11 @@ address = 127.0.0.1 port = 4444 ## Optional keys file for proxy local destination # keys = http-proxy-keys.dat +## Enable address helper for adding .i2p domains with "jump URLs" (default: true) +# addresshelper = true +## Address of a proxy server inside I2P, which is used to visit regular Internet +# outproxy = http://false.i2p +## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. [socksproxy] ## Uncomment and set to 'false' to disable SOCKS Proxy @@ -135,13 +115,13 @@ address = 127.0.0.1 port = 4447 ## Optional keys file for proxy local destination # keys = socks-proxy-keys.dat - ## Socks outproxy. Example below is set to use Tor for all connections except i2p ## Uncomment and set to 'true' to enable using of SOCKS outproxy # outproxy.enabled = false ## Address and port of outproxy # outproxy = 127.0.0.1 # outproxyport = 9050 +## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. [sam] ## Uncomment and set to 'true' to enable SAM Bridge @@ -170,3 +150,71 @@ enabled = true ## Address and port service will listen on # address = 127.0.0.1 # port = 7650 +## Authentication password. "itoopie" by default +# password = itoopie + +[precomputation] +## Enable or disable elgamal precomputation table +## By default, enabled on i386 hosts +# elgamal = true + +[upnp] +## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) +# enabled = false +## Name i2pd appears in UPnP forwardings list (default = I2Pd) +# name = I2Pd + +[reseed] +## Options for bootstrapping into I2P network, aka reseeding +## Enable or disable reseed data verification. +verify = true +## URLs to request reseed data from, separated by comma +## Default: "mainline" I2P Network reseeds +# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ +## Path to local reseed data file (.su3) for manual reseeding +# file = /path/to/i2pseeds.su3 +## or HTTPS URL to reseed from +# file = https://legit-website.com/i2pseeds.su3 +## Path to local ZIP file or HTTPS URL to reseed from +# zipfile = /path/to/netDb.zip +## If you run i2pd behind a proxy server, set proxy server for reseeding here +## Should be http://address:port or socks://address:port +# proxy = http://127.0.0.1:8118 +## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default +# threshold = 25 + +[addressbook] +## AddressBook subscription URL for initial setup +## Default: inr.i2p at "mainline" I2P Network +# defaulturl = http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt +## Optional subscriptions URLs, separated by comma +# subscriptions = http://inr.i2p/export/alive-hosts.txt,http://stats.i2p/cgi-bin/newhosts.txt,http://rus.i2p/hosts.txt + +[limits] +## Maximum active transit sessions (default:2500) +# transittunnels = 2500 +## Limit number of open file descriptors (0 - use system limit) +# openfiles = 0 +## Maximum size of corefile in Kb (0 - use system limit) +# coresize = 0 +## Threshold to start probabalistic backoff with ntcp sessions (0 - use system limit) +# ntcpsoft = 0 +## Maximum number of ntcp sessions (0 - use system limit) +# ntcphard = 0 + +[trust] +## Enable explicit trust options. false by default +# enabled = true +## Make direct I2P connections only to routers in specified Family. +# family = MyFamily +## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities. +# routers = +## Should we hide our router from other routers? false by default +# hidden = true + +[exploratory] +## Exploratory tunnels settings with default values +# inbound.length = 2 +# inbound.quantity = 3 +# outbound.length = 2 +# outbound.quantity = 3 From 6bd73cdea2db75b0f976da308629dc35f3c4ec80 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 18:11:46 +0300 Subject: [PATCH 078/195] Update help message, debian manpage. Prepare changelog message --- debian/changelog | 8 ++++++++ debian/i2pd.1 | 38 +++++++++++++++++++++++++------------- libi2pd/Config.cpp | 7 +++---- 3 files changed, 36 insertions(+), 17 deletions(-) diff --git a/debian/changelog b/debian/changelog index afddc797..79c368a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +i2pd (2.19.0-1) unstable; urgency=low + + * updated to version 2.19.0/0.9.35 + * update manpage (1) + * fixes in systemd unit (#1089, #1142, #1154, #1155) + + -- R4SAS Tue, 19 Jun 2018 18:00:00 +0000 + i2pd (2.18.0-1) unstable; urgency=low * updated to version 2.18.0/0.9.33 diff --git a/debian/i2pd.1 b/debian/i2pd.1 index e1390891..77e62a6e 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -1,4 +1,4 @@ -.TH I2PD "1" "March 31, 2015" +.TH I2PD "1" "June 15, 2018" .SH NAME i2pd \- Load-balanced unspoofable packet switching network @@ -40,7 +40,10 @@ Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not se Path to logfile (default - autodetect) .TP \fB\-\-loglevel=\fR -Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR) +Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR, \fInone\fR) +.TP +\fB\-\-logclftime\fR +Log messages with full CLF-formatted date and time .TP \fB\-\-datadir=\fR Path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -51,14 +54,17 @@ The external IP address \fB\-\-port=\fR The port to listen on for incoming connections .TP -\fB\-\-daemon\fR -Router will go to background after start +\fB\-\-ifname=\fR +The network interface to bind to .TP -\fB\-\-service\fR -Router will use system folders like \fI/var/lib/i2pd\fR +\fB\-\-ifname4=\fR +The network interface to bind to for IPv4 connections +.TP +\fB\-\-ifname6=\fR +The network interface to bind to for IPv6 connections .TP \fB\-\-ipv6\fR -Enable communication through ipv6. false by default +Enable communication through ipv6 (disabled by default) .TP \fB\-\-notransit\fR Router will not accept transit tunnels at startup @@ -67,7 +73,16 @@ Router will not accept transit tunnels at startup Router will be floodfill .TP \fB\-\-bandwidth=\fR -Bandwidth limit: integer in KBps or letter aliases: \fIL (32KBps)\fR, O (256), P (2048), X (>9000) +Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256)\fR, \fIP (2048)\fR, \fIX (>9000)\fR +.TP +\fB\-\-share=\fR +Limit of transit traffic from max bandwidth in percents. (default: 100) +.TP +\fB\-\-daemon\fR +Router will go to background after start +.TP +\fB\-\-service\fR +Router will use system folders like \fI/var/lib/i2pd\fR .TP \fB\-\-family=\fR Name of a family, router belongs to. @@ -90,16 +105,13 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) -.RE -.PP -/usr/share/doc/i2pd/examples/hosts.txt.gz -.RS 4 -default I2P hosts file .SH AUTHOR This manual page was written by kytv for the Debian system (but may be used by others). .PP Updated by hagen in 2016. .PP +Updated by R4SAS in 2018. +.PP Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation .BR On Debian systems, the complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fR diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index a7bc305c..5f108fbb 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -37,8 +37,8 @@ namespace config { ("pidfile", value()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") - ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)") - ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") + ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") + ("logclftime", value()->zero_tokens()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") @@ -63,7 +63,7 @@ namespace config { #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") - ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something + ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif ; @@ -331,4 +331,3 @@ namespace config { } // namespace config } // namespace i2p - From bdc7acffbeac0c85aea288936eadc9b4d6e9a514 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 22:38:59 +0300 Subject: [PATCH 079/195] remove zero_tokens(), update manpage --- debian/i2pd.1 | 33 +++++++++++++++++++++++++-------- libi2pd/Config.cpp | 32 ++++++++++++++++---------------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 77e62a6e..6cd63b36 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -1,4 +1,4 @@ -.TH I2PD "1" "June 15, 2018" +.TH I2PD "1" "June 16, 2018" .SH NAME i2pd \- Load-balanced unspoofable packet switching network @@ -36,14 +36,14 @@ Where to write pidfile (don\'t write by default) \fB\-\-log=\fR Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not set, \fIfile\fR - otherwise, for compatibility) .TP -\fB\-\-logfile\fR +\fB\-\-logfile=\fR Path to logfile (default - autodetect) .TP \fB\-\-loglevel=\fR Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR, \fInone\fR) .TP \fB\-\-logclftime\fR -Log messages with full CLF-formatted date and time +Log messages with full CLF-formatted date and time (\fIfalse\fR by default) .TP \fB\-\-datadir=\fR Path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -63,14 +63,26 @@ The network interface to bind to for IPv4 connections \fB\-\-ifname6=\fR The network interface to bind to for IPv6 connections .TP +\fB\-\-ipv4\fR +Enable communication through ipv6 (\fItrue\fR by default) +.TP \fB\-\-ipv6\fR -Enable communication through ipv6 (disabled by default) +Enable communication through ipv6 (\fIfalse\fR by default) +.TP +\fB\-\-ntcp\fR +Enable usage of NTCP transport (\fItrue\fR by default) +.TP +\fB\-\-ntcpproxy\fR +Set proxy URL for NTCP transport +.TP +\fB\-\-ssu\fR +Enable usage of SSU transport (\fItrue\fR by default) .TP \fB\-\-notransit\fR -Router will not accept transit tunnels at startup +Router will not accept transit tunnels at startup (\fIfalse\fR by default) .TP \fB\-\-floodfill\fR -Router will be floodfill +Router will be floodfill (\fIfalse\fR by default) .TP \fB\-\-bandwidth=\fR Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256)\fR, \fIP (2048)\fR, \fIX (>9000)\fR @@ -79,10 +91,10 @@ Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256) Limit of transit traffic from max bandwidth in percents. (default: 100) .TP \fB\-\-daemon\fR -Router will go to background after start +Router will go to background after start (\fIfalse\fR by default) .TP \fB\-\-service\fR -Router will use system folders like \fI/var/lib/i2pd\fR +Router will use system folders like \fI/var/lib/i2pd\fR (\fIfalse\fR by default) .TP \fB\-\-family=\fR Name of a family, router belongs to. @@ -105,6 +117,11 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) +.Sh SEE ALSO +Documentation at +.Pa https://i2pd.readthedocs.io/en/latest/ . +.Pp + .SH AUTHOR This manual page was written by kytv for the Debian system (but may be used by others). .PP diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 5f108fbb..8492601b 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -38,7 +38,7 @@ namespace config { ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") - ("logclftime", value()->zero_tokens()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") + ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") @@ -48,21 +48,21 @@ namespace config { ("nat", value()->default_value(true), "Should we assume we are behind NAT?") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", value()->default_value(true), "Enable communication through ipv4") - ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") + ("ipv6", value()->default_value(false), "Enable communication through ipv6") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") - ("daemon", value()->zero_tokens()->default_value(false), "Router will go to background after start") - ("service", value()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") - ("notransit", value()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup") - ("floodfill", value()->zero_tokens()->default_value(false), "Router will be floodfill") + ("daemon", value()->default_value(false), "Router will go to background after start") + ("service", value()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") + ("notransit", value()->default_value(false), "Router will not accept transit tunnels at startup") + ("floodfill", value()->default_value(false), "Router will be floodfill") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100") ("ntcp", value()->default_value(true), "Enable NTCP transport") ("ssu", value()->default_value(true), "Enable SSU transport") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", value()->zero_tokens()->default_value(false), "Enable NTCP2 (experimental)") + ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") - ("insomnia", value()->zero_tokens()->default_value(false), "Prevent system from sleeping") + ("insomnia", value()->default_value(false), "Prevent system from sleeping") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif ; @@ -79,14 +79,14 @@ namespace config { options_description httpserver("HTTP Server options"); httpserver.add_options() - ("http.enabled", value()->default_value(true), "Enable or disable webconsole") - ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") - ("http.port", value()->default_value(7070), "Webconsole listen port") - ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") - ("http.user", value()->default_value("i2pd"), "Username for basic auth") - ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") - ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") - ("http.hostname", value()->default_value("localhost"),"Expected hostname for WebUI") + ("http.enabled", value()->default_value(true), "Enable or disable webconsole") + ("http.address", value()->default_value("127.0.0.1"), "Webconsole listen address") + ("http.port", value()->default_value(7070), "Webconsole listen port") + ("http.auth", value()->default_value(false), "Enable Basic HTTP auth for webconsole") + ("http.user", value()->default_value("i2pd"), "Username for basic auth") + ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") + ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") + ("http.hostname", value()->default_value("localhost"), "Expected hostname for WebUI") ; options_description httpproxy("HTTP Proxy options"); From a027a42c462e51b909ad43d6d90d0e967b636924 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 22:57:18 +0300 Subject: [PATCH 080/195] fix links to online documentation in manpage --- debian/i2pd.1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 6cd63b36..3e0a90ff 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -117,10 +117,13 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) -.Sh SEE ALSO +.SH SEE ALSO +.PP Documentation at -.Pa https://i2pd.readthedocs.io/en/latest/ . -.Pp +.UR https://i2pd.readthedocs.io/en/latest/ +Read the Docs +.UE . +.PP .SH AUTHOR This manual page was written by kytv for the Debian system (but may be used by others). From 985b618932005404baa485d5a8e6b3ff793f789f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 16 Jun 2018 23:06:01 +0300 Subject: [PATCH 081/195] addng forgotten bracket --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 8492601b..2e6d40bb 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -55,7 +55,7 @@ namespace config { ("notransit", value()->default_value(false), "Router will not accept transit tunnels at startup") ("floodfill", value()->default_value(false), "Router will be floodfill") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") - ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100") + ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") ("ntcp", value()->default_value(true), "Enable NTCP transport") ("ssu", value()->default_value(true), "Enable SSU transport") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") From 58c92b8405f5da687734c1b0d6f7ec63dbb2d3b0 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 18 Jun 2018 12:56:47 -0400 Subject: [PATCH 082/195] aead/chacha20/poly1305 from openssl 1.1 --- libi2pd/Crypto.cpp | 40 ++++++++++++++++++++++++++++++++++++---- libi2pd/Crypto.h | 3 ++- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index bdcf5acd..f8fb9946 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -8,9 +8,13 @@ #include #include "TunnelBase.h" #include -#include "I2PEndian.h" +#if LEGACY_OPENSSL #include "ChaCha20.h" #include "Poly1305.h" +#else +#include +#endif +#include "I2PEndian.h" #include "Log.h" #include "Crypto.h" @@ -1064,7 +1068,10 @@ namespace crypto bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) { - if (encrypt && msgLen + 16 < len) return 0; + if (len < msgLen) return false; + if (encrypt && len < msgLen + 16) return false; + bool ret = true; +#if LEGACY_OPENSSL // generate one time poly key uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); @@ -1106,9 +1113,34 @@ namespace crypto uint32_t tag[8]; // calculate Poly1305 tag Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); - if (memcmp (tag, msg + msgLen, 16)) return false; // compare with provided + if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided } - return true; +#else + int outlen = 0; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); + if (encrypt) + { + EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); + EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen); + EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen); + EVP_EncryptFinal_ex(ctx, buf, &outlen); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen); + } + else + { + EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen)); + EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce); + EVP_DecryptUpdate(ctx, NULL, &outlen, ad, adLen); + ret = EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen) > 0; + } + + EVP_CIPHER_CTX_free (ctx); +#endif + return ret; } // init and terminate diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index af4ec1f8..25646dbb 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -265,7 +265,8 @@ namespace crypto // take care about openssl version #include -#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL +#define LEGACY_OPENSSL ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL +#if LEGACY_OPENSSL // define getters and setters introduced in 1.1.0 inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) { From 3cec9232940761ebbab170a668f6fc4e26c9bb08 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 19 Jun 2018 15:08:16 +0300 Subject: [PATCH 083/195] Update tunnels.conf --- contrib/tunnels.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/tunnels.conf b/contrib/tunnels.conf index be8681dc..cd6cc910 100644 --- a/contrib/tunnels.conf +++ b/contrib/tunnels.conf @@ -31,3 +31,4 @@ keys = irc-keys.dat #keys = pop3-keys.dat # see more examples in /usr/share/doc/i2pd/configuration.md.gz +# or at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ From 4d9143734fe3aff50dc63c8365450a115c57f5eb Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 19 Jun 2018 15:11:48 +0300 Subject: [PATCH 084/195] store standart configs as docs in deb packages --- debian/docs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/docs b/debian/docs index b43bf86b..b67deb18 100644 --- a/debian/docs +++ b/debian/docs @@ -1 +1,4 @@ README.md +contrib/i2pd.conf +contrib/subscriptions.txt +contrib/tunnels.conf From 9c7cadb191584a064150b1002cb734fed909bf4d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jun 2018 11:14:22 -0400 Subject: [PATCH 085/195] better implementation of x25519 --- libi2pd/Ed25519.cpp | 65 +++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 05721d80..17264926 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -419,13 +419,8 @@ namespace crypto auto z2 = BN_CTX_get (ctx); BN_zero (z2); auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); auto z3 = BN_CTX_get (ctx); BN_one (z3); - auto a24 = BN_CTX_get (ctx); BN_set_word (a24, 121665); - auto a = BN_CTX_get (ctx); auto aa = BN_CTX_get (ctx); - auto b = BN_CTX_get (ctx); auto bb = BN_CTX_get (ctx); - auto e = BN_CTX_get (ctx); auto c = BN_CTX_get (ctx); - auto d = BN_CTX_get (ctx); - auto da = BN_CTX_get (ctx); auto cb = BN_CTX_get (ctx); - auto tmp1 = BN_CTX_get (ctx); auto tmp2 = BN_CTX_get (ctx); + auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666); + auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); unsigned int swap = 0; auto bits = BN_num_bits (k); while(bits) @@ -439,49 +434,33 @@ namespace crypto std::swap (z2, z3); } swap = k_t; - // a = x2 + z2 - BN_mod_add(a, x2, z2, q, ctx); - // aa = a^2 - BN_mod_sqr(aa, a, q, ctx); - // b = x2 - z2 - BN_mod_sub(b, x2, z2, q, ctx); - // bb = b^2 - BN_mod_sqr(bb, b, q, ctx); - // e = aa - bb - BN_mod_sub(e, aa, bb, q, ctx); - // c = x3 + z3 - BN_mod_add(c, x3, z3, q, ctx); - // d = x3 - z3 - BN_mod_sub(d, x3, z3, q, ctx); - // da = d * a - BN_mod_mul(da, d, a, q, ctx); - // cb = c * b - BN_mod_mul(cb, c, b, q, ctx); - // x3 = ( da + cb )^2 - BN_mod_add(tmp1, da, cb, q, ctx); - BN_mod_sqr(x3, tmp1, q, ctx); - // z3 == x1 * (da - cb)^2 - BN_mod_sub(tmp1, da, cb, q, ctx); - BN_mod_sqr(tmp2, tmp1, q, ctx); - BN_mod_mul(z3, x1, tmp2, q, ctx); - // x2 = aa * bb - BN_mod_mul(x2, aa, bb, q, ctx); - // z2 = e * (aa + a24 * e) - BN_mod_mul(tmp1, a24, e, q, ctx); - BN_mod_add(tmp2, aa, tmp1, q, ctx); - BN_mod_mul(z2, e, tmp2, q, ctx); + BN_mod_sub(tmp0, x3, z3, q, ctx); + BN_mod_sub(tmp1, x2, z2, q, ctx); + BN_mod_add(x2, x2, z2, q, ctx); + BN_mod_add(z2, x3, z3, q, ctx); + BN_mod_mul(z3, tmp0, x2, q, ctx); + BN_mod_mul(z2, z2, tmp1, q, ctx); + BN_mod_sqr(tmp0, tmp1, q, ctx); + BN_mod_sqr(tmp1, x2, q, ctx); + BN_mod_add(x3, z3, z2, q, ctx); + BN_mod_sub(z2, z3, z2, q, ctx); + BN_mod_mul(x2, tmp1, tmp0, q, ctx); + BN_mod_sub(tmp1, tmp1, tmp0, q, ctx); + BN_mod_sqr(z2, z2, q, ctx); + BN_mod_mul(z3, tmp1, c121666, q, ctx); + BN_mod_sqr(x3, x3, q, ctx); + BN_mod_add(tmp0, tmp0, z3, q, ctx); + BN_mod_mul(z3, x1, z2, q, ctx); + BN_mod_mul(z2, tmp1, tmp0, q, ctx); } if (swap) { std::swap (x2, x3); std::swap (z2, z3); } - // x2 * (z2 ^ (q - 2)) - BN_set_word(tmp1, 2); - BN_sub(tmp2, q, tmp1); - BN_mod_exp(tmp1, z2, tmp2, q, ctx); + BN_mod_inverse (z2, z2, q, ctx); BIGNUM * res = BN_new (); // not from ctx - BN_mod_mul(res, x2, tmp1, q, ctx); + BN_mod_mul(res, x2, z2, q, ctx); BN_CTX_end (ctx); return res; } From b5682012d3657deecd5047f3569c26d18587707d Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 19 Jun 2018 15:43:47 -0400 Subject: [PATCH 086/195] process SessionRequest and send SessionCreated for NTCP2 --- libi2pd/Crypto.cpp | 2 +- libi2pd/NTCP2.cpp | 123 +++++++++++++++++++++++++++++++++++++++++---- libi2pd/NTCP2.h | 13 +++-- 3 files changed, 123 insertions(+), 15 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index f8fb9946..7e320888 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -8,6 +8,7 @@ #include #include "TunnelBase.h" #include +#include "Crypto.h" #if LEGACY_OPENSSL #include "ChaCha20.h" #include "Poly1305.h" @@ -16,7 +17,6 @@ #endif #include "I2PEndian.h" #include "Log.h" -#include "Crypto.h" namespace i2p { diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 71af855c..187f4435 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -66,7 +66,7 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } - void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) { static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes uint8_t h[64]; @@ -81,12 +81,12 @@ namespace transport // x25519 between rs and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (rs, m_ExpandedPrivateKey, inputKeyMaterial, ctx); // rs*priv + i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, ctx); // rs*priv BN_CTX_free (ctx); MixKey (inputKeyMaterial, derived); } - void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + void NTCP2Session::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) { uint8_t h[64]; memcpy (h, m_H, 32); @@ -106,7 +106,7 @@ namespace transport // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx); + i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, ctx); BN_CTX_free (ctx); MixKey (inputKeyMaterial, derived); } @@ -122,11 +122,9 @@ namespace transport void NTCP2Session::CreateEphemeralKey (uint8_t * pub) { - uint8_t key[32]; - RAND_bytes (key, 32); - i2p::crypto::Ed25519::ExpandPrivateKey (key, m_ExpandedPrivateKey); + RAND_bytes (m_EphemeralPrivateKey, 32); BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMulB (m_ExpandedPrivateKey, pub, ctx); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, ctx); BN_CTX_free (ctx); } @@ -148,7 +146,7 @@ namespace transport encryption.GetIV (m_IV); // save IV for SessionCreated // encryption key for next block uint8_t key[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, x, key); + KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralPrivateKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -184,6 +182,96 @@ namespace transport } } + void NTCP2Session::HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + (void) bytes_transferred; + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest read error: ", ecode.message ()); + Terminate (); + } + else + { + // decrypt X + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (i2p::context.GetIdentHash ()); + decryption.SetIV (i2p::context.GetNTCP2IV ()); + decryption.Decrypt (m_SessionRequestBuffer, 32, m_Y); + decryption.GetIV (m_IV); // save IV for SessionCreated + // decryption key for next block + uint8_t key[32]; + KeyDerivationFunction1 (m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Y, key); + // verify MAC and decrypt options block (32 bytes), use m_H as AD + uint8_t nonce[12], options[16]; + memset (nonce, 0, 12); // set nonce to zero + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, key, nonce, options, 16, false)) // decrypt + { + uint16_t version = bufbe16toh (options); + if (version == 2) + { + uint16_t paddingLen = bufbe16toh (options + 2); + m_SessionRequestBufferLen = paddingLen + 64; + // TODO: check tsA + if (paddingLen > 0) + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + else + SendSessionCreated (); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", version); + Terminate (); + } + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed "); + Terminate (); + } + } + } + + void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest padding read error: ", ecode.message ()); + Terminate (); + } + else + SendSessionCreated (); + } + + void NTCP2Session::SendSessionCreated () + { + m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + // generate key pair (y) + uint8_t y[32]; + CreateEphemeralKey (y); + // encrypt Y + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (i2p::context.GetIdentHash ()); + encryption.SetIV (m_IV); + encryption.Encrypt (y, 32, m_SessionCreatedBuffer); + // encryption key for next block (m_K) + KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + auto paddingLen = rand () % (287 - 56); + uint8_t options[8]; + memset (options, 0, 8); + htobe16buf (options, paddingLen); // padLen + htobe32buf (options + 4, i2p::util::GetSecondsSinceEpoch ()); // tsB + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 8, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 24, true); // encrypt + // fill padding + RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 56), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) { if (ecode) @@ -201,7 +289,7 @@ namespace transport decryption.SetIV (m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y); // decryption key for next block (m_K) - KeyDerivationFunction2 (m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); // decrypt and verify MAC uint8_t payload[8]; uint8_t nonce[12]; @@ -240,6 +328,7 @@ namespace transport } } + void NTCP2Session::SendSessionConfirmed () { // update AD @@ -287,11 +376,25 @@ namespace transport Terminate (); // TODO } + void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); + Terminate (); // TODO + } + void NTCP2Session::ClientLogin () { SendSessionRequest (); } + void NTCP2Session::ServerLogin () + { + m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer, 64), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index e9a170bd..1bfcd0c2 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -25,20 +25,25 @@ namespace transport boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; void ClientLogin (); // Alice + void ServerLogin (); // Bob void SendI2NPMessages (const std::vector >& msgs) {}; // TODO private: void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); - void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest - void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); + void SendSessionCreated (); void SendSessionConfirmed (); void HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); @@ -49,8 +54,8 @@ namespace transport boost::asio::ip::tcp::socket m_Socket; bool m_IsEstablished, m_IsTerminated; - uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32]; + uint8_t m_EphemeralPrivateKey[32]; // x25519 + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; }; From 3cec5235c9db310d4b6f729a154cc27c1da10665 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 20 Jun 2018 16:09:22 -0400 Subject: [PATCH 087/195] NTCP2 according to new specs --- libi2pd/NTCP2.cpp | 71 ++++++++++++++++++++++++++++++----------------- libi2pd/NTCP2.h | 1 + 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 187f4435..462c3ad1 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -68,10 +68,17 @@ namespace transport void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) { - static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes - uint8_t h[64]; - memcpy (m_CK, protocolName, 32); - SHA256 ((const uint8_t *)protocolName, 32, h); + static const uint8_t protocolNameHash[] = + { + 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, + 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 + }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") + static uint8_t h[64] = + { + 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, + 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e + }; // SHA256 (protocolNameHash) + memcpy (m_CK, protocolNameHash, 32); // h = SHA256(h || rs) memcpy (h + 32, rs, 32); SHA256 (h, 64, h); @@ -120,6 +127,18 @@ namespace transport MixKey (inputKeyMaterial, derived); } + void NTCP2Session::KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived) + { + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // zerolen + static uint8_t one[1] = { 1 }; + uint8_t k_ab[33], k_ba[32]; + HMAC(EVP_sha256(), tempKey, 32, one, 1, k_ab, &len); + k_ab[32] = 2; + HMAC(EVP_sha256(), k_ab, 33, one, 1, k_ba, &len); + memcpy (derived, isAlice ? k_ab : k_ba, 32); + } + void NTCP2Session::CreateEphemeralKey (uint8_t * pub) { RAND_bytes (m_EphemeralPrivateKey, 32); @@ -150,7 +169,7 @@ namespace transport // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); - htobe16buf (options, 2); // ver + options[1] = 2; // ver htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 4, i2p::context.GetRouterInfo ().GetBufferLen () + 20); // m3p2Len (RI header + RI + MAC for now) TODO: implement options // 2 bytes reserved @@ -176,8 +195,8 @@ namespace transport else { m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size - // we receive first 56 bytes (32 Y, and 24 ChaCha/Poly frame) first - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 56), boost::asio::transfer_all (), + // we receive first 64 bytes (32 Y, and 32 ChaCha/Poly frame) first + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } @@ -206,8 +225,7 @@ namespace transport memset (nonce, 0, 12); // set nonce to zero if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, key, nonce, options, 16, false)) // decrypt { - uint16_t version = bufbe16toh (options); - if (version == 2) + if (options[1] == 2) { uint16_t paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; @@ -220,7 +238,7 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", version); + LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]); Terminate (); } } @@ -256,19 +274,19 @@ namespace transport encryption.Encrypt (y, 32, m_SessionCreatedBuffer); // encryption key for next block (m_K) KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); - auto paddingLen = rand () % (287 - 56); - uint8_t options[8]; - memset (options, 0, 8); - htobe16buf (options, paddingLen); // padLen - htobe32buf (options + 4, i2p::util::GetSecondsSinceEpoch ()); // tsB + auto paddingLen = rand () % (287 - 64); + uint8_t options[16]; + memset (options, 0, 16); + htobe16buf (options + 2, paddingLen); // padLen + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 8, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 24, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 56), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -282,7 +300,7 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); - m_SessionCreatedBufferLen = 56; + m_SessionCreatedBufferLen = 64; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); @@ -291,16 +309,17 @@ namespace transport // decryption key for next block (m_K) KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); // decrypt and verify MAC - uint8_t payload[8]; + uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, m_K, nonce, payload, 8, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt { - uint16_t paddingLen = bufbe16toh(payload); + uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); + // TODO: check tsB if (paddingLen > 0) { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 56, paddingLen), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } else @@ -334,14 +353,14 @@ namespace transport // update AD uint8_t h[80]; memcpy (h, m_H, 32); - memcpy (h + 32, m_SessionCreatedBuffer + 32, 24); // encrypted payload - SHA256 (h, 56, h); - int paddingLength = m_SessionCreatedBufferLen - 56; + memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256 (h, 64, h); + int paddingLength = m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { std::vector h1(paddingLength + 32); memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, m_SessionCreatedBuffer + 56, paddingLength); + memcpy (h1.data () + 32, m_SessionCreatedBuffer + 64, paddingLength); SHA256 (h1.data (), paddingLength + 32, h); } // part1 48 bytes diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1bfcd0c2..076a12d4 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -34,6 +34,7 @@ namespace transport void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 + void KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived); void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); From dd392941d0734d421d6a27bcf12c9582b5dc6b8d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 20 Jun 2018 05:07:24 +0300 Subject: [PATCH 088/195] update Config.cpp, links to examples, manpage --- contrib/tunnels.conf | 3 +- debian/changelog | 5 ++-- debian/control | 2 +- debian/i2pd.1 | 70 +++++++++++++++++++------------------------- libi2pd/Config.cpp | 24 +++++++-------- 5 files changed, 47 insertions(+), 57 deletions(-) diff --git a/contrib/tunnels.conf b/contrib/tunnels.conf index cd6cc910..3358ffc4 100644 --- a/contrib/tunnels.conf +++ b/contrib/tunnels.conf @@ -30,5 +30,4 @@ keys = irc-keys.dat #destinationport = 110 #keys = pop3-keys.dat -# see more examples in /usr/share/doc/i2pd/configuration.md.gz -# or at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ +# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ diff --git a/debian/changelog b/debian/changelog index 79c368a6..1b87e73c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,11 @@ -i2pd (2.19.0-1) unstable; urgency=low +i2pd (2.19.0-pre1) unstable; urgency=low * updated to version 2.19.0/0.9.35 * update manpage (1) + * update docfiles * fixes in systemd unit (#1089, #1142, #1154, #1155) - -- R4SAS Tue, 19 Jun 2018 18:00:00 +0000 + -- R4SAS Wed, 20 Jun 2018 02:11:00 +0000 i2pd (2.18.0-1) unstable; urgency=low diff --git a/debian/control b/debian/control index 7bd18ebb..76d753d4 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Architecture: any Pre-Depends: adduser Depends: ${shlibs:Depends}, ${misc:Depends} Suggests: tor, privoxy, apparmor -Description: A full-featured C++ implementation of I2P client. +Description: Full-featured C++ implementation of I2P client. I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants don't reveal their real IP addresses. diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 3e0a90ff..72b2c261 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -1,22 +1,19 @@ -.TH I2PD "1" "June 16, 2018" +.TH "I2PD" "1" "June 20, 2018" -.SH NAME -i2pd \- Load-balanced unspoofable packet switching network - -.SH SYNOPSIS +.SH "NAME" +i2pd \- Full-featured C++ implementation of I2P client. +.SH "SYNOPSIS" .B i2pd [\fIOPTION1\fR] [\fIOPTION2\fR]... - -.SH DESCRIPTION +.SH "DESCRIPTION" i2pd is a C++ implementation of the router for the I2P anonymizing network, offering a simple layer that identity-sensitive applications can use to securely communicate. All data is wrapped with several layers of encryption, and the network is both distributed and dynamic, with no trusted parties. - .PP Any of the configuration options below can be used in the \fBDAEMON_ARGS\fR variable in \fI/etc/default/i2pd\fR. -.BR +.SH "OPTIONS" .TP \fB\-\-help\fR Show available options. @@ -43,7 +40,7 @@ Path to logfile (default - autodetect) Log messages above this level (\fIdebug\fR, \fBinfo\fR, \fIwarn\fR, \fIerror\fR, \fInone\fR) .TP \fB\-\-logclftime\fR -Log messages with full CLF-formatted date and time (\fIfalse\fR by default) +Log messages with full CLF-formatted date and time (\fIdisabled\fR by default) .TP \fB\-\-datadir=\fR Path to storage of i2pd data (RI, keys, peer profiles, ...) @@ -64,25 +61,25 @@ The network interface to bind to for IPv4 connections The network interface to bind to for IPv6 connections .TP \fB\-\-ipv4\fR -Enable communication through ipv6 (\fItrue\fR by default) +Enable communication through ipv6 (\fIenabled\fR by default) .TP \fB\-\-ipv6\fR -Enable communication through ipv6 (\fIfalse\fR by default) +Enable communication through ipv6 (\fIdisabled\fR by default) .TP \fB\-\-ntcp\fR -Enable usage of NTCP transport (\fItrue\fR by default) +Enable usage of NTCP transport (\fIenabled\fR by default) .TP -\fB\-\-ntcpproxy\fR +\fB\-\-ntcpproxy=\fR Set proxy URL for NTCP transport .TP \fB\-\-ssu\fR -Enable usage of SSU transport (\fItrue\fR by default) +Enable usage of SSU transport (\fIenabled\fR by default) .TP \fB\-\-notransit\fR -Router will not accept transit tunnels at startup (\fIfalse\fR by default) +Router will not accept transit tunnels at startup (\fIdisabled\fR by default) .TP \fB\-\-floodfill\fR -Router will be floodfill (\fIfalse\fR by default) +Router will be floodfill (\fIdisabled\fR by default) .TP \fB\-\-bandwidth=\fR Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256)\fR, \fIP (2048)\fR, \fIX (>9000)\fR @@ -91,22 +88,21 @@ Bandwidth limit: integer in KBps or letter aliases: \fBL (32KBps)\fR, \fIO (256) Limit of transit traffic from max bandwidth in percents. (default: 100) .TP \fB\-\-daemon\fR -Router will go to background after start (\fIfalse\fR by default) +Router will go to background after start (\fIdisabled\fR by default) .TP \fB\-\-service\fR -Router will use system folders like \fI/var/lib/i2pd\fR (\fIfalse\fR by default) +Router will use system folders like \fI/var/lib/i2pd\fR (\fIdisabled\fR by default) .TP \fB\-\-family=\fR Name of a family, router belongs to. .PP -See service-specific parameters in example config file \fIcontrib/i2pd.conf\fR - -.SH FILES -.PP +Switchs, which enabled by default (like \fB\-\-ssu\fR, \fB\-\-ntcp\fR, etc.), can be disabled in config file. +.RE +See service-specific parameters in example config file \fI/usr/share/doc/i2pd/i2pd.conf.gz\fR +.SH "FILES" /etc/i2pd/i2pd.conf, /etc/i2pd/tunnels.conf, /etc/default/i2pd .RS 4 i2pd configuration files (when running as a system service) - .RE .PP /var/lib/i2pd/ @@ -117,21 +113,15 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR $HOME/.i2pd/ .RS 4 i2pd profile directory (when running as a normal user) -.SH SEE ALSO +.SH "SEE ALSO" +Documentation at Read the Docs: \m[blue]\fBhttps://i2pd\&.readthedocs\&.io/en/latest/\fR\m[] +.SH "AUTHOR" +This manual page was written by kytv <\m[blue]\fBkillyourtv@i2pmail\&.org\fR\m[]> for the Debian system (but may be used by others). +.RE +Updated by hagen <\m[blue]\fBhagen@i2pmail\&.org\fR\m[]> in 2016. +.RE +Updated by R4SAS <\m[blue]\fBr4sas@i2pmail\&.org\fR\m[]> in 2018. .PP -Documentation at -.UR https://i2pd.readthedocs.io/en/latest/ -Read the Docs -.UE . -.PP - -.SH AUTHOR -This manual page was written by kytv for the Debian system (but may be used by others). -.PP -Updated by hagen in 2016. -.PP -Updated by R4SAS in 2018. -.PP -Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation -.BR +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 or any later version published by the Free Software Foundation. +.RE On Debian systems, the complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fR diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 2e6d40bb..251e91df 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -38,31 +38,31 @@ namespace config { ("log", value()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("logfile", value()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("loglevel", value()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") - ("logclftime", value()->default_value(false), "Write full CLF-formatted date and time to log (default: write only time)") + ("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)") ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") ("ifname", value()->default_value(""), "Network interface to bind to") ("ifname4", value()->default_value(""), "Network interface to bind to for ipv4") ("ifname6", value()->default_value(""), "Network interface to bind to for ipv6") - ("nat", value()->default_value(true), "Should we assume we are behind NAT?") + ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") - ("ipv4", value()->default_value(true), "Enable communication through ipv4") - ("ipv6", value()->default_value(false), "Enable communication through ipv6") + ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") - ("daemon", value()->default_value(false), "Router will go to background after start") - ("service", value()->default_value(false), "Router will use system folders like '/var/lib/i2pd'") - ("notransit", value()->default_value(false), "Router will not accept transit tunnels at startup") - ("floodfill", value()->default_value(false), "Router will be floodfill") + ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") + ("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") + ("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)") + ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", value()->default_value(true), "Enable NTCP transport") - ("ssu", value()->default_value(true), "Enable SSU transport") + ("ntcp", bool_switch()->default_value(true), "Enable NTCP transport (default: enabled)") + ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental)") + ("ntcp2", bool_switch()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") - ("insomnia", value()->default_value(false), "Prevent system from sleeping") + ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") ("close", value()->default_value("ask"), "Action on close: minimize, exit, ask") #endif ; From 7d862d8eba11364e957d2a9efc2614acef84fd05 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 20 Jun 2018 14:48:29 +0300 Subject: [PATCH 089/195] service and daemon works as bool without values, other requires true/false --- debian/i2pd.1 | 6 +++--- libi2pd/Config.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 72b2c261..91e3b60f 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -60,19 +60,19 @@ The network interface to bind to for IPv4 connections \fB\-\-ifname6=\fR The network interface to bind to for IPv6 connections .TP -\fB\-\-ipv4\fR +\fB\-\-ipv4=\fR Enable communication through ipv6 (\fIenabled\fR by default) .TP \fB\-\-ipv6\fR Enable communication through ipv6 (\fIdisabled\fR by default) .TP -\fB\-\-ntcp\fR +\fB\-\-ntcp=\fR Enable usage of NTCP transport (\fIenabled\fR by default) .TP \fB\-\-ntcpproxy=\fR Set proxy URL for NTCP transport .TP -\fB\-\-ssu\fR +\fB\-\-ssu=\fR Enable usage of SSU transport (\fIenabled\fR by default) .TP \fB\-\-notransit\fR diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 251e91df..1ff55dd6 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -45,9 +45,9 @@ namespace config { ("ifname", value()->default_value(""), "Network interface to bind to") ("ifname4", value()->default_value(""), "Network interface to bind to for ipv4") ("ifname6", value()->default_value(""), "Network interface to bind to for ipv6") - ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") + ("nat", value()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") - ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("ipv4", value()->default_value(true), "Enable communication through ipv4 (default: enabled)") ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") @@ -56,10 +56,10 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", bool_switch()->default_value(true), "Enable NTCP transport (default: enabled)") - ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") + ("ntcp", value()->default_value(true), "Enable NTCP transport (default: enabled)") + ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", bool_switch()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") + ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") From 96411cc93eda6582b795e91e4ddf67c82646ae39 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 21 Jun 2018 12:39:24 -0400 Subject: [PATCH 090/195] derive keys for siphash --- libi2pd/NTCP2.cpp | 26 +++++++++++++++++++------- libi2pd/NTCP2.h | 4 +++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 462c3ad1..a925e62f 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -7,6 +7,7 @@ #include "I2PEndian.h" #include "Crypto.h" #include "Ed25519.h" +#include "Siphash.h" #include "RouterContext.h" #include "NTCP2.h" @@ -127,16 +128,26 @@ namespace transport MixKey (inputKeyMaterial, derived); } - void NTCP2Session::KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived) + void NTCP2Session::KeyDerivationFunctionDataPhase () { uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // zerolen + HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; - uint8_t k_ab[33], k_ba[32]; - HMAC(EVP_sha256(), tempKey, 32, one, 1, k_ab, &len); - k_ab[32] = 2; - HMAC(EVP_sha256(), k_ab, 33, one, 1, k_ba, &len); - memcpy (derived, isAlice ? k_ab : k_ba, 32); + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Kab, &len); // k_ab = HMAC-SHA256(temp_key, byte(0x01)). + m_Kab[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)). + + static uint8_t ask[4] = { 'a', 's', 'k', 1 }, master[32]; + HMAC(EVP_sha256(), tempKey, 32, ask, 4, master, &len); // ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01)) + uint8_t h[39]; + memcpy (h, m_H, 32); + memcpy (h + 32, "siphash", 7); + HMAC(EVP_sha256(), master, 32, h, 39, tempKey, &len); // temp_key = HMAC-SHA256(ask_master, h || "siphash") + HMAC(EVP_sha256(), tempKey, 32, one, 1, master, &len); // sip_master = HMAC-SHA256(temp_key, byte(0x01)) + HMAC(EVP_sha256(), master, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(sip_master, zerolen) + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Siphashab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). + m_Siphashab[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_Siphashab, 33, m_Siphashba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -392,6 +403,7 @@ namespace transport void NTCP2Session::HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); + KeyDerivationFunctionDataPhase (); Terminate (); // TODO } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 076a12d4..57556674 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -34,7 +34,7 @@ namespace transport void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 - void KeyDerivationFunctionDataPhase (bool isAlice, uint8_t * derived); + void KeyDerivationFunctionDataPhase (); void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); @@ -59,6 +59,8 @@ namespace transport uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; + // data phase + uint8_t m_Kab[33], m_Kba[32], m_Siphashab[33], m_Siphashba[32]; }; class NTCP2Server From 5b295921743cb6f51c6618f825850c9ac93707e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 21 Jun 2018 16:24:19 -0400 Subject: [PATCH 091/195] generate sipkeys for data pahse of NTCP2 --- libi2pd/NTCP2.cpp | 62 +++++++++++++++++++++++++++++++++++++++++------ libi2pd/NTCP2.h | 12 ++++++++- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a925e62f..db509186 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -19,7 +19,8 @@ namespace transport TransportSession (in_RemoteRouter, 30), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), + m_NextReceivedBuffer (nullptr) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -36,6 +37,7 @@ namespace transport delete[] m_SessionRequestBuffer; delete[] m_SessionCreatedBuffer; delete[] m_SessionConfirmedBuffer; + delete[] m_NextReceivedBuffer; } void NTCP2Session::Terminate () @@ -130,13 +132,13 @@ namespace transport void NTCP2Session::KeyDerivationFunctionDataPhase () { + char buf[100]; uint8_t tempKey[32]; unsigned int len; HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Kab, &len); // k_ab = HMAC-SHA256(temp_key, byte(0x01)). m_Kab[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)). - + HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02)) static uint8_t ask[4] = { 'a', 's', 'k', 1 }, master[32]; HMAC(EVP_sha256(), tempKey, 32, ask, 4, master, &len); // ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01)) uint8_t h[39]; @@ -145,9 +147,9 @@ namespace transport HMAC(EVP_sha256(), master, 32, h, 39, tempKey, &len); // temp_key = HMAC-SHA256(ask_master, h || "siphash") HMAC(EVP_sha256(), tempKey, 32, one, 1, master, &len); // sip_master = HMAC-SHA256(temp_key, byte(0x01)) HMAC(EVP_sha256(), master, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(sip_master, zerolen) - HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Siphashab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). - m_Siphashab[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_Siphashab, 33, m_Siphashba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Sipkeysab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)). + m_Sipkeysab[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_Sipkeysab, 33, m_Sipkeysba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) } void NTCP2Session::CreateEphemeralKey (uint8_t * pub) @@ -394,6 +396,11 @@ namespace transport KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey (), key); memset (nonce, 0, 12); // set nonce to 0 again i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + uint8_t tmp[48]; + memcpy (tmp, m_SessionConfirmedBuffer, 48); + memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext); + memcpy (m_SessionConfirmedBuffer, tmp, 48); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), @@ -404,7 +411,8 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - Terminate (); // TODO + memcpy (m_IV, m_Sipkeysba + 16, 8); //Alice + ReceiveLength (); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -426,6 +434,46 @@ namespace transport std::placeholders::_1, std::placeholders::_2)); } + void NTCP2Session::ReceiveLength () + { + boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); + Terminate (); + } + else + { + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Kba); // assume Alice TODO: + m_NextReceivedLen = be16toh (m_NextReceivedLen ^ buf16toh(m_ReceiveIV)); + LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); + delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; + Receive (); + } + } + + void NTCP2Session::Receive () + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); + Terminate (); + } + Terminate (); // TODO + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 57556674..5f8d116d 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -36,6 +36,7 @@ namespace transport void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void KeyDerivationFunctionDataPhase (); + // establish void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void SendSessionCreated (); @@ -49,6 +50,12 @@ namespace transport void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + // data + void ReceiveLength (); + void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void Receive (); + void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + private: NTCP2Server& m_Server; @@ -60,7 +67,10 @@ namespace transport uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase - uint8_t m_Kab[33], m_Kba[32], m_Siphashab[33], m_Siphashba[32]; + uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; + uint16_t m_NextReceivedLen; + uint8_t * m_NextReceivedBuffer; + uint8_t m_ReceiveIV[8]; }; class NTCP2Server From 5884852612d2f091c8793912fa1641c8bc69b24b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 22 Jun 2018 12:20:35 -0400 Subject: [PATCH 092/195] correct usage of sipkeys --- libi2pd/NTCP2.cpp | 7 +++---- libi2pd/Siphash.h | 14 +++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index db509186..f7e5e796 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -132,7 +132,6 @@ namespace transport void NTCP2Session::KeyDerivationFunctionDataPhase () { - char buf[100]; uint8_t tempKey[32]; unsigned int len; HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; @@ -411,7 +410,7 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - memcpy (m_IV, m_Sipkeysba + 16, 8); //Alice + memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); //Alice ReceiveLength (); } @@ -449,8 +448,8 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Kba); // assume Alice TODO: - m_NextReceivedLen = be16toh (m_NextReceivedLen ^ buf16toh(m_ReceiveIV)); + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Sipkeysba); // assume Alice TODO: + m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; diff --git a/libi2pd/Siphash.h b/libi2pd/Siphash.h index 3e74c6e9..aa8b8631 100644 --- a/libi2pd/Siphash.h +++ b/libi2pd/Siphash.h @@ -19,14 +19,14 @@ namespace crypto constexpr int crounds = 2; constexpr int drounds = 4; - uint64_t rotl(const uint64_t & x, int b) + inline uint64_t rotl(const uint64_t & x, int b) { uint64_t ret = x << b; ret |= x >> (64 - b); return ret; } - void u32to8le(const uint32_t & v, uint8_t * p) + inline void u32to8le(const uint32_t & v, uint8_t * p) { p[0] = (uint8_t) v; p[1] = (uint8_t) (v >> 8); @@ -34,7 +34,7 @@ namespace crypto p[3] = (uint8_t) (v >> 24); } - void u64to8le(const uint64_t & v, uint8_t * p) + inline void u64to8le(const uint64_t & v, uint8_t * p) { p[0] = v & 0xff; p[1] = (v >> 8) & 0xff; @@ -46,7 +46,7 @@ namespace crypto p[7] = (v >> 56) & 0xff; } - uint64_t u8to64le(const uint8_t * p) + inline uint64_t u8to64le(const uint8_t * p) { uint64_t i = 0; int idx = 0; @@ -58,7 +58,7 @@ namespace crypto return i; } - void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) + inline void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) { _v0 += _v1; _v1 = rotl(_v1, 13); @@ -79,7 +79,7 @@ namespace crypto /** hashsz must be 8 or 16 */ template - void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) + inline void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) { uint64_t v0 = 0x736f6d6570736575ULL; uint64_t v1 = 0x646f72616e646f6dULL; @@ -149,4 +149,4 @@ namespace crypto } } -#endif \ No newline at end of file +#endif From 0aa618b938bd76f0fac8f5ca07b594649a23f6c8 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 22 Jun 2018 15:02:49 -0400 Subject: [PATCH 093/195] process AEAD/Chacha20/Poly1305 frame for data phase of NTCP2 --- libi2pd/Crypto.cpp | 22 +++++++++++++--------- libi2pd/NTCP2.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- libi2pd/NTCP2.h | 2 ++ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 7e320888..6d859342 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1081,19 +1081,23 @@ namespace crypto chacha20 (buf, msgLen, nonce, key, 1); // create Poly1305 message + if (!ad) adLen = 0; std::vector polyMsg(adLen + msgLen + 3*16); - size_t offset = 0; + size_t offset = 0; uint8_t padding[16]; memset (padding, 0, 16); - memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data - auto rem = adLen & 0x0F; // %16 - if (rem) - { - // padding1 - rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + if (ad) + { + memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data + auto rem = adLen & 0x0F; // %16 + if (rem) + { + // padding1 + rem = 16 - rem; + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + } } memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data - rem = msgLen & 0x0F; // %16 + auto rem = msgLen & 0x0F; // %16 if (rem) { // padding2 diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f7e5e796..4551a8cd 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -20,7 +20,7 @@ namespace transport m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), - m_NextReceivedBuffer (nullptr) + m_NextReceivedBuffer (nullptr), m_ReceiveSequenceNumber (0) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -470,7 +470,43 @@ namespace transport LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); Terminate (); } - Terminate (); // TODO + else + { + uint8_t nonce[12]; + memset (nonce, 0, 4); htole64buf (nonce + 4, m_ReceiveSequenceNumber); m_ReceiveSequenceNumber++; + uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; + if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_Kba, nonce, decrypted, m_NextReceivedLen, false)) // decrypt. assume Alice TODO: + { + LogPrint (eLogInfo, "NTCP2: received message decrypted"); + ProcessNextFrame (decrypted, m_NextReceivedLen-16); + ReceiveLength (); + } + else + { + LogPrint (eLogWarning, "NTCP2: Received MAC verification failed "); + Terminate (); + } + delete[] decrypted; + } + } + + void NTCP2Session::ProcessNextFrame (const uint8_t * frame, size_t len) + { + size_t offset = 0; + while (offset < len) + { + uint8_t blk = frame[offset]; + offset++; + auto size = bufbe16toh (frame + offset); + offset += 2; + LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size); + if (size > len) + { + LogPrint (eLogError, "NTCP2: Unexpected block length ", size); + break; + } + offset += size; + } } NTCP2Server::NTCP2Server (): diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 5f8d116d..744b3375 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -55,6 +55,7 @@ namespace transport void HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred); void Receive (); void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void ProcessNextFrame (const uint8_t * frame, size_t len); private: @@ -71,6 +72,7 @@ namespace transport uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer; uint8_t m_ReceiveIV[8]; + uint64_t m_ReceiveSequenceNumber; }; class NTCP2Server From 510d29b381511b5fb9278d9909fc216774cce381 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 23 Jun 2018 06:56:05 -0400 Subject: [PATCH 094/195] gcc 8 arch support --- Makefile.linux | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.linux b/Makefile.linux index 2c30bbb0..cf045eb4 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -21,7 +21,7 @@ else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6 NEEDED_CXXFLAGS += -std=c++0x else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0 NEEDED_CXXFLAGS += -std=c++11 -else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 ubuntu +else ifeq ($(shell expr match ${CXXVER} "[7-8]"),1) # gcc 7 ubuntu or gcc 8 arch NEEDED_CXXFLAGS += -std=c++11 else # not supported $(error Compiler too old) From 39eed0f6fbe8e1bae4b10c9dfddb105e5d2ad4df Mon Sep 17 00:00:00 2001 From: shak Date: Sat, 23 Jun 2018 23:52:16 +0000 Subject: [PATCH 095/195] Read explicitPeer config settings into params --- libi2pd_client/ClientContext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index b40c2832..f3ab3fd9 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -389,6 +389,7 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY); options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); + options[I2CP_PARAM_EXPLICIT_PEERS] = GetI2CPOption(section, I2CP_PARAM_EXPLICIT_PEERS, NULL); } void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const @@ -406,6 +407,8 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; + if (i2p::config::GetOption(prefix + I2CP_PARAM_EXPLICIT_PEERS, value)) + options[I2CP_PARAM_EXPLICIT_PEERS] = value; } void ClientContext::ReadTunnels () From f0b32e3f54fa536667d54e7a28cf2c487e2e72cf Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 24 Jun 2018 06:46:22 -0400 Subject: [PATCH 096/195] Revert "Read explicitPeer config settings into params" --- libi2pd_client/ClientContext.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index f3ab3fd9..b40c2832 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -389,7 +389,6 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY); options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY); - options[I2CP_PARAM_EXPLICIT_PEERS] = GetI2CPOption(section, I2CP_PARAM_EXPLICIT_PEERS, NULL); } void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map& options) const @@ -407,8 +406,6 @@ namespace client options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; - if (i2p::config::GetOption(prefix + I2CP_PARAM_EXPLICIT_PEERS, value)) - options[I2CP_PARAM_EXPLICIT_PEERS] = value; } void ClientContext::ReadTunnels () From 5bc157eb190e5b64a087d56bdd24cef1778cc7f2 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 25 Jun 2018 12:28:07 -0400 Subject: [PATCH 097/195] send data frame for NTCP2 --- libi2pd/NTCP2.cpp | 44 +++++++++++++++++++++++++++++++++++++++++--- libi2pd/NTCP2.h | 10 +++++++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 4551a8cd..594f4a93 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -20,7 +20,8 @@ namespace transport m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), - m_NextReceivedBuffer (nullptr), m_ReceiveSequenceNumber (0) + m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), + m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0) { auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) @@ -38,6 +39,7 @@ namespace transport delete[] m_SessionCreatedBuffer; delete[] m_SessionConfirmedBuffer; delete[] m_NextReceivedBuffer; + delete[] m_NextSendBuffer; } void NTCP2Session::Terminate () @@ -69,6 +71,12 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } + void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) + { + memset (nonce, 0, 4); + htole64buf (nonce + 4, seqn); + } + void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) { static const uint8_t protocolNameHash[] = @@ -378,7 +386,7 @@ namespace transport // part1 48 bytes m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; - memset (nonce, 0, 4); htole64buf (nonce + 4, 1); // set nonce to 1 + CreateNonce (1, nonce); i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again @@ -411,7 +419,16 @@ namespace transport LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); //Alice + memcpy (m_SendIV, m_Sipkeysab + 16, 8); //Alice ReceiveLength (); + + // TODO: remove + uint8_t pad[1024]; + auto paddingLength = rand () % 1000; + RAND_bytes (pad + 3, paddingLength); + pad[0] = 254; + htobe16buf (pad + 1, paddingLength); + SendNextFrame (pad, paddingLength + 3); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -473,7 +490,7 @@ namespace transport else { uint8_t nonce[12]; - memset (nonce, 0, 4); htole64buf (nonce + 4, m_ReceiveSequenceNumber); m_ReceiveSequenceNumber++; + CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_Kba, nonce, decrypted, m_NextReceivedLen, false)) // decrypt. assume Alice TODO: { @@ -509,6 +526,27 @@ namespace transport } } + void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len) + { + uint8_t nonce[12]; + CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; + m_NextSendBuffer = new uint8_t[len + 16 + 2]; + i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_Kab, nonce, m_NextSendBuffer + 2, len + 16, true); // encrypt. assume Alice TODO: + i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_Sipkeysab); // assume Alice TODO: + htobuf16 (m_NextSendBuffer, bufbe16toh (m_SendIV) ^ htobe16(len + 16)); + LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); + + // send message + boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, len + 16 + 2), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleNextFrameSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + + void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; + LogPrint (eLogDebug, "NTCP2: Next frame sent"); + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) { diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 744b3375..6ee76aad 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -31,6 +31,7 @@ namespace transport private: void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); + void CreateNonce (uint64_t seqn, uint8_t * nonce); void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 @@ -57,6 +58,9 @@ namespace transport void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void ProcessNextFrame (const uint8_t * frame, size_t len); + void SendNextFrame (const uint8_t * payload, size_t len); + void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + private: NTCP2Server& m_Server; @@ -70,9 +74,9 @@ namespace transport // data phase uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; uint16_t m_NextReceivedLen; - uint8_t * m_NextReceivedBuffer; - uint8_t m_ReceiveIV[8]; - uint64_t m_ReceiveSequenceNumber; + uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; + uint8_t m_ReceiveIV[8], m_SendIV[8]; + uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; }; class NTCP2Server From b226e22d2fead08013c23d13888c90429c29ea36 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jun 2018 07:25:16 -0400 Subject: [PATCH 098/195] fixed QT build --- qt/i2pd_qt/DaemonQT.h | 1 + qt/i2pd_qt/i2pd_qt.pro | 3 +++ 2 files changed, 4 insertions(+) diff --git a/qt/i2pd_qt/DaemonQT.h b/qt/i2pd_qt/DaemonQT.h index 780d2f73..aa329f56 100644 --- a/qt/i2pd_qt/DaemonQT.h +++ b/qt/i2pd_qt/DaemonQT.h @@ -1,6 +1,7 @@ #ifndef DAEMONQT_H #define DAEMONQT_H +#include #include #include #include diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 6c0464ab..0488f289 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -66,6 +66,9 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../libi2pd/TunnelGateway.cpp \ ../../libi2pd/TunnelPool.cpp \ ../../libi2pd/util.cpp \ + ../../libi2pd/Ed25519.cpp \ + ../../libi2pd/Chacha20.cpp \ + ../../libi2pd/Poly1305.cpp \ ../../libi2pd_client/AddressBook.cpp \ ../../libi2pd_client/BOB.cpp \ ../../libi2pd_client/ClientContext.cpp \ From 27fbf6735222a6e7768b03c195b33fe9e0c382e7 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 18:07:06 +0300 Subject: [PATCH 099/195] add systemd configs, change build info, update changelog --- debian/changelog | 5 +++-- debian/control | 6 ++---- debian/i2pd.service | 1 + debian/i2pd.tmpfile | 2 ++ debian/rules | 10 +++++----- 5 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 debian/i2pd.service create mode 100644 debian/i2pd.tmpfile diff --git a/debian/changelog b/debian/changelog index 1b87e73c..230dd9a8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,12 @@ -i2pd (2.19.0-pre1) unstable; urgency=low +i2pd (2.19.0-1) unstable; urgency=low * updated to version 2.19.0/0.9.35 * update manpage (1) * update docfiles * fixes in systemd unit (#1089, #1142, #1154, #1155) + * package now building with systemd support - -- R4SAS Wed, 20 Jun 2018 02:11:00 +0000 + -- R4SAS Tue, 26 Jun 2018 15:00:00 +0000 i2pd (2.18.0-1) unstable; urgency=low diff --git a/debian/control b/debian/control index 76d753d4..8ef0b08c 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: i2pd Section: net Priority: optional Maintainer: R4SAS -Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev, dh-apparmor +Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.17.2~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev Standards-Version: 3.9.6 Homepage: http://i2pd.website/ Vcs-Git: git://github.com/PurpleI2P/i2pd.git @@ -11,8 +11,7 @@ Vcs-Browser: https://github.com/PurpleI2P/i2pd Package: i2pd Architecture: any Pre-Depends: adduser -Depends: ${shlibs:Depends}, ${misc:Depends} -Suggests: tor, privoxy, apparmor +Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base, Description: Full-featured C++ implementation of I2P client. I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants @@ -25,7 +24,6 @@ Architecture: any Priority: extra Section: debug Depends: i2pd (= ${binary:Version}), ${misc:Depends} -Suggests: gdb Description: i2pd debugging symbols I2P (Invisible Internet Protocol) is a universal anonymous network layer. All communications over I2P are anonymous and end-to-end encrypted, participants diff --git a/debian/i2pd.service b/debian/i2pd.service new file mode 100644 index 00000000..ca477e3b --- /dev/null +++ b/debian/i2pd.service @@ -0,0 +1 @@ +../i2pd.service \ No newline at end of file diff --git a/debian/i2pd.tmpfile b/debian/i2pd.tmpfile new file mode 100644 index 00000000..6cd19112 --- /dev/null +++ b/debian/i2pd.tmpfile @@ -0,0 +1,2 @@ +d /var/run/i2pd 0755 i2pd i2pd - - +d /var/log/i2pd 0755 i2pd i2pd - - diff --git a/debian/rules b/debian/rules index 4654ae6c..53244c56 100755 --- a/debian/rules +++ b/debian/rules @@ -5,14 +5,14 @@ #export DH_VERBOSE=1 DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow -DPKG_EXPORT_BUILDFLAGS = 1 -include /usr/share/dpkg/buildflags.mk -CXXFLAGS+=$(CPPFLAGS) -PREFIX=/usr +#DPKG_EXPORT_BUILDFLAGS = 1 +#include /usr/share/dpkg/buildflags.mk +#CXXFLAGS+=$(CPPFLAGS) +#PREFIX=/usr %: dh $@ --parallel - dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd + #dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd override_dh_strip: dh_strip --dbg-package=i2pd-dbg From a188de2e5cd627b6850dca2501084d6e3eed4bd9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 16:23:21 +0000 Subject: [PATCH 100/195] increase limits by default, fix symbolic links, change rules --- contrib/i2pd.service | 2 +- debian/i2pd.service | 2 +- debian/i2pd.tmpfile | 3 +-- debian/rules | 7 ++++--- 4 files changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 120000 debian/i2pd.service mode change 100644 => 120000 debian/i2pd.tmpfile diff --git a/contrib/i2pd.service b/contrib/i2pd.service index 3f53bfb8..debd49b0 100644 --- a/contrib/i2pd.service +++ b/contrib/i2pd.service @@ -24,7 +24,7 @@ KillSignal=SIGQUIT #TimeoutStopSec=10m # If you have problems with hanging i2pd, you can try enable this -#LimitNOFILE=4096 +LimitNOFILE=4096 PrivateDevices=yes [Install] diff --git a/debian/i2pd.service b/debian/i2pd.service deleted file mode 100644 index ca477e3b..00000000 --- a/debian/i2pd.service +++ /dev/null @@ -1 +0,0 @@ -../i2pd.service \ No newline at end of file diff --git a/debian/i2pd.service b/debian/i2pd.service new file mode 120000 index 00000000..57d6b4da --- /dev/null +++ b/debian/i2pd.service @@ -0,0 +1 @@ +../contrib/debian/i2pd.service \ No newline at end of file diff --git a/debian/i2pd.tmpfile b/debian/i2pd.tmpfile deleted file mode 100644 index 6cd19112..00000000 --- a/debian/i2pd.tmpfile +++ /dev/null @@ -1,2 +0,0 @@ -d /var/run/i2pd 0755 i2pd i2pd - - -d /var/log/i2pd 0755 i2pd i2pd - - diff --git a/debian/i2pd.tmpfile b/debian/i2pd.tmpfile new file mode 120000 index 00000000..22dfb4cf --- /dev/null +++ b/debian/i2pd.tmpfile @@ -0,0 +1 @@ +../contrib/debian/i2pd.tmpfile \ No newline at end of file diff --git a/debian/rules b/debian/rules index 53244c56..8e537049 100755 --- a/debian/rules +++ b/debian/rules @@ -12,10 +12,11 @@ DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow %: dh $@ --parallel - #dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd +# dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd override_dh_strip: dh_strip --dbg-package=i2pd-dbg -override_dh_shlibdeps: - dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info +## uncoment this if you have "missing info" problem when building package +#override_dh_shlibdeps: +# dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info From 34c45f26945445fcfbd7839738976a1bec2038e3 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 16:26:28 +0000 Subject: [PATCH 101/195] update debian changelog --- debian/changelog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 230dd9a8..74c366d1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,13 @@ -i2pd (2.19.0-1) unstable; urgency=low +i2pd (2.19.0-1) unstable; urgency=medium * updated to version 2.19.0/0.9.35 * update manpage (1) * update docfiles + * update build rules * fixes in systemd unit (#1089, #1142, #1154, #1155) * package now building with systemd support - -- R4SAS Tue, 26 Jun 2018 15:00:00 +0000 + -- R4SAS Tue, 26 Jun 2018 16:27:45 +0000 i2pd (2.18.0-1) unstable; urgency=low From 00df3f8d4e7b58c56d08936bc975f40c12b35e38 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jun 2018 13:36:30 -0400 Subject: [PATCH 102/195] 2.19.0 --- ChangeLog | 25 +++++++++++++++++++++++++ Win32/installer.iss | 2 +- android/AndroidManifest.xml | 4 ++-- libi2pd/version.h | 4 ++-- qt/i2pd_qt/android/AndroidManifest.xml | 2 +- 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index d2bfe7bf..54989d44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,31 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.19.0] - 2018-06-26 +### Added +- ECIES support for RouterInfo +- HTTP outproxy authorization +- AVX/AESNI runtime detection +- Initial implementation of NTCP2 +- I2CP session reconfigure +- I2CP method ClientServicesInfo +- Datagrams to websocks +### Changed +- RouterInfo uses EdDSA signature by default +- Remove stream bans +- Android build system changed to gradle +- Multiple changes in QT GUI +- Dockerfile +### Fixed +- zero tunnelID issue +- tunnels reload +- headers in webconsole +- XSS in webconsole from SAM session name +- build for gcc 8 +- cmake build scripts +- systemd service files +- some netbsd issues + ## [2.18.0] - 2018-01-30 ### Added - Show tunnel nicknames for I2CP destination in WebUI diff --git a/Win32/installer.iss b/Win32/installer.iss index 15ce4372..c4e1fffd 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.18.0" +#define I2Pd_ver "2.19.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index cfc9d55b..ca66c17d 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -3,7 +3,7 @@ package="org.purplei2p.i2pd" android:installLocation="auto" android:versionCode="1" - android:versionName="2.18.0"> + android:versionName="2.19.0"> - \ No newline at end of file + diff --git a/libi2pd/version.h b/libi2pd/version.h index e0443415..129035ad 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -7,7 +7,7 @@ #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 18 +#define I2PD_VERSION_MINOR 19 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 34 +#define I2P_VERSION_MICRO 35 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) diff --git a/qt/i2pd_qt/android/AndroidManifest.xml b/qt/i2pd_qt/android/AndroidManifest.xml index 56b37e6a..d98e24d4 100644 --- a/qt/i2pd_qt/android/AndroidManifest.xml +++ b/qt/i2pd_qt/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + From 0dff636dbe8b284da3e77483078b2681fb2aa6a3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 26 Jun 2018 13:38:02 -0400 Subject: [PATCH 103/195] 2.19.0 --- contrib/rpm/i2pd.spec | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 22c31192..1c07a887 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -96,6 +96,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Jun 26 2018 orignal - 2.19.0 +- update to 2.19.0 + * Mon Feb 05 2018 r4sas - 2.18.0-2 - Fixed blocking system shutdown for 10 minutes (#1089) From fc16e76af13b0ca5bd39b5768e71245bd74ae831 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 26 Jun 2018 17:46:01 +0000 Subject: [PATCH 104/195] 2.19.0 --- android/build.gradle | 2 +- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 4 ++-- contrib/rpm/i2pd.spec | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index d58e098f..c5834e19 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -25,7 +25,7 @@ android { targetSdkVersion 25 minSdkVersion 14 versionCode 1 - versionName "2.18.0" + versionName "2.19.0" ndk { abiFilters 'armeabi-v7a' //abiFilters 'x86' diff --git a/appveyor.yml b/appveyor.yml index 68b74529..27f563ef 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.18.{build} +version: 2.19.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 6e02779d..02986475 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.18.0 +Version: 2.19.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -99,4 +99,4 @@ getent passwd i2pd >/dev/null || \ %changelog * Thu Feb 01 2018 r4sas - 2.18.0 -- Initial i2pd-git based on i2pd 2.18.0-1 spec \ No newline at end of file +- Initial i2pd-git based on i2pd 2.18.0-1 spec diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 1c07a887..db480d35 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,6 +1,6 @@ Name: i2pd -Version: 2.18.0 -Release: 2%{?dist} +Version: 2.19.0 +Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git From dec848f0721be8afd06a8c4c5e1dd97cb8476b2d Mon Sep 17 00:00:00 2001 From: yangfl Date: Wed, 27 Jun 2018 17:09:46 +0800 Subject: [PATCH 105/195] use builtin __AVX__ and __AES__ macros and reduce code duplication --- Makefile.homebrew | 2 +- Makefile.linux | 2 +- Makefile.mingw | 2 +- Makefile.osx | 2 +- build/CMakeLists.txt | 7 +- libi2pd/CPU.cpp | 14 +++- libi2pd/Crypto.cpp | 162 ++++++++++++++----------------------------- libi2pd/Crypto.h | 23 +++--- libi2pd/Identity.cpp | 39 ++++++----- 9 files changed, 104 insertions(+), 149 deletions(-) diff --git a/Makefile.homebrew b/Makefile.homebrew index a6e645ee..6830b051 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -34,7 +34,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes endif ifeq ($(USE_AVX),1) CXXFLAGS += -mavx diff --git a/Makefile.linux b/Makefile.linux index cf045eb4..e9609876 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -64,7 +64,7 @@ ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifeq ($(machine), aarch64) CXXFLAGS += -DARM64AES else - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes endif endif endif diff --git a/Makefile.mingw b/Makefile.mingw index b40d0ada..fe897ae0 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -37,7 +37,7 @@ endif # don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes else CPU_FLAGS += -msse endif diff --git a/Makefile.osx b/Makefile.osx index 8bbf37f0..5752b2fe 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -21,7 +21,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes else CXXFLAGS += -msse endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 632edc03..bed5ee10 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -39,7 +39,7 @@ include_directories(${LIBI2PD_CLIENT_SRC_DIR}) set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/BloomFilter.cpp" "${LIBI2PD_SRC_DIR}/Config.cpp" - "${LIBI2PD_SRC_DIR}/CPU.cpp" + "${LIBI2PD_SRC_DIR}/CPU.cpp" "${LIBI2PD_SRC_DIR}/Crypto.cpp" "${LIBI2PD_SRC_DIR}/CryptoKey.cpp" "${LIBI2PD_SRC_DIR}/Garlic.cpp" @@ -77,10 +77,10 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/api.cpp" "${LIBI2PD_SRC_DIR}/Event.cpp" "${LIBI2PD_SRC_DIR}/Gost.cpp" - "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" + "${LIBI2PD_SRC_DIR}/ChaCha20.cpp" "${LIBI2PD_SRC_DIR}/Poly1305.cpp" "${LIBI2PD_SRC_DIR}/Ed25519.cpp" - "${LIBI2PD_SRC_DIR}/NTCP2.cpp" + "${LIBI2PD_SRC_DIR}/NTCP2.cpp" ) if (WITH_WEBSOCKETS) @@ -234,7 +234,6 @@ endif () if (WITH_AESNI) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes" ) - add_definitions ( -DAESNI ) endif() if (WITH_AVX) diff --git a/libi2pd/CPU.cpp b/libi2pd/CPU.cpp index d2868a20..a707c3dc 100644 --- a/libi2pd/CPU.cpp +++ b/libi2pd/CPU.cpp @@ -21,23 +21,35 @@ namespace cpu void Detect() { +#if defined(__AES__) || defined(__AVX__) + #if defined(__x86_64__) || defined(__i386__) int info[4]; __cpuid(0, info[0], info[1], info[2], info[3]); if (info[0] >= 0x00000001) { __cpuid(0x00000001, info[0], info[1], info[2], info[3]); +#ifdef __AES__ aesni = info[2] & bit_AES; // AESNI +#endif // __AES__ +#ifdef __AVX__ avx = info[2] & bit_AVX; // AVX +#endif // __AVX__ } -#endif +#endif // defined(__x86_64__) || defined(__i386__) + +#ifdef __AES__ if(aesni) { LogPrint(eLogInfo, "AESNI enabled"); } +#endif // __AES__ +#ifdef __AVX__ if(avx) { LogPrint(eLogInfo, "AVX enabled"); } +#endif // __AVX__ +#endif // defined(__AES__) || defined(__AVX__) } } } diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 6d859342..24ce9c72 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -399,7 +399,7 @@ namespace crypto bn2buf (x, encrypted + 1, len); bn2buf (y, encrypted + 1 + len, len); RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len); - } + } else { bn2buf (x, encrypted, len); @@ -468,10 +468,10 @@ namespace crypto CBCDecryption decryption; decryption.SetKey (shared); decryption.SetIV (iv); - if (zeroPadding) + if (zeroPadding) decryption.Decrypt (encrypted + 258, 256, m); else - decryption.Decrypt (encrypted + 256, 256, m); + decryption.Decrypt (encrypted + 256, 256, m); // verify and copy uint8_t hash[32]; SHA256 (m + 33, 222, hash); @@ -522,9 +522,9 @@ namespace crypto { uint64_t buf[256]; uint64_t hash[12]; // 96 bytes +#ifdef __AVX__ if(i2p::cpu::avx) { -#ifdef AVX __asm__ ( "vmovups %[key], %%ymm0 \n" @@ -543,30 +543,9 @@ namespace crypto [buf]"r"(buf), [hash]"r"(hash) : "memory", "%xmm0" // TODO: change to %ymm0 later ); -#else - // ikeypad - buf[0] = key.GetLL ()[0] ^ IPAD; - buf[1] = key.GetLL ()[1] ^ IPAD; - buf[2] = key.GetLL ()[2] ^ IPAD; - buf[3] = key.GetLL ()[3] ^ IPAD; - buf[4] = IPAD; - buf[5] = IPAD; - buf[6] = IPAD; - buf[7] = IPAD; - // okeypad - hash[0] = key.GetLL ()[0] ^ OPAD; - hash[1] = key.GetLL ()[1] ^ OPAD; - hash[2] = key.GetLL ()[2] ^ OPAD; - hash[3] = key.GetLL ()[3] ^ OPAD; - hash[4] = OPAD; - hash[5] = OPAD; - hash[6] = OPAD; - hash[7] = OPAD; - // fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P) - memset (hash + 10, 0, 16); -#endif } else +#endif { // ikeypad buf[0] = key.GetLL ()[0] ^ IPAD; @@ -600,12 +579,12 @@ namespace crypto } // AES -#ifdef AESNI +#ifdef __AES__ #ifdef ARM64AES void init_aesenc(void){ // TODO: Implementation } - + #endif #define KeyExpansion256(round0,round1) \ @@ -632,7 +611,7 @@ namespace crypto "movaps %%xmm3, "#round1"(%[sched]) \n" #endif -#ifdef AESNI +#ifdef __AES__ void ECBCryptoAESNI::ExpandKey (const AESKey& key) { __asm__ @@ -669,11 +648,11 @@ namespace crypto : [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged ); - } + } #endif -#if AESNI +#ifdef __AES__ #define EncryptAES256(sched) \ "pxor (%["#sched"]), %%xmm0 \n" \ "aesenc 16(%["#sched"]), %%xmm0 \n" \ @@ -691,12 +670,12 @@ namespace crypto "aesenc 208(%["#sched"]), %%xmm0 \n" \ "aesenclast 224(%["#sched"]), %%xmm0 \n" #endif - + void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[in]), %%xmm0 \n" @@ -704,17 +683,15 @@ namespace crypto "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); -#else - AES_encrypt (in->buf, out->buf, &m_Key); -#endif } else +#endif { AES_encrypt (in->buf, out->buf, &m_Key); - } + } } -#ifdef AESNI +#ifdef __AES__ #define DecryptAES256(sched) \ "pxor 224(%["#sched"]), %%xmm0 \n" \ "aesdec 208(%["#sched"]), %%xmm0 \n" \ @@ -732,12 +709,12 @@ namespace crypto "aesdec 16(%["#sched"]), %%xmm0 \n" \ "aesdeclast (%["#sched"]), %%xmm0 \n" #endif - + void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[in]), %%xmm0 \n" @@ -745,17 +722,15 @@ namespace crypto "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); -#else - AES_decrypt (in->buf, out->buf, &m_Key); -#endif } else +#endif { AES_decrypt (in->buf, out->buf, &m_Key); } } -#ifdef AESNI +#ifdef __AES__ #define CallAESIMC(offset) \ "movaps "#offset"(%[shed]), %%xmm0 \n" \ "aesimc %%xmm0, %%xmm0 \n" \ @@ -764,25 +739,23 @@ namespace crypto void ECBEncryption::SetKey (const AESKey& key) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI - ExpandKey (key); -#else - AES_set_encrypt_key (key, 256, &m_Key); -#endif + ExpandKey (key); } else +#endif { AES_set_encrypt_key (key, 256, &m_Key); } } - + void ECBDecryption::SetKey (const AESKey& key) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI ExpandKey (key); // expand encryption key first // then invert it using aesimc __asm__ @@ -802,11 +775,9 @@ namespace crypto CallAESIMC(208) : : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory" ); -#else - AES_set_decrypt_key (key, 256, &m_Key); -#endif } else +#endif { AES_set_decrypt_key (key, 256, &m_Key); } @@ -815,9 +786,9 @@ namespace crypto void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -837,16 +808,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) : "%xmm0", "%xmm1", "cc", "memory" ); -#else - for (int i = 0; i < numBlocks; i++) - { - *m_LastBlock.GetChipherBlock () ^= in[i]; - m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ()); - out[i] = *m_LastBlock.GetChipherBlock (); - } -#endif } else +#endif { for (int i = 0; i < numBlocks; i++) { @@ -867,9 +831,9 @@ namespace crypto void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -883,19 +847,17 @@ namespace crypto [in]"r"(in), [out]"r"(out) : "%xmm0", "%xmm1", "memory" ); -#else - Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); -#endif } else +#endif Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); } void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -916,17 +878,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); -#else - for (int i = 0; i < numBlocks; i++) - { - ChipherBlock tmp = in[i]; - m_ECBDecryption.Decrypt (in + i, out + i); - out[i] ^= *m_IV.GetChipherBlock (); - *m_IV.GetChipherBlock () = tmp; - } -#endif } else +#endif { for (int i = 0; i < numBlocks; i++) { @@ -947,9 +901,9 @@ namespace crypto void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( "movups (%[iv]), %%xmm1 \n" @@ -963,19 +917,17 @@ namespace crypto [in]"r"(in), [out]"r"(out) : "%xmm0", "%xmm1", "memory" ); -#else - Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); -#endif } else +#endif Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); } void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( // encrypt IV @@ -1001,14 +953,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes : "%xmm0", "%xmm1", "cc", "memory" ); -#else - m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv - m_LayerEncryption.SetIV (out); - m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv -#endif } else +#endif { m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_LayerEncryption.SetIV (out); @@ -1019,9 +966,9 @@ namespace crypto void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) { +#ifdef __AES__ if(i2p::cpu::aesni) { -#ifdef AESNI __asm__ ( // decrypt IV @@ -1048,14 +995,9 @@ namespace crypto [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); -#else - m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv - m_LayerDecryption.SetIV (out); - m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data - m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv -#endif } else +#endif { m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_LayerDecryption.SetIV (out); @@ -1068,7 +1010,7 @@ namespace crypto bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) { - if (len < msgLen) return false; + if (len < msgLen) return false; if (encrypt && len < msgLen + 16) return false; bool ret = true; #if LEGACY_OPENSSL @@ -1076,40 +1018,40 @@ namespace crypto uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); chacha20 (polyKey, 64, nonce, key, 0); - // encrypt data + // encrypt data memcpy (buf, msg, msgLen); chacha20 (buf, msgLen, nonce, key, 1); - + // create Poly1305 message - if (!ad) adLen = 0; + if (!ad) adLen = 0; std::vector polyMsg(adLen + msgLen + 3*16); size_t offset = 0; uint8_t padding[16]; memset (padding, 0, 16); if (ad) - { + { memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data auto rem = adLen & 0x0F; // %16 - if (rem) + if (rem) { // padding1 rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } } memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data auto rem = msgLen & 0x0F; // %16 - if (rem) + if (rem) { // padding2 rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } - htole64buf (polyMsg.data () + offset, adLen); offset += 8; + htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8; if (encrypt) { - // calculate Poly1305 tag and write in after encrypted data + // calculate Poly1305 tag and write in after encrypted data Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); } else @@ -1118,9 +1060,9 @@ namespace crypto // calculate Poly1305 tag Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided - } + } #else - int outlen = 0; + int outlen = 0; EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); if (encrypt) { @@ -1141,8 +1083,8 @@ namespace crypto EVP_DecryptUpdate(ctx, NULL, &outlen, ad, adLen); ret = EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen) > 0; } - - EVP_CIPHER_CTX_free (ctx); + + EVP_CIPHER_CTX_free (ctx); #endif return ret; } diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 25646dbb..fe0fcddf 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -69,9 +69,9 @@ namespace crypto void operator^=(const ChipherBlock& other) // XOR { +#ifdef __AVX__ if (i2p::cpu::avx) { -#ifdef AVX __asm__ ( "vmovups (%[buf]), %%xmm0 \n" @@ -82,12 +82,9 @@ namespace crypto : [buf]"r"(buf), [other]"r"(other.buf) : "%xmm0", "%xmm1", "memory" ); -#else - for (int i = 0; i < 16; i++) - buf[i] ^= other.buf[i]; -#endif } else +#endif { // TODO: implement it better for (int i = 0; i < 16; i++) @@ -123,7 +120,7 @@ namespace crypto }; -#ifdef AESNI +#ifdef __AES__ #ifdef ARM64AES void init_aesenc(void) __attribute__((constructor)); #endif @@ -143,7 +140,7 @@ namespace crypto }; #endif -#ifdef AESNI +#ifdef __AES__ class ECBEncryption: public ECBCryptoAESNI #else class ECBEncryption @@ -152,14 +149,14 @@ namespace crypto public: void SetKey (const AESKey& key); - + void Encrypt(const ChipherBlock * in, ChipherBlock * out); private: AES_KEY m_Key; }; -#ifdef AESNI +#ifdef __AES__ class ECBDecryption: public ECBCryptoAESNI #else class ECBDecryption @@ -188,7 +185,7 @@ namespace crypto void Encrypt (const uint8_t * in, uint8_t * out); // one block ECBEncryption & ECB() { return m_ECBEncryption; } - + private: AESAlignedBuffer<16> m_LastBlock; @@ -211,7 +208,7 @@ namespace crypto void Decrypt (const uint8_t * in, uint8_t * out); // one block ECBDecryption & ECB() { return m_ECBDecryption; } - + private: AESAlignedBuffer<16> m_IV; @@ -255,8 +252,8 @@ namespace crypto }; // AEAD/ChaCha20/Poly1305 - bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag - + bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag + // init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 3fcd16ad..7f64d931 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -719,24 +719,29 @@ namespace data XORMetric operator^(const IdentHash& key1, const IdentHash& key2) { XORMetric m; -#if defined(__AVX__) // for AVX - __asm__ - ( - "vmovups %1, %%ymm0 \n" - "vmovups %2, %%ymm1 \n" - "vxorps %%ymm0, %%ymm1, %%ymm1 \n" - "vmovups %%ymm1, %0 \n" - : "=m"(*m.metric) - : "m"(*key1), "m"(*key2) - : "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler - ); -#else - const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); - m.metric_ll[0] = hash1[0] ^ hash2[0]; - m.metric_ll[1] = hash1[1] ^ hash2[1]; - m.metric_ll[2] = hash1[2] ^ hash2[2]; - m.metric_ll[3] = hash1[3] ^ hash2[3]; +#ifdef __AVX__ + if(i2p::cpu::avx) + { + __asm__ + ( + "vmovups %1, %%ymm0 \n" + "vmovups %2, %%ymm1 \n" + "vxorps %%ymm0, %%ymm1, %%ymm1 \n" + "vmovups %%ymm1, %0 \n" + : "=m"(*m.metric) + : "m"(*key1), "m"(*key2) + : "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler + ); + } + else #endif + { + const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); + m.metric_ll[0] = hash1[0] ^ hash2[0]; + m.metric_ll[1] = hash1[1] ^ hash2[1]; + m.metric_ll[2] = hash1[2] ^ hash2[2]; + m.metric_ll[3] = hash1[3] ^ hash2[3]; + } return m; } From 41e8ab53835eb599243856001adbeb314f106658 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Jun 2018 17:47:22 +0300 Subject: [PATCH 106/195] Limit tampering with standard C++ library to Linux Otherwise it breaks e.g. FreeBSD build where it is not needed at all --- build/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index bed5ee10..73e76ae0 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -202,9 +202,11 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") endif () elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # more tweaks - if (NOT (MSVC OR MSYS OR APPLE)) + if (LINUX) set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libstdc++" ) # required for list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++") # required to link with -stdlib=libstdc++ + endif() + if (NOT (MSVC OR MSYS OR APPLE)) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions" ) endif() endif () From 4ffbb46cf9c63dfddc062771a9bb29a5d50524af Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Wed, 27 Jun 2018 22:31:01 +0300 Subject: [PATCH 107/195] Fix "macro expansion producing 'defined' has undefined behavior" clang warning --- libi2pd/Crypto.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index fe0fcddf..43f1def9 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -262,7 +262,12 @@ namespace crypto // take care about openssl version #include -#define LEGACY_OPENSSL ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL +#if ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL +# define LEGACY_OPENSSL 1 +#else +# define LEGACY_OPENSSL 0 +#endif + #if LEGACY_OPENSSL // define getters and setters introduced in 1.1.0 inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) From db5b45222a7c8f9f4e4beacccce133c15ba097fc Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 27 Jun 2018 23:20:02 +0300 Subject: [PATCH 108/195] store and install assets on android --- android/build.gradle | 1 + .../src/org/purplei2p/i2pd/I2PDActivity.java | 492 ++++++++++-------- 2 files changed, 284 insertions(+), 209 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index c5834e19..683f3d27 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -37,6 +37,7 @@ android { java.srcDirs = ['src'] res.srcDirs = ['res'] jniLibs.srcDirs = ['libs'] + assets.srcDirs = ['assets'] } } signingConfigs { diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 99672eb7..28e30251 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -1,5 +1,10 @@ package org.purplei2p.i2pd; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Timer; @@ -10,7 +15,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.res.AssetManager; import android.os.Bundle; +import android.os.Environment; import android.os.IBinder; import android.util.Log; import android.view.Menu; @@ -19,24 +26,24 @@ import android.widget.TextView; import android.widget.Toast; public class I2PDActivity extends Activity { - private static final String TAG = "i2pdActvt"; - public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; - - private TextView textView; - + private static final String TAG = "i2pdActvt"; + public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; + + private TextView textView; + private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); - + private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = - new DaemonSingleton.StateUpdateListener() { - + new DaemonSingleton.StateUpdateListener() { + @Override public void daemonStateUpdate() { runOnUiThread(new Runnable(){ - + @Override public void run() { try { - if(textView==null)return; + if(textView==null) return; Throwable tr = daemon.getLastThrowable(); if(tr!=null) { textView.setText(throwableToString(tr)); @@ -44,242 +51,309 @@ public class I2PDActivity extends Activity { } DaemonSingleton.State state = daemon.getState(); textView.setText( - String.valueOf(state)+ - (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ - (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") - ); - } catch (Throwable tr) { + String.valueOf(state)+ + (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ + (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") + ); + } catch (Throwable tr) { Log.e(TAG,"error ignored",tr); } } }); } }; - private static volatile long graceStartedMillis; - private static final Object graceStartedMillis_LOCK=new Object(); - - private static String formatGraceTimeRemaining() { - long remainingSeconds; - synchronized (graceStartedMillis_LOCK){ - remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D); - } - long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D); - long remSec=remainingSeconds-remainingMinutes*60; - return remainingMinutes+":"+(remSec/10)+remSec%10; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - textView = new TextView(this); - setContentView(textView); - daemon.addStateChangeListener(daemonStateUpdatedListener); - daemonStateUpdatedListener.daemonStateUpdate(); - - //set the app be foreground - doBindService(); - - final Timer gracefulQuitTimer = getGracefulQuitTimer(); - if(gracefulQuitTimer!=null){ - long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; - } - rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); - } - } - - @Override + private static volatile long graceStartedMillis; + private static final Object graceStartedMillis_LOCK=new Object(); + + private static String formatGraceTimeRemaining() { + long remainingSeconds; + synchronized (graceStartedMillis_LOCK){ + remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D); + } + long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D); + long remSec=remainingSeconds-remainingMinutes*60; + return remainingMinutes+":"+(remSec/10)+remSec%10; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // copy assets + copyAsset("certificates"); + copyAsset("i2pd.conf"); + copyAsset("subsciptions.txt"); + copyAsset("tunnels.conf"); + + textView = new TextView(this); + setContentView(textView); + daemon.addStateChangeListener(daemonStateUpdatedListener); + daemonStateUpdatedListener.daemonStateUpdate(); + + // set the app be foreground + doBindService(); + + final Timer gracefulQuitTimer = getGracefulQuitTimer(); + if(gracefulQuitTimer!=null){ + long gracefulStopAtMillis; + synchronized (graceStartedMillis_LOCK) { + gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + } + rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); + } + } + + @Override protected void onDestroy() { super.onDestroy(); - textView = null; - daemon.removeStateChangeListener(daemonStateUpdatedListener); - //cancelGracefulStop(); + textView = null; + daemon.removeStateChangeListener(daemonStateUpdatedListener); + //cancelGracefulStop(); try{ - doUnbindService(); - }catch(Throwable tr){ + doUnbindService(); + }catch(Throwable tr){ Log.e(TAG, "", tr); } } - - private static void cancelGracefulStop() { - Timer gracefulQuitTimer = getGracefulQuitTimer(); - if(gracefulQuitTimer!=null) { - gracefulQuitTimer.cancel(); - setGracefulQuitTimer(null); - } - } - - private CharSequence throwableToString(Throwable tr) { - StringWriter sw = new StringWriter(8192); - PrintWriter pw = new PrintWriter(sw); - tr.printStackTrace(pw); - pw.close(); - return sw.toString(); + + private static void cancelGracefulStop() { + Timer gracefulQuitTimer = getGracefulQuitTimer(); + if(gracefulQuitTimer!=null) { + gracefulQuitTimer.cancel(); + setGracefulQuitTimer(null); + } } - -// private LocalService mBoundService; - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - // This is called when the connection with the service has been - // established, giving us the service object we can use to - // interact with the service. Because we have bound to a explicit - // service that we know is running in our own process, we can - // cast its IBinder to a concrete class and directly access it. -// mBoundService = ((LocalService.LocalBinder)service).getService(); - - // Tell the user about this for our demo. -// Toast.makeText(Binding.this, R.string.local_service_connected, -// Toast.LENGTH_SHORT).show(); - } - - public void onServiceDisconnected(ComponentName className) { - // This is called when the connection with the service has been - // unexpectedly disconnected -- that is, its process crashed. - // Because it is running in our same process, we should never - // see this happen. -// mBoundService = null; -// Toast.makeText(Binding.this, R.string.local_service_disconnected, -// Toast.LENGTH_SHORT).show(); - } - }; - - - private static volatile boolean mIsBound; - - private void doBindService() { - synchronized (I2PDActivity.class) { - if (mIsBound) return; - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - } - } - - private void doUnbindService() { - synchronized (I2PDActivity.class) { - if (mIsBound) { - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; - } - } - } - + + private CharSequence throwableToString(Throwable tr) { + StringWriter sw = new StringWriter(8192); + PrintWriter pw = new PrintWriter(sw); + tr.printStackTrace(pw); + pw.close(); + return sw.toString(); + } + + // private LocalService mBoundService; + + private ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + // This is called when the connection with the service has been + // established, giving us the service object we can use to + // interact with the service. Because we have bound to a explicit + // service that we know is running in our own process, we can + // cast its IBinder to a concrete class and directly access it. + // mBoundService = ((LocalService.LocalBinder)service).getService(); + + // Tell the user about this for our demo. + // Toast.makeText(Binding.this, R.string.local_service_connected, + // Toast.LENGTH_SHORT).show(); + } + + public void onServiceDisconnected(ComponentName className) { + // This is called when the connection with the service has been + // unexpectedly disconnected -- that is, its process crashed. + // Because it is running in our same process, we should never + // see this happen. + // mBoundService = null; + // Toast.makeText(Binding.this, R.string.local_service_disconnected, + // Toast.LENGTH_SHORT).show(); + } + }; + + + private static volatile boolean mIsBound; + + private void doBindService() { + synchronized (I2PDActivity.class) { + if (mIsBound) return; + // Establish a connection with the service. We use an explicit + // class name because we want a specific service implementation that + // we know will be running in our own process (and thus won't be + // supporting component replacement by other applications). + bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); + mIsBound = true; + } + } + + private void doUnbindService() { + synchronized (I2PDActivity.class) { + if (mIsBound) { + // Detach our existing connection. + unbindService(mConnection); + mIsBound = false; + } + } + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.options_main, menu); return true; } - + @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - + switch(id){ - case R.id.action_stop: - i2pdStop(); - return true; - case R.id.action_graceful_stop: - i2pdGracefulStop(); - return true; - } - + case R.id.action_stop: + i2pdStop(); + return true; + case R.id.action_graceful_stop: + i2pdGracefulStop(); + return true; + } + return super.onOptionsItemSelected(item); } - + private void i2pdStop() { - cancelGracefulStop(); - new Thread(new Runnable(){ - - @Override - public void run() { - Log.d(TAG, "stopping"); - try{ - daemon.stopDaemon(); - }catch (Throwable tr) { - Log.e(TAG, "", tr); - } - } - - },"stop").start(); - } - - private static volatile Timer gracefulQuitTimer; - - private void i2pdGracefulStop() { - if(daemon.getState()==DaemonSingleton.State.stopped){ - Toast.makeText(this, R.string.already_stopped, - Toast.LENGTH_SHORT).show(); - return; - } - if(getGracefulQuitTimer()!=null){ - Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, - Toast.LENGTH_SHORT).show(); - return; - } - Toast.makeText(this, R.string.graceful_stop_is_in_progress, - Toast.LENGTH_SHORT).show(); - new Thread(new Runnable(){ - + cancelGracefulStop(); + new Thread(new Runnable(){ + + @Override + public void run() { + Log.d(TAG, "stopping"); + try{ + daemon.stopDaemon(); + }catch (Throwable tr) { + Log.e(TAG, "", tr); + } + } + + },"stop").start(); + } + + private static volatile Timer gracefulQuitTimer; + + private void i2pdGracefulStop() { + if(daemon.getState()==DaemonSingleton.State.stopped){ + Toast.makeText(this, R.string.already_stopped, + Toast.LENGTH_SHORT).show(); + return; + } + if(getGracefulQuitTimer()!=null){ + Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, + Toast.LENGTH_SHORT).show(); + return; + } + Toast.makeText(this, R.string.graceful_stop_is_in_progress, + Toast.LENGTH_SHORT).show(); + new Thread(new Runnable(){ + @Override public void run() { try{ Log.d(TAG, "grac stopping"); - if(daemon.isStartedOkay()) { - daemon.stopAcceptingTunnels(); - long gracefulStopAtMillis; - synchronized (graceStartedMillis_LOCK) { - graceStartedMillis = System.currentTimeMillis(); - gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; - } - rescheduleGraceStop(null,gracefulStopAtMillis); - }else{ - i2pdStop(); - } - } catch(Throwable tr) { + if(daemon.isStartedOkay()) { + daemon.stopAcceptingTunnels(); + long gracefulStopAtMillis; + synchronized (graceStartedMillis_LOCK) { + graceStartedMillis = System.currentTimeMillis(); + gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; + } + rescheduleGraceStop(null,gracefulStopAtMillis); + }else{ + i2pdStop(); + } + } catch(Throwable tr) { Log.e(TAG,"",tr); } } - - },"gracInit").start(); - } - - private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { - if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); - final Timer gracefulQuitTimer = new Timer(true); - setGracefulQuitTimer(gracefulQuitTimer); - gracefulQuitTimer.schedule(new TimerTask(){ - - @Override - public void run() { - i2pdStop(); - } - - }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); - final TimerTask tickerTask = new TimerTask() { - @Override - public void run() { - daemonStateUpdatedListener.daemonStateUpdate(); - } - }; - gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); - } - - private static Timer getGracefulQuitTimer() { - return gracefulQuitTimer; + + },"gracInit").start(); } - + + private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { + if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); + final Timer gracefulQuitTimer = new Timer(true); + setGracefulQuitTimer(gracefulQuitTimer); + gracefulQuitTimer.schedule(new TimerTask(){ + + @Override + public void run() { + i2pdStop(); + } + + }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); + final TimerTask tickerTask = new TimerTask() { + @Override + public void run() { + daemonStateUpdatedListener.daemonStateUpdate(); + } + }; + gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); + } + + private static Timer getGracefulQuitTimer() { + return gracefulQuitTimer; + } + private static void setGracefulQuitTimer(Timer gracefulQuitTimer) { - I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; + I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; + } + + /** + * Copy the asset at the specified path to this app's data directory. If the + * asset is a directory, its contents are also copied. + * + * @param path + * Path to asset, relative to app's assets directory. + */ + private void copyAsset(String path) { + AssetManager manager = getAssets(); + + // If we have a directory, we make it and recurse. If a file, we copy its + // contents. + try { + String[] contents = manager.list(path); + + // The documentation suggests that list throws an IOException, but doesn't + // say under what conditions. It'd be nice if it did so when the path was + // to a file. That doesn't appear to be the case. If the returned array is + // null or has 0 length, we assume the path is to a file. This means empty + // directories will get turned into files. + if (contents == null || contents.length == 0) + throw new IOException(); + + // Make the directory. + File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); + dir.mkdirs(); + + // Recurse on the contents. + for (String entry : contents) { + copyAsset(path + "/" + entry); + } + } catch (IOException e) { + copyFileAsset(path); + } + } + + /** + * Copy the asset file specified by path to app's data directory. Assumes + * parent directories have already been created. + * + * @param path + * Path to asset, relative to app's assets directory. + */ + private void copyFileAsset(String path) { + File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); + try { + InputStream in = getAssets().open(path); + OutputStream out = new FileOutputStream(file); + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + while (read != -1) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + out.close(); + in.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } } } From 5233e7220586a1ddf809a979e338b754fd5761a0 Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 27 Jun 2018 23:43:49 +0300 Subject: [PATCH 109/195] add assets symlinks --- android/assets/certificates | 1 + android/assets/i2pd.conf | 1 + android/assets/subscriptions.txt | 1 + android/assets/tunnels.conf | 1 + 4 files changed, 4 insertions(+) create mode 120000 android/assets/certificates create mode 120000 android/assets/i2pd.conf create mode 120000 android/assets/subscriptions.txt create mode 120000 android/assets/tunnels.conf diff --git a/android/assets/certificates b/android/assets/certificates new file mode 120000 index 00000000..01b21e5d --- /dev/null +++ b/android/assets/certificates @@ -0,0 +1 @@ +../../contrib/certificates \ No newline at end of file diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf new file mode 120000 index 00000000..f4a68aa2 --- /dev/null +++ b/android/assets/i2pd.conf @@ -0,0 +1 @@ +../../contrib/i2pd.conf \ No newline at end of file diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt new file mode 120000 index 00000000..4fcc444f --- /dev/null +++ b/android/assets/subscriptions.txt @@ -0,0 +1 @@ +../../contrib/subscriptions.txt \ No newline at end of file diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf new file mode 120000 index 00000000..08767c73 --- /dev/null +++ b/android/assets/tunnels.conf @@ -0,0 +1 @@ +../../contrib/tunnels.conf \ No newline at end of file From 64aee9c8ae00a37ab4809766b7dde47f7cfeed44 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 29 Jun 2018 02:27:19 +0300 Subject: [PATCH 110/195] add DEBUG option for make By default, binary will be built without stripping debug symbols --- Makefile | 8 ++++++++ Makefile.bsd | 4 ++-- Makefile.homebrew | 7 ++++--- Makefile.linux | 8 ++++---- Makefile.mingw | 6 +++--- Makefile.osx | 7 +++---- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 6d56ec7d..c51018f9 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,14 @@ USE_AVX := yes USE_STATIC := no USE_MESHNET := no USE_UPNP := no +DEBUG := yes + +ifeq ($(DEBUG),yes) + CXX_DEBUG = -g +else + CXX_DEBUG = -Os + LD_DEBUG = -s +endif ifeq ($(WEBSOCKETS),1) NEEDED_CXXFLAGS += -DWITH_EVENTS diff --git a/Makefile.bsd b/Makefile.bsd index f2293540..39e5651a 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -1,5 +1,5 @@ CXX = clang++ -CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation +CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation ## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. ## For example, when adding 'hardening flags' to the build @@ -8,5 +8,5 @@ CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-ind ## custom FLAGS to work at build-time. NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 INCFLAGS = -I/usr/include/ -I/usr/local/include/ -LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib +LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread diff --git a/Makefile.homebrew b/Makefile.homebrew index 6830b051..41a89e93 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -3,8 +3,9 @@ BREWROOT = /usr/local BOOSTROOT = ${BREWROOT}/opt/boost SSLROOT = ${BREWROOT}/opt/libressl UPNPROOT = ${BREWROOT}/opt/miniupnpc -CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual +CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include +LDFLAGS = ${LD_DEBUG} ifndef TRAVIS CXX = clang++ @@ -13,7 +14,7 @@ endif ifeq ($(USE_STATIC),yes) LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread else - LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib + LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread endif @@ -34,7 +35,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes + CXXFLAGS += -maes -DAESNI endif ifeq ($(USE_AVX),1) CXXFLAGS += -mavx diff --git a/Makefile.linux b/Makefile.linux index e9609876..bd8d8fd3 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -1,13 +1,13 @@ # set defaults instead redefine -CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -INCFLAGS ?= +CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation +LDFLAGS ?= ${LD_DEBUG} ## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. ## For example, when adding 'hardening flags' to the build ## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove ## -std=c++11. If you want to remove this variable please do so in a way that allows setting -## custom FLAGS to work at build-time. +## custom FDLAGS to work at build-time. # detect proper flag for c++11 support by compilers CXXVER := $(shell $(CXX) -dumpversion) @@ -64,7 +64,7 @@ ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifeq ($(machine), aarch64) CXXFLAGS += -DARM64AES else - CPU_FLAGS += -maes + CPU_FLAGS += -maes -DAESNI endif endif endif diff --git a/Makefile.mingw b/Makefile.mingw index fe897ae0..ac2d0363 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,11 +1,11 @@ USE_WIN32_APP=yes CXX = g++ WINDRES = windres -CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN NEEDED_CXXFLAGS = -std=c++11 BOOST_SUFFIX = -mt INCFLAGS = -Idaemon -I. -LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ +LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ # UPNP Support ifeq ($(USE_UPNP),yes) @@ -37,7 +37,7 @@ endif # don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes + CPU_FLAGS += -maes -DAESNI else CPU_FLAGS += -msse endif diff --git a/Makefile.osx b/Makefile.osx index 5752b2fe..2db88784 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -1,8 +1,7 @@ CXX = clang++ -CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX -#CXXFLAGS = -g -O2 -Wall -std=c++11 +CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX INCFLAGS = -I/usr/local/include -LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib +LDFLAGS := ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib ifeq ($(USE_STATIC),yes) LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread @@ -21,7 +20,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes + CXXFLAGS += -maes -DAESNI else CXXFLAGS += -msse endif From 55af4ed385ce0e5d2242f6ca8ae72439b8722665 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 29 Jun 2018 02:30:03 +0300 Subject: [PATCH 111/195] delete old AESNI definition --- Makefile.homebrew | 2 +- Makefile.linux | 2 +- Makefile.mingw | 2 +- Makefile.osx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.homebrew b/Makefile.homebrew index 41a89e93..688fdaea 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -35,7 +35,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes endif ifeq ($(USE_AVX),1) CXXFLAGS += -mavx diff --git a/Makefile.linux b/Makefile.linux index bd8d8fd3..b9a740ad 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -64,7 +64,7 @@ ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) ifeq ($(machine), aarch64) CXXFLAGS += -DARM64AES else - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes endif endif endif diff --git a/Makefile.mingw b/Makefile.mingw index ac2d0363..5dae3723 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -37,7 +37,7 @@ endif # don't change following line to ifeq ($(USE_AESNI),yes) !!! ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -DAESNI + CPU_FLAGS += -maes else CPU_FLAGS += -msse endif diff --git a/Makefile.osx b/Makefile.osx index 2db88784..3358cb10 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -20,7 +20,7 @@ ifeq ($(USE_UPNP),yes) endif ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes -DAESNI + CXXFLAGS += -maes else CXXFLAGS += -msse endif From 6054bd6621a6c8e1bc6e611da07c2447b03b56be Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Jul 2018 16:26:02 -0400 Subject: [PATCH 112/195] NTCP2 session establisher --- libi2pd/NTCP2.cpp | 197 +++++++++++++++++++++++----------------------- libi2pd/NTCP2.h | 27 +++++-- 2 files changed, 118 insertions(+), 106 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 594f4a93..5938d232 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -15,6 +15,73 @@ namespace i2p { namespace transport { + void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) + { + // temp_key = HMAC-SHA256(ck, input_key_material) + uint8_t tempKey[32]; unsigned int len; + HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); + // ck = HMAC-SHA256(temp_key, byte(0x01)) + static uint8_t one[1] = { 1 }; + HMAC(EVP_sha256(), tempKey, 32, one, 1, m_CK, &len); + // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) + m_CK[32] = 2; + HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); + } + + void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) + { + static const uint8_t protocolNameHash[] = + { + 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, + 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 + }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") + static uint8_t h[64] = + { + 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, + 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e + }; // SHA256 (protocolNameHash) + memcpy (m_CK, protocolNameHash, 32); + // h = SHA256(h || rs) + memcpy (h + 32, rs, 32); + SHA256 (h, 64, h); + // h = SHA256(h || pub) + memcpy (h + 32, pub, 32); + SHA256 (h, 64, m_H); + // x25519 between rs and priv + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv + MixKey (inputKeyMaterial, derived); + } + + void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + { + uint8_t h[64]; + memcpy (h, m_H, 32); + memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload + SHA256 (h, 64, h); + int paddingLength = sessionRequestLen - 64; + if (paddingLength > 0) + { + std::vector h1(paddingLength + 32); + memcpy (h1.data (), h, 32); + memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); + SHA256 (h1.data (), paddingLength + 32, h); + } + memcpy (h + 32, pub, 32); + SHA256 (h, 64, m_H); + + // x25519 between remote pub and priv + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, derived); + } + + void NTCP2Establisher::CreateEphemeralKey (uint8_t * pub) + { + RAND_bytes (m_EphemeralPrivateKey, 32); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, m_Ctx); + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, 30), m_Server (server), m_Socket (m_Server.GetService ()), @@ -23,11 +90,12 @@ namespace transport m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0) { + m_Establisher.reset (new NTCP2Establisher); auto addr = in_RemoteRouter->GetNTCPAddress (); if (addr->ntcp2) { - memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32); - memcpy (m_IV, addr->ntcp2->iv, 16); + memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); + memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); } else LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); @@ -58,90 +126,26 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } - void NTCP2Session::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) - { - // temp_key = HMAC-SHA256(ck, input_key_material) - uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len); - // ck = HMAC-SHA256(temp_key, byte(0x01)) - static uint8_t one[1] = { 1 }; - HMAC(EVP_sha256(), tempKey, 32, one, 1, m_CK, &len); - // derived = HMAC-SHA256(temp_key, ck || byte(0x02)) - m_CK[32] = 2; - HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); - } - void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) { memset (nonce, 0, 4); htole64buf (nonce + 4, seqn); } - void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) - { - static const uint8_t protocolNameHash[] = - { - 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, - 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 - }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") - static uint8_t h[64] = - { - 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, - 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e - }; // SHA256 (protocolNameHash) - memcpy (m_CK, protocolNameHash, 32); - // h = SHA256(h || rs) - memcpy (h + 32, rs, 32); - SHA256 (h, 64, h); - // h = SHA256(h || pub) - memcpy (h + 32, pub, 32); - SHA256 (h, 64, m_H); - // x25519 between rs and priv - uint8_t inputKeyMaterial[32]; - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, ctx); // rs*priv - BN_CTX_free (ctx); - MixKey (inputKeyMaterial, derived); - } - - void NTCP2Session::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) - { - uint8_t h[64]; - memcpy (h, m_H, 32); - memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload - SHA256 (h, 64, h); - int paddingLength = sessionRequestLen - 64; - if (paddingLength > 0) - { - std::vector h1(paddingLength + 32); - memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, h); - } - memcpy (h + 32, pub, 32); - SHA256 (h, 64, m_H); - - // x25519 between remote pub and priv - uint8_t inputKeyMaterial[32]; - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, ctx); - BN_CTX_free (ctx); - MixKey (inputKeyMaterial, derived); - } void NTCP2Session::KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived) { uint8_t inputKeyMaterial[32]; BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (m_Y, staticPrivKey, inputKeyMaterial, ctx); + i2p::crypto::GetEd25519 ()->ScalarMul (m_Establisher->m_Y, staticPrivKey, inputKeyMaterial, ctx); BN_CTX_free (ctx); - MixKey (inputKeyMaterial, derived); + m_Establisher->MixKey (inputKeyMaterial, derived); } void NTCP2Session::KeyDerivationFunctionDataPhase () { uint8_t tempKey[32]; unsigned int len; - HMAC(EVP_sha256(), m_CK, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) + HMAC(EVP_sha256(), m_Establisher->GetCK (), 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen) static uint8_t one[1] = { 1 }; HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Kab, &len); // k_ab = HMAC-SHA256(temp_key, byte(0x01)). m_Kab[32] = 2; @@ -149,7 +153,7 @@ namespace transport static uint8_t ask[4] = { 'a', 's', 'k', 1 }, master[32]; HMAC(EVP_sha256(), tempKey, 32, ask, 4, master, &len); // ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01)) uint8_t h[39]; - memcpy (h, m_H, 32); + memcpy (h, m_Establisher->GetH (), 32); memcpy (h + 32, "siphash", 7); HMAC(EVP_sha256(), master, 32, h, 39, tempKey, &len); // temp_key = HMAC-SHA256(ask_master, h || "siphash") HMAC(EVP_sha256(), tempKey, 32, one, 1, master, &len); // sip_master = HMAC-SHA256(temp_key, byte(0x01)) @@ -159,13 +163,6 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_Sipkeysab, 33, m_Sipkeysba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02)) } - void NTCP2Session::CreateEphemeralKey (uint8_t * pub) - { - RAND_bytes (m_EphemeralPrivateKey, 32); - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, ctx); - BN_CTX_free (ctx); - } void NTCP2Session::SendSessionRequest () { @@ -176,16 +173,16 @@ namespace transport RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); // generate key pair (X) uint8_t x[32]; - CreateEphemeralKey (x); + m_Establisher->CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_IV); + encryption.SetIV (m_Establisher->m_IV); encryption.Encrypt (x, 32, m_SessionRequestBuffer); - encryption.GetIV (m_IV); // save IV for SessionCreated + encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // encryption key for next block uint8_t key[32]; - KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralPrivateKey, x, key); + m_Establisher->KeyDerivationFunction1 (m_Establisher->m_RemoteStaticKey, m_Establisher->m_EphemeralPrivateKey, x, key); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -198,7 +195,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -235,15 +232,15 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_SessionRequestBuffer, 32, m_Y); - decryption.GetIV (m_IV); // save IV for SessionCreated + decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->m_Y); + decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // decryption key for next block uint8_t key[32]; - KeyDerivationFunction1 (m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Y, key); + m_Establisher->KeyDerivationFunction1 (m_Establisher->m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Establisher->m_Y, key); // verify MAC and decrypt options block (32 bytes), use m_H as AD uint8_t nonce[12], options[16]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, key, nonce, options, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, key, nonce, options, 16, false)) // decrypt { if (options[1] == 2) { @@ -286,14 +283,14 @@ namespace transport m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size // generate key pair (y) uint8_t y[32]; - CreateEphemeralKey (y); + m_Establisher->CreateEphemeralKey (y); // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); - encryption.SetIV (m_IV); + encryption.SetIV (m_Establisher->m_IV); encryption.Encrypt (y, 32, m_SessionCreatedBuffer); // encryption key for next block (m_K) - KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); @@ -302,7 +299,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->m_H, 32, m_Establisher->m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message @@ -324,15 +321,15 @@ namespace transport // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - decryption.SetIV (m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y); + decryption.SetIV (m_Establisher->m_IV); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->m_Y); // decryption key for next block (m_K) - KeyDerivationFunction2 (m_EphemeralPrivateKey, m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_K); + m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->m_K, nonce, payload, 16, false)) // decrypt { uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); @@ -372,7 +369,7 @@ namespace transport { // update AD uint8_t h[80]; - memcpy (h, m_H, 32); + memcpy (h, m_Establisher->GetH (), 32); memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload SHA256 (h, 64, h); int paddingLength = m_SessionCreatedBufferLen - 64; @@ -387,11 +384,11 @@ namespace transport m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again memcpy (h + 32, m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_H); + SHA256 (h, 80, m_Establisher->m_H); size_t m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; std::vector buf(m3p2Len - 16); @@ -402,11 +399,11 @@ namespace transport uint8_t key[32]; KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey (), key); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_H, 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt uint8_t tmp[48]; memcpy (tmp, m_SessionConfirmedBuffer, 48); - memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext); + memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); memcpy (m_SessionConfirmedBuffer, tmp, 48); // send message diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 6ee76aad..38b7caf1 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "RouterInfo.h" #include "TransportSession.h" @@ -12,6 +13,25 @@ namespace i2p { namespace transport { + struct NTCP2Establisher + { + NTCP2Establisher () { m_Ctx = BN_CTX_new (); }; + ~NTCP2Establisher () { BN_CTX_free (m_Ctx); }; + + const uint8_t * GetCK () const { return m_CK; }; + const uint8_t * GetH () const { return m_H; }; + + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate + void CreateEphemeralKey (uint8_t * pub); + + BN_CTX * m_Ctx; + uint8_t m_EphemeralPrivateKey[32]; // x25519 + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; + + }; + class NTCP2Server; class NTCP2Session: public TransportSession, public std::enable_shared_from_this { @@ -30,15 +50,11 @@ namespace transport private: - void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void CreateNonce (uint64_t seqn, uint8_t * nonce); - void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest - void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void KeyDerivationFunctionDataPhase (); // establish - void CreateEphemeralKey (uint8_t * pub); void SendSessionRequest (); void SendSessionCreated (); void SendSessionConfirmed (); @@ -67,8 +83,7 @@ namespace transport boost::asio::ip::tcp::socket m_Socket; bool m_IsEstablished, m_IsTerminated; - uint8_t m_EphemeralPrivateKey[32]; // x25519 - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; + std::unique_ptr m_Establisher; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase From 5218c8584f37a0a89a95721637995c1cf1f4f1f9 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Jul 2018 14:15:40 -0400 Subject: [PATCH 113/195] some refactoring of NTCP2 code --- libi2pd/NTCP2.cpp | 110 +++++++++++++++++++++++++--------------------- libi2pd/NTCP2.h | 26 +++++++---- 2 files changed, 79 insertions(+), 57 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 5938d232..f0d15926 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -15,6 +15,17 @@ namespace i2p { namespace transport { + NTCP2Establisher::NTCP2Establisher () + { + m_Ctx = BN_CTX_new (); + CreateEphemeralKey (); + } + + NTCP2Establisher::~NTCP2Establisher () + { + BN_CTX_free (m_Ctx); + } + void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) { // temp_key = HMAC-SHA256(ck, input_key_material) @@ -28,7 +39,7 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } - void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived) + void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub) { static const uint8_t protocolNameHash[] = { @@ -50,10 +61,20 @@ namespace transport // x25519 between rs and priv uint8_t inputKeyMaterial[32]; i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv - MixKey (inputKeyMaterial, derived); + MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived) + void NTCP2Establisher::KDF1Alice () + { + KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ()); + } + + void NTCP2Establisher::KDF1Bob () + { + KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), GetRemotePub ()); + } + + void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) { uint8_t h[64]; memcpy (h, m_H, 32); @@ -62,24 +83,32 @@ namespace transport int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) { - std::vector h1(paddingLength + 32); - memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, sessionRequest + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, h); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, sessionRequest + 64, paddingLength); + SHA256_Final (h, &ctx); } - memcpy (h + 32, pub, 32); + memcpy (h + 32, GetRemotePub (), 32); SHA256 (h, 64, m_H); // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; - i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); - MixKey (inputKeyMaterial, derived); + i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), GetPriv (), inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::CreateEphemeralKey (uint8_t * pub) + void NTCP2Establisher::KeyDerivationFunction3 (const uint8_t * staticPrivKey) + { + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), staticPrivKey, inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, m_K); + } + + void NTCP2Establisher::CreateEphemeralKey () { RAND_bytes (m_EphemeralPrivateKey, 32); - i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, pub, m_Ctx); + i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): @@ -133,15 +162,6 @@ namespace transport } - void NTCP2Session::KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived) - { - uint8_t inputKeyMaterial[32]; - BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::GetEd25519 ()->ScalarMul (m_Establisher->m_Y, staticPrivKey, inputKeyMaterial, ctx); - BN_CTX_free (ctx); - m_Establisher->MixKey (inputKeyMaterial, derived); - } - void NTCP2Session::KeyDerivationFunctionDataPhase () { uint8_t tempKey[32]; unsigned int len; @@ -171,18 +191,14 @@ namespace transport m_SessionRequestBufferLen = paddingLength + 64; m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); - // generate key pair (X) - uint8_t x[32]; - m_Establisher->CreateEphemeralKey (x); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (x, 32, m_SessionRequestBuffer); + encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionRequestBuffer); // X encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // encryption key for next block - uint8_t key[32]; - m_Establisher->KeyDerivationFunction1 (m_Establisher->m_RemoteStaticKey, m_Establisher->m_EphemeralPrivateKey, x, key); + m_Establisher->KDF1Alice (); // fill options uint8_t options[32]; // actual options size is 16 bytes memset (options, 0, 16); @@ -195,7 +211,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -232,15 +248,14 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->m_Y); + decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // decryption key for next block - uint8_t key[32]; - m_Establisher->KeyDerivationFunction1 (m_Establisher->m_Y, i2p::context.GetNTCP2StaticPrivateKey (), m_Establisher->m_Y, key); + m_Establisher->KDF1Bob (); // verify MAC and decrypt options block (32 bytes), use m_H as AD uint8_t nonce[12], options[16]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, key, nonce, options, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt { if (options[1] == 2) { @@ -281,16 +296,13 @@ namespace transport void NTCP2Session::SendSessionCreated () { m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size - // generate key pair (y) - uint8_t y[32]; - m_Establisher->CreateEphemeralKey (y); // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (y, 32, m_SessionCreatedBuffer); + encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); + m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); @@ -299,7 +311,7 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->m_H, 32, m_Establisher->m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message @@ -322,14 +334,14 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_Establisher->m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->m_Y); + decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); // decryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_Establisher->m_EphemeralPrivateKey, m_Establisher->m_Y, m_SessionRequestBuffer, m_SessionRequestBufferLen, m_Establisher->m_K); + m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->m_K, nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt { uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); @@ -375,16 +387,17 @@ namespace transport int paddingLength = m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { - std::vector h1(paddingLength + 32); - memcpy (h1.data (), h, 32); - memcpy (h1.data () + 32, m_SessionCreatedBuffer + 64, paddingLength); - SHA256 (h1.data (), paddingLength + 32, h); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (h, &ctx); } // part1 48 bytes m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again memcpy (h + 32, m_SessionConfirmedBuffer, 48); @@ -396,10 +409,9 @@ namespace transport htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI buf[3] = 0; // flag memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); - uint8_t key[32]; - KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey (), key); + m_Establisher->KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey ()); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, key, nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt uint8_t tmp[48]; memcpy (tmp, m_SessionConfirmedBuffer, 48); memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 38b7caf1..cb4cc5d8 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -15,20 +15,31 @@ namespace transport { struct NTCP2Establisher { - NTCP2Establisher () { m_Ctx = BN_CTX_new (); }; - ~NTCP2Establisher () { BN_CTX_free (m_Ctx); }; + NTCP2Establisher (); + ~NTCP2Establisher (); + const uint8_t * GetPub () const { return m_EphemeralPublicKey; }; + const uint8_t * GetPriv () const { return m_EphemeralPrivateKey; }; + const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob + uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set + + const uint8_t * GetK () const { return m_K; }; const uint8_t * GetCK () const { return m_CK; }; const uint8_t * GetH () const { return m_H; }; + void KDF1Alice (); + void KDF1Bob (); + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); - void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub, uint8_t * derived); // for SessionRequest - void KeyDerivationFunction2 (const uint8_t * priv, const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate - void CreateEphemeralKey (uint8_t * pub); + void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest + void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate + void KeyDerivationFunction3 (const uint8_t * staticPrivKey); // for SessionConfirmed part 2 + void CreateEphemeralKey (); + BN_CTX * m_Ctx; - uint8_t m_EphemeralPrivateKey[32]; // x25519 - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /* derived after SessionCreated */, m_Y[32] /* or X for Bob */; + uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 + uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; }; @@ -51,7 +62,6 @@ namespace transport private: void CreateNonce (uint64_t seqn, uint8_t * nonce); - void KeyDerivationFunction3 (const uint8_t * staticPrivKey, uint8_t * derived); // for SessionConfirmed part 2 void KeyDerivationFunctionDataPhase (); // establish From 00c71dc26aa01d116a022b30161bc06a9b4ff417 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Jul 2018 15:56:23 -0400 Subject: [PATCH 114/195] handle SessionConfirmed --- libi2pd/NTCP2.cpp | 114 ++++++++++++++++++++++++++++++++++++++-------- libi2pd/NTCP2.h | 7 ++- 2 files changed, 101 insertions(+), 20 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f0d15926..36ebc0ca 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -98,10 +98,17 @@ namespace transport MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::KeyDerivationFunction3 (const uint8_t * staticPrivKey) + void NTCP2Establisher::KDF3Alice () { uint8_t inputKeyMaterial[32]; - i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), staticPrivKey, inputKeyMaterial, m_Ctx); + i2p::crypto::GetEd25519 ()->ScalarMul (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), inputKeyMaterial, m_Ctx); + MixKey (inputKeyMaterial, m_K); + } + + void NTCP2Establisher::KDF3Bob () + { + uint8_t inputKeyMaterial[32]; + i2p::crypto::GetEd25519 ()->ScalarMul (m_RemoteStaticKey, m_EphemeralPrivateKey, inputKeyMaterial, m_Ctx); MixKey (inputKeyMaterial, m_K); } @@ -204,7 +211,8 @@ namespace transport memset (options, 0, 16); options[1] = 2; // ver htobe16buf (options + 2, paddingLength); // padLen - htobe16buf (options + 4, i2p::context.GetRouterInfo ().GetBufferLen () + 20); // m3p2Len (RI header + RI + MAC for now) TODO: implement options + m_Establisher->m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options + htobe16buf (options + 4, m_Establisher->m3p2Len); // 2 bytes reserved htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA // 4 bytes reserved @@ -261,6 +269,7 @@ namespace transport { uint16_t paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; + m_Establisher->m3p2Len = bufbe16toh (options + 4); // TODO: check tsA if (paddingLen > 0) boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), @@ -315,7 +324,8 @@ namespace transport // fill padding RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, paddingLen + 64), boost::asio::transfer_all (), + m_SessionCreatedBufferLen = paddingLen + 64; + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -403,23 +413,22 @@ namespace transport memcpy (h + 32, m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_Establisher->m_H); - size_t m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; - std::vector buf(m3p2Len - 16); + std::vector buf(m_Establisher->m3p2Len - 16); // -MAC buf[0] = 2; // block htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI buf[3] = 0; // flag memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); - m_Establisher->KeyDerivationFunction3 (i2p::context.GetNTCP2StaticPrivateKey ()); + m_Establisher->KDF3Alice (); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt uint8_t tmp[48]; memcpy (tmp, m_SessionConfirmedBuffer, 48); memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); memcpy (m_SessionConfirmedBuffer, tmp, 48); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m3p2Len + 48), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -427,8 +436,13 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); //Alice - memcpy (m_SendIV, m_Sipkeysab + 16, 8); //Alice + // Alice + m_SendKey = m_Kab; + m_ReceiveKey = m_Kba; + m_SendSipKey = m_Sipkeysab; + m_ReceiveSipKey = m_Sipkeysba; + memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); + memcpy (m_SendIV, m_Sipkeysab + 16, 8); ReceiveLength (); // TODO: remove @@ -442,8 +456,72 @@ namespace transport void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); - Terminate (); // TODO + (void) bytes_transferred; + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: couldn't send SessionCreated message: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); + m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + } + + void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred) + { + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part 1 read error: ", ecode.message ()); + Terminate (); + } + else + { + LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part 1 received"); + // update AD + uint8_t h[80]; + memcpy (h, m_Establisher->GetH (), 32); + memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256 (h, 64, h); + int paddingLength = m_SessionCreatedBufferLen - 64; + if (paddingLength > 0) + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (h, &ctx); + } + // part 1 + uint8_t nonce[12]; + CreateNonce (1, nonce); + i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 48, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false); // decrypt S + // part 2 + // update AD again + memcpy (h + 32, m_SessionConfirmedBuffer, 48); + SHA256 (h, 80, m_Establisher->m_H); + + std::vector buf(m_Establisher->m3p2Len - 16); // -MAC + m_Establisher->KDF3Bob (); + memset (nonce, 0, 12); // set nonce to 0 again + i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt + // TODO: process RI and options + // caclulate new h again for KDF data + memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + KeyDerivationFunctionDataPhase (); + // Bob + m_SendKey = m_Kba; + m_ReceiveKey = m_Kab; + m_SendSipKey = m_Sipkeysba; + m_ReceiveSipKey = m_Sipkeysab; + memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); + memcpy (m_SendIV, m_Sipkeysba + 16, 8); + ReceiveLength (); + } } void NTCP2Session::ClientLogin () @@ -474,7 +552,7 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_Sipkeysba); // assume Alice TODO: + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); delete[] m_NextReceivedBuffer; @@ -501,7 +579,7 @@ namespace transport uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; - if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_Kba, nonce, decrypted, m_NextReceivedLen, false)) // decrypt. assume Alice TODO: + if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, decrypted, m_NextReceivedLen, false)) { LogPrint (eLogInfo, "NTCP2: received message decrypted"); ProcessNextFrame (decrypted, m_NextReceivedLen-16); @@ -540,8 +618,8 @@ namespace transport uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; m_NextSendBuffer = new uint8_t[len + 16 + 2]; - i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_Kab, nonce, m_NextSendBuffer + 2, len + 16, true); // encrypt. assume Alice TODO: - i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_Sipkeysab); // assume Alice TODO: + i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true); + i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_SendSipKey); htobuf16 (m_NextSendBuffer, bufbe16toh (m_SendIV) ^ htobe16(len + 16)); LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index cb4cc5d8..0576d3c2 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -33,14 +33,15 @@ namespace transport void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate - void KeyDerivationFunction3 (const uint8_t * staticPrivKey); // for SessionConfirmed part 2 + void KDF3Alice (); // for SessionConfirmed part 2 + void KDF3Bob (); void CreateEphemeralKey (); BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; - + uint16_t m3p2Len; }; class NTCP2Server; @@ -76,6 +77,7 @@ namespace transport void HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred); // data void ReceiveLength (); @@ -98,6 +100,7 @@ namespace transport size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; + const uint8_t * m_SendKey, * m_ReceiveKey, * m_SendSipKey, * m_ReceiveSipKey; uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; uint8_t m_ReceiveIV[8], m_SendIV[8]; From 52f3081a40d94b9944bb82b847be4e08eaf57c23 Mon Sep 17 00:00:00 2001 From: yangfl Date: Tue, 10 Jul 2018 17:39:21 +0800 Subject: [PATCH 115/195] fix typo --- ChangeLog | 4 ++-- build/CMakeLists.txt | 4 ++-- daemon/HTTPServer.cpp | 2 +- debian/i2pd.1 | 2 +- debian/rules | 2 +- docs/Doxyfile | 4 ++-- libi2pd/Destination.cpp | 2 +- libi2pd/NetDb.cpp | 2 +- libi2pd/Reseed.cpp | 2 +- libi2pd/Tunnel.cpp | 2 +- libi2pd_client/AddressBook.cpp | 2 +- libi2pd_client/HTTPProxy.cpp | 2 +- libi2pd_client/I2CP.cpp | 10 +++++----- libi2pd_client/SOCKS.cpp | 4 ++-- .../src/org/kde/necessitas/ministro/IMinistro.aidl | 2 +- .../org/qtproject/qt5/android/bindings/QtActivity.java | 2 +- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 54989d44..59a19a3c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -68,7 +68,7 @@ - NTCP soft and hard descriptors limits - Support full timestamps in logs ### Changed -- Faster implmentation of GOST R 34.11 hash +- Faster implementation of GOST R 34.11 hash - Reject routers with RSA signtures - Reload config and shudown from Windows GUI - Update tunnels address(destination) without restart @@ -168,7 +168,7 @@ - Initial iOS support ### Changed -- Reduced file descriptiors usage +- Reduced file descriptors usage - Strict reseed checks enabled by default ## Fixed diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 73e76ae0..5876a0f7 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -190,7 +190,7 @@ if (CXX11_SUPPORTED) elseif (CXX0X_SUPPORTED) # gcc 4.6 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" ) elseif (NOT MSVC) - message(SEND_ERROR "C++11 standart not seems to be supported by compiler. Too old version?") + message(SEND_ERROR "C++11 standard not seems to be supported by compiler. Too old version?") endif () if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") @@ -340,7 +340,7 @@ target_link_libraries(libi2pdclient libi2pd) find_package ( Boost COMPONENTS system filesystem program_options date_time REQUIRED ) if(NOT DEFINED Boost_INCLUDE_DIRS) - message(SEND_ERROR "Boost is not found, or your boost version was bellow 1.46. Please download Boost!") + message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") endif() find_package ( OpenSSL REQUIRED ) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index faf386d8..3fa23dfe 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -862,7 +862,7 @@ namespace http { { /* deny request as it's from a non whitelisted hostname */ res.code = 403; - content = "host missmatch"; + content = "host mismatch"; SendReply(res, content); return; } diff --git a/debian/i2pd.1 b/debian/i2pd.1 index 91e3b60f..9dd44093 100644 --- a/debian/i2pd.1 +++ b/debian/i2pd.1 @@ -96,7 +96,7 @@ Router will use system folders like \fI/var/lib/i2pd\fR (\fIdisabled\fR by defau \fB\-\-family=\fR Name of a family, router belongs to. .PP -Switchs, which enabled by default (like \fB\-\-ssu\fR, \fB\-\-ntcp\fR, etc.), can be disabled in config file. +Switches, which enabled by default (like \fB\-\-ssu\fR, \fB\-\-ntcp\fR, etc.), can be disabled in config file. .RE See service-specific parameters in example config file \fI/usr/share/doc/i2pd/i2pd.conf.gz\fR .SH "FILES" diff --git a/debian/rules b/debian/rules index 8e537049..77ecd7b7 100755 --- a/debian/rules +++ b/debian/rules @@ -17,6 +17,6 @@ DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow override_dh_strip: dh_strip --dbg-package=i2pd-dbg -## uncoment this if you have "missing info" problem when building package +## uncomment this if you have "missing info" problem when building package #override_dh_shlibdeps: # dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info diff --git a/docs/Doxyfile b/docs/Doxyfile index c434d2dc..275d668e 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1094,7 +1094,7 @@ HTML_STYLESHEET = # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. +# standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra stylesheet files is of importance (e.g. the last # stylesheet in the list overrules the setting of the previous ones in the @@ -1637,7 +1637,7 @@ EXTRA_PACKAGES = # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, # $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty string, # for the replacement values of the other commands the user is referred to # HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index d3632881..ad7725fc 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -64,7 +64,7 @@ namespace client { it = params->find (I2CP_PARAM_OUTBOUND_NICKNAME); if (it != params->end ()) m_Nickname = it->second; - // otherwise we set deafult nickname in Start when we know local address + // otherwise we set default nickname in Start when we know local address } } } diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index b136dfd5..410b71e6 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -734,7 +734,7 @@ namespace data m_Requests.RequestComplete (ident, nullptr); } else - // no more requests for detination possible. delete it + // no more requests for destination possible. delete it m_Requests.RequestComplete (ident, nullptr); } else if(!m_FloodfillBootstrap) diff --git a/libi2pd/Reseed.cpp b/libi2pd/Reseed.cpp index 4a2f8055..eebe9b38 100644 --- a/libi2pd/Reseed.cpp +++ b/libi2pd/Reseed.cpp @@ -300,7 +300,7 @@ namespace data s.read (localFileName, fileNameLength); localFileName[fileNameLength] = 0; s.seekg (extraFieldLength, std::ios::cur); - // take care about data desriptor if presented + // take care about data descriptor if presented if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) { size_t pos = s.tellg (); diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index c7e1b1b4..66620717 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -511,7 +511,7 @@ namespace tunnel HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); break; default: - LogPrint (eLogWarning, "Tunnel: unexpected messsage type ", (int) typeID); + LogPrint (eLogWarning, "Tunnel: unexpected message type ", (int) typeID); } msg = m_Queue.Get (); diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index f29ecee3..bca0e25b 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -377,7 +377,7 @@ namespace client } numAddresses++; auto it = m_Addresses.find (name); - if (it != m_Addresses.end ()) // aleady exists ? + if (it != m_Addresses.end ()) // already exists ? { if (it->second != ident->GetIdentHash ()) // address changed? { diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index ea95a6bd..f0530ac1 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -387,7 +387,7 @@ namespace proxy { LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host); m_ClientRequestURL.schema = ""; m_ClientRequestURL.host = ""; - std::string origURI = m_ClientRequest.uri; // TODO: what do we need to chage uri for? + std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); m_ClientRequest.write(m_ClientRequestBuffer); diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index b08fded1..7d7ce558 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -250,7 +250,7 @@ namespace client if (handler) (this->*handler)(m_Payload, m_PayloadLen); else - LogPrint (eLogError, "I2CP: Unknown I2CP messsage ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]); + LogPrint (eLogError, "I2CP: Unknown I2CP message ", (int)m_Header[I2CP_HEADER_TYPE_OFFSET]); } void I2CPSession::Terminate () @@ -398,7 +398,7 @@ namespace client } else { - LogPrint (eLogError, "I2CP: create session signature verification falied"); + LogPrint (eLogError, "I2CP: create session signature verification failed"); SendSessionStatusMessage (3); // invalid } } @@ -455,16 +455,16 @@ namespace client LogPrint(eLogError, "I2CP: invalid reconfigure message signature"); } else - LogPrint(eLogError, "I2CP: mapping size missmatch"); + LogPrint(eLogError, "I2CP: mapping size mismatch"); } else - LogPrint(eLogError, "I2CP: destination missmatch"); + LogPrint(eLogError, "I2CP: destination mismatch"); } else LogPrint(eLogError, "I2CP: malfromed destination"); } else - LogPrint(eLogError, "I2CP: session missmatch"); + LogPrint(eLogError, "I2CP: session mismatch"); } else LogPrint(eLogError, "I2CP: short message"); diff --git a/libi2pd_client/SOCKS.cpp b/libi2pd_client/SOCKS.cpp index ddf4bbe9..8a67901c 100644 --- a/libi2pd_client/SOCKS.cpp +++ b/libi2pd_client/SOCKS.cpp @@ -84,8 +84,8 @@ namespace proxy SOCKS5_HOST_UNREACH = 4, // Host unreachable SOCKS5_CONN_REFUSED = 5, // Connection refused by the peer SOCKS5_TTL_EXPIRED = 6, // TTL Expired - SOCKS5_CMD_UNSUP = 7, // Command unsuported - SOCKS5_ADDR_UNSUP = 8, // Address type unsuported + SOCKS5_CMD_UNSUP = 7, // Command unsupported + SOCKS5_ADDR_UNSUP = 8, // Address type unsupported SOCKS4_OK = 90, // No error for SOCKS4 SOCKS4_FAIL = 91, // Failed establishing connecting or not allowed SOCKS4_IDENTD_MISSING = 92, // Couldn't connect to the identd server diff --git a/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl b/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl index bbd8116d..e23cb699 100644 --- a/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl +++ b/qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl @@ -51,7 +51,7 @@ interface IMinistro * "sources" StringArray Sources list from where Ministro will download the libs. Make sure you are using ONLY secure locations. * "repository" String Overwrites the default Ministro repository. Possible values: default, stable, testing and unstable * "required.modules" StringArray Required modules by your application -* "application.title" String Application name, used to show more informations to user +* "application.title" String Application name, used to show more information to user * "qt.provider" String Qt libs provider, currently only "necessitas" is supported. * "minimum.ministro.api" Integer Minimum Ministro API level, used to check if Ministro service compatible with your application. Current API Level is 3 ! * "minimum.qt.version" Integer Minimim Qt version (e.g. 0x040800, which means Qt 4.8.0, check http://qt-project.org/doc/qt-4.8/qtglobal.html#QT_VERSION)! diff --git a/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java b/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java index 677e8f46..9c607109 100644 --- a/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -97,7 +97,7 @@ import android.view.ActionMode.Callback; public class QtActivity extends Activity { - private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro instalation is finished + private final static int MINISTRO_INSTALL_REQUEST_CODE = 0xf3ee; // request code used to know when Ministro installation is finished private static final int MINISTRO_API_LEVEL = 5; // Ministro api level (check IMinistro.aidl file) private static final int NECESSITAS_API_LEVEL = 2; // Necessitas api level used by platform plugin private static final int QT_VERSION = 0x050100; // This app requires at least Qt version 5.1.0 From 5575b981c85a6bab605cd4ed63b73c1c5eeff76b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 13 Jul 2018 15:59:28 -0400 Subject: [PATCH 116/195] enable NTCP2 as transport --- libi2pd/NTCP2.cpp | 10 ++++++++++ libi2pd/NTCP2.h | 2 ++ libi2pd/Transports.cpp | 24 +++++++++++++++++++++++- libi2pd/Transports.h | 3 +++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 36ebc0ca..a5e70c24 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -9,6 +9,7 @@ #include "Ed25519.h" #include "Siphash.h" #include "RouterContext.h" +#include "Transports.h" #include "NTCP2.h" namespace i2p @@ -162,6 +163,13 @@ namespace transport m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); } + void NTCP2Session::Established () + { + m_IsEstablished = true; + m_Establisher.reset (nullptr); + transports.PeerConnected (shared_from_this ()); + } + void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) { memset (nonce, 0, 4); @@ -443,6 +451,7 @@ namespace transport m_ReceiveSipKey = m_Sipkeysba; memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); memcpy (m_SendIV, m_Sipkeysab + 16, 8); + Established (); ReceiveLength (); // TODO: remove @@ -520,6 +529,7 @@ namespace transport m_ReceiveSipKey = m_Sipkeysab; memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); memcpy (m_SendIV, m_Sipkeysba + 16, 8); + Established (); ReceiveLength (); } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 0576d3c2..167b0528 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -62,6 +62,8 @@ namespace transport private: + void Established (); + void CreateNonce (uint64_t seqn, uint8_t * nonce); void KeyDerivationFunctionDataPhase (); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 9914c75e..32f1dc30 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -117,7 +117,8 @@ namespace transport Transports::Transports (): m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), - m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys + m_NTCPServer (nullptr), m_SSUServer (nullptr), m_NTCP2Server (nullptr), + m_DHKeysPairSupplier (5), // 5 pre-generated keys m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0), m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), @@ -191,6 +192,13 @@ namespace transport LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy); return; } + // create NTCP2. TODO: move to acceptor + bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + if (ntcp2) + { + m_NTCP2Server = new NTCP2Server (); + m_NTCP2Server->Start (); + } // create acceptors auto& addresses = context.GetRouterInfo ().GetAddresses (); @@ -262,6 +270,13 @@ namespace transport m_NTCPServer = nullptr; } + if (m_NTCP2Server) + { + m_NTCP2Server->Stop (); + delete m_NTCP2Server; + m_NTCP2Server = nullptr; + } + m_DHKeysPairSupplier.Stop (); m_IsRunning = false; if (m_Service) m_Service->stop (); @@ -390,6 +405,13 @@ namespace transport { peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); + if (address && address->IsNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled + { + auto s = std::make_shared (*m_NTCP2Server, peer.router); + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } + if (address && m_NTCPServer) { #if BOOST_VERSION >= 104900 diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index d4410cb3..47944fff 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -15,6 +15,7 @@ #include "TransportSession.h" #include "NTCPSession.h" #include "SSU.h" +#include "NTCP2.h" #include "RouterInfo.h" #include "I2NPProtocol.h" #include "Identity.h" @@ -154,6 +155,7 @@ namespace transport NTCPServer * m_NTCPServer; SSUServer * m_SSUServer; + NTCP2Server * m_NTCP2Server; mutable std::mutex m_PeersMutex; std::map m_Peers; @@ -179,6 +181,7 @@ namespace transport // for HTTP only const NTCPServer * GetNTCPServer () const { return m_NTCPServer; }; const SSUServer * GetSSUServer () const { return m_SSUServer; }; + const NTCP2Server * GetNTCP2Server () const { return m_NTCP2Server; }; const decltype(m_Peers)& GetPeers () const { return m_Peers; }; }; From 8c5111e11a25568befa87e2f107d0f7422de79a7 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 17 Jul 2018 15:17:05 -0400 Subject: [PATCH 117/195] handle NTCP2 I2NP messages --- libi2pd/I2NPProtocol.h | 20 ++++++++++++++++++++ libi2pd/NTCP2.cpp | 33 ++++++++++++++++++++++++++++++++- libi2pd/NTCP2.h | 12 ++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index f394d284..01b474be 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -26,6 +26,9 @@ namespace i2p const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1; const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4; + // I2NP NTCP2 header + const size_t I2NP_NTCP2_HEADER_SIZE = I2NP_HEADER_EXPIRATION_OFFSET + 4; + // Tunnel Gateway header const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0; const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4; @@ -194,6 +197,23 @@ namespace tunnel len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET); return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET); } + // for NTCP2 only + uint8_t * GetNTCP2Header () { return GetPayload () - I2NP_NTCP2_HEADER_SIZE; }; + void FromNTCP2 () + { + const uint8_t * ntcp2 = GetNTCP2Header (); + memcpy (GetHeader () + I2NP_HEADER_TYPEID_OFFSET, ntcp2 + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid + SetExpiration (bufbe32toh (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET)*1000LL); + SetSize (len - offset - I2NP_HEADER_SIZE); + SetChks (0); + } + + void ToNTCP2 () + { + uint8_t * ntcp2 = GetNTCP2Header (); + htobe32buf (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET, bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL); + memcpy (ntcp2 + I2NP_HEADER_TYPEID_OFFSET, GetHeader () + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid + } void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0); void RenewI2NPMessageHeader (); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a5e70c24..3a6aa1c6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -167,7 +167,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); - transports.PeerConnected (shared_from_this ()); + // transports.PeerConnected (shared_from_this ()); } void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) @@ -619,8 +619,39 @@ namespace transport LogPrint (eLogError, "NTCP2: Unexpected block length ", size); break; } + switch (blk) + { + case eNTCP2BlkDateTime: + LogPrint (eLogDebug, "NTCP2: datetime"); + break; + case eNTCP2BlkOptions: + LogPrint (eLogDebug, "NTCP2: options"); + break; + case eNTCP2BlkRouterInfo: + LogPrint (eLogDebug, "NTCP2: RouterInfo"); + break; + case eNTCP2BlkI2NPMessage: + { + LogPrint (eLogDebug, "NTCP2: I2NP"); + auto nextMsg = NewI2NPMessage (size); + nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header + memcpy (nextMsg->GetNTCP2Header (), frame + offset, size); + nextMsg->FromNTCP2 (); + m_Handler.PutNextMessage (nextMsg); + break; + } + case eNTCP2BlkTermination: + LogPrint (eLogDebug, "NTCP2: termination"); + break; + case eNTCP2BlkPadding: + LogPrint (eLogDebug, "NTCP2: padding"); + break; + default: + LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk); + } offset += size; } + m_Handler.Flush (); } void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 167b0528..8ce0ba6d 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -13,6 +13,16 @@ namespace i2p { namespace transport { + enum NTCP2BlockType + { + eNTCP2BlkDateTime = 0, + eNTCP2BlkOptions, // 1 + eNTCP2BlkRouterInfo, // 2 + eNTCP2BlkI2NPMessage, // 3 + eNTCP2BlkTermination, // 4 + eNTCP2BlkPadding = 254 + }; + struct NTCP2Establisher { NTCP2Establisher (); @@ -107,6 +117,8 @@ namespace transport uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; uint8_t m_ReceiveIV[8], m_SendIV[8]; uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; + + i2p::I2NPMessagesHandler m_Handler; }; class NTCP2Server From f38891cace7c63e3d1ba990046b6d828472a1d75 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 11:15:27 -0400 Subject: [PATCH 118/195] fixed build for gcc < 4.8 --- libi2pd/Poly1305.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index 5378d3cb..fdfee5bc 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -133,9 +133,14 @@ namespace crypto struct Poly1305 { - +#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8 + Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0) + { + memset (m_H, 0, sizeof (m_H)); +#else Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) { +#endif m_R.PutKey(key); m_Pad.Put(key + 16); } From b99f8285830112ec92c7ae5d588347ff14918534 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 11:16:40 -0400 Subject: [PATCH 119/195] send I2NP messages through NTCP2 --- libi2pd/I2NPProtocol.h | 1 + libi2pd/NTCP2.cpp | 61 ++++++++++++++++++++++++++++++++++++------ libi2pd/NTCP2.h | 10 ++++++- 3 files changed, 63 insertions(+), 9 deletions(-) diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 01b474be..deaa2292 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -199,6 +199,7 @@ namespace tunnel } // for NTCP2 only uint8_t * GetNTCP2Header () { return GetPayload () - I2NP_NTCP2_HEADER_SIZE; }; + size_t GetNTCP2Length () const { return GetPayloadLength () + I2NP_NTCP2_HEADER_SIZE; }; void FromNTCP2 () { const uint8_t * ntcp2 = GetNTCP2Header (); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 3a6aa1c6..fe277a63 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -125,7 +125,7 @@ namespace transport m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), - m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0) + m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { m_Establisher.reset (new NTCP2Establisher); auto addr = in_RemoteRouter->GetNTCPAddress (); @@ -167,7 +167,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); - // transports.PeerConnected (shared_from_this ()); + transports.PeerConnected (shared_from_this ()); } void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) @@ -455,12 +455,8 @@ namespace transport ReceiveLength (); // TODO: remove - uint8_t pad[1024]; - auto paddingLength = rand () % 1000; - RAND_bytes (pad + 3, paddingLength); - pad[0] = 254; - htobe16buf (pad + 1, paddingLength); - SendNextFrame (pad, paddingLength + 3); + //m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); + //SendQueue (); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -665,6 +661,7 @@ namespace transport LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); // send message + m_IsSending = true; boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, len + 16 + 2), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleNextFrameSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -673,6 +670,54 @@ namespace transport { delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; LogPrint (eLogDebug, "NTCP2: Next frame sent"); + m_IsSending = false; + SendQueue (); + } + + void NTCP2Session::SendQueue () + { + if (!m_SendQueue.empty ()) + { + uint8_t * payload = new uint8_t[NTCP2_UNENCRYPTED_FRAME_MAX_SIZE]; + size_t s = 0; + // add I2NP blocks + while (!m_SendQueue.empty ()) + { + auto msg = m_SendQueue.front (); + size_t len = msg->GetNTCP2Length (); + if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header + { + payload[s] = eNTCP2BlkI2NPMessage; // blk + htobe16buf (payload + s + 1, len); // size + s += 3; + msg->ToNTCP2 (); + memcpy (payload + s, msg->GetNTCP2Header (), len); + s += len; + m_SendQueue.pop_front (); + } + else + break; + } + // add padding block + int paddingSize = (s*NTCP2_MAX_PADDING_RATIO)/100; + if (s + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - s -3; + if (paddingSize) paddingSize = rand () % paddingSize; + payload[s] = eNTCP2BlkPadding; // blk + htobe16buf (payload + s + 1, paddingSize); // size + s += 3; + RAND_bytes (payload + s, paddingSize); + s += paddingSize; + // send + SendNextFrame (payload, s); + delete[] payload; + } + } + + void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) + { + for (auto it: msgs) + m_SendQueue.push_back (it); + if (!m_IsSending) SendQueue (); } NTCP2Server::NTCP2Server (): diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 8ce0ba6d..1e04587a 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "RouterInfo.h" @@ -13,6 +14,9 @@ namespace i2p { namespace transport { + + const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; + const int NTCP2_MAX_PADDING_RATIO = 6; // in % enum NTCP2BlockType { eNTCP2BlkDateTime = 0, @@ -68,7 +72,7 @@ namespace transport void ClientLogin (); // Alice void ServerLogin (); // Bob - void SendI2NPMessages (const std::vector >& msgs) {}; // TODO + void SendI2NPMessages (const std::vector >& msgs); private: @@ -100,6 +104,7 @@ namespace transport void SendNextFrame (const uint8_t * payload, size_t len); void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void SendQueue (); private: @@ -119,6 +124,9 @@ namespace transport uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; i2p::I2NPMessagesHandler m_Handler; + + bool m_IsSending; + std::list > m_SendQueue; }; class NTCP2Server From fc52b2b94098fcdb400f727de7fd101f884c7c1d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 12:56:46 -0400 Subject: [PATCH 120/195] fixed typo --- libi2pd/Poly1305.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index fdfee5bc..9ee46640 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -136,7 +136,7 @@ namespace crypto #if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8 Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0) { - memset (m_H, 0, sizeof (m_H)); + memset (&m_H, 0, sizeof (m_H)); #else Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) { From 910a9600bd8f4a04f71de36910cb051637c46a97 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 12:58:29 -0400 Subject: [PATCH 121/195] display NTCP2 session in web console --- daemon/HTTPServer.cpp | 91 +++++++++++++++++++++++++------------------ libi2pd/NTCP2.cpp | 45 ++++++++++++++++++++- libi2pd/NTCP2.h | 14 +++++++ 3 files changed, 112 insertions(+), 38 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 3fa23dfe..c9d6ba40 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -259,6 +259,12 @@ namespace http { s << "Our external address:" << "
\r\n" ; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { + if (address->IsNTCP2 ()) + { + // TODO: show actual address + s << "NTCP2   supported
\r\n"; + continue; + } switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: @@ -540,6 +546,46 @@ namespace http { } } + template + static void ShowNTCPTransports (std::stringstream& s, const Sessions& sessions, const std::string name) + { + std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; + for (const auto& it: sessions ) + { + if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + { + // incoming connection doesn't have remote RI + if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; + tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " + << it.second->GetSocket ().remote_endpoint().address ().to_string (); + if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; + tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + tmp_s << "
\r\n" << std::endl; + cnt++; + } + if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) + { + if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; + tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " + << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; + if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; + tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; + tmp_s6 << "
\r\n" << std::endl; + cnt6++; + } + } + if (!tmp_s.str ().empty ()) + { + s << "
\r\n\r\n

"; + s << tmp_s.str () << "

\r\n
\r\n"; + } + if (!tmp_s6.str ().empty ()) + { + s << "
\r\n\r\n

"; + s << tmp_s6.str () << "

\r\n
\r\n"; + } + } + void ShowTransports (std::stringstream& s) { s << "Transports:
\r\n
\r\n"; @@ -548,43 +594,14 @@ namespace http { { auto sessions = ntcpServer->GetNTCPSessions (); if (!sessions.empty ()) - { - std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; - for (const auto& it: sessions ) - { - if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) - { - // incoming connection doesn't have remote RI - if (it.second->IsOutgoing ()) tmp_s << " ⇒ "; - tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << it.second->GetSocket ().remote_endpoint().address ().to_string (); - if (!it.second->IsOutgoing ()) tmp_s << " ⇒ "; - tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - tmp_s << "
\r\n" << std::endl; - cnt++; - } - if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ()) - { - if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; - tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " - << "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]"; - if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ "; - tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; - tmp_s6 << "
\r\n" << std::endl; - cnt6++; - } - } - if (!tmp_s.str ().empty ()) - { - s << "
\r\n\r\n

"; - s << tmp_s.str () << "

\r\n
\r\n"; - } - if (!tmp_s6.str ().empty ()) - { - s << "
\r\n\r\n

"; - s << tmp_s6.str () << "

\r\n
\r\n"; - } - } + ShowNTCPTransports (s, sessions, "NTCP"); + } + auto ntcp2Server = i2p::transport::transports.GetNTCP2Server (); + if (ntcp2Server) + { + auto sessions = ntcp2Server->GetNTCP2Sessions (); + if (!sessions.empty ()) + ShowNTCPTransports (s, sessions, "NTCP2"); } auto ssuServer = i2p::transport::transports.GetSSUServer (); if (ssuServer) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index fe277a63..07ae9b99 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -154,6 +154,9 @@ namespace transport m_IsTerminated = true; m_IsEstablished = false; m_Socket.close (); + transports.PeerDisconnected (shared_from_this ()); + m_Server.RemoveNTCP2Session (shared_from_this ()); + m_SendQueue.clear (); LogPrint (eLogDebug, "NTCP2: session terminated"); } } @@ -741,6 +744,14 @@ namespace transport void NTCP2Server::Stop () { + { + // we have to copy it because Terminate changes m_NTCP2Sessions + auto ntcpSessions = m_NTCP2Sessions; + for (auto& it: ntcpSessions) + it.second->Terminate (); + } + m_NTCP2Sessions.clear (); + if (m_IsRunning) { m_IsRunning = false; @@ -769,12 +780,44 @@ namespace transport } } + bool NTCP2Server::AddNTCP2Session (std::shared_ptr session) + { + if (!session || !session->GetRemoteIdentity ()) return false; + auto& ident = session->GetRemoteIdentity ()->GetIdentHash (); + auto it = m_NTCP2Sessions.find (ident); + if (it != m_NTCP2Sessions.end ()) + { + LogPrint (eLogWarning, "NTCP2: session to ", ident.ToBase64 (), " already exists"); + session->Terminate(); + return false; + } + m_NTCP2Sessions.insert (std::make_pair (ident, session)); + return true; + } + + void NTCP2Server::RemoveNTCP2Session (std::shared_ptr session) + { + if (session && session->GetRemoteIdentity ()) + m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ()); + } + + std::shared_ptr NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident) + { + auto it = m_NTCP2Sessions.find (ident); + if (it != m_NTCP2Sessions.end ()) + return it->second; + return nullptr; + } + void NTCP2Server::Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn) { LogPrint (eLogDebug, "NTCP2: Connecting to ", address ,":", port); m_Service.post([this, address, port, conn]() { - conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + if (this->AddNTCP2Session (conn)) + { + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + } }); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1e04587a..34d8b943 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "RouterInfo.h" @@ -70,6 +71,9 @@ namespace transport boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; + bool IsEstablished () const { return m_IsEstablished; }; + bool IsTerminated () const { return m_IsTerminated; }; + void ClientLogin (); // Alice void ServerLogin (); // Bob void SendI2NPMessages (const std::vector >& msgs); @@ -139,6 +143,10 @@ namespace transport void Start (); void Stop (); + bool AddNTCP2Session (std::shared_ptr session); + void RemoveNTCP2Session (std::shared_ptr session); + std::shared_ptr FindNTCP2Session (const i2p::data::IdentHash& ident); + boost::asio::io_service& GetService () { return m_Service; }; void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); @@ -154,6 +162,12 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + std::map > m_NTCP2Sessions; + + public: + + // for HTTP/I2PControl + const decltype(m_NTCP2Sessions)& GetNTCP2Sessions () const { return m_NTCP2Sessions; }; }; } } From e0790700cddadbf27f1cbb1945d7c3b341ade00b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 14:19:12 -0400 Subject: [PATCH 122/195] don't connect to unpublished NTCP2 addresses --- libi2pd/NTCP2.cpp | 2 +- libi2pd/RouterInfo.cpp | 3 ++- libi2pd/RouterInfo.h | 2 ++ libi2pd/Transports.cpp | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 07ae9b99..85c7c7ac 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -590,7 +590,7 @@ namespace transport uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, decrypted, m_NextReceivedLen, false)) { - LogPrint (eLogInfo, "NTCP2: received message decrypted"); + LogPrint (eLogDebug, "NTCP2: received message decrypted"); ProcessNextFrame (decrypted, m_NextReceivedLen-16); ReceiveLength (); } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index a0b818fb..535c7bd8 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -259,6 +259,7 @@ namespace data if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); + address->ntcp2->isPublished = true; // presence if "i" means "published" } else if (key[0] == 'i') { @@ -292,7 +293,7 @@ namespace data if (!s) return; } if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented - if (supportedTransports && !isNtcp2) // we ignore NTCP2 addresses for now. TODO: + if (supportedTransports && (!isNtcp2 || address->IsPublishedNTCP2 ())) // we ignore unpublished NTCP2 only addresses { addresses->push_back(address); m_SupportedTransports |= supportedTransports; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index a12b23e3..07cc3af4 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -94,6 +94,7 @@ namespace data { Tag<32> staticKey; Tag<16> iv; + bool isPublished = false; }; struct Address @@ -124,6 +125,7 @@ namespace data } bool IsNTCP2 () const { return (bool)ntcp2; }; + bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; }; typedef std::list > Addresses; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 32f1dc30..5f2747a6 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -405,7 +405,7 @@ namespace transport { peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); - if (address && address->IsNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled + if (address && address->IsPublishedNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled { auto s = std::make_shared (*m_NTCP2Server, peer.router); m_NTCP2Server->Connect (address->host, address->port, s); From d9685e991e6b20d39bda87c1268334896058dd48 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 15:57:18 -0400 Subject: [PATCH 123/195] handle RouterInfo block --- libi2pd/NTCP2.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 85c7c7ac..5bb866cf 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -10,6 +10,7 @@ #include "Siphash.h" #include "RouterContext.h" #include "Transports.h" +#include "NetDb.hpp" #include "NTCP2.h" namespace i2p @@ -516,7 +517,21 @@ namespace transport m_Establisher->KDF3Bob (); memset (nonce, 0, 12); // set nonce to 0 again i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt - // TODO: process RI and options + // process RI + if (buf[0] == eNTCP2BlkRouterInfo) + { + auto size = bufbe16toh (buf.data () + 1); + if (size <= buf.size () - 3) + { + // TODO: check flag + i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + // TODO: process options + } + else + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + } + else + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); // caclulate new h again for KDF data memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); @@ -585,6 +600,8 @@ namespace transport } else { + m_NumReceivedBytes += bytes_transferred + 2; // + length + i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; @@ -627,8 +644,11 @@ namespace transport LogPrint (eLogDebug, "NTCP2: options"); break; case eNTCP2BlkRouterInfo: - LogPrint (eLogDebug, "NTCP2: RouterInfo"); - break; + { + LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", frame[offset]); + i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); + break; + } case eNTCP2BlkI2NPMessage: { LogPrint (eLogDebug, "NTCP2: I2NP"); @@ -671,6 +691,8 @@ namespace transport void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + m_NumSentBytes += bytes_transferred; + i2p::transport::transports.UpdateSentBytes (bytes_transferred); delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; LogPrint (eLogDebug, "NTCP2: Next frame sent"); m_IsSending = false; From 66bf4314818facb2485e97a652beb324bf75ee46 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Jul 2018 16:27:43 -0400 Subject: [PATCH 124/195] correct KDF1 calculation --- libi2pd/NTCP2.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 5bb866cf..4421f237 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -48,13 +48,15 @@ namespace transport 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") - static uint8_t h[64] = + static const uint8_t hh[32] = { 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e }; // SHA256 (protocolNameHash) memcpy (m_CK, protocolNameHash, 32); // h = SHA256(h || rs) + uint8_t h[64]; + memcpy (h, hh, 32); memcpy (h + 32, rs, 32); SHA256 (h, 64, h); // h = SHA256(h || pub) @@ -645,7 +647,7 @@ namespace transport break; case eNTCP2BlkRouterInfo: { - LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", frame[offset]); + LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); break; } From f6495e59c5ac50a94da2962e0b67accaad23b10c Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jul 2018 09:27:59 -0400 Subject: [PATCH 125/195] better MixHash --- libi2pd/NTCP2.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 4421f237..61d20ed8 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -54,14 +54,17 @@ namespace transport 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e }; // SHA256 (protocolNameHash) memcpy (m_CK, protocolNameHash, 32); - // h = SHA256(h || rs) - uint8_t h[64]; - memcpy (h, hh, 32); - memcpy (h + 32, rs, 32); - SHA256 (h, 64, h); + // h = SHA256(hh || rs) + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, hh, 32); + SHA256_Update (&ctx, rs, 32); + SHA256_Final (m_H, &ctx); // h = SHA256(h || pub) - memcpy (h + 32, pub, 32); - SHA256 (h, 64, m_H); + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, pub, 32); + SHA256_Final (m_H, &ctx); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv @@ -79,22 +82,25 @@ namespace transport } void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) - { - uint8_t h[64]; - memcpy (h, m_H, 32); - memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload - SHA256 (h, 64, h); + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, sessionRequest + 32, 32); // encrypted payload + SHA256_Final (m_H, &ctx); + int paddingLength = sessionRequestLen - 64; if (paddingLength > 0) { - SHA256_CTX ctx; SHA256_Init (&ctx); - SHA256_Update (&ctx, h, 32); + SHA256_Update (&ctx, m_H, 32); SHA256_Update (&ctx, sessionRequest + 64, paddingLength); - SHA256_Final (h, &ctx); + SHA256_Final (m_H, &ctx); } - memcpy (h + 32, GetRemotePub (), 32); - SHA256 (h, 64, m_H); + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, GetRemotePub (), 32); + SHA256_Final (m_H, &ctx); // x25519 between remote pub and priv uint8_t inputKeyMaterial[32]; From 5001592fb4c45fbffc9fd1c718181ee5ff0ec6c2 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jul 2018 09:45:24 -0400 Subject: [PATCH 126/195] replace ntcp2 by ntcp2.enabled --- libi2pd/Config.cpp | 7 ++++++- libi2pd/RouterContext.cpp | 4 ++-- libi2pd/Transports.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 1ff55dd6..3233c875 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -59,7 +59,6 @@ namespace config { ("ntcp", value()->default_value(true), "Enable NTCP transport (default: enabled)") ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Proxy URL for NTCP transport") - ("ntcp2", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") ("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)") @@ -232,6 +231,11 @@ namespace config { ("exploratory.outbound.quantity", value()->default_value(3), "Exploratory outbound tunnels quantity") ; + options_description ntcp2("NTCP2 Options"); + ntcp2.add_options() + ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") + ; + m_OptionsDesc .add(general) .add(limits) @@ -249,6 +253,7 @@ namespace config { .add(trust) .add(websocket) .add(exploratory) + .add(ntcp2) ; } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9bd6da9f..48fe400f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -50,7 +50,7 @@ namespace i2p port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv6; i2p::config::GetOption("ipv6", ipv6); - bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool nat; i2p::config::GetOption("nat", nat); std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname4; i2p::config::GetOption("ifname4", ifname4); @@ -452,7 +452,7 @@ namespace i2p SetReachable (); // we assume reachable until we discover firewall through peer tests // read NTCP2 - bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 5f2747a6..e4a3021b 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -193,7 +193,7 @@ namespace transport return; } // create NTCP2. TODO: move to acceptor - bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { m_NTCP2Server = new NTCP2Server (); From 5bedfc1c84a987339d826de7c5e789c5c146ccbb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Jul 2018 12:46:19 -0400 Subject: [PATCH 127/195] post I2NP messages to NTCP2 thread --- libi2pd/NTCP2.cpp | 9 ++++++++- libi2pd/NTCP2.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 61d20ed8..94f0641e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -748,9 +748,16 @@ namespace transport void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) { + m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); + } + + void NTCP2Session::PostI2NPMessages (std::vector > msgs) + { + if (m_IsTerminated) return; for (auto it: msgs) m_SendQueue.push_back (it); - if (!m_IsSending) SendQueue (); + if (!m_IsSending) + SendQueue (); } NTCP2Server::NTCP2Server (): diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 34d8b943..c14c6876 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -109,6 +109,7 @@ namespace transport void SendNextFrame (const uint8_t * payload, size_t len); void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendQueue (); + void PostI2NPMessages (std::vector > msgs); private: From 460cf6fd20eab9497a5a898b23dd7cc7975cc5b8 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 20 Jul 2018 22:55:41 +0300 Subject: [PATCH 128/195] update windows build script, change makefile.mingw line ending --- Makefile.mingw | 108 +++++++++++++++++++++--------------------- build/build_mingw.cmd | 8 ++-- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Makefile.mingw b/Makefile.mingw index 5dae3723..5f3292d1 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,54 +1,54 @@ -USE_WIN32_APP=yes -CXX = g++ -WINDRES = windres -CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -NEEDED_CXXFLAGS = -std=c++11 -BOOST_SUFFIX = -mt -INCFLAGS = -Idaemon -I. -LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ - -# UPNP Support -ifeq ($(USE_UPNP),yes) - CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB - LDLIBS = -lminiupnpc -endif - -LDLIBS += \ - -lboost_system$(BOOST_SUFFIX) \ - -lboost_date_time$(BOOST_SUFFIX) \ - -lboost_filesystem$(BOOST_SUFFIX) \ - -lboost_program_options$(BOOST_SUFFIX) \ - -lssl \ - -lcrypto \ - -lz \ - -lwsock32 \ - -lws2_32 \ - -lgdi32 \ - -liphlpapi \ - -lstdc++ \ - -lpthread - -ifeq ($(USE_WIN32_APP), yes) - CXXFLAGS += -DWIN32_APP - LDFLAGS += -mwindows - DAEMON_RC += Win32/Resource.rc - DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) -endif - -# don't change following line to ifeq ($(USE_AESNI),yes) !!! -ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -else - CPU_FLAGS += -msse -endif - -ifeq ($(USE_AVX),1) - CPU_FLAGS += -mavx -endif - -ifeq ($(USE_ASLR),yes) - LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols -endif - -obj/%.o : %.rc - $(WINDRES) -i $< -o $@ +USE_WIN32_APP=yes +CXX = g++ +WINDRES = windres +CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +NEEDED_CXXFLAGS = -std=c++11 +BOOST_SUFFIX = -mt +INCFLAGS = -Idaemon -I. +LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ + +# UPNP Support +ifeq ($(USE_UPNP),yes) + CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB + LDLIBS = -lminiupnpc +endif + +LDLIBS += \ + -lboost_system$(BOOST_SUFFIX) \ + -lboost_date_time$(BOOST_SUFFIX) \ + -lboost_filesystem$(BOOST_SUFFIX) \ + -lboost_program_options$(BOOST_SUFFIX) \ + -lssl \ + -lcrypto \ + -lz \ + -lwsock32 \ + -lws2_32 \ + -lgdi32 \ + -liphlpapi \ + -lstdc++ \ + -lpthread + +ifeq ($(USE_WIN32_APP), yes) + CXXFLAGS += -DWIN32_APP + LDFLAGS += -mwindows + DAEMON_RC += Win32/Resource.rc + DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) +endif + +# don't change following line to ifeq ($(USE_AESNI),yes) !!! +ifeq ($(USE_AESNI),1) + CPU_FLAGS += -maes +else + CPU_FLAGS += -msse +endif + +ifeq ($(USE_AVX),1) + CPU_FLAGS += -mavx +endif + +ifeq ($(USE_ASLR),yes) + LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols +endif + +obj/%.o : %.rc + $(WINDRES) -i $< -o $@ diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index e7811b0b..7f163878 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -62,12 +62,12 @@ exit /b 0 %xSH% "make clean" >> nul echo Building i2pd %tag% for win%bitness%: echo Build AVX+AESNI... -%xSH% "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 echo Build AVX... -%xSH% "make USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 echo Build AESNI... -%xSH% "make USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 echo Build without extensions... -%xSH% "make USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 :EOF \ No newline at end of file From c0a650f28b8d0a2e829c51f95f5b4b32d5e816f9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 20 Jul 2018 23:04:29 +0300 Subject: [PATCH 129/195] update gitignore --- .gitignore | 2 +- android/.gitignore | 9 ++++++--- android_binary_only/.gitignore | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 android_binary_only/.gitignore diff --git a/.gitignore b/.gitignore index 353d839f..c2db70e0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ netDb /i2pd /libi2pd.a /libi2pdclient.a -i2pd.exe +*.exe # Autotools diff --git a/android/.gitignore b/android/.gitignore index 90cd315e..6e42311a 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -1,12 +1,15 @@ gen tests +bin +libs +log* +obj +.gradle .idea +.externalNativeBuild ant.properties local.properties build.sh -bin -log* -.gradle android.iml build gradle diff --git a/android_binary_only/.gitignore b/android_binary_only/.gitignore new file mode 100644 index 00000000..6e42311a --- /dev/null +++ b/android_binary_only/.gitignore @@ -0,0 +1,18 @@ +gen +tests +bin +libs +log* +obj +.gradle +.idea +.externalNativeBuild +ant.properties +local.properties +build.sh +android.iml +build +gradle +gradlew +gradlew.bat + From cb1e47eb7138d13b3bf48ec4f3a38fa23485caa4 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Fri, 20 Jul 2018 23:15:22 +0300 Subject: [PATCH 130/195] use preconfigured configs for android package --- android/assets/i2pd.conf | 79 +++++++++++++++++++++++++++++++- android/assets/subscriptions.txt | 4 +- android/assets/tunnels.conf | 34 +++++++++++++- 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf index f4a68aa2..8022b3d9 120000 --- a/android/assets/i2pd.conf +++ b/android/assets/i2pd.conf @@ -1 +1,78 @@ -../../contrib/i2pd.conf \ No newline at end of file +## Configuration file for a typical i2pd user +## See https://i2pd.readthedocs.org/en/latest/configuration.html +## for more options you can use in this file. + +#logfile = /sdcard/i2pd/i2pd.log +loglevel = none + +# host = 1.2.3.4 +# port = 4567 + +ipv4 = true +ipv6 = false + +# ntcp = true +# ntcpproxy = http://127.0.0.1:8118 +# ssu = true + +bandwidth = O +# share = 100 + +# notransit = true +# floodfill = true + +[http] +enabled = true +address = 127.0.0.1 +port = 7070 +# auth = true +# user = i2pd +# pass = changeme + +[httpproxy] +enabled = true +address = 127.0.0.1 +port = 4444 +# keys = http-proxy-keys.dat +# addresshelper = true +# outproxy = http://false.i2p +## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[socksproxy] +enabled = true +address = 127.0.0.1 +port = 4447 +# keys = socks-proxy-keys.dat +# outproxy.enabled = false +# outproxy = 127.0.0.1 +# outproxyport = 9050 +## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[sam] +enabled = false +# address = 127.0.0.1 +# port = 7656 + +[precomputation] +elgamal = true + +[upnp] +enabled = true +# name = I2Pd + +[reseed] +verify = true +## Path to local reseed data file (.su3) for manual reseeding +# file = /path/to/i2pseeds.su3 +## or HTTPS URL to reseed from +# file = https://legit-website.com/i2pseeds.su3 +## Path to local ZIP file or HTTPS URL to reseed from +# zipfile = /path/to/netDb.zip +## If you run i2pd behind a proxy server, set proxy server for reseeding here +## Should be http://address:port or socks://address:port +# proxy = http://127.0.0.1:8118 +## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default +# threshold = 25 + +[limits] +transittunnels = 50 diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt index 4fcc444f..8f4afb03 120000 --- a/android/assets/subscriptions.txt +++ b/android/assets/subscriptions.txt @@ -1 +1,3 @@ -../../contrib/subscriptions.txt \ No newline at end of file +http://inr.i2p/export/alive-hosts.txt +http://stats.i2p/cgi-bin/newhosts.txt +http://i2p-projekt.i2p/hosts.txt diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf index 08767c73..e95fdf2e 120000 --- a/android/assets/tunnels.conf +++ b/android/assets/tunnels.conf @@ -1 +1,33 @@ -../../contrib/tunnels.conf \ No newline at end of file +[IRC-IRC2P] +#type = client +#address = 127.0.0.1 +#port = 6668 +#destination = irc.postman.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[IRC-ILITA] +#type = client +#address = 127.0.0.1 +#port = 6669 +#destination = irc.ilita.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[SMTP] +#type = client +#address = 127.0.0.1 +#port = 7659 +#destination = smtp.postman.i2p +#destinationport = 25 +#keys = smtp-keys.dat + +#[POP3] +#type = client +#address = 127.0.0.1 +#port = 7660 +#destination = pop.postman.i2p +#destinationport = 110 +#keys = pop3-keys.dat + +# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ From 2406d57d516354ae83e09b685f5cc004148bf38a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 21 Jul 2018 00:02:54 +0300 Subject: [PATCH 131/195] update android target API to 28, use gradle and ndk parallel building --- android/AndroidManifest.xml | 2 +- android/assets/i2pd.conf | 0 android/assets/subscriptions.txt | 0 android/assets/tunnels.conf | 0 android/build.gradle | 13 +++++++++---- android/gradle.properties | 1 + android/project.properties | 2 +- android/settings.gradle | 1 + 8 files changed, 13 insertions(+), 6 deletions(-) mode change 120000 => 100644 android/assets/i2pd.conf mode change 120000 => 100644 android/assets/subscriptions.txt mode change 120000 => 100644 android/assets/tunnels.conf create mode 100644 android/gradle.properties create mode 100644 android/settings.gradle diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index ca66c17d..705cce4e 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -7,7 +7,7 @@ + android:targetSdkVersion="28" /> diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf deleted file mode 120000 index 8022b3d9..00000000 --- a/android/assets/i2pd.conf +++ /dev/null @@ -1,78 +0,0 @@ -## Configuration file for a typical i2pd user -## See https://i2pd.readthedocs.org/en/latest/configuration.html -## for more options you can use in this file. - -#logfile = /sdcard/i2pd/i2pd.log -loglevel = none - -# host = 1.2.3.4 -# port = 4567 - -ipv4 = true -ipv6 = false - -# ntcp = true -# ntcpproxy = http://127.0.0.1:8118 -# ssu = true - -bandwidth = O -# share = 100 - -# notransit = true -# floodfill = true - -[http] -enabled = true -address = 127.0.0.1 -port = 7070 -# auth = true -# user = i2pd -# pass = changeme - -[httpproxy] -enabled = true -address = 127.0.0.1 -port = 4444 -# keys = http-proxy-keys.dat -# addresshelper = true -# outproxy = http://false.i2p -## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. - -[socksproxy] -enabled = true -address = 127.0.0.1 -port = 4447 -# keys = socks-proxy-keys.dat -# outproxy.enabled = false -# outproxy = 127.0.0.1 -# outproxyport = 9050 -## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. - -[sam] -enabled = false -# address = 127.0.0.1 -# port = 7656 - -[precomputation] -elgamal = true - -[upnp] -enabled = true -# name = I2Pd - -[reseed] -verify = true -## Path to local reseed data file (.su3) for manual reseeding -# file = /path/to/i2pseeds.su3 -## or HTTPS URL to reseed from -# file = https://legit-website.com/i2pseeds.su3 -## Path to local ZIP file or HTTPS URL to reseed from -# zipfile = /path/to/netDb.zip -## If you run i2pd behind a proxy server, set proxy server for reseeding here -## Should be http://address:port or socks://address:port -# proxy = http://127.0.0.1:8118 -## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default -# threshold = 25 - -[limits] -transittunnels = 50 diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf new file mode 100644 index 00000000..8022b3d9 --- /dev/null +++ b/android/assets/i2pd.conf @@ -0,0 +1,78 @@ +## Configuration file for a typical i2pd user +## See https://i2pd.readthedocs.org/en/latest/configuration.html +## for more options you can use in this file. + +#logfile = /sdcard/i2pd/i2pd.log +loglevel = none + +# host = 1.2.3.4 +# port = 4567 + +ipv4 = true +ipv6 = false + +# ntcp = true +# ntcpproxy = http://127.0.0.1:8118 +# ssu = true + +bandwidth = O +# share = 100 + +# notransit = true +# floodfill = true + +[http] +enabled = true +address = 127.0.0.1 +port = 7070 +# auth = true +# user = i2pd +# pass = changeme + +[httpproxy] +enabled = true +address = 127.0.0.1 +port = 4444 +# keys = http-proxy-keys.dat +# addresshelper = true +# outproxy = http://false.i2p +## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[socksproxy] +enabled = true +address = 127.0.0.1 +port = 4447 +# keys = socks-proxy-keys.dat +# outproxy.enabled = false +# outproxy = 127.0.0.1 +# outproxyport = 9050 +## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. + +[sam] +enabled = false +# address = 127.0.0.1 +# port = 7656 + +[precomputation] +elgamal = true + +[upnp] +enabled = true +# name = I2Pd + +[reseed] +verify = true +## Path to local reseed data file (.su3) for manual reseeding +# file = /path/to/i2pseeds.su3 +## or HTTPS URL to reseed from +# file = https://legit-website.com/i2pseeds.su3 +## Path to local ZIP file or HTTPS URL to reseed from +# zipfile = /path/to/netDb.zip +## If you run i2pd behind a proxy server, set proxy server for reseeding here +## Should be http://address:port or socks://address:port +# proxy = http://127.0.0.1:8118 +## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default +# threshold = 25 + +[limits] +transittunnels = 50 diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt deleted file mode 120000 index 8f4afb03..00000000 --- a/android/assets/subscriptions.txt +++ /dev/null @@ -1,3 +0,0 @@ -http://inr.i2p/export/alive-hosts.txt -http://stats.i2p/cgi-bin/newhosts.txt -http://i2p-projekt.i2p/hosts.txt diff --git a/android/assets/subscriptions.txt b/android/assets/subscriptions.txt new file mode 100644 index 00000000..8f4afb03 --- /dev/null +++ b/android/assets/subscriptions.txt @@ -0,0 +1,3 @@ +http://inr.i2p/export/alive-hosts.txt +http://stats.i2p/cgi-bin/newhosts.txt +http://i2p-projekt.i2p/hosts.txt diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf deleted file mode 120000 index e95fdf2e..00000000 --- a/android/assets/tunnels.conf +++ /dev/null @@ -1,33 +0,0 @@ -[IRC-IRC2P] -#type = client -#address = 127.0.0.1 -#port = 6668 -#destination = irc.postman.i2p -#destinationport = 6667 -#keys = irc-keys.dat - -#[IRC-ILITA] -#type = client -#address = 127.0.0.1 -#port = 6669 -#destination = irc.ilita.i2p -#destinationport = 6667 -#keys = irc-keys.dat - -#[SMTP] -#type = client -#address = 127.0.0.1 -#port = 7659 -#destination = smtp.postman.i2p -#destinationport = 25 -#keys = smtp-keys.dat - -#[POP3] -#type = client -#address = 127.0.0.1 -#port = 7660 -#destination = pop.postman.i2p -#destinationport = 110 -#keys = pop3-keys.dat - -# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ diff --git a/android/assets/tunnels.conf b/android/assets/tunnels.conf new file mode 100644 index 00000000..e95fdf2e --- /dev/null +++ b/android/assets/tunnels.conf @@ -0,0 +1,33 @@ +[IRC-IRC2P] +#type = client +#address = 127.0.0.1 +#port = 6668 +#destination = irc.postman.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[IRC-ILITA] +#type = client +#address = 127.0.0.1 +#port = 6669 +#destination = irc.ilita.i2p +#destinationport = 6667 +#keys = irc-keys.dat + +#[SMTP] +#type = client +#address = 127.0.0.1 +#port = 7659 +#destination = smtp.postman.i2p +#destinationport = 25 +#keys = smtp-keys.dat + +#[POP3] +#type = client +#address = 127.0.0.1 +#port = 7660 +#destination = pop.postman.i2p +#destinationport = 110 +#keys = pop3-keys.dat + +# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/ diff --git a/android/build.gradle b/android/build.gradle index 683f3d27..2a8ad6f4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -18,17 +18,22 @@ repositories { } android { - compileSdkVersion 25 - buildToolsVersion "25.0.3" + compileSdkVersion 28 + buildToolsVersion "28.0.1" defaultConfig { applicationId "org.purplei2p.i2pd" - targetSdkVersion 25 + targetSdkVersion 28 minSdkVersion 14 versionCode 1 versionName "2.19.0" ndk { abiFilters 'armeabi-v7a' - //abiFilters 'x86' + abiFilters 'x86' + } + externalNativeBuild { + ndkBuild { + arguments "-j4" + } } } sourceSets { diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..af82e006 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.parallel=true \ No newline at end of file diff --git a/android/project.properties b/android/project.properties index f72b9716..919ca9c3 100644 --- a/android/project.properties +++ b/android/project.properties @@ -11,4 +11,4 @@ #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. -target=android-25 +target=android-28 diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 00000000..2a620ef9 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "i2pd" From c8f51380e6fb317b32f4bac45063717260d369d9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Jul 2018 16:59:58 -0400 Subject: [PATCH 132/195] publish NTCP2 for new routers --- libi2pd/RouterContext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 48fe400f..100d9c44 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -93,10 +93,11 @@ namespace i2p m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); - if (ntcp2) + if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now { NewNTCP2Keys (); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + UpdateRouterInfo (); } } From 1a38e925bf3980e459264264f135fbbe47109e1e Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jul 2018 13:51:29 -0400 Subject: [PATCH 133/195] publish NTCP2 address --- libi2pd/RouterContext.cpp | 18 +++++++++++++++++- libi2pd/RouterContext.h | 3 ++- libi2pd/RouterInfo.cpp | 10 +++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 100d9c44..9529a757 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -146,7 +146,7 @@ namespace i2p bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->port != port) + if (!address->IsNTCP2 () && address->port != port) { address->port = port; updated = true; @@ -156,6 +156,22 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::PublishNTCP2Address (int port) + { + bool updated = false; + for (auto& address : m_RouterInfo.GetAddresses ()) + { + if (address->IsNTCP2 () && address->port != port) + { + address->port = port; + address->ntcp2->isPublished = true; + updated = true; + } + } + if (updated) + UpdateRouterInfo (); + } + void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index ae4aa17e..b840e19a 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -76,8 +76,9 @@ namespace i2p void SetNetID (int netID) { m_NetID = netID; }; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; - void UpdatePort (int port); // called from Daemon + void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon + void PublishNTCP2Address (int port); bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool IsUnreachable () const; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 535c7bd8..a38d8fa7 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -456,7 +456,7 @@ namespace data else WriteString ("", s); - if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) { WriteString ("host", properties); properties << '='; @@ -538,7 +538,7 @@ namespace data } } - if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement + if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) { WriteString ("port", properties); properties << '='; @@ -552,7 +552,11 @@ namespace data WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; WriteString ("v", properties); properties << '='; WriteString ("2", properties); properties << ';'; - // TODO: publish "i" + if (address.IsPublishedNTCP2 ()) + { + WriteString ("i", properties); properties << '='; + WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; + } } uint16_t size = htobe16 (properties.str ().size ()); From 998653ea9dfc0fb10099d72a8ee0efe8e7ef7508 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jul 2018 15:30:51 -0400 Subject: [PATCH 134/195] NTCP2 acceptors --- libi2pd/NTCP2.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++++ libi2pd/NTCP2.h | 5 +++ 2 files changed, 103 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 94f0641e..e5487a4e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -776,6 +776,48 @@ namespace transport { m_IsRunning = true; m_Thread = new std::thread (std::bind (&NTCP2Server::Run, this)); + auto& addresses = context.GetRouterInfo ().GetAddresses (); + for (const auto& address: addresses) + { + if (!address) continue; + if (address->IsPublishedNTCP2 ()) + { + if (address->host.is_v4()) + { + try + { + m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port))); + } + catch ( std::exception & ex ) + { + LogPrint(eLogError, "NTCP2: Failed to bind to ip4 port ",address->port, ex.what()); + continue; + } + + LogPrint (eLogInfo, "NTC2P: Start listening TCP port ", address->port); + auto conn = std::make_shared(*this); + m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); + } + else if (address->host.is_v6() && context.SupportsV6 ()) + { + m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (m_Service)); + try + { + m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); + m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); + m_NTCP2V6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port)); + m_NTCP2V6Acceptor->listen (); + + LogPrint (eLogInfo, "NTCP2: Start listening V6 TCP port ", address->port); + auto conn = std::make_shared (*this); + m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1)); + } catch ( std::exception & ex ) { + LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port); + continue; + } + } + } + } } } @@ -786,6 +828,8 @@ namespace transport auto ntcpSessions = m_NTCP2Sessions; for (auto& it: ntcpSessions) it.second->Terminate (); + for (auto& it: m_PendingIncomingSessions) + it->Terminate (); } m_NTCP2Sessions.clear (); @@ -871,6 +915,60 @@ namespace transport conn->ClientLogin (); } } + + void NTCP2Server::HandleAccept (std::shared_ptr conn, const boost::system::error_code& error) + { + if (!error) + { + boost::system::error_code ec; + auto ep = conn->GetSocket ().remote_endpoint(ec); + if (!ec) + { + LogPrint (eLogDebug, "NTCP2: Connected from ", ep); + if (conn) + { + conn->ServerLogin (); + // m_PendingIncomingSessions.push_back (conn); + } + } + else + LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ()); + } + + if (error != boost::asio::error::operation_aborted) + { + conn = std::make_shared (*this); + m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, + conn, std::placeholders::_1)); + } + } + + void NTCP2Server::HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error) + { + if (!error) + { + boost::system::error_code ec; + auto ep = conn->GetSocket ().remote_endpoint(ec); + if (!ec) + { + LogPrint (eLogDebug, "NTCP2: Connected from ", ep); + if (conn) + { + conn->ServerLogin (); + // m_PendingIncomingSessions.push_back (conn); + } + } + else + LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ()); + } + + if (error != boost::asio::error::operation_aborted) + { + conn = std::make_shared (*this); + m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, + conn, std::placeholders::_1)); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index c14c6876..93a2ac1e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -155,6 +155,9 @@ namespace transport private: void Run (); + void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); + void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); private: @@ -163,7 +166,9 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + std::unique_ptr m_NTCP2Acceptor, m_NTCP2V6Acceptor; std::map > m_NTCP2Sessions; + std::list > m_PendingIncomingSessions; public: From 10e4b5b2a31c09355e643eeb588518d4afd9b77b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Jul 2018 15:44:36 -0400 Subject: [PATCH 135/195] ignore NTCP2 addresses --- libi2pd/NTCPSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index a297ad6a..caddd110 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -819,7 +819,7 @@ namespace transport for (const auto& address: addresses) { if (!address) continue; - if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP) + if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !address->IsNTCP2 ()) { if (address->host.is_v4()) { From 07e7c2d852cdc076fb271771d0df66d7d4de8ae5 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 31 Jul 2018 12:59:38 -0400 Subject: [PATCH 136/195] ntcp2.published and ntcp2.port parameters --- daemon/Daemon.cpp | 11 +++++++++++ libi2pd/Config.cpp | 4 +++- libi2pd/RouterContext.cpp | 2 ++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index ee56a1c7..5efdc693 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -152,6 +152,17 @@ namespace i2p i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV4 (ipv4); + bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); + if (ntcp2) + { + bool published; i2p::config::GetOption("ntcp2.published", published); + if (published) + { + uint16_t port; i2p::config::GetOption("ntcp2.port", port); + i2p::context.PublishNTCP2Address (port); + } + } + bool transit; i2p::config::GetOption("notransit", transit); i2p::context.SetAcceptsTunnels (!transit); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 3233c875..098a7baa 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -233,7 +233,9 @@ namespace config { options_description ntcp2("NTCP2 Options"); ntcp2.add_options() - ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (experimental, default: disabled)") + ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (default: disabled)") + ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)") + ("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ; m_OptionsDesc diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 9529a757..e8629ad5 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -158,6 +158,8 @@ namespace i2p void RouterContext::PublishNTCP2Address (int port) { + if (!port) + port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { From 0ff9c9da27abb4b04dc032709fe7c6f9bc8022e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 31 Jul 2018 15:41:13 -0400 Subject: [PATCH 137/195] complete Bob side of NTCP2 --- libi2pd/NTCP2.cpp | 135 +++++++++++++++++++++++--------------- libi2pd/NTCP2.h | 10 +-- libi2pd/RouterContext.cpp | 2 +- libi2pd/RouterInfo.cpp | 20 ++++++ libi2pd/RouterInfo.h | 1 + 5 files changed, 109 insertions(+), 59 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index e5487a4e..f31044b8 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -41,7 +41,7 @@ namespace transport HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); } - void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub) + void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, const uint8_t * priv, const uint8_t * rs, const uint8_t * epub) { static const uint8_t protocolNameHash[] = { @@ -60,28 +60,28 @@ namespace transport SHA256_Update (&ctx, hh, 32); SHA256_Update (&ctx, rs, 32); SHA256_Final (m_H, &ctx); - // h = SHA256(h || pub) + // h = SHA256(h || epub) SHA256_Init (&ctx); SHA256_Update (&ctx, m_H, 32); - SHA256_Update (&ctx, pub, 32); + SHA256_Update (&ctx, epub, 32); SHA256_Final (m_H, &ctx); // x25519 between rs and priv uint8_t inputKeyMaterial[32]; - i2p::crypto::GetEd25519 ()->ScalarMul (rs, priv, inputKeyMaterial, m_Ctx); // rs*priv + i2p::crypto::GetEd25519 ()->ScalarMul (pub, priv, inputKeyMaterial, m_Ctx); // rs*priv MixKey (inputKeyMaterial, m_K); } void NTCP2Establisher::KDF1Alice () { - KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), GetPub ()); + KeyDerivationFunction1 (m_RemoteStaticKey, GetPriv (), m_RemoteStaticKey, GetPub ()); } void NTCP2Establisher::KDF1Bob () { - KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), GetRemotePub ()); + KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticPrivateKey (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); } - void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen) + void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) { SHA256_CTX ctx; SHA256_Init (&ctx); @@ -99,7 +99,7 @@ namespace transport } SHA256_Init (&ctx); SHA256_Update (&ctx, m_H, 32); - SHA256_Update (&ctx, GetRemotePub (), 32); + SHA256_Update (&ctx, epub, 32); SHA256_Final (m_H, &ctx); // x25519 between remote pub and priv @@ -108,6 +108,16 @@ namespace transport MixKey (inputKeyMaterial, m_K); } + void NTCP2Establisher::KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen) + { + KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetRemotePub ()); + } + + void NTCP2Establisher::KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen) + { + KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetPub ()); + } + void NTCP2Establisher::KDF3Alice () { uint8_t inputKeyMaterial[32]; @@ -137,14 +147,17 @@ namespace transport m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { m_Establisher.reset (new NTCP2Establisher); - auto addr = in_RemoteRouter->GetNTCPAddress (); - if (addr->ntcp2) + if (in_RemoteRouter) // Alice { - memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); - memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); + auto addr = in_RemoteRouter->GetNTCP2Address (); + if (addr->ntcp2) + { + memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); + memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); + } + else + LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } - else - LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters"); } NTCP2Session::~NTCP2Session () @@ -331,7 +344,7 @@ namespace transport encryption.SetIV (m_Establisher->m_IV); encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen); auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); @@ -342,7 +355,7 @@ namespace transport memset (nonce, 0, 12); // set nonce to zero i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt // fill padding - RAND_bytes (m_SessionCreatedBuffer + 56, paddingLen); + RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); // send message m_SessionCreatedBufferLen = paddingLen + 64; boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), @@ -366,7 +379,7 @@ namespace transport decryption.SetIV (m_Establisher->m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); // decryption key for next block (m_K) - m_Establisher->KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Alice (m_SessionRequestBuffer, m_SessionRequestBufferLen); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; @@ -386,7 +399,7 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed "); + LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed "); Terminate (); } } @@ -492,12 +505,12 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part 1 read error: ", ecode.message ()); + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 read error: ", ecode.message ()); Terminate (); } else { - LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part 1 received"); + LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part1 received"); // update AD uint8_t h[80]; memcpy (h, m_Establisher->GetH (), 32); @@ -515,44 +528,58 @@ namespace transport // part 1 uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 48, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false); // decrypt S - // part 2 - // update AD again - memcpy (h + 32, m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_Establisher->m_H); - - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - m_Establisher->KDF3Bob (); - memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false); // decrypt - // process RI - if (buf[0] == eNTCP2BlkRouterInfo) + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S { - auto size = bufbe16toh (buf.data () + 1); - if (size <= buf.size () - 3) + // part 2 + // update AD again + memcpy (h + 32, m_SessionConfirmedBuffer, 48); + SHA256 (h, 80, m_Establisher->m_H); + + std::vector buf(m_Establisher->m3p2Len - 16); // -MAC + m_Establisher->KDF3Bob (); + memset (nonce, 0, 12); // set nonce to 0 again + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt { - // TODO: check flag - i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag - // TODO: process options - } + // process RI + if (buf[0] == eNTCP2BlkRouterInfo) + { + auto size = bufbe16toh (buf.data () + 1); + if (size <= buf.size () - 3) + { + // TODO: check flag + i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + // TODO: process options + } + else + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + } + else + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); + // caclulate new h again for KDF data + memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + KeyDerivationFunctionDataPhase (); + // Bob + m_SendKey = m_Kba; + m_ReceiveKey = m_Kab; + m_SendSipKey = m_Sipkeysba; + m_ReceiveSipKey = m_Sipkeysab; + memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); + memcpy (m_SendIV, m_Sipkeysba + 16, 8); + Established (); + ReceiveLength (); + } else - LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed "); + Terminate (); + } } else - LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); - // caclulate new h again for KDF data - memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); - KeyDerivationFunctionDataPhase (); - // Bob - m_SendKey = m_Kba; - m_ReceiveKey = m_Kab; - m_SendSipKey = m_Sipkeysba; - m_ReceiveSipKey = m_Sipkeysab; - memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); - memcpy (m_SendIV, m_Sipkeysba + 16, 8); - Established (); - ReceiveLength (); + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); + Terminate (); + } } } @@ -794,7 +821,7 @@ namespace transport continue; } - LogPrint (eLogInfo, "NTC2P: Start listening TCP port ", address->port); + LogPrint (eLogInfo, "NTCP2: Start listening TCP port ", address->port); auto conn = std::make_shared(*this); m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 93a2ac1e..74043ca1 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -44,12 +44,14 @@ namespace transport void KDF1Alice (); void KDF1Bob (); - - void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); - void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * priv, const uint8_t * pub); // for SessionRequest - void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen); // for SessionCreate + void KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen); + void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen); void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Bob (); + + void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); + void KeyDerivationFunction1 (const uint8_t * pub, const uint8_t * priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH + void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index e8629ad5..93cb741c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -478,7 +478,7 @@ namespace i2p if (n2k) { n2k.seekg (0, std::ios::end); - len = fk.tellg(); + len = n2k.tellg(); n2k.seekg (0, std::ios::beg); if (len == sizeof (NTCP2PrivateKeys)) { diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index a38d8fa7..73716989 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -873,6 +873,7 @@ namespace data std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const { + // TODO: make it more gereric using comparator #if (BOOST_VERSION >= 105300) auto addresses = boost::atomic_load (&m_Addresses); #else @@ -889,6 +890,25 @@ namespace data return nullptr; } + std::shared_ptr RouterInfo::GetNTCP2Address (bool v4only) const + { + // TODO: implement through GetAddress +#if (BOOST_VERSION >= 105300) + auto addresses = boost::atomic_load (&m_Addresses); +#else + auto addresses = m_Addresses; +#endif + for (const auto& address : *addresses) + { + if (address->IsPublishedNTCP2 ()) + { + if (!v4only || address->host.is_v4 ()) + return address; + } + } + return nullptr; + } + std::shared_ptr RouterInfo::GetProfile () const { if (!m_Profile) diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 07cc3af4..525c6e65 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -142,6 +142,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr std::shared_ptr GetNTCPAddress (bool v4only = true) const; + std::shared_ptr GetNTCP2Address (bool v4only = true) const; std::shared_ptr GetSSUAddress (bool v4only = true) const; std::shared_ptr GetSSUV6Address () const; From a8dcfc44f5055ec5925a53f77c118c72c892a25b Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 1 Aug 2018 09:43:48 -0400 Subject: [PATCH 138/195] handle termination message --- libi2pd/NTCP2.cpp | 10 ++++++++-- libi2pd/NTCP2.h | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index f31044b8..77882b46 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -447,7 +447,7 @@ namespace transport SHA256 (h, 80, m_Establisher->m_H); std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - buf[0] = 2; // block + buf[0] = eNTCP2BlkRouterInfo; // block htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI buf[3] = 0; // flag memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); @@ -695,7 +695,13 @@ namespace transport break; } case eNTCP2BlkTermination: - LogPrint (eLogDebug, "NTCP2: termination"); + if (size >= 9) + { + LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 9])); + Terminate (); + } + else + LogPrint (eLogWarning, "NTCP2: Unexpected temination block size ", size); break; case eNTCP2BlkPadding: LogPrint (eLogDebug, "NTCP2: padding"); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 74043ca1..b1fe21e6 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -28,6 +28,29 @@ namespace transport eNTCP2BlkPadding = 254 }; + enum NTCP2TerminationReason + { + eNTCP2NormalClose = 0, + eNTCP2TerminationReceived, // 1 + eNTCP2IdleTimeout, // 2 + eNTCP2RouterShutdown, // 3 + eNTCP2DataPhaseAEADFailure, // 4 + eNTCP2IncompatibleOptions, // 5 + eNTCP2IncompatibleSignatureType, // 6 + eNTCP2ClockSkew, // 7 + eNTCP2PaddingViolation, // 8 + eNTCP2AEADFraminError, // 9 + eNTCP2PayloadFromatError, // 10 + eNTCP2Message1Error, // 11 + eNTCP2Message2Error, // 12 + eNTCP2Message3Error, // 13 + eNTCP2IntraFrameReadTimeout, // 14 + eNTCP2RouterInfoSignatureVerificationFail, // 15 + eNTCP2IncorrectSParameter, // 16 + eNTCP2Banned, // 17 + }; + + struct NTCP2Establisher { NTCP2Establisher (); From 2b64cf9126329030f6dc86630c77189b5cd4a484 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 1 Aug 2018 12:28:34 -0400 Subject: [PATCH 139/195] publish i in correct place for NTCP2 --- libi2pd/RouterInfo.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 73716989..14153ba0 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -538,6 +538,13 @@ namespace data } } + if (address.IsPublishedNTCP2 ()) + { + // publish i for NTCP2 + WriteString ("i", properties); properties << '='; + WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; + } + if (!address.IsNTCP2 () || address.IsPublishedNTCP2 ()) { WriteString ("port", properties); @@ -552,11 +559,6 @@ namespace data WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; WriteString ("v", properties); properties << '='; WriteString ("2", properties); properties << ';'; - if (address.IsPublishedNTCP2 ()) - { - WriteString ("i", properties); properties << '='; - WriteString (address.ntcp2->iv.ToBase64 (), properties); properties << ';'; - } } uint16_t size = htobe16 (properties.str ().size ()); From f96bfa6afa216d78d99c9ebbbf33df0134ac5efb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Aug 2018 12:42:39 -0400 Subject: [PATCH 140/195] send RouterInfo --- libi2pd/NTCP2.cpp | 29 +++++++++++++++++++++++++---- libi2pd/NTCP2.h | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 77882b46..cda25553 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -337,7 +337,9 @@ namespace transport void NTCP2Session::SendSessionCreated () { - m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + auto paddingLen = rand () % (287 - 64); + m_SessionCreatedBufferLen = paddingLen + 64; + m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); @@ -345,7 +347,6 @@ namespace transport encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen); - auto paddingLen = rand () % (287 - 64); uint8_t options[16]; memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen @@ -357,7 +358,6 @@ namespace transport // fill padding RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); // send message - m_SessionCreatedBufferLen = paddingLen + 64; boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -437,7 +437,7 @@ namespace transport SHA256_Final (h, &ctx); } // part1 48 bytes - m_SessionConfirmedBuffer = new uint8_t[2048]; // TODO: actual size + m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; CreateNonce (1, nonce); i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt @@ -567,6 +567,7 @@ namespace transport memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); memcpy (m_SendIV, m_Sipkeysba + 16, 8); Established (); + SendRouterInfo (); ReceiveLength (); } else @@ -598,6 +599,7 @@ namespace transport void NTCP2Session::ReceiveLength () { + if (IsTerminated ()) return; boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -622,6 +624,7 @@ namespace transport void NTCP2Session::Receive () { + if (IsTerminated ()) return; boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -716,6 +719,7 @@ namespace transport void NTCP2Session::SendNextFrame (const uint8_t * payload, size_t len) { + if (IsTerminated ()) return; uint8_t nonce[12]; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; m_NextSendBuffer = new uint8_t[len + 16 + 2]; @@ -779,6 +783,23 @@ namespace transport } } + void NTCP2Session::SendRouterInfo () + { + auto riLen = i2p::context.GetRouterInfo ().GetBufferLen (); + int paddingSize = (riLen*NTCP2_MAX_PADDING_RATIO)/100; + size_t payloadLen = riLen + paddingSize + 7; // 7 = 2*3 bytes header + 1 byte RI flag + uint8_t * payload = new uint8_t[payloadLen]; + payload[0] = eNTCP2BlkRouterInfo; + htobe16buf (payload + 1, riLen + 1); // size + payload[3] = 0; // flag + memcpy (payload + 4, i2p::context.GetRouterInfo ().GetBuffer (), riLen); + payload[riLen + 4] = eNTCP2BlkPadding; + htobe16buf (payload + riLen + 5, paddingSize); + RAND_bytes (payload + riLen + 7, paddingSize); + SendNextFrame (payload, payloadLen); + delete[] payload; + } + void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) { m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index b1fe21e6..5ac6a280 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -134,6 +134,7 @@ namespace transport void SendNextFrame (const uint8_t * payload, size_t len); void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendQueue (); + void SendRouterInfo (); void PostI2NPMessages (std::vector > msgs); private: From 6cf158ac634c8cf477da0a6304fdd316065b6a61 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Aug 2018 13:58:47 -0400 Subject: [PATCH 141/195] check RouterInfo from SessionConfirmed --- libi2pd/NTCP2.cpp | 66 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index cda25553..7a3df9bf 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -150,7 +150,7 @@ namespace transport if (in_RemoteRouter) // Alice { auto addr = in_RemoteRouter->GetNTCP2Address (); - if (addr->ntcp2) + if (addr) { memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); @@ -469,7 +469,7 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent"); KeyDerivationFunctionDataPhase (); - // Alice + // Alice data phase keys m_SendKey = m_Kab; m_ReceiveKey = m_Kba; m_SendSipKey = m_Sipkeysab; @@ -540,35 +540,63 @@ namespace transport memset (nonce, 0, 12); // set nonce to 0 again if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt { - // process RI - if (buf[0] == eNTCP2BlkRouterInfo) - { - auto size = bufbe16toh (buf.data () + 1); - if (size <= buf.size () - 3) - { - // TODO: check flag - i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag - // TODO: process options - } - else - LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); - } - else - LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); // caclulate new h again for KDF data memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); KeyDerivationFunctionDataPhase (); - // Bob + // Bob data phase keys m_SendKey = m_Kba; m_ReceiveKey = m_Kab; m_SendSipKey = m_Sipkeysba; m_ReceiveSipKey = m_Sipkeysab; memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); memcpy (m_SendIV, m_Sipkeysba + 16, 8); + + // process RI + if (buf[0] != eNTCP2BlkRouterInfo) + { + LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); + Terminate (); + return; + } + auto size = bufbe16toh (buf.data () + 1); + if (size > buf.size () - 3) + { + LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed"); + Terminate (); + return; + } + // TODO: check flag + i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag + if (ri.IsUnreachable ()) + { + LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); + Terminate (); + return; + } + auto addr = ri.GetNTCP2Address (); + if (!addr) + { + LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); + Terminate (); + return; + } + if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32)) + { + LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed"); + Terminate (); + return; + } + + i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // TODO: should insert ri and not parse it twice + // TODO: process options + + // ready to communicate + auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already + SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); Established (); SendRouterInfo (); - ReceiveLength (); + ReceiveLength (); } else { From 0a33c18e367a23dff697e7fc514dea5d4c3c1cc9 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Aug 2018 15:31:15 -0400 Subject: [PATCH 142/195] send termination message --- libi2pd/NTCP2.cpp | 24 +++++++++++++++++++----- libi2pd/NTCP2.h | 4 +++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 7a3df9bf..00d874cc 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -570,8 +570,8 @@ namespace transport i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag if (ri.IsUnreachable ()) { - LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); - Terminate (); + LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); return; } auto addr = ri.GetNTCP2Address (); @@ -583,8 +583,8 @@ namespace transport } if (memcmp (addr->ntcp2->staticKey, m_Establisher->m_RemoteStaticKey, 32)) { - LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed"); - Terminate (); + LogPrint (eLogError, "NTCP2: Static key mistmatch in SessionConfirmed"); + SendTerminationAndTerminate (eNTCP2IncorrectSParameter); return; } @@ -728,7 +728,7 @@ namespace transport case eNTCP2BlkTermination: if (size >= 9) { - LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 9])); + LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 8])); Terminate (); } else @@ -828,6 +828,20 @@ namespace transport delete[] payload; } + void NTCP2Session::SendTermination (NTCP2TerminationReason reason) + { + uint8_t payload[12] = { eNTCP2BlkTermination, 0, 9 }; + htobe64buf (payload + 3, m_ReceiveSequenceNumber); + payload[11] = (uint8_t)reason; + SendNextFrame (payload, 12); + } + + void NTCP2Session::SendTerminationAndTerminate (NTCP2TerminationReason reason) + { + SendTermination (reason); + m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go + } + void NTCP2Session::SendI2NPMessages (const std::vector >& msgs) { m_Server.GetService ().post (std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this (), msgs)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 5ac6a280..c7c53b53 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -40,7 +40,7 @@ namespace transport eNTCP2ClockSkew, // 7 eNTCP2PaddingViolation, // 8 eNTCP2AEADFraminError, // 9 - eNTCP2PayloadFromatError, // 10 + eNTCP2PayloadFormatError, // 10 eNTCP2Message1Error, // 11 eNTCP2Message2Error, // 12 eNTCP2Message3Error, // 13 @@ -135,6 +135,8 @@ namespace transport void HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void SendQueue (); void SendRouterInfo (); + void SendTermination (NTCP2TerminationReason reason); + void SendTerminationAndTerminate (NTCP2TerminationReason reason); void PostI2NPMessages (std::vector > msgs); private: From 83bbe6a9d91c48f0d4d122a8e2a1b5e764c18d7b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 12:07:09 -0400 Subject: [PATCH 143/195] show NTCP2 address --- daemon/HTTPServer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index c9d6ba40..c55714a7 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -259,20 +259,21 @@ namespace http { s << "Our external address:" << "
\r\n" ; for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) { - if (address->IsNTCP2 ()) + if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ()) { - // TODO: show actual address s << "NTCP2   supported
\r\n"; continue; } switch (address->transportStyle) { case i2p::data::RouterInfo::eTransportNTCP: - if (address->host.is_v6 ()) - s << "NTCP6  "; - else - s << "NTCP  "; - break; + { + s << "NTCP"; + if (address->IsPublishedNTCP2 ()) s << "2"; + if (address->host.is_v6 ()) s << "6"; + s << "  "; + break; + } case i2p::data::RouterInfo::eTransportSSU: if (address->host.is_v6 ()) s << "SSU6     "; From 50cd321818042775cee6d899664bca63694e93b3 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 13:10:32 -0400 Subject: [PATCH 144/195] NTCP2 idle timeout --- libi2pd/NTCP2.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++----- libi2pd/NTCP2.h | 16 ++++++++-- 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 00d874cc..a6e756fb 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -139,7 +139,7 @@ namespace transport } NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): - TransportSession (in_RemoteRouter, 30), + TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), @@ -183,6 +183,11 @@ namespace transport } } + void NTCP2Session::TerminateByTimeout () + { + SendTerminationAndTerminate (eNTCP2IdleTimeout); + } + void NTCP2Session::Done () { m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); @@ -192,6 +197,7 @@ namespace transport { m_IsEstablished = true; m_Establisher.reset (nullptr); + SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT); transports.PeerConnected (shared_from_this ()); } @@ -666,6 +672,7 @@ namespace transport } else { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_NumReceivedBytes += bytes_transferred + 2; // + length i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); uint8_t nonce[12]; @@ -679,8 +686,8 @@ namespace transport } else { - LogPrint (eLogWarning, "NTCP2: Received MAC verification failed "); - Terminate (); + LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed "); + SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure); } delete[] decrypted; } @@ -764,6 +771,7 @@ namespace transport void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_NumSentBytes += bytes_transferred; i2p::transport::transports.UpdateSentBytes (bytes_transferred); delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; @@ -857,7 +865,8 @@ namespace transport } NTCP2Server::NTCP2Server (): - m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service) + m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), + m_TerminationTimer (m_Service) { } @@ -914,6 +923,7 @@ namespace transport } } } + ScheduleTermination (); } } @@ -993,13 +1003,27 @@ namespace transport { if (this->AddNTCP2Session (conn)) { - conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn)); + auto timer = std::make_shared(m_Service); + auto timeout = NTCP2_CONNECT_TIMEOUT * 5; + conn->SetTerminationTimeout(timeout * 2); + timer->expires_from_now (boost::posix_time::seconds(timeout)); + timer->async_wait ([conn, timeout](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds"); + //i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); + conn->Terminate (); + } + }); + conn->GetSocket ().async_connect (boost::asio::ip::tcp::endpoint (address, port), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); } }); } - void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn) + void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer) { + timer->cancel (); if (ecode) { LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ()); @@ -1024,7 +1048,7 @@ namespace transport if (conn) { conn->ServerLogin (); - // m_PendingIncomingSessions.push_back (conn); + m_PendingIncomingSessions.push_back (conn); } } else @@ -1051,7 +1075,7 @@ namespace transport if (conn) { conn->ServerLogin (); - // m_PendingIncomingSessions.push_back (conn); + m_PendingIncomingSessions.push_back (conn); } } else @@ -1065,6 +1089,44 @@ namespace transport conn, std::placeholders::_1)); } } + + void NTCP2Server::ScheduleTermination () + { + m_TerminationTimer.expires_from_now (boost::posix_time::seconds(NTCP2_TERMINATION_CHECK_TIMEOUT)); + m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer, + this, std::placeholders::_1)); + } + + void NTCP2Server::HandleTerminationTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + auto ts = i2p::util::GetSecondsSinceEpoch (); + // established + for (auto& it: m_NTCP2Sessions) + if (it.second->IsTerminationTimeoutExpired (ts)) + { + auto session = it.second; + LogPrint (eLogDebug, "NTCP2: No activity for ", session->GetTerminationTimeout (), " seconds"); + session->TerminateByTimeout (); // it doesn't change m_NTCP2Session right a way + } + // pending + for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();) + { + if ((*it)->IsEstablished () || (*it)->IsTerminated ()) + it = m_PendingIncomingSessions.erase (it); // established or terminated + else if ((*it)->IsTerminationTimeoutExpired (ts)) + { + (*it)->Terminate (); + it = m_PendingIncomingSessions.erase (it); // expired + } + else + it++; + } + + ScheduleTermination (); + } + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index c7c53b53..e4b2cddd 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -18,6 +18,12 @@ namespace transport const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; const int NTCP2_MAX_PADDING_RATIO = 6; // in % + + const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds + const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds + const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes + const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds + enum NTCP2BlockType { eNTCP2BlkDateTime = 0, @@ -39,7 +45,7 @@ namespace transport eNTCP2IncompatibleSignatureType, // 6 eNTCP2ClockSkew, // 7 eNTCP2PaddingViolation, // 8 - eNTCP2AEADFraminError, // 9 + eNTCP2AEADFramingError, // 9 eNTCP2PayloadFormatError, // 10 eNTCP2Message1Error, // 11 eNTCP2Message2Error, // 12 @@ -92,6 +98,7 @@ namespace transport NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter = nullptr); ~NTCP2Session (); void Terminate (); + void TerminateByTimeout (); void Done (); boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; @@ -186,7 +193,11 @@ namespace transport void HandleAccept (std::shared_ptr conn, const boost::system::error_code& error); void HandleAcceptV6 (std::shared_ptr conn, const boost::system::error_code& error); - void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn); + void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr conn, std::shared_ptr timer); + + // timer + void ScheduleTermination (); + void HandleTerminationTimer (const boost::system::error_code& ecode); private: @@ -194,6 +205,7 @@ namespace transport std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; + boost::asio::deadline_timer m_TerminationTimer; std::unique_ptr m_NTCP2Acceptor, m_NTCP2V6Acceptor; std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; From 4cf79088f944956862ee5fde0160091879aed673 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 13:19:35 -0400 Subject: [PATCH 145/195] NTCP2 idle timeout --- libi2pd/NTCP2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index a6e756fb..35100ef6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -942,6 +942,7 @@ namespace transport if (m_IsRunning) { m_IsRunning = false; + m_TerminationTimer.cancel (); m_Service.stop (); if (m_Thread) { From f7415c8a8fa9942f48ee089c5035dd2155081d18 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 14:49:28 -0400 Subject: [PATCH 146/195] enable/disable NTCP2 address --- daemon/Daemon.cpp | 4 +++- libi2pd/RouterContext.cpp | 41 ++++++++++++++++++++++++++++++++------- libi2pd/RouterContext.h | 3 ++- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 5efdc693..1302ebe8 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -159,8 +159,10 @@ namespace i2p if (published) { uint16_t port; i2p::config::GetOption("ntcp2.port", port); - i2p::context.PublishNTCP2Address (port); + i2p::context.PublishNTCP2Address (port, true); // publish } + else + i2p::context.PublishNTCP2Address (port, false); // unpublish } bool transit; i2p::config::GetOption("notransit", transit); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 93cb741c..d34acc57 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -96,8 +96,7 @@ namespace i2p if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now { NewNTCP2Keys (); - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - UpdateRouterInfo (); + UpdateNTCP2Address (true); } } @@ -156,17 +155,17 @@ namespace i2p UpdateRouterInfo (); } - void RouterContext::PublishNTCP2Address (int port) + void RouterContext::PublishNTCP2Address (int port, bool publish) { if (!port) port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool updated = false; for (auto& address : m_RouterInfo.GetAddresses ()) { - if (address->IsNTCP2 () && address->port != port) + if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish)) { address->port = port; - address->ntcp2->isPublished = true; + address->ntcp2->isPublished = publish; updated = true; } } @@ -174,6 +173,32 @@ namespace i2p UpdateRouterInfo (); } + void RouterContext::UpdateNTCP2Address (bool enable) + { + auto& addresses = m_RouterInfo.GetAddresses (); + bool found = false, updated = false; + for (auto it = addresses.begin (); it != addresses.end (); ++it) + { + if ((*it)->IsNTCP2 ()) + { + found = true; + if (!enable) + { + addresses.erase (it); + updated= true; + } + break; + } + } + if (enable && !found) + { + m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + updated = true; + } + if (updated) + UpdateRouterInfo (); + } + void RouterContext::UpdateAddress (const boost::asio::ip::address& host) { bool updated = false; @@ -310,7 +335,7 @@ namespace i2p auto& addresses = m_RouterInfo.GetAddresses (); for (auto it = addresses.begin (); it != addresses.end (); ++it) { - if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && + if ((*it)->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !(*it)->IsNTCP2 () && (*it)->host.is_v4 ()) { addresses.erase (it); @@ -490,9 +515,11 @@ namespace i2p if (!m_NTCP2Keys) { NewNTCP2Keys (); - m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + UpdateNTCP2Address (true); // enable NTCP2 } } + else + UpdateNTCP2Address (false); // disable NTCP2 return true; } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index b840e19a..f1a62c5a 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -78,7 +78,8 @@ namespace i2p void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon - void PublishNTCP2Address (int port); + void PublishNTCP2Address (int port, bool publish = true); + void UpdateNTCP2Address (bool enable); bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool IsUnreachable () const; From 26d0177c0113b60795dd783dc0fc733f4ab29e7f Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 20:28:29 -0400 Subject: [PATCH 147/195] always make NTCP address first --- libi2pd/RouterInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 14153ba0..2151ef3d 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -672,7 +672,7 @@ namespace data for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; - m_Addresses->push_back(std::move(addr)); + m_Addresses->push_front(std::move(addr)); // always make NTCP first } void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu) From 09c6faf9232935bdf9adb8e0e5974ca6a0d71e2b Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Aug 2018 21:16:35 -0400 Subject: [PATCH 148/195] don't overwrite NTCP2 keys --- libi2pd/RouterContext.cpp | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index d34acc57..a1ce6838 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -95,7 +95,7 @@ namespace i2p if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now { - NewNTCP2Keys (); + if (!m_NTCP2Keys) NewNTCP2Keys (); UpdateNTCP2Address (true); } } @@ -473,7 +473,21 @@ namespace i2p m_Keys.FromBuffer (buf, len); delete[] buf; } - + // read NTCP2 keys if available + std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); + if (n2k) + { + n2k.seekg (0, std::ios::end); + len = n2k.tellg(); + n2k.seekg (0, std::ios::beg); + if (len == sizeof (NTCP2PrivateKeys)) + { + m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); + n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); + } + n2k.close (); + } + // read RouterInfo m_RouterInfo.SetRouterIdentity (GetIdentity ()); i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); if (!routerInfo.IsUnreachable ()) // router.info looks good @@ -499,24 +513,8 @@ namespace i2p bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { - std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); - if (n2k) - { - n2k.seekg (0, std::ios::end); - len = n2k.tellg(); - n2k.seekg (0, std::ios::beg); - if (len == sizeof (NTCP2PrivateKeys)) - { - m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); - n2k.read ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); - } - n2k.close (); - } - if (!m_NTCP2Keys) - { - NewNTCP2Keys (); - UpdateNTCP2Address (true); // enable NTCP2 - } + if (!m_NTCP2Keys) NewNTCP2Keys (); + UpdateNTCP2Address (true); // enable NTCP2 } else UpdateNTCP2Address (false); // disable NTCP2 From 41b9f19b019fb8223975d4b6afe0b54ac7b19c25 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 4 Aug 2018 08:47:58 -0400 Subject: [PATCH 149/195] get unpublished NTCP2 address --- libi2pd/NTCP2.cpp | 4 ++-- libi2pd/RouterInfo.cpp | 50 ++++++++++++++++++++---------------------- libi2pd/RouterInfo.h | 5 +++-- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 35100ef6..0d66f08f 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -149,7 +149,7 @@ namespace transport m_Establisher.reset (new NTCP2Establisher); if (in_RemoteRouter) // Alice { - auto addr = in_RemoteRouter->GetNTCP2Address (); + auto addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address if (addr) { memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); @@ -580,7 +580,7 @@ namespace transport SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); return; } - auto addr = ri.GetNTCP2Address (); + auto addr = ri.GetNTCP2Address (false); // any NTCP2 address if (!addr) { LogPrint (eLogError, "NTCP2: No NTCP2 address found in SessionConfirmed"); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 2151ef3d..21f7132f 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -860,20 +860,33 @@ namespace data std::shared_ptr RouterInfo::GetNTCPAddress (bool v4only) const { - return GetAddress (eTransportNTCP, v4only); + return GetAddress ( + [v4only](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportNTCP) && (!v4only || address->host.is_v4 ()); + }); } std::shared_ptr RouterInfo::GetSSUAddress (bool v4only) const { - return GetAddress (eTransportSSU, v4only); + return GetAddress ( + [v4only](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportSSU) && (!v4only || address->host.is_v4 ()); + }); } std::shared_ptr RouterInfo::GetSSUV6Address () const { - return GetAddress (eTransportSSU, false, true); + return GetAddress ( + [](std::shared_ptr address)->bool + { + return (address->transportStyle == eTransportSSU) && address->host.is_v6 (); + }); } - std::shared_ptr RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const + template + std::shared_ptr RouterInfo::GetAddress (Filter filter) const { // TODO: make it more gereric using comparator #if (BOOST_VERSION >= 105300) @@ -882,33 +895,18 @@ namespace data auto addresses = m_Addresses; #endif for (const auto& address : *addresses) - { - if (address->transportStyle == s) - { - if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ())) - return address; - } - } + if (filter (address)) return address; + return nullptr; } - std::shared_ptr RouterInfo::GetNTCP2Address (bool v4only) const + std::shared_ptr RouterInfo::GetNTCP2Address (bool publishedOnly, bool v4only) const { - // TODO: implement through GetAddress -#if (BOOST_VERSION >= 105300) - auto addresses = boost::atomic_load (&m_Addresses); -#else - auto addresses = m_Addresses; -#endif - for (const auto& address : *addresses) - { - if (address->IsPublishedNTCP2 ()) + return GetAddress ( + [publishedOnly, v4only](std::shared_ptr address)->bool { - if (!v4only || address->host.is_v4 ()) - return address; - } - } - return nullptr; + return address->IsNTCP2 () && (!publishedOnly || address->IsPublishedNTCP2 ()) && (!v4only || address->host.is_v4 ()); + }); } std::shared_ptr RouterInfo::GetProfile () const diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 525c6e65..f95659d7 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -142,7 +142,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr std::shared_ptr GetNTCPAddress (bool v4only = true) const; - std::shared_ptr GetNTCP2Address (bool v4only = true) const; + std::shared_ptr GetNTCP2Address (bool publishedOnly, bool v4only = true) const; std::shared_ptr GetSSUAddress (bool v4only = true) const; std::shared_ptr GetSSUV6Address () const; @@ -216,7 +216,8 @@ namespace data size_t ReadString (char* str, size_t len, std::istream& s) const; void WriteString (const std::string& str, std::ostream& s) const; void ExtractCaps (const char * value); - std::shared_ptr GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; + template + std::shared_ptr GetAddress (Filter filter) const; void UpdateCapsProperty (); private: From f407022fe6c4f5373fea360d7c4672a2cdbbc9d8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 4 Aug 2018 13:48:09 -0400 Subject: [PATCH 150/195] connect to NTCP2 address if presented --- libi2pd/Transports.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index e4a3021b..922625d2 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -404,14 +404,19 @@ namespace transport if (!peer.numAttempts) // NTCP { peer.numAttempts++; - auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); - if (address && address->IsPublishedNTCP2 () && m_NTCP2Server) // NTCP2 have priority over NTCP if enabled + if (m_NTCP2Server) // we support NTCP2 { - auto s = std::make_shared (*m_NTCP2Server, peer.router); - m_NTCP2Server->Connect (address->host, address->port, s); - return true; - } - + // NTCP2 have priority over NTCP + auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only + if (address) + { + auto s = std::make_shared (*m_NTCP2Server, peer.router); + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } + } + // otherwise NTCP1 + auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address && m_NTCPServer) { #if BOOST_VERSION >= 104900 From 2b61f9a7312fe7c462f9d69741abf588fc1bfce4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 7 Aug 2018 10:35:25 -0400 Subject: [PATCH 151/195] fixed #1217. verify decryption result --- libi2pd/Crypto.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 24ce9c72..0a9093a2 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1081,7 +1081,8 @@ namespace crypto EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, 16, (uint8_t *)(msg + msgLen)); EVP_DecryptInit_ex(ctx, NULL, NULL, key, nonce); EVP_DecryptUpdate(ctx, NULL, &outlen, ad, adLen); - ret = EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen) > 0; + EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen); + ret = EVP_DecryptFinal_ex(ctx, buf + outlen, &outlen) > 0; } EVP_CIPHER_CTX_free (ctx); From f7728aa1f614ca098c8099073c3587e7c0661981 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Aug 2018 16:23:44 -0400 Subject: [PATCH 152/195] reuse NTCP2 frame buffers --- libi2pd/NTCP2.cpp | 17 +++++++++++------ libi2pd/NTCP2.h | 8 ++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0d66f08f..3dda72e2 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -143,7 +143,7 @@ namespace transport m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), - m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), + m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { m_Establisher.reset (new NTCP2Establisher); @@ -647,11 +647,15 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); + i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); + uint16_t oldLen = m_NextReceivedLen; m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); - delete[] m_NextReceivedBuffer; - m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; + if (m_NextReceivedLen > oldLen) + { + delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; + } Receive (); } } @@ -784,7 +788,8 @@ namespace transport { if (!m_SendQueue.empty ()) { - uint8_t * payload = new uint8_t[NTCP2_UNENCRYPTED_FRAME_MAX_SIZE]; + auto buf = m_Server.NewNTCP2FrameBuffer (); + uint8_t * payload = buf->data (); size_t s = 0; // add I2NP blocks while (!m_SendQueue.empty ()) @@ -815,7 +820,7 @@ namespace transport s += paddingSize; // send SendNextFrame (payload, s); - delete[] payload; + m_Server.DeleteNTCP2FrameBuffer (buf); } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index e4b2cddd..f63479ed 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -6,8 +6,10 @@ #include #include #include +#include #include #include +#include "util.h" #include "RouterInfo.h" #include "TransportSession.h" @@ -57,6 +59,7 @@ namespace transport }; + typedef std::array NTCP2FrameBuffer; struct NTCP2Establisher { NTCP2Establisher (); @@ -187,6 +190,9 @@ namespace transport void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr conn); + NTCP2FrameBuffer * NewNTCP2FrameBuffer () { return m_NTCP2FrameBuffersPool.Acquire(); } + void DeleteNTCP2FrameBuffer (NTCP2FrameBuffer * buf) { return m_NTCP2FrameBuffersPool.Release(buf); } + private: void Run (); @@ -210,6 +216,8 @@ namespace transport std::map > m_NTCP2Sessions; std::list > m_PendingIncomingSessions; + i2p::util::MemoryPool m_NTCP2FrameBuffersPool; + public: // for HTTP/I2PControl From 5cc84133e3f1a493e5ae01c9834eedd87e6f5095 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Aug 2018 17:38:21 -0400 Subject: [PATCH 153/195] fixed incorrect lenght --- libi2pd/NTCP2.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 3dda72e2..8b75353d 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -648,14 +648,10 @@ namespace transport else { i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); - uint16_t oldLen = m_NextReceivedLen; m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); - if (m_NextReceivedLen > oldLen) - { - delete[] m_NextReceivedBuffer; - m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; - } + delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; Receive (); } } From d8c6dede7e4983bced0c430a552a4a4878b69f79 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 12:53:36 -0400 Subject: [PATCH 154/195] moved NTCP2 handshake buffers to establisher --- libi2pd/NTCP2.cpp | 146 ++++++++++++++++++++++++++-------------------- libi2pd/NTCP2.h | 12 ++-- 2 files changed, 91 insertions(+), 67 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8b75353d..0e3f263f 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -17,7 +17,8 @@ namespace i2p { namespace transport { - NTCP2Establisher::NTCP2Establisher () + NTCP2Establisher::NTCP2Establisher (): + m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr) { m_Ctx = BN_CTX_new (); CreateEphemeralKey (); @@ -26,6 +27,9 @@ namespace transport NTCP2Establisher::~NTCP2Establisher () { BN_CTX_free (m_Ctx); + delete[] m_SessionRequestBuffer; + delete[] m_SessionCreatedBuffer; + delete[] m_SessionConfirmedBuffer; } void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) @@ -108,14 +112,14 @@ namespace transport MixKey (inputKeyMaterial, m_K); } - void NTCP2Establisher::KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen) + void NTCP2Establisher::KDF2Alice () { - KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetRemotePub ()); + KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetRemotePub ()); } - void NTCP2Establisher::KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen) + void NTCP2Establisher::KDF2Bob () { - KeyDerivationFunction2 (sessionRequest, sessionRequestLen, GetPub ()); + KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); } void NTCP2Establisher::KDF3Alice () @@ -138,11 +142,24 @@ namespace transport i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } + void NTCP2Establisher::CreateSessionRequestBuffer (size_t paddingLen) + { + m_SessionRequestBufferLen = paddingLen + 64; + m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; + RAND_bytes (m_SessionRequestBuffer + 64, paddingLen); + } + + void NTCP2Establisher::CreateSessionCreatedBuffer (size_t paddingLen) + { + m_SessionCreatedBufferLen = paddingLen + 64; + m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; + RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), m_IsEstablished (false), m_IsTerminated (false), - m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr), m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false) { @@ -162,9 +179,6 @@ namespace transport NTCP2Session::~NTCP2Session () { - delete[] m_SessionRequestBuffer; - delete[] m_SessionCreatedBuffer; - delete[] m_SessionConfirmedBuffer; delete[] m_NextReceivedBuffer; delete[] m_NextSendBuffer; } @@ -234,14 +248,12 @@ namespace transport { // create buffer and fill padding auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_SessionRequestBufferLen = paddingLength + 64; - m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; - RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + m_Establisher->CreateSessionRequestBuffer (paddingLength); // encrypt X i2p::crypto::CBCEncryption encryption; encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionRequestBuffer); // X + encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionRequestBuffer); // X encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // encryption key for next block m_Establisher->KDF1Alice (); @@ -258,9 +270,9 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionRequestBuffer + 32, 32, true); // encrypt // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -274,9 +286,9 @@ namespace transport } else { - m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size + m_Establisher->m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size // we receive first 64 bytes (32 Y, and 32 ChaCha/Poly frame) first - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer, 64), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } @@ -295,24 +307,34 @@ namespace transport i2p::crypto::CBCDecryption decryption; decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); + decryption.Decrypt (m_Establisher->m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated // decryption key for next block m_Establisher->KDF1Bob (); // verify MAC and decrypt options block (32 bytes), use m_H as AD uint8_t nonce[12], options[16]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt { if (options[1] == 2) { uint16_t paddingLen = bufbe16toh (options + 2); - m_SessionRequestBufferLen = paddingLen + 64; + m_Establisher->m_SessionRequestBufferLen = paddingLen + 64; m_Establisher->m3p2Len = bufbe16toh (options + 4); // TODO: check tsA if (paddingLen > 0) - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + { + if (paddingLen <= 287 - 64) // session request is 287 bytes max + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); + Terminate (); + } + } else SendSessionCreated (); } @@ -344,15 +366,14 @@ namespace transport void NTCP2Session::SendSessionCreated () { auto paddingLen = rand () % (287 - 64); - m_SessionCreatedBufferLen = paddingLen + 64; - m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; + m_Establisher->CreateSessionCreatedBuffer (paddingLen); // encrypt Y i2p::crypto::CBCEncryption encryption; encryption.SetKey (i2p::context.GetIdentHash ()); encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_SessionCreatedBuffer); // Y + encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionCreatedBuffer); // Y // encryption key for next block (m_K) - m_Establisher->KDF2Bob (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Bob (); uint8_t options[16]; memset (options, 0, 16); htobe16buf (options + 2, paddingLen); // padLen @@ -360,11 +381,9 @@ namespace transport // sign and encrypt options, use m_H as AD uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt - // fill padding - RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionCreatedBuffer + 32, 32, true); // encrypt // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionCreatedBuffer, m_SessionCreatedBufferLen), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -378,26 +397,26 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); - m_SessionCreatedBufferLen = 64; + m_Establisher->m_SessionCreatedBufferLen = 64; // decrypt Y i2p::crypto::CBCDecryption decryption; decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetIV (m_Establisher->m_IV); - decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); + decryption.Decrypt (m_Establisher->m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); // decryption key for next block (m_K) - m_Establisher->KDF2Alice (m_SessionRequestBuffer, m_SessionRequestBufferLen); + m_Establisher->KDF2Alice (); // decrypt and verify MAC uint8_t payload[16]; uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt { uint16_t paddingLen = bufbe16toh(payload + 2); LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); // TODO: check tsB if (paddingLen > 0) { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } else @@ -420,7 +439,7 @@ namespace transport } else { - m_SessionCreatedBufferLen += bytes_transferred; + m_Establisher->m_SessionCreatedBufferLen += bytes_transferred; SendSessionConfirmed (); } } @@ -431,25 +450,25 @@ namespace transport // update AD uint8_t h[80]; memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload SHA256 (h, 64, h); - int paddingLength = m_SessionCreatedBufferLen - 64; + int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { SHA256_CTX ctx; SHA256_Init (&ctx); SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); SHA256_Final (h, &ctx); } // part1 48 bytes - m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer, 48, true); // encrypt // part 2 // update AD again - memcpy (h + 32, m_SessionConfirmedBuffer, 48); + memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_Establisher->m_H); std::vector buf(m_Establisher->m3p2Len - 16); // -MAC @@ -459,15 +478,15 @@ namespace transport memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); m_Establisher->KDF3Alice (); memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt + i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt uint8_t tmp[48]; - memcpy (tmp, m_SessionConfirmedBuffer, 48); - memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); - memcpy (m_SessionConfirmedBuffer, tmp, 48); + memcpy (tmp, m_Establisher->m_SessionConfirmedBuffer, 48); + memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + memcpy (m_Establisher->m_SessionConfirmedBuffer, tmp, 48); // send message - boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), + boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -501,8 +520,8 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated sent"); - m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), + m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } } @@ -511,44 +530,44 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 read error: ", ecode.message ()); + LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ()); Terminate (); } else { - LogPrint (eLogDebug, "NTCP2: SessionConfirmed Part1 received"); + LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); // update AD uint8_t h[80]; memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_SessionCreatedBuffer + 32, 32); // encrypted payload + memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload SHA256 (h, 64, h); - int paddingLength = m_SessionCreatedBufferLen - 64; + int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; if (paddingLength > 0) { SHA256_CTX ctx; SHA256_Init (&ctx); SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); SHA256_Final (h, &ctx); } // part 1 uint8_t nonce[12]; CreateNonce (1, nonce); - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S { // part 2 // update AD again - memcpy (h + 32, m_SessionConfirmedBuffer, 48); + memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); SHA256 (h, 80, m_Establisher->m_H); std::vector buf(m_Establisher->m3p2Len - 16); // -MAC m_Establisher->KDF3Bob (); memset (nonce, 0, 12); // set nonce to 0 again - if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt + if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt { // caclulate new h again for KDF data - memcpy (m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); + memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext + SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); KeyDerivationFunctionDataPhase (); // Bob data phase keys m_SendKey = m_Kba; @@ -625,8 +644,8 @@ namespace transport void NTCP2Session::ServerLogin () { - m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now - boost::asio::async_read (m_Socket, boost::asio::buffer(m_SessionRequestBuffer, 64), boost::asio::transfer_all (), + m_Establisher->m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -650,7 +669,7 @@ namespace transport i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); - delete[] m_NextReceivedBuffer; + if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; Receive (); } @@ -682,6 +701,7 @@ namespace transport { LogPrint (eLogDebug, "NTCP2: received message decrypted"); ProcessNextFrame (decrypted, m_NextReceivedLen-16); + delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = nullptr; // we don't need received buffer anymore ReceiveLength (); } else diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index f63479ed..00f4275e 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -76,8 +76,8 @@ namespace transport void KDF1Alice (); void KDF1Bob (); - void KDF2Alice (const uint8_t * sessionRequest, size_t sessionRequestLen); - void KDF2Bob (const uint8_t * sessionRequest, size_t sessionRequestLen); + void KDF2Alice (); + void KDF2Bob (); void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Bob (); @@ -86,11 +86,17 @@ namespace transport void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); + void CreateSessionRequestBuffer (size_t paddingLength); + void CreateSessionCreatedBuffer (size_t paddingLength); BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; uint16_t m3p2Len; + + uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; + size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; + }; class NTCP2Server; @@ -156,8 +162,6 @@ namespace transport bool m_IsEstablished, m_IsTerminated; std::unique_ptr m_Establisher; - uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; - size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; // data phase uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32]; const uint8_t * m_SendKey, * m_ReceiveKey, * m_SendSipKey, * m_ReceiveSipKey; From 88e87d589bdd5835a928a48033b2a2d1a3ff3473 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 14:20:10 -0400 Subject: [PATCH 155/195] add incoming NTCP2 session to the sessions list --- libi2pd/NTCP2.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0e3f263f..6f524920 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -619,6 +619,7 @@ namespace transport // ready to communicate auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); + m_Server.AddNTCP2Session (shared_from_this ()); Established (); SendRouterInfo (); ReceiveLength (); From f7e4afc2827d285b66fb570f82f411bd6f9b94bb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 15:47:02 -0400 Subject: [PATCH 156/195] use same buffer for input and output for AEAD/Chacha20/Poly1305 --- libi2pd/Crypto.cpp | 18 ++++++++++++++---- libi2pd/NTCP2.cpp | 6 ++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 0a9093a2..3f214b0e 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1018,9 +1018,6 @@ namespace crypto uint8_t polyKey[64]; memset(polyKey, 0, sizeof(polyKey)); chacha20 (polyKey, 64, nonce, key, 0); - // encrypt data - memcpy (buf, msg, msgLen); - chacha20 (buf, msgLen, nonce, key, 1); // create Poly1305 message if (!ad) adLen = 0; @@ -1038,7 +1035,20 @@ namespace crypto memcpy (polyMsg.data () + offset, padding, rem); offset += rem; } } - memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data + // encrypt/decrypt data and add to hash + memcpy (buf, msg, msgLen); + if (encrypt) + { + chacha20 (buf, msgLen, nonce, key, 1); // encrypt + memcpy (polyMsg.data () + offset, buf, msgLen); // after encryption + } + else + { + memcpy (polyMsg.data () + offset, buf, msgLen); // before decryption + chacha20 (buf, msgLen, nonce, key, 1); // decrypt + } + offset += msgLen; // encrypted data + auto rem = msgLen & 0x0F; // %16 if (rem) { diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6f524920..91b897f5 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -697,11 +697,10 @@ namespace transport i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); uint8_t nonce[12]; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; - uint8_t * decrypted = new uint8_t[m_NextReceivedLen]; - if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, decrypted, m_NextReceivedLen, false)) + if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) { LogPrint (eLogDebug, "NTCP2: received message decrypted"); - ProcessNextFrame (decrypted, m_NextReceivedLen-16); + ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = nullptr; // we don't need received buffer anymore ReceiveLength (); } @@ -710,7 +709,6 @@ namespace transport LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed "); SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure); } - delete[] decrypted; } } From d320a89590c704ddd4f63d7d52193bf23e0c6dee Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 9 Aug 2018 16:32:43 -0400 Subject: [PATCH 157/195] don't copy buffer to ifself --- libi2pd/Crypto.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 3f214b0e..7a947d34 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1036,7 +1036,8 @@ namespace crypto } } // encrypt/decrypt data and add to hash - memcpy (buf, msg, msgLen); + if (buf != msg) + memcpy (buf, msg, msgLen); if (encrypt) { chacha20 (buf, msgLen, nonce, key, 1); // encrypt From 5b83d4bef81000d75d9081296adeb9677134e8e7 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 10:53:34 -0400 Subject: [PATCH 158/195] move handshake messages creation to NTCP2Establisher --- libi2pd/NTCP2.cpp | 183 +++++++++++++++++++++++++--------------------- libi2pd/NTCP2.h | 7 +- 2 files changed, 104 insertions(+), 86 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 91b897f5..b54d6cd7 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -142,20 +142,108 @@ namespace transport i2p::crypto::GetEd25519 ()->ScalarMulB (m_EphemeralPrivateKey, m_EphemeralPublicKey, m_Ctx); } - void NTCP2Establisher::CreateSessionRequestBuffer (size_t paddingLen) + void NTCP2Establisher::CreateSessionRequestMessage () { - m_SessionRequestBufferLen = paddingLen + 64; + // create buffer and fill padding + auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes + m_SessionRequestBufferLen = paddingLength + 64; m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen]; - RAND_bytes (m_SessionRequestBuffer + 64, paddingLen); + RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); + // encrypt X + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (m_RemoteIdentHash); + encryption.SetIV (m_IV); + encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X + encryption.GetIV (m_IV); // save IV for SessionCreated + // encryption key for next block + KDF1Alice (); + // fill options + uint8_t options[32]; // actual options size is 16 bytes + memset (options, 0, 16); + options[1] = 2; // ver + htobe16buf (options + 2, paddingLength); // padLen + m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options + htobe16buf (options + 4, m3p2Len); + // 2 bytes reserved + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA + // 4 bytes reserved + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt } - void NTCP2Establisher::CreateSessionCreatedBuffer (size_t paddingLen) + void NTCP2Establisher::CreateSessionCreatedMessage () { + auto paddingLen = rand () % (287 - 64); m_SessionCreatedBufferLen = paddingLen + 64; m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen]; RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen); + // encrypt Y + i2p::crypto::CBCEncryption encryption; + encryption.SetKey (i2p::context.GetIdentHash ()); + encryption.SetIV (m_IV); + encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y + // encryption key for next block (m_K) + KDF2Bob (); + uint8_t options[16]; + memset (options, 0, 16); + htobe16buf (options + 2, paddingLen); // padLen + htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB + // sign and encrypt options, use m_H as AD + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, m_K, nonce, m_SessionCreatedBuffer + 32, 32, true); // encrypt + } + void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce) + { + // update AD + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256_Final (m_H, &ctx); + + int paddingLength = m_SessionCreatedBufferLen - 64; + if (paddingLength > 0) + { + SHA256_CTX ctx1; + SHA256_Init (&ctx1); + SHA256_Update (&ctx1, m_H, 32); + SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (m_H, &ctx1); + } + // part1 48 bytes + m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; + i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, m_H, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt + } + + void NTCP2Establisher::CreateSessionConfirmedMessagePart2 (const uint8_t * nonce) + { + // part 2 + // update AD again + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48); + SHA256_Final (m_H, &ctx); + // fill and encrypt + uint8_t * buf = m_SessionConfirmedBuffer + 48; + buf[0] = eNTCP2BlkRouterInfo; // block + htobe16buf (buf + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI + buf[3] = 0; // flag + memcpy (buf + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); + KDF3Alice (); + i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, m_K, nonce, buf, m3p2Len, true); // encrypt + // update h again + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, buf, m3p2Len); + SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext) + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), @@ -166,6 +254,7 @@ namespace transport m_Establisher.reset (new NTCP2Establisher); if (in_RemoteRouter) // Alice { + m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash (); auto addr = in_RemoteRouter->GetNTCP2Address (true); // we need a published address if (addr) { @@ -246,31 +335,7 @@ namespace transport void NTCP2Session::SendSessionRequest () { - // create buffer and fill padding - auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes - m_Establisher->CreateSessionRequestBuffer (paddingLength); - // encrypt X - i2p::crypto::CBCEncryption encryption; - encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionRequestBuffer); // X - encryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated - // encryption key for next block - m_Establisher->KDF1Alice (); - // fill options - uint8_t options[32]; // actual options size is 16 bytes - memset (options, 0, 16); - options[1] = 2; // ver - htobe16buf (options + 2, paddingLength); // padLen - m_Establisher->m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options - htobe16buf (options + 4, m_Establisher->m3p2Len); - // 2 bytes reserved - htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA - // 4 bytes reserved - // sign and encrypt options, use m_H as AD - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionRequestBuffer + 32, 32, true); // encrypt + m_Establisher->CreateSessionRequestMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -365,23 +430,7 @@ namespace transport void NTCP2Session::SendSessionCreated () { - auto paddingLen = rand () % (287 - 64); - m_Establisher->CreateSessionCreatedBuffer (paddingLen); - // encrypt Y - i2p::crypto::CBCEncryption encryption; - encryption.SetKey (i2p::context.GetIdentHash ()); - encryption.SetIV (m_Establisher->m_IV); - encryption.Encrypt (m_Establisher->GetPub (), 32, m_Establisher->m_SessionCreatedBuffer); // Y - // encryption key for next block (m_K) - m_Establisher->KDF2Bob (); - uint8_t options[16]; - memset (options, 0, 16); - htobe16buf (options + 2, paddingLen); // padLen - htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsB - // sign and encrypt options, use m_H as AD - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionCreatedBuffer + 32, 32, true); // encrypt + m_Establisher->CreateSessionCreatedMessage (); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); @@ -444,47 +493,13 @@ namespace transport } } - void NTCP2Session::SendSessionConfirmed () { - // update AD - uint8_t h[80]; - memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload - SHA256 (h, 64, h); - int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; - if (paddingLength > 0) - { - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); - SHA256_Final (h, &ctx); - } - // part1 48 bytes - m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48]; uint8_t nonce[12]; - CreateNonce (1, nonce); - i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer, 48, true); // encrypt - // part 2 - // update AD again - memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_Establisher->m_H); - - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - buf[0] = eNTCP2BlkRouterInfo; // block - htobe16buf (buf.data () + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI - buf[3] = 0; // flag - memcpy (buf.data () + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ()); - m_Establisher->KDF3Alice (); - memset (nonce, 0, 12); // set nonce to 0 again - i2p::crypto::AEADChaCha20Poly1305 (buf.data (), m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len, true); // encrypt - uint8_t tmp[48]; - memcpy (tmp, m_Establisher->m_SessionConfirmedBuffer, 48); - memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); - memcpy (m_Establisher->m_SessionConfirmedBuffer, tmp, 48); - + CreateNonce (1, nonce); // set nonce to 1 + m_Establisher->CreateSessionConfirmedMessagePart1 (nonce); + memset (nonce, 0, 12); // set nonce back to 0 + m_Establisher->CreateSessionConfirmedMessagePart2 (nonce); // send message boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 00f4275e..b5540b43 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -86,12 +86,15 @@ namespace transport void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); - void CreateSessionRequestBuffer (size_t paddingLength); - void CreateSessionCreatedBuffer (size_t paddingLength); + void CreateSessionRequestMessage (); + void CreateSessionCreatedMessage (); + void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); + void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; + i2p::data::IdentHash m_RemoteIdentHash; uint16_t m3p2Len; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer; From 9884a4336f35e3c71c075d1c1d706b17585c8165 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 13:42:59 -0400 Subject: [PATCH 159/195] don't connect to NTCP2 only address using NTCP --- libi2pd/RouterContext.cpp | 11 +++++------ libi2pd/RouterInfo.cpp | 10 ++++++---- libi2pd/RouterInfo.h | 2 ++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index a1ce6838..ee895e32 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -84,6 +84,11 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } + if (ntcp2) + { + if (!m_NTCP2Keys) NewNTCP2Keys (); + routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); + } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC @@ -92,12 +97,6 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); - - if (ntcp2) // TODO: should update routerInfo, but we ignore upublished NTCP2 addresses for now - { - if (!m_NTCP2Keys) NewNTCP2Keys (); - UpdateNTCP2Address (true); - } } void RouterContext::UpdateRouterInfo () diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 21f7132f..95e88963 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -176,13 +176,13 @@ namespace data auto address = std::make_shared
(); s.read ((char *)&address->cost, sizeof (address->cost)); s.read ((char *)&address->date, sizeof (address->date)); - bool isNtcp2 = false; + bool isNTCP2Only = false; char transportStyle[6]; auto transportStyleLen = ReadString (transportStyle, 6, s) - 1; if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2 { address->transportStyle = eTransportNTCP; - if (transportStyleLen > 4 || transportStyle[4] == '2') isNtcp2= true; + if (transportStyleLen > 4 && transportStyle[4] == '2') isNTCP2Only= true; } else if (!strcmp (transportStyle, "SSU")) { @@ -293,7 +293,8 @@ namespace data if (!s) return; } if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented - if (supportedTransports && (!isNtcp2 || address->IsPublishedNTCP2 ())) // we ignore unpublished NTCP2 only addresses + if (isNTCP2Only && address->ntcp2) address->ntcp2->isNTCP2Only = true; + if (supportedTransports) { addresses->push_back(address); m_SupportedTransports |= supportedTransports; @@ -705,6 +706,7 @@ namespace data addr->cost = 14; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); + addr->ntcp2->isNTCP2Only = true; // NTCP2 only address memcpy (addr->ntcp2->staticKey, staticKey, 32); memcpy (addr->ntcp2->iv, iv, 16); m_Addresses->push_back(std::move(addr)); @@ -863,7 +865,7 @@ namespace data return GetAddress ( [v4only](std::shared_ptr address)->bool { - return (address->transportStyle == eTransportNTCP) && (!v4only || address->host.is_v4 ()); + return (address->transportStyle == eTransportNTCP) && !address->IsNTCP2Only () && (!v4only || address->host.is_v4 ()); }); } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index f95659d7..47a5d680 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -95,6 +95,7 @@ namespace data Tag<32> staticKey; Tag<16> iv; bool isPublished = false; + bool isNTCP2Only = false; }; struct Address @@ -126,6 +127,7 @@ namespace data bool IsNTCP2 () const { return (bool)ntcp2; }; bool IsPublishedNTCP2 () const { return IsNTCP2 () && ntcp2->isPublished; }; + bool IsNTCP2Only () const { return ntcp2 && ntcp2->isNTCP2Only; }; }; typedef std::list > Addresses; From ee700ac86101d127d568326b3778525039f6aa67 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 15:14:07 -0400 Subject: [PATCH 160/195] fixed incorrect iv for published NTCP2 addresses --- libi2pd/RouterContext.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index ee895e32..d9bea661 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -84,11 +84,6 @@ namespace i2p routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (host.c_str(), port); } - if (ntcp2) - { - if (!m_NTCP2Keys) NewNTCP2Keys (); - routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv); - } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer); // LR, BC @@ -97,6 +92,13 @@ namespace i2p routerInfo.CreateBuffer (m_Keys); m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); + + if (ntcp2) // we don't store iv in the address if non published so we must update it from keys + { + if (!m_NTCP2Keys) NewNTCP2Keys (); + UpdateNTCP2Address (true); + } + } void RouterContext::UpdateRouterInfo () From a2c41c9e36e83c912450be8351052d3ef09b482c Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 10 Aug 2018 15:35:43 -0400 Subject: [PATCH 161/195] allow NTCP2 only transports --- daemon/Daemon.cpp | 5 +++-- libi2pd/Transports.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 1302ebe8..0b88e983 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -289,9 +289,10 @@ namespace i2p if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled"); i2p::transport::transports.Start(ntcp, ssu); - if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU()) { + if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2()) LogPrint(eLogInfo, "Daemon: Transports started"); - } else { + else + { LogPrint(eLogError, "Daemon: failed to start Transports"); /** shut down netdb right away */ i2p::transport::transports.Stop(); diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index 47944fff..cb523545 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -81,6 +81,7 @@ namespace transport bool IsBoundNTCP() const { return m_NTCPServer != nullptr; } bool IsBoundSSU() const { return m_SSUServer != nullptr; } + bool IsBoundNTCP2() const { return m_NTCP2Server != nullptr; } bool IsOnline() const { return m_IsOnline; }; void SetOnline (bool online) { m_IsOnline = online; }; From 6d46fc9f9f1a46ce0b7c3bde726fc6ec3e24556e Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 11 Aug 2018 16:08:21 -0400 Subject: [PATCH 162/195] check send frame error code --- libi2pd/NTCP2.cpp | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index b54d6cd7..084fe0d6 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -465,8 +465,16 @@ namespace transport // TODO: check tsB if (paddingLen > 0) { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + if (paddingLen <= 287 - 64) // session created is 287 bytes max + { + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long"); + Terminate (); + } } else SendSessionConfirmed (); @@ -677,7 +685,8 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); + if (ecode != boost::asio::error::operation_aborted) + LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); Terminate (); } else @@ -702,7 +711,8 @@ namespace transport { if (ecode) { - LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); + if (ecode != boost::asio::error::operation_aborted) + LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); Terminate (); } else @@ -805,13 +815,21 @@ namespace transport void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); - m_NumSentBytes += bytes_transferred; - i2p::transport::transports.UpdateSentBytes (bytes_transferred); - delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; - LogPrint (eLogDebug, "NTCP2: Next frame sent"); m_IsSending = false; - SendQueue (); + delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; + + if (ecode) + { + LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ()); + } + else + { + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_NumSentBytes += bytes_transferred; + i2p::transport::transports.UpdateSentBytes (bytes_transferred); + LogPrint (eLogDebug, "NTCP2: Next frame sent"); + SendQueue (); + } } void NTCP2Session::SendQueue () From 29b91075d28a32132003b78360324fb2b81c71d8 Mon Sep 17 00:00:00 2001 From: l-n-s Date: Sun, 12 Aug 2018 02:36:00 -0400 Subject: [PATCH 163/195] Don't add SSU/NTCP addresses to RI if they are disabled in config (#1220) --- libi2pd/RouterContext.cpp | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index d9bea661..b2774aa2 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -50,6 +50,8 @@ namespace i2p port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool ssu; i2p::config::GetOption("ssu", ssu); + bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool nat; i2p::config::GetOption("nat", nat); std::string ifname; i2p::config::GetOption("ifname", ifname); @@ -67,8 +69,10 @@ namespace i2p if(ifname4.size()) host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string(); - routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); - routerInfo.AddNTCPAddress (host.c_str(), port); + if (ssu) + routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + if (ntcp) + routerInfo.AddNTCPAddress (host.c_str(), port); } if (ipv6) { @@ -81,8 +85,10 @@ namespace i2p if(ifname6.size()) host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string(); - routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); - routerInfo.AddNTCPAddress (host.c_str(), port); + if (ssu) + routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + if (ntcp) + routerInfo.AddNTCPAddress (host.c_str(), port); } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | @@ -363,16 +369,19 @@ namespace i2p caps |= i2p::data::RouterInfo::eFloodfill; m_RouterInfo.SetCaps (caps); - // insert NTCP back auto& addresses = m_RouterInfo.GetAddresses (); - for (const auto& addr : addresses) - { - if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU && - addr->host.is_v4 ()) + // insert NTCP back + bool ntcp; i2p::config::GetOption("ntcp", ntcp); + if (ntcp) { + for (const auto& addr : addresses) { - // insert NTCP address with host/port from SSU - m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port); - break; + if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU && + addr->host.is_v4 ()) + { + // insert NTCP address with host/port from SSU + m_RouterInfo.AddNTCPAddress (addr->host.to_string ().c_str (), addr->port); + break; + } } } // delete previous introducers From d36d825ac119d15306d928749894124c0e0326e3 Mon Sep 17 00:00:00 2001 From: xcps Date: Mon, 13 Aug 2018 21:41:43 +0500 Subject: [PATCH 164/195] Update HTTPServer.cpp Fix transport sections in web interface --- daemon/HTTPServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index c55714a7..e5509f2b 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "Base.h" #include "FS.h" @@ -577,7 +578,7 @@ namespace http { } if (!tmp_s.str ().empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; s << tmp_s.str () << "

\r\n
\r\n"; } if (!tmp_s6.str ().empty ()) From 634101ceb598a2d4b8b6ff799c2e070d21254882 Mon Sep 17 00:00:00 2001 From: xcps Date: Mon, 13 Aug 2018 22:29:58 +0500 Subject: [PATCH 165/195] Update HTTPServer.cpp Fix transport sections in web interface 2 --- daemon/HTTPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index e5509f2b..cda3f2ec 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -578,7 +578,7 @@ namespace http { } if (!tmp_s.str ().empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; s << tmp_s.str () << "

\r\n
\r\n"; } if (!tmp_s6.str ().empty ()) From cd39a52c2543324639fe927a55443e3ff8ac2a37 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Aug 2018 13:43:51 -0400 Subject: [PATCH 166/195] correct endianness for siphash length --- libi2pd/NTCP2.cpp | 22 ++++++++++++---------- libi2pd/NTCP2.h | 6 +++++- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 084fe0d6..10373715 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -522,14 +522,14 @@ namespace transport m_ReceiveKey = m_Kba; m_SendSipKey = m_Sipkeysab; m_ReceiveSipKey = m_Sipkeysba; - memcpy (m_ReceiveIV, m_Sipkeysba + 16, 8); - memcpy (m_SendIV, m_Sipkeysab + 16, 8); + memcpy (m_ReceiveIV.buf, m_Sipkeysba + 16, 8); + memcpy (m_SendIV.buf, m_Sipkeysab + 16, 8); Established (); ReceiveLength (); // TODO: remove - //m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); - //SendQueue (); + // m_SendQueue.push_back (CreateDeliveryStatusMsg (1)); + // SendQueue (); } void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -597,8 +597,8 @@ namespace transport m_ReceiveKey = m_Kab; m_SendSipKey = m_Sipkeysba; m_ReceiveSipKey = m_Sipkeysab; - memcpy (m_ReceiveIV, m_Sipkeysab + 16, 8); - memcpy (m_SendIV, m_Sipkeysba + 16, 8); + memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); + memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); // process RI if (buf[0] != eNTCP2BlkRouterInfo) @@ -691,8 +691,9 @@ namespace transport } else { - i2p::crypto::Siphash<8> (m_ReceiveIV, m_ReceiveIV, 8, m_ReceiveSipKey); - m_NextReceivedLen = be16toh (m_NextReceivedLen ^ bufbe16toh(m_ReceiveIV)); + i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); + // m_NextRecivedLen comes from the network in BigEndian + m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ m_ReceiveIV.key; LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; @@ -803,8 +804,9 @@ namespace transport CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; m_NextSendBuffer = new uint8_t[len + 16 + 2]; i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true); - i2p::crypto::Siphash<8> (m_SendIV, m_SendIV, 8, m_SendSipKey); - htobuf16 (m_NextSendBuffer, bufbe16toh (m_SendIV) ^ htobe16(len + 16)); + i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey); + // length must be in BigEndian + htobe16buf (m_NextSendBuffer, (len + 16) ^ m_SendIV.key); LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); // send message diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index b5540b43..2be3f144 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -170,7 +170,11 @@ namespace transport const uint8_t * m_SendKey, * m_ReceiveKey, * m_SendSipKey, * m_ReceiveSipKey; uint16_t m_NextReceivedLen; uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer; - uint8_t m_ReceiveIV[8], m_SendIV[8]; + union + { + uint8_t buf[8]; + uint16_t key; + } m_ReceiveIV, m_SendIV; uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber; i2p::I2NPMessagesHandler m_Handler; From 49a44fc92edb8b8ae5a56d47e5131fca4f4f8555 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 13 Aug 2018 14:07:57 -0400 Subject: [PATCH 167/195] assume siphash IV in Litte Endian --- libi2pd/NTCP2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 10373715..36ca1dac 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -693,7 +693,7 @@ namespace transport { i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); // m_NextRecivedLen comes from the network in BigEndian - m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ m_ReceiveIV.key; + m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; @@ -806,7 +806,7 @@ namespace transport i2p::crypto::AEADChaCha20Poly1305 (payload, len, nullptr, 0, m_SendKey, nonce, m_NextSendBuffer + 2, len + 16, true); i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey); // length must be in BigEndian - htobe16buf (m_NextSendBuffer, (len + 16) ^ m_SendIV.key); + htobe16buf (m_NextSendBuffer, (len + 16) ^ le16toh (m_SendIV.key)); LogPrint (eLogDebug, "NTCP2: sent length ", len + 16); // send message From 86782aeb1bf9f8adced25fe52e79b7d1c012e27c Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 14 Aug 2018 11:27:27 -0400 Subject: [PATCH 168/195] don't send RouterInfo twice --- libi2pd/NTCP2.cpp | 7 ++++++- libi2pd/NTCP2.h | 2 ++ libi2pd/TransportSession.h | 1 + libi2pd/Transports.cpp | 11 +++++++---- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 36ca1dac..b54a83ef 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -644,7 +644,6 @@ namespace transport SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); m_Server.AddNTCP2Session (shared_from_this ()); Established (); - SendRouterInfo (); ReceiveLength (); } else @@ -919,6 +918,12 @@ namespace transport SendQueue (); } + void NTCP2Session::SendLocalRouterInfo () + { + if (!IsOutgoing ()) // we send it in SessionConfirmed + SendRouterInfo (); + } + NTCP2Server::NTCP2Server (): m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_TerminationTimer (m_Service) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 2be3f144..3e202dc5 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -120,6 +120,8 @@ namespace transport void ClientLogin (); // Alice void ServerLogin (); // Bob + + void SendLocalRouterInfo (); // after handshake void SendI2NPMessages (const std::vector >& msgs); private: diff --git a/libi2pd/TransportSession.h b/libi2pd/TransportSession.h index 62bed352..49067ce2 100644 --- a/libi2pd/TransportSession.h +++ b/libi2pd/TransportSession.h @@ -79,6 +79,7 @@ namespace transport bool IsTerminationTimeoutExpired (uint64_t ts) const { return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); }; + virtual void SendLocalRouterInfo () { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); }; virtual void SendI2NPMessages (const std::vector >& msgs) = 0; protected: diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 922625d2..6a833ae0 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -401,7 +401,7 @@ namespace transport { if (peer.router) // we have RI already { - if (!peer.numAttempts) // NTCP + if (!peer.numAttempts) // NTCP2 { peer.numAttempts++; if (m_NTCP2Server) // we support NTCP2 @@ -415,7 +415,10 @@ namespace transport return true; } } - // otherwise NTCP1 + } + if (peer.numAttempts == 1) // NTCP1 + { + peer.numAttempts++; auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ()); if (address && m_NTCPServer) { @@ -473,7 +476,7 @@ namespace transport else LogPrint (eLogDebug, "Transports: NTCP address is not present for ", i2p::data::GetIdentHashAbbreviation (ident), ", trying SSU"); } - if (peer.numAttempts == 1)// SSU + if (peer.numAttempts == 2)// SSU { peer.numAttempts++; if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ())) @@ -736,7 +739,7 @@ namespace transport sendDatabaseStore = false; // we have it in the list already } if (sendDatabaseStore) - session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); + session->SendLocalRouterInfo (); else session->SetTerminationTimeout (10); // most likely it's publishing, no follow-up messages expected, set timeout to 10 seconds it->second.sessions.push_back (session); From e4ab51329d1aa720c6cc64d25ed02f12bbf35b29 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 14 Aug 2018 14:01:04 -0400 Subject: [PATCH 169/195] move handshake messages processing to NTCP2Establisher --- libi2pd/NTCP2.cpp | 242 ++++++++++++++++++++++++++++------------------ libi2pd/NTCP2.h | 5 + 2 files changed, 152 insertions(+), 95 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index b54a83ef..325af961 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -244,6 +244,119 @@ namespace transport SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext) } + bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen) + { + // decrypt X + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (i2p::context.GetIdentHash ()); + decryption.SetIV (i2p::context.GetNTCP2IV ()); + decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); + decryption.GetIV (m_IV); // save IV for SessionCreated + // decryption key for next block + KDF1Bob (); + // verify MAC and decrypt options block (32 bytes), use m_H as AD + uint8_t nonce[12], options[16]; + memset (nonce, 0, 12); // set nonce to zero + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt + { + if (options[1] == 2) + { + paddingLen = bufbe16toh (options + 2); + m_SessionRequestBufferLen = paddingLen + 64; + m3p2Len = bufbe16toh (options + 4); + // TODO: check tsA + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]); + return false; + } + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed "); + return false; + } + return true; + } + + bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen) + { + m_SessionCreatedBufferLen = 64; + // decrypt Y + i2p::crypto::CBCDecryption decryption; + decryption.SetKey (m_RemoteIdentHash); + decryption.SetIV (m_IV); + decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ()); + // decryption key for next block (m_K) + KDF2Alice (); + // decrypt and verify MAC + uint8_t payload[16]; + uint8_t nonce[12]; + memset (nonce, 0, 12); // set nonce to zero + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt + { + paddingLen = bufbe16toh(payload + 2); + // TODO: check tsB + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed "); + return false; + } + return true; + } + + bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce) + { + // update AD + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32); // encrypted payload + SHA256_Final (m_H, &ctx); + + int paddingLength = m_SessionCreatedBufferLen - 64; + if (paddingLength > 0) + { + SHA256_CTX ctx1; + SHA256_Init (&ctx1); + SHA256_Update (&ctx1, m_H, 32); + SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength); + SHA256_Final (m_H, &ctx1); + } + if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, m_H, 32, m_K, nonce, m_RemoteStaticKey, 32, false)) // decrypt S + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); + return false; + } + return true; + } + + bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf) + { + // update AD again + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48); + SHA256_Final (m_H, &ctx); + + KDF3Bob (); + if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt + { + // caclulate new h again for KDF data + memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext + SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext); + } + else + { + LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed "); + return false; + } + return true; + } + NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr in_RemoteRouter): TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), m_Server (server), m_Socket (m_Server.GetService ()), @@ -368,52 +481,28 @@ namespace transport } else { - // decrypt X - i2p::crypto::CBCDecryption decryption; - decryption.SetKey (i2p::context.GetIdentHash ()); - decryption.SetIV (i2p::context.GetNTCP2IV ()); - decryption.Decrypt (m_Establisher->m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ()); - decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated - // decryption key for next block - m_Establisher->KDF1Bob (); - // verify MAC and decrypt options block (32 bytes), use m_H as AD - uint8_t nonce[12], options[16]; - memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt + LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred); + uint16_t paddingLen = 0; + if (m_Establisher->ProcessSessionRequestMessage (paddingLen)) { - if (options[1] == 2) + if (paddingLen > 0) { - uint16_t paddingLen = bufbe16toh (options + 2); - m_Establisher->m_SessionRequestBufferLen = paddingLen + 64; - m_Establisher->m3p2Len = bufbe16toh (options + 4); - // TODO: check tsA - if (paddingLen > 0) + if (paddingLen <= 287 - 64) // session request is 287 bytes max { - if (paddingLen <= 287 - 64) // session request is 287 bytes max - { - boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), - std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); - } - else - { - LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); - Terminate (); - } + boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (), + std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } else - SendSessionCreated (); + { + LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); + Terminate (); + } } else - { - LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]); - Terminate (); - } - } - else - { - LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed "); - Terminate (); + SendSessionCreated (); } + else + Terminate (); } } @@ -446,23 +535,9 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); - m_Establisher->m_SessionCreatedBufferLen = 64; - // decrypt Y - i2p::crypto::CBCDecryption decryption; - decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); - decryption.SetIV (m_Establisher->m_IV); - decryption.Decrypt (m_Establisher->m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ()); - // decryption key for next block (m_K) - m_Establisher->KDF2Alice (); - // decrypt and verify MAC - uint8_t payload[16]; - uint8_t nonce[12]; - memset (nonce, 0, 12); // set nonce to zero - if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt - { - uint16_t paddingLen = bufbe16toh(payload + 2); - LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen); - // TODO: check tsB + uint16_t paddingLen = 0; + if (m_Establisher->ProcessSessionCreatedMessage (paddingLen)) + { if (paddingLen > 0) { if (paddingLen <= 287 - 64) // session created is 287 bytes max @@ -480,10 +555,7 @@ namespace transport SendSessionConfirmed (); } else - { - LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed "); Terminate (); - } } } @@ -559,38 +631,16 @@ namespace transport else { LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); - // update AD - uint8_t h[80]; - memcpy (h, m_Establisher->GetH (), 32); - memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload - SHA256 (h, 64, h); - int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64; - if (paddingLength > 0) - { - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength); - SHA256_Final (h, &ctx); - } // part 1 uint8_t nonce[12]; CreateNonce (1, nonce); - if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S + if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce)) { // part 2 - // update AD again - memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48); - SHA256 (h, 80, m_Establisher->m_H); - std::vector buf(m_Establisher->m3p2Len - 16); // -MAC - m_Establisher->KDF3Bob (); memset (nonce, 0, 12); // set nonce to 0 again - if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt + if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ())) { - // caclulate new h again for KDF data - memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext - SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext); KeyDerivationFunctionDataPhase (); // Bob data phase keys m_SendKey = m_Kba; @@ -599,7 +649,7 @@ namespace transport m_ReceiveSipKey = m_Sipkeysab; memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); - + // payload // process RI if (buf[0] != eNTCP2BlkRouterInfo) { @@ -644,19 +694,13 @@ namespace transport SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); m_Server.AddNTCP2Session (shared_from_this ()); Established (); - ReceiveLength (); - } + ReceiveLength (); + } else - { - LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed "); Terminate (); - } } else - { - LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); Terminate (); - } } } @@ -691,12 +735,20 @@ namespace transport else { i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); - // m_NextRecivedLen comes from the network in BigEndian + // m_NextReceivedLen comes from the network in BigEndian m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); - if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; - m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; - Receive (); + if (m_NextReceivedLen >= 16) + { + if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; + m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; + Receive (); + } + else + { + LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short"); + Terminate (); + } } } diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 3e202dc5..1f5700be 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -91,6 +91,11 @@ namespace transport void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); + bool ProcessSessionRequestMessage (uint16_t& paddingLen); + bool ProcessSessionCreatedMessage (uint16_t& paddingLen); + bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce); + bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf); + BN_CTX * m_Ctx; uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; From db5a40d743e8e03f4614ea595997f3e26a0b73fe Mon Sep 17 00:00:00 2001 From: r4sas Date: Tue, 14 Aug 2018 22:39:57 +0300 Subject: [PATCH 170/195] enable NTCP2 for android, use L flag for bandwidth, additional change for multiarch build --- android/assets/i2pd.conf | 5 ++++- android/jni/Application.mk | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf index 8022b3d9..cf113da2 100644 --- a/android/assets/i2pd.conf +++ b/android/assets/i2pd.conf @@ -15,12 +15,15 @@ ipv6 = false # ntcpproxy = http://127.0.0.1:8118 # ssu = true -bandwidth = O +bandwidth = L # share = 100 # notransit = true # floodfill = true +[ntcp2] +enabled = true + [http] enabled = true address = 127.0.0.1 diff --git a/android/jni/Application.mk b/android/jni/Application.mk index b5b920fa..a7554706 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -2,7 +2,7 @@ #APP_ABI := armeabi-v7a x86 #APP_ABI := x86 #APP_ABI := x86_64 -APP_ABI := armeabi-v7a +#APP_ABI := armeabi-v7a #can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there. APP_PLATFORM := android-14 From 331a23fc209ae2d2d9a1806238caa564bbfd117b Mon Sep 17 00:00:00 2001 From: r4sas Date: Tue, 14 Aug 2018 22:44:08 +0300 Subject: [PATCH 171/195] build JNI for arm v7a and x86 both --- android/jni/Application.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/jni/Application.mk b/android/jni/Application.mk index a7554706..92622ee9 100755 --- a/android/jni/Application.mk +++ b/android/jni/Application.mk @@ -1,5 +1,5 @@ #APP_ABI := all -#APP_ABI := armeabi-v7a x86 +APP_ABI := armeabi-v7a x86 #APP_ABI := x86 #APP_ABI := x86_64 #APP_ABI := armeabi-v7a From db4c26a400ab1f8c6afe8e2697239e7fbf862622 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 15 Aug 2018 09:52:13 -0400 Subject: [PATCH 172/195] copy assets before daemon start --- .../src/org/purplei2p/i2pd/I2PDActivity.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 28e30251..997b90ac 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -30,6 +30,7 @@ public class I2PDActivity extends Activity { public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; private TextView textView; + private boolean assetsCopied; private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); @@ -37,7 +38,25 @@ public class I2PDActivity extends Activity { new DaemonSingleton.StateUpdateListener() { @Override - public void daemonStateUpdate() { + public void daemonStateUpdate() + { + try + { + // copy assets + if (!assetsCopied) + { + assetsCopied = true; + copyAsset("certificates"); + copyAsset("i2pd.conf"); + copyAsset("subsciptions.txt"); + copyAsset("tunnels.conf"); + } + } + catch (Throwable tr) + { + Log.e(TAG,"copy assets",tr); + }; + runOnUiThread(new Runnable(){ @Override @@ -79,12 +98,6 @@ public class I2PDActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // copy assets - copyAsset("certificates"); - copyAsset("i2pd.conf"); - copyAsset("subsciptions.txt"); - copyAsset("tunnels.conf"); - textView = new TextView(this); setContentView(textView); daemon.addStateChangeListener(daemonStateUpdatedListener); From c41081d35c237dcf79bb7f714ed876ea7cf4df94 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 15 Aug 2018 11:42:56 -0400 Subject: [PATCH 173/195] check timestamps --- libi2pd/NTCP2.cpp | 26 +++++++++++++++++++++----- libi2pd/NTCP2.h | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 325af961..0cac7efa 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -259,12 +259,20 @@ namespace transport memset (nonce, 0, 12); // set nonce to zero if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt { - if (options[1] == 2) + // options + if (options[1] == 2) // ver is always 2 { paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; m3p2Len = bufbe16toh (options + 4); - // TODO: check tsA + // check timestamp + auto ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t tsA = bufbe32toh (options + 8); + if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", ts - tsA, " exceeds clock skew"); + return false; + } } else { @@ -295,9 +303,17 @@ namespace transport uint8_t nonce[12]; memset (nonce, 0, 12); // set nonce to zero if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt - { + { + // options paddingLen = bufbe16toh(payload + 2); - // TODO: check tsB + // check timestamp + auto ts = i2p::util::GetSecondsSinceEpoch (); + uint32_t tsB = bufbe32toh (payload + 8); + if (tsB < ts - NTCP2_CLOCK_SKEW || tsB > ts + NTCP2_CLOCK_SKEW) + { + LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", ts - tsB, " exceeds clock skew"); + return false; + } } else { @@ -414,7 +430,7 @@ namespace transport m_IsEstablished = true; m_Establisher.reset (nullptr); SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT); - transports.PeerConnected (shared_from_this ()); + // transports.PeerConnected (shared_from_this ()); } void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 1f5700be..81395e46 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -26,6 +26,8 @@ namespace transport const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds + const int NTCP2_CLOCK_SKEW = 60; // in seconds + enum NTCP2BlockType { eNTCP2BlkDateTime = 0, From 02e8c5faca53e745c0c02afb7efe7e69a3ca0889 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 15 Aug 2018 13:23:10 -0400 Subject: [PATCH 174/195] fixed typo --- libi2pd/NTCP2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 0cac7efa..d182e4a9 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -430,7 +430,7 @@ namespace transport m_IsEstablished = true; m_Establisher.reset (nullptr); SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT); - // transports.PeerConnected (shared_from_this ()); + transports.PeerConnected (shared_from_this ()); } void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce) From 11142690a0830bc37f0b4ea414f9edafb3c17d92 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Aug 2018 10:13:32 -0400 Subject: [PATCH 175/195] show correct value of time drift --- libi2pd/NTCP2.cpp | 4 ++-- libi2pd/NTCPSession.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index d182e4a9..6d8814b4 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -270,7 +270,7 @@ namespace transport uint32_t tsA = bufbe32toh (options + 8); if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW) { - LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", ts - tsA, " exceeds clock skew"); + LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew"); return false; } } @@ -311,7 +311,7 @@ namespace transport uint32_t tsB = bufbe32toh (payload + 8); if (tsB < ts - NTCP2_CLOCK_SKEW || tsB > ts + NTCP2_CLOCK_SKEW) { - LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", ts - tsB, " exceeds clock skew"); + LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", (int)(ts - tsB), " exceeds clock skew"); return false; } } diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index caddd110..e9de08e2 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -402,7 +402,7 @@ namespace transport uint32_t tsA1 = be32toh (tsA); if (tsA1 < ts - NTCP_CLOCK_SKEW || tsA1 > ts + NTCP_CLOCK_SKEW) { - LogPrint (eLogError, "NTCP: Phase3 time difference ", ts - tsA1, " exceeds clock skew"); + LogPrint (eLogError, "NTCP: Phase3 time difference ", (int)(ts - tsA1), " exceeds clock skew"); Terminate (); return; } @@ -485,7 +485,7 @@ namespace transport auto ts = i2p::util::GetSecondsSinceEpoch (); if (tsB < ts - NTCP_CLOCK_SKEW || tsB > ts + NTCP_CLOCK_SKEW) { - LogPrint (eLogError, "NTCP: Phase4 time difference ", ts - tsB, " exceeds clock skew"); + LogPrint (eLogError, "NTCP: Phase4 time difference ", (int)(ts - tsB), " exceeds clock skew"); Terminate (); return; } From 863baeb68b4b75d08c33f865dd5821789a7e8316 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Aug 2018 11:02:53 -0400 Subject: [PATCH 176/195] ignore unpublished addresses --- daemon/UPnP.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/daemon/UPnP.cpp b/daemon/UPnP.cpp index ba7b408c..3aad19c6 100644 --- a/daemon/UPnP.cpp +++ b/daemon/UPnP.cpp @@ -131,8 +131,8 @@ namespace transport const auto& a = context.GetRouterInfo().GetAddresses(); for (const auto& address : a) { - if (!address->host.is_v6 ()) - TryPortMapping (address); + if (!address->host.is_v6 () && address->port) + TryPortMapping (address); } m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes m_Timer.async_wait ([this](const boost::system::error_code& ecode) @@ -148,7 +148,7 @@ namespace transport const auto& a = context.GetRouterInfo().GetAddresses(); for (const auto& address : a) { - if (!address->host.is_v6 ()) + if (!address->host.is_v6 () && address->port) CloseMapping (address); } } From 77a409935d2c37ac69cf7506bdf16b7d76d357bd Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Aug 2018 13:46:59 -0400 Subject: [PATCH 177/195] license added --- libi2pd/NTCP2.cpp | 11 +++++++++++ libi2pd/NTCP2.h | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 6d8814b4..31f3c999 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1,3 +1,14 @@ +/* +* Copyright (c) 2013-2018, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +* +* Kovri go write your own code +* +*/ + #include #include #include diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index 81395e46..2b6748ab 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -1,3 +1,13 @@ +/* +* Copyright (c) 2013-2018, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +* +* Kovri go write your own code +* +*/ #ifndef NTCP2_H__ #define NTCP2_H__ From 5e110e9f7b2ec3cbab1d46ac28d3cc57a21c179a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 16 Aug 2018 13:48:47 -0400 Subject: [PATCH 178/195] enable NTCP2 by default --- libi2pd/Config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index 098a7baa..9eaaf068 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -233,7 +233,7 @@ namespace config { options_description ntcp2("NTCP2 Options"); ntcp2.add_options() - ("ntcp2.enabled", value()->default_value(false), "Enable NTCP2 (default: disabled)") + ("ntcp2.enabled", value()->default_value(true), "Enable NTCP2 (default: enabled)") ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)") ("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ; From f1fb42460add9b7efe370a25186f205e06e826ed Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 15 Aug 2018 00:12:46 +0300 Subject: [PATCH 179/195] rename ipv6 transports --- daemon/HTTPServer.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index cda3f2ec..90bd772f 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -262,7 +262,9 @@ namespace http { { if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ()) { - s << "NTCP2   supported
\r\n"; + s << "NTCP2"; + if (address->host.is_v6 ()) s << "v6"; + s << "   supported
\r\n"; continue; } switch (address->transportStyle) @@ -271,13 +273,13 @@ namespace http { { s << "NTCP"; if (address->IsPublishedNTCP2 ()) s << "2"; - if (address->host.is_v6 ()) s << "6"; + if (address->host.is_v6 ()) s << "v6"; s << "  "; break; } case i2p::data::RouterInfo::eTransportSSU: if (address->host.is_v6 ()) - s << "SSU6     "; + s << "SSUv6     "; else s << "SSU     "; break; @@ -583,7 +585,7 @@ namespace http { } if (!tmp_s6.str ().empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; s << tmp_s6.str () << "

\r\n
\r\n"; } } @@ -628,7 +630,7 @@ namespace http { auto sessions6 = ssuServer->GetSessionsV6 (); if (!sessions6.empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; for (const auto& it: sessions6) { auto endpoint = it.second->GetRemoteEndpoint (); From d009a29426e30a87da7b9e46cac238fce76bde0a Mon Sep 17 00:00:00 2001 From: r4sas Date: Wed, 15 Aug 2018 01:49:10 +0300 Subject: [PATCH 180/195] android - dont rewrite files from assets if they exist --- .../src/org/purplei2p/i2pd/I2PDActivity.java | 102 +++++++++--------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 997b90ac..21cb0572 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -28,17 +28,16 @@ import android.widget.Toast; public class I2PDActivity extends Activity { private static final String TAG = "i2pdActvt"; public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; - + private TextView textView; private boolean assetsCopied; - + private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); - + private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() { - @Override - public void daemonStateUpdate() + public void daemonStateUpdate() { try { @@ -48,17 +47,17 @@ public class I2PDActivity extends Activity { assetsCopied = true; copyAsset("certificates"); copyAsset("i2pd.conf"); - copyAsset("subsciptions.txt"); + copyAsset("subscriptions.txt"); copyAsset("tunnels.conf"); } } - catch (Throwable tr) + catch (Throwable tr) { Log.e(TAG,"copy assets",tr); }; runOnUiThread(new Runnable(){ - + @Override public void run() { try { @@ -74,7 +73,7 @@ public class I2PDActivity extends Activity { (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") ); - } catch (Throwable tr) { + } catch (Throwable tr) { Log.e(TAG,"error ignored",tr); } } @@ -83,7 +82,7 @@ public class I2PDActivity extends Activity { }; private static volatile long graceStartedMillis; private static final Object graceStartedMillis_LOCK=new Object(); - + private static String formatGraceTimeRemaining() { long remainingSeconds; synchronized (graceStartedMillis_LOCK){ @@ -93,19 +92,19 @@ public class I2PDActivity extends Activity { long remSec=remainingSeconds-remainingMinutes*60; return remainingMinutes+":"+(remSec/10)+remSec%10; } - + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + textView = new TextView(this); setContentView(textView); daemon.addStateChangeListener(daemonStateUpdatedListener); daemonStateUpdatedListener.daemonStateUpdate(); - + // set the app be foreground doBindService(); - + final Timer gracefulQuitTimer = getGracefulQuitTimer(); if(gracefulQuitTimer!=null){ long gracefulStopAtMillis; @@ -115,7 +114,7 @@ public class I2PDActivity extends Activity { rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); } } - + @Override protected void onDestroy() { super.onDestroy(); @@ -128,7 +127,7 @@ public class I2PDActivity extends Activity { Log.e(TAG, "", tr); } } - + private static void cancelGracefulStop() { Timer gracefulQuitTimer = getGracefulQuitTimer(); if(gracefulQuitTimer!=null) { @@ -136,7 +135,7 @@ public class I2PDActivity extends Activity { setGracefulQuitTimer(null); } } - + private CharSequence throwableToString(Throwable tr) { StringWriter sw = new StringWriter(8192); PrintWriter pw = new PrintWriter(sw); @@ -144,9 +143,9 @@ public class I2PDActivity extends Activity { pw.close(); return sw.toString(); } - + // private LocalService mBoundService; - + private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been @@ -155,12 +154,12 @@ public class I2PDActivity extends Activity { // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. // mBoundService = ((LocalService.LocalBinder)service).getService(); - + // Tell the user about this for our demo. // Toast.makeText(Binding.this, R.string.local_service_connected, // Toast.LENGTH_SHORT).show(); } - + public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. @@ -171,10 +170,9 @@ public class I2PDActivity extends Activity { // Toast.LENGTH_SHORT).show(); } }; - - + private static volatile boolean mIsBound; - + private void doBindService() { synchronized (I2PDActivity.class) { if (mIsBound) return; @@ -186,7 +184,7 @@ public class I2PDActivity extends Activity { mIsBound = true; } } - + private void doUnbindService() { synchronized (I2PDActivity.class) { if (mIsBound) { @@ -196,21 +194,21 @@ public class I2PDActivity extends Activity { } } } - + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.options_main, menu); return true; } - + @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); - + switch(id){ case R.id.action_stop: i2pdStop(); @@ -219,14 +217,14 @@ public class I2PDActivity extends Activity { i2pdGracefulStop(); return true; } - + return super.onOptionsItemSelected(item); } - + private void i2pdStop() { cancelGracefulStop(); new Thread(new Runnable(){ - + @Override public void run() { Log.d(TAG, "stopping"); @@ -236,12 +234,12 @@ public class I2PDActivity extends Activity { Log.e(TAG, "", tr); } } - + },"stop").start(); } - + private static volatile Timer gracefulQuitTimer; - + private void i2pdGracefulStop() { if(daemon.getState()==DaemonSingleton.State.stopped){ Toast.makeText(this, R.string.already_stopped, @@ -256,7 +254,7 @@ public class I2PDActivity extends Activity { Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.LENGTH_SHORT).show(); new Thread(new Runnable(){ - + @Override public void run() { try{ @@ -276,21 +274,21 @@ public class I2PDActivity extends Activity { Log.e(TAG,"",tr); } } - + },"gracInit").start(); } - + private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); final Timer gracefulQuitTimer = new Timer(true); setGracefulQuitTimer(gracefulQuitTimer); gracefulQuitTimer.schedule(new TimerTask(){ - + @Override public void run() { i2pdStop(); } - + }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); final TimerTask tickerTask = new TimerTask() { @Override @@ -300,30 +298,30 @@ public class I2PDActivity extends Activity { }; gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); } - + private static Timer getGracefulQuitTimer() { return gracefulQuitTimer; } - + private static void setGracefulQuitTimer(Timer gracefulQuitTimer) { I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; } - + /** * Copy the asset at the specified path to this app's data directory. If the * asset is a directory, its contents are also copied. - * + * * @param path * Path to asset, relative to app's assets directory. */ private void copyAsset(String path) { AssetManager manager = getAssets(); - + // If we have a directory, we make it and recurse. If a file, we copy its // contents. try { String[] contents = manager.list(path); - + // The documentation suggests that list throws an IOException, but doesn't // say under what conditions. It'd be nice if it did so when the path was // to a file. That doesn't appear to be the case. If the returned array is @@ -331,30 +329,30 @@ public class I2PDActivity extends Activity { // directories will get turned into files. if (contents == null || contents.length == 0) throw new IOException(); - + // Make the directory. File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); dir.mkdirs(); - + // Recurse on the contents. for (String entry : contents) { copyAsset(path + "/" + entry); } - } catch (IOException e) { + } catch (IOException e) { copyFileAsset(path); } } - + /** * Copy the asset file specified by path to app's data directory. Assumes * parent directories have already been created. - * + * * @param path * Path to asset, relative to app's assets directory. */ private void copyFileAsset(String path) { File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); - try { + if(!file.exists()) try { InputStream in = getAssets().open(path); OutputStream out = new FileOutputStream(file); byte[] buffer = new byte[1024]; @@ -365,7 +363,7 @@ public class I2PDActivity extends Activity { } out.close(); in.close(); - } catch (IOException e) { + } catch (IOException e) { Log.e(TAG, "", e); } } From 405429a300bf00e634785f9be3ffecd9e78eec1a Mon Sep 17 00:00:00 2001 From: r4sas Date: Thu, 16 Aug 2018 23:32:33 +0300 Subject: [PATCH 181/195] android - add file for notify about successful unpacking assets --- android/src/org/purplei2p/i2pd/I2PDActivity.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 21cb0572..78f67c8b 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -1,6 +1,7 @@ package org.purplei2p.i2pd; import java.io.File; +import java.io.FileWriter; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -25,6 +26,9 @@ import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; +// For future package update checking +import org.purplei2p.i2pd.BuildConfig; + public class I2PDActivity extends Activity { private static final String TAG = "i2pdActvt"; public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; @@ -44,11 +48,19 @@ public class I2PDActivity extends Activity { // copy assets if (!assetsCopied) { - assetsCopied = true; copyAsset("certificates"); copyAsset("i2pd.conf"); copyAsset("subscriptions.txt"); copyAsset("tunnels.conf"); + assetsCopied = true; + + // create holder file about successful copying + File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", "assets.ready"); + FileWriter writer = new FileWriter(file); + String versionName = BuildConfig.VERSION_NAME; // here will be 2.XX.0 + writer.append(versionName); + writer.flush(); + writer.close(); } } catch (Throwable tr) From 45596a0342849f31b2cb1d62dd38a4c4adf99fef Mon Sep 17 00:00:00 2001 From: r4sas Date: Fri, 17 Aug 2018 01:41:26 +0300 Subject: [PATCH 182/195] android - holder-based updater for certificate If holder exsists, check string (version) of assets creation. If it differs from current app version or null, try delete certificates forder contents for unpacking new certificates. --- .../src/org/purplei2p/i2pd/I2PDActivity.java | 91 +++++++++++++------ 1 file changed, 64 insertions(+), 27 deletions(-) diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 78f67c8b..bc6f7209 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -1,7 +1,9 @@ package org.purplei2p.i2pd; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; +import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -35,6 +37,7 @@ public class I2PDActivity extends Activity { private TextView textView; private boolean assetsCopied; + private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/"; private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); @@ -43,31 +46,7 @@ public class I2PDActivity extends Activity { @Override public void daemonStateUpdate() { - try - { - // copy assets - if (!assetsCopied) - { - copyAsset("certificates"); - copyAsset("i2pd.conf"); - copyAsset("subscriptions.txt"); - copyAsset("tunnels.conf"); - assetsCopied = true; - - // create holder file about successful copying - File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", "assets.ready"); - FileWriter writer = new FileWriter(file); - String versionName = BuildConfig.VERSION_NAME; // here will be 2.XX.0 - writer.append(versionName); - writer.flush(); - writer.close(); - } - } - catch (Throwable tr) - { - Log.e(TAG,"copy assets",tr); - }; - + processAssets(); runOnUiThread(new Runnable(){ @Override @@ -343,7 +322,7 @@ public class I2PDActivity extends Activity { throw new IOException(); // Make the directory. - File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); + File dir = new File(i2pdpath, path); dir.mkdirs(); // Recurse on the contents. @@ -363,7 +342,7 @@ public class I2PDActivity extends Activity { * Path to asset, relative to app's assets directory. */ private void copyFileAsset(String path) { - File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); + File file = new File(i2pdpath, path); if(!file.exists()) try { InputStream in = getAssets().open(path); OutputStream out = new FileOutputStream(file); @@ -379,4 +358,62 @@ public class I2PDActivity extends Activity { Log.e(TAG, "", e); } } + + private void deleteRecursive(File fileOrDirectory) { + if (fileOrDirectory.isDirectory()) { + for (File child : fileOrDirectory.listFiles()) { + deleteRecursive(child); + } + } + fileOrDirectory.delete(); + } + + private void processAssets() { + if (!assetsCopied) try { + assetsCopied = true; // prevent from running on every state update + + File holderfile = new File(i2pdpath, "assets.ready"); + String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX + StringBuilder text = new StringBuilder(); + + if (holderfile.exists()) try { // if holder file exists, read assets version string + BufferedReader br = new BufferedReader(new FileReader(holderfile)); + String line; + + while ((line = br.readLine()) != null) { + text.append(line); + } + br.close(); + } + catch (IOException e) { + Log.e(TAG, "", e); + } + + // if version differs from current app version or null, try to delete certificates folder + if (!text.toString().contains(versionName)) try { + holderfile.delete(); + File certpath = new File(i2pdpath, "certificates"); + deleteRecursive(certpath); + } + catch (Throwable tr) { + Log.e(TAG, "", tr); + } + + // copy assets. If processed file exists, it won't be overwrited + copyAsset("certificates"); + copyAsset("i2pd.conf"); + copyAsset("subscriptions.txt"); + copyAsset("tunnels.conf"); + + // update holder file about successful copying + FileWriter writer = new FileWriter(holderfile); + writer.append(versionName); + writer.flush(); + writer.close(); + } + catch (Throwable tr) + { + Log.e(TAG,"copy assets",tr); + } + } } From e190a005db288f0c5ba64d6e043d2e06e3b6e315 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 17 Aug 2018 11:17:17 -0400 Subject: [PATCH 183/195] make sure assets are ready before proceed --- android/jni/DaemonAndroid.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 75584740..5ea5e495 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -1,10 +1,13 @@ -#include "DaemonAndroid.h" -#include "Daemon.h" #include +#include +#include +#include #include #include -#include //#include "mainwindow.h" +#include "FS.h" +#include "DaemonAndroid.h" +#include "Daemon.h" namespace i2p { @@ -80,6 +83,17 @@ namespace android //mutex=new QMutex(QMutex::Recursive); //setRunningCallback(0); //m_IsRunning=false; + + // make sure assets are ready before proceed + i2p::fs::DetectDataDir("", false); + int numAttempts = 0; + do + { + if (i2p::fs::Exists (i2p::fs::DataDirPath("assets.ready"))) break; // assets ready + numAttempts++; + std::this_thread::sleep_for (std::chrono::seconds(1)); // otherwise wait for 1 more second + } + while (numAttempts <= 10); // 10 seconds max return Daemon.init(argc,argv); } From 1dd003d26a62f2700df2e83219d638f9ed4bef5c Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 18 Aug 2018 08:27:36 -0400 Subject: [PATCH 184/195] check m2p3len --- libi2pd/NTCP2.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 31f3c999..14e5e333 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -276,6 +276,11 @@ namespace transport paddingLen = bufbe16toh (options + 2); m_SessionRequestBufferLen = paddingLen + 64; m3p2Len = bufbe16toh (options + 4); + if (m3p2Len < 16) + { + LogPrint (eLogWarning, "NTCP2: SessionRequest m3p2len=", m3p2Len, " is too short"); + return false; + } // check timestamp auto ts = i2p::util::GetSecondsSinceEpoch (); uint32_t tsA = bufbe32toh (options + 8); @@ -944,7 +949,7 @@ namespace transport payload[s] = eNTCP2BlkPadding; // blk htobe16buf (payload + s + 1, paddingSize); // size s += 3; - RAND_bytes (payload + s, paddingSize); + memset (payload + s, 0, paddingSize); s += paddingSize; // send SendNextFrame (payload, s); From 2d758ce9636da3fb33a030487d06dc643a0f0c39 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 18 Aug 2018 13:52:35 -0400 Subject: [PATCH 185/195] change cost for NTCP and NTCP2 --- libi2pd/RouterInfo.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 95e88963..79a70462 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -668,7 +668,7 @@ namespace data addr->host = boost::asio::ip::address::from_string (host); addr->port = port; addr->transportStyle = eTransportNTCP; - addr->cost = 2; + addr->cost = 6; addr->date = 0; for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; @@ -703,7 +703,7 @@ namespace data auto addr = std::make_shared

(); addr->port = 0; addr->transportStyle = eTransportNTCP; - addr->cost = 14; + addr->cost = 3; addr->date = 0; addr->ntcp2.reset (new NTCP2Ext ()); addr->ntcp2->isNTCP2Only = true; // NTCP2 only address From 9882365ab45b8e0ae75fdbd102820ae83be3ea69 Mon Sep 17 00:00:00 2001 From: r4sas Date: Sat, 18 Aug 2018 22:56:31 +0000 Subject: [PATCH 186/195] fix NTCP IPv6 category name in transports, add conversion for leasesets expiring time --- daemon/HTTPServer.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 90bd772f..09b00707 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -92,6 +92,8 @@ namespace http { const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_ADDRESS[] = "address"; + static std::string ConvertTime (uint64_t time); + static void ShowUptime (std::stringstream& s, int seconds) { int num; @@ -464,14 +466,14 @@ namespace http { s << "
!! Invalid !!
\r\n"; s << "
\r\n"; s << "\r\n

\r\n"; - s << "Expires: " << ls.GetExpirationTime() << "
\r\n"; + s << "Expires: " << ConvertTime(ls.GetExpirationTime()) << "
\r\n"; auto leases = ls.GetNonExpiredLeases(); s << "Non Expired Leases: " << leases.size() << "
\r\n"; for ( auto & l : leases ) { s << "Gateway: " << l->tunnelGateway.ToBase64() << "
\r\n"; s << "TunnelID: " << l->tunnelID << "
\r\n"; - s << "EndDate: " << l->endDate << "
\r\n"; + s << "EndDate: " << ConvertTime(l->endDate) << "
\r\n"; } s << "

\r\n
\r\n
\r\n"; } @@ -585,7 +587,7 @@ namespace http { } if (!tmp_s6.str ().empty ()) { - s << "
\r\n\r\n

"; + s << "

\r\n\r\n

"; s << tmp_s6.str () << "

\r\n
\r\n"; } } @@ -765,6 +767,16 @@ namespace http { } } + std::string ConvertTime (uint64_t time) + { + ldiv_t divTime = ldiv(time,1000); + time_t t = divTime.quot; + struct tm *tm = localtime(&t); + char date[128]; + snprintf(date, sizeof(date), "%02d/%02d/%d %02d:%02d:%02d.%03ld", tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, divTime.rem); + return date; + } + HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr socket): m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0), expected_host(hostname) From d9476fb5cae256d41005df96785cd7e7a06d3d48 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 19 Aug 2018 16:17:57 -0400 Subject: [PATCH 187/195] set correct IV when NTCP2 address gets published --- libi2pd/RouterContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index b2774aa2..a3d33113 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -164,6 +164,7 @@ namespace i2p void RouterContext::PublishNTCP2Address (int port, bool publish) { + if (!m_NTCP2Keys) return; if (!port) port = rand () % (30777 - 9111) + 9111; // I2P network ports range bool updated = false; @@ -173,6 +174,7 @@ namespace i2p { address->port = port; address->ntcp2->isPublished = publish; + address->ntcp2->iv = m_NTCP2Keys->iv; updated = true; } } From 65cf14bfce16fecc1c862203627390a1d70c43ac Mon Sep 17 00:00:00 2001 From: r4sas Date: Mon, 20 Aug 2018 01:01:27 +0300 Subject: [PATCH 188/195] update android miniupnpc to 2.1 --- android/jni/Android.mk | 4 ++-- android_binary_only/jni/Android.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/jni/Android.mk b/android/jni/Android.mk index d5a8f05f..80935236 100755 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -68,6 +68,6 @@ include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := miniupnpc -LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a -LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include +LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a +LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include include $(PREBUILT_STATIC_LIBRARY) diff --git a/android_binary_only/jni/Android.mk b/android_binary_only/jni/Android.mk index ae56110c..fa677c83 100755 --- a/android_binary_only/jni/Android.mk +++ b/android_binary_only/jni/Android.mk @@ -69,6 +69,6 @@ include $(PREBUILT_STATIC_LIBRARY) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := miniupnpc -LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a -LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include +LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a +LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include include $(PREBUILT_STATIC_LIBRARY) From b259ee89aa15b0a88f15789d64756678f6fe6fe6 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 22 Aug 2018 12:33:43 -0400 Subject: [PATCH 189/195] send RouterInfo from NTCP2Server's thread --- libi2pd/NTCP2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 14e5e333..ff6eb01e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -1005,7 +1005,7 @@ namespace transport void NTCP2Session::SendLocalRouterInfo () { if (!IsOutgoing ()) // we send it in SessionConfirmed - SendRouterInfo (); + m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); } NTCP2Server::NTCP2Server (): From a83a839cffc33162c128b467a265f6cd685b9b6c Mon Sep 17 00:00:00 2001 From: l-n-s Date: Wed, 22 Aug 2018 18:22:54 -0400 Subject: [PATCH 190/195] Build docker image from openssl branch --- contrib/docker/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index e7e60f37..22990995 100644 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -2,7 +2,7 @@ FROM alpine:latest LABEL authors "Mikal Villa , Darknet Villain " # Expose git branch, tag and URL variables as arguments -ARG GIT_BRANCH="master" +ARG GIT_BRANCH="openssl" ENV GIT_BRANCH=${GIT_BRANCH} ARG GIT_TAG="" ENV GIT_TAG=${GIT_TAG} From 022f4d2c119a6d2ccc37d22d487ef806c9e506cb Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Aug 2018 07:23:50 -0400 Subject: [PATCH 191/195] don't send message to not established session --- libi2pd/NTCP2.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index ff6eb01e..58f928b4 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -959,6 +959,7 @@ namespace transport void NTCP2Session::SendRouterInfo () { + if (!IsEstablished ()) return; auto riLen = i2p::context.GetRouterInfo ().GetBufferLen (); int paddingSize = (riLen*NTCP2_MAX_PADDING_RATIO)/100; size_t payloadLen = riLen + paddingSize + 7; // 7 = 2*3 bytes header + 1 byte RI flag @@ -976,6 +977,7 @@ namespace transport void NTCP2Session::SendTermination (NTCP2TerminationReason reason) { + if (!IsEstablished ()) return; uint8_t payload[12] = { eNTCP2BlkTermination, 0, 9 }; htobe64buf (payload + 3, m_ReceiveSequenceNumber); payload[11] = (uint8_t)reason; From 71ac0286b1dd43491de669da30762f2a715d3078 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 23 Aug 2018 10:24:44 -0400 Subject: [PATCH 192/195] 2.20.0 --- ChangeLog | 11 +++++++++++ Win32/installer.iss | 2 +- android/AndroidManifest.xml | 2 +- android/build.gradle | 2 +- contrib/rpm/i2pd.spec | 3 +++ debian/changelog | 6 ++++++ libi2pd/version.h | 4 ++-- 7 files changed, 25 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 59a19a3c..d8ab87de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,17 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.20.0] - 2018-08-23 +### Added +- Full implementation of NTCP2 +- Assets for android +### Changed +- armeabi-v7a and x86 in one apk for android +- NTCP2 is enabled by default +- Show lease's expiration time in readable format in the web console +### Fixed +- Correct names for transports in the web console + ## [2.19.0] - 2018-06-26 ### Added - ECIES support for RouterInfo diff --git a/Win32/installer.iss b/Win32/installer.iss index c4e1fffd..e340c65f 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.19.0" +#define I2Pd_ver "2.20.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 705cce4e..9a2cffd5 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -3,7 +3,7 @@ package="org.purplei2p.i2pd" android:installLocation="auto" android:versionCode="1" - android:versionName="2.19.0"> + android:versionName="2.20.0"> /dev/null || \ %changelog +* Thu Aug 23 2018 orignal - 2.20.0 +- update to 2.20.0 + * Tue Jun 26 2018 orignal - 2.19.0 - update to 2.19.0 diff --git a/debian/changelog b/debian/changelog index 74c366d1..9d721eb8 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.20.0-1) unstable; urgency=medium + + * updated to version 2.20.0/0.9.36 + + -- orignal Thu, 23 Aug 2018 16:00:00 +0000 + i2pd (2.19.0-1) unstable; urgency=medium * updated to version 2.19.0/0.9.35 diff --git a/libi2pd/version.h b/libi2pd/version.h index 129035ad..7c015e84 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -7,7 +7,7 @@ #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 19 +#define I2PD_VERSION_MINOR 20 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 35 +#define I2P_VERSION_MICRO 36 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) From e70feceafe29c74ea59a25a130cb06ac648b5800 Mon Sep 17 00:00:00 2001 From: r4sas Date: Thu, 23 Aug 2018 18:06:37 +0300 Subject: [PATCH 193/195] add install target in OSX Makefile for homebrew formula --- Makefile.osx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Makefile.osx b/Makefile.osx index 3358cb10..13376040 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -31,6 +31,14 @@ endif # Disabled, since it will be the default make rule. I think its better # to define the default rule in Makefile and not Makefile. - torkel -#install: all -# test -d ${PREFIX} || mkdir -p ${PREFIX}/ -# cp -r i2p ${PREFIX}/ +install-brew: all + install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd + install -m 755 ${I2PD} ${PREFIX}/bin/ + install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd + @cp -R contrib/certificates ${PREFIX}/share/i2pd/ + install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd + @gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1 + @ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/ + @ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf + @ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt + @ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf From c0d1e2c07aac4bf2282b9244aafb8bce15069835 Mon Sep 17 00:00:00 2001 From: r4sas Date: Thu, 23 Aug 2018 18:10:05 +0300 Subject: [PATCH 194/195] 2.20 --- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 2 +- contrib/rpm/i2pd.spec | 2 +- qt/i2pd_qt/android/AndroidManifest.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 27f563ef..e0c09fc1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.19.{build} +version: 2.20.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 02986475..3539c19b 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.19.0 +Version: 2.20.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 1a20e483..edad8228 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.19.0 +Version: 2.20.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git diff --git a/qt/i2pd_qt/android/AndroidManifest.xml b/qt/i2pd_qt/android/AndroidManifest.xml index d98e24d4..c62e118e 100644 --- a/qt/i2pd_qt/android/AndroidManifest.xml +++ b/qt/i2pd_qt/android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + From 062d8d0f4fb59c0392dd03c1893bdd8ba1936adc Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 25 Aug 2018 13:27:03 -0400 Subject: [PATCH 195/195] fixed potential race condition --- libi2pd_client/AddressBook.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index bca0e25b..e745ceaf 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -755,7 +755,8 @@ namespace client }, SUBSCRIPTION_REQUEST_TIMEOUT); std::unique_lock l(newDataReceivedMutex); - if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT)) == std::cv_status::timeout) + // wait 1 more second + if (newDataReceived.wait_for (l, std::chrono::seconds (SUBSCRIPTION_REQUEST_TIMEOUT + 1)) == std::cv_status::timeout) { LogPrint (eLogError, "Addressbook: subscriptions request timeout expired"); numAttempts++;