mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-10 08:00:38 +03:00
commit
fb229d4064
25
ChangeLog
25
ChangeLog
@ -1,6 +1,31 @@
|
|||||||
# for this file format description,
|
# for this file format description,
|
||||||
# see https://github.com/olivierlacan/keep-a-changelog
|
# 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
|
## [2.18.0] - 2018-01-30
|
||||||
### Added
|
### Added
|
||||||
- Show tunnel nicknames for I2CP destination in WebUI
|
- Show tunnel nicknames for I2CP destination in WebUI
|
||||||
|
@ -21,7 +21,7 @@ else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
|||||||
NEEDED_CXXFLAGS += -std=c++0x
|
NEEDED_CXXFLAGS += -std=c++0x
|
||||||
else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0
|
else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0
|
||||||
NEEDED_CXXFLAGS += -std=c++11
|
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
|
NEEDED_CXXFLAGS += -std=c++11
|
||||||
else # not supported
|
else # not supported
|
||||||
$(error Compiler too old)
|
$(error Compiler too old)
|
||||||
@ -60,7 +60,12 @@ endif
|
|||||||
ifeq ($(USE_AESNI),yes)
|
ifeq ($(USE_AESNI),yes)
|
||||||
#check if AES-NI is supported by CPU
|
#check if AES-NI is supported by CPU
|
||||||
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
||||||
|
machine := $(shell uname -m)
|
||||||
|
ifeq ($(machine), aarch64)
|
||||||
|
CXXFLAGS += -DARM64AES
|
||||||
|
else
|
||||||
CPU_FLAGS += -maes -DAESNI
|
CPU_FLAGS += -maes -DAESNI
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#define I2Pd_AppName "i2pd"
|
#define I2Pd_AppName "i2pd"
|
||||||
#define I2Pd_ver "2.18.0"
|
#define I2Pd_ver "2.19.0"
|
||||||
#define I2Pd_Publisher "PurpleI2P"
|
#define I2Pd_Publisher "PurpleI2P"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
package="org.purplei2p.i2pd"
|
package="org.purplei2p.i2pd"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="1"
|
android:versionCode="1"
|
||||||
android:versionName="2.18.0">
|
android:versionName="2.19.0">
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="14"
|
android:minSdkVersion="14"
|
||||||
|
@ -19,13 +19,13 @@ repositories {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 25
|
compileSdkVersion 25
|
||||||
buildToolsVersion "25.0.2"
|
buildToolsVersion "25.0.3"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.purplei2p.i2pd"
|
applicationId "org.purplei2p.i2pd"
|
||||||
targetSdkVersion 25
|
targetSdkVersion 25
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "2.18.0"
|
versionName "2.19.0"
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'armeabi-v7a'
|
abiFilters 'armeabi-v7a'
|
||||||
//abiFilters 'x86'
|
//abiFilters 'x86'
|
||||||
@ -49,7 +49,7 @@ android {
|
|||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled true
|
||||||
signingConfig signingConfigs.orignal
|
signingConfig signingConfigs.orignal
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
|||||||
APP_CPPFLAGS += -DANDROID_ARM7A
|
APP_CPPFLAGS += -DANDROID_ARM7A
|
||||||
endif
|
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/Boost-for-Android-Prebuilt.git
|
||||||
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||||
|
74
android_binary_only/jni/Android.mk
Executable file
74
android_binary_only/jni/Android.mk
Executable file
@ -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)
|
43
android_binary_only/jni/Application.mk
Executable file
43
android_binary_only/jni/Application.mk
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#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_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||||
|
APP_LDFLAGS += -rdynamic -fPIE -pie
|
||||||
|
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||||
|
APP_CPPFLAGS += -DANDROID_ARM7A
|
||||||
|
endif
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# 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
|
||||||
|
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
|
@ -1,4 +1,4 @@
|
|||||||
version: 2.18.{build}
|
version: 2.19.{build}
|
||||||
pull_requests:
|
pull_requests:
|
||||||
do_not_increment_build_number: true
|
do_not_increment_build_number: true
|
||||||
branches:
|
branches:
|
||||||
@ -17,7 +17,7 @@ environment:
|
|||||||
- MSYSTEM: MINGW32
|
- MSYSTEM: MINGW32
|
||||||
|
|
||||||
install:
|
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 "
|
||||||
|
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
|
||||||
|
@ -77,6 +77,10 @@ set (LIBI2PD_SRC
|
|||||||
"${LIBI2PD_SRC_DIR}/api.cpp"
|
"${LIBI2PD_SRC_DIR}/api.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Event.cpp"
|
"${LIBI2PD_SRC_DIR}/Event.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Gost.cpp"
|
"${LIBI2PD_SRC_DIR}/Gost.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/ChaCha20.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/Poly1305.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/Ed25519.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/NTCP2.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WITH_WEBSOCKETS)
|
if (WITH_WEBSOCKETS)
|
||||||
@ -94,7 +98,9 @@ endif()
|
|||||||
|
|
||||||
add_library(libi2pd ${LIBI2PD_SRC})
|
add_library(libi2pd ${LIBI2PD_SRC})
|
||||||
set_target_properties(libi2pd PROPERTIES PREFIX "")
|
set_target_properties(libi2pd PROPERTIES PREFIX "")
|
||||||
install(TARGETS libi2pd
|
|
||||||
|
if (WITH_LIBRARY)
|
||||||
|
install(TARGETS libi2pd
|
||||||
EXPORT libi2pd
|
EXPORT libi2pd
|
||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
@ -102,6 +108,7 @@ install(TARGETS libi2pd
|
|||||||
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
|
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
|
||||||
# FIXME This pulls stdafx
|
# FIXME This pulls stdafx
|
||||||
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
set (CLIENT_SRC
|
set (CLIENT_SRC
|
||||||
"${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp"
|
"${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp"
|
||||||
@ -120,13 +127,17 @@ set (CLIENT_SRC
|
|||||||
if(WITH_WEBSOCKETS)
|
if(WITH_WEBSOCKETS)
|
||||||
list (APPEND CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/Websocket.cpp")
|
list (APPEND CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/Websocket.cpp")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_library(libi2pdclient ${CLIENT_SRC})
|
add_library(libi2pdclient ${CLIENT_SRC})
|
||||||
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
|
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
|
||||||
install(TARGETS libi2pdclient
|
|
||||||
|
if (WITH_LIBRARY)
|
||||||
|
install(TARGETS libi2pdclient
|
||||||
EXPORT libi2pdclient
|
EXPORT libi2pdclient
|
||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
COMPONENT Libraries)
|
COMPONENT Libraries)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(DAEMON_SRC_DIR ../daemon)
|
set(DAEMON_SRC_DIR ../daemon)
|
||||||
|
|
||||||
|
@ -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 "WD=C:\msys64\usr\bin\"
|
||||||
set MSYS2_PATH_TYPE=inherit
|
set MSYS2_PATH_TYPE=inherit
|
||||||
set CHERE_INVOKING=enabled_from_arguments
|
set CHERE_INVOKING=enabled_from_arguments
|
||||||
set MSYSTEM=MSYS
|
REM set MSYSTEM=MSYS
|
||||||
|
set MSYSTEM=MINGW32
|
||||||
|
|
||||||
set "xSH=%WD%bash -lc"
|
set "xSH=%WD%bash -lc"
|
||||||
|
|
||||||
|
@ -17,14 +17,16 @@
|
|||||||
/etc/host.conf r,
|
/etc/host.conf r,
|
||||||
/etc/hosts r,
|
/etc/hosts r,
|
||||||
/etc/nsswitch.conf r,
|
/etc/nsswitch.conf r,
|
||||||
|
/etc/resolv.conf r,
|
||||||
/run/resolvconf/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)
|
# path specific (feel free to modify if you have another paths)
|
||||||
/etc/i2pd/** r,
|
/etc/i2pd/** r,
|
||||||
/run/i2pd/i2pd.pid rw,
|
/run/i2pd/i2pd.pid rwk,
|
||||||
/var/lib/i2pd/** rw,
|
/var/lib/i2pd/** rw,
|
||||||
/var/log/i2pd/i2pd.log w,
|
/var/log/i2pd/i2pd.log w,
|
||||||
/var/run/i2pd/i2pd.pid rw,
|
/var/run/i2pd/i2pd.pid rwk,
|
||||||
/usr/sbin/i2pd mr,
|
/usr/sbin/i2pd mr,
|
||||||
/usr/share/i2pd/** r,
|
/usr/share/i2pd/** r,
|
||||||
|
|
||||||
|
33
contrib/certificates/reseed/hottuna_at_mail.i2p.crt
Normal file
33
contrib/certificates/reseed/hottuna_at_mail.i2p.crt
Normal file
@ -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-----
|
@ -26,15 +26,11 @@
|
|||||||
## Log messages above this level (debug, *info, warn, error, none)
|
## Log messages above this level (debug, *info, warn, error, none)
|
||||||
## If you set it to none, logging will be disabled
|
## If you set it to none, logging will be disabled
|
||||||
# loglevel = info
|
# loglevel = info
|
||||||
|
## Write full CLF-formatted date and time to log (default: write only time)
|
||||||
## Path to storage of i2pd data (RI, keys, peer profiles, ...)
|
# logclftime = true
|
||||||
## Default: ~/.i2pd or /var/lib/i2pd
|
|
||||||
# datadir = /var/lib/i2pd
|
|
||||||
|
|
||||||
## Daemon mode. Router will go to background after start
|
## Daemon mode. Router will go to background after start
|
||||||
# daemon = true
|
# 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)
|
## Specify a family, router belongs to (default - none)
|
||||||
# family =
|
# family =
|
||||||
@ -55,9 +51,15 @@ ipv6 = false
|
|||||||
|
|
||||||
## Network interface to bind to
|
## Network interface to bind to
|
||||||
# ifname =
|
# ifname =
|
||||||
|
## You can specify different interfaces for IPv4 and IPv6
|
||||||
|
# ifname4 =
|
||||||
|
# ifname6 =
|
||||||
|
|
||||||
## Enable NTCP transport (default = true)
|
## Enable NTCP transport (default = true)
|
||||||
# ntcp = 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)
|
## Enable SSU transport (default = true)
|
||||||
# ssu = true
|
# ssu = true
|
||||||
|
|
||||||
@ -69,6 +71,8 @@ ipv6 = false
|
|||||||
## X - unlimited
|
## X - unlimited
|
||||||
## Default is X for floodfill, L for regular node
|
## Default is X for floodfill, L for regular node
|
||||||
# bandwidth = L
|
# 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
|
## Router will not accept transit tunnels, disabling transit traffic completely
|
||||||
## (default = false)
|
## (default = false)
|
||||||
@ -77,46 +81,17 @@ ipv6 = false
|
|||||||
## Router will be floodfill
|
## Router will be floodfill
|
||||||
# floodfill = true
|
# 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]
|
[http]
|
||||||
|
## Web Console settings
|
||||||
## Uncomment and set to 'false' to disable Web Console
|
## Uncomment and set to 'false' to disable Web Console
|
||||||
# enabled = true
|
# enabled = true
|
||||||
## Address and port service will listen on
|
## Address and port service will listen on
|
||||||
address = 127.0.0.1
|
address = 127.0.0.1
|
||||||
port = 7070
|
port = 7070
|
||||||
|
## Uncomment following lines to enable Web Console authentication
|
||||||
|
# auth = true
|
||||||
|
# user = i2pd
|
||||||
|
# pass = changeme
|
||||||
|
|
||||||
[httpproxy]
|
[httpproxy]
|
||||||
## Uncomment and set to 'false' to disable HTTP Proxy
|
## Uncomment and set to 'false' to disable HTTP Proxy
|
||||||
@ -126,6 +101,11 @@ address = 127.0.0.1
|
|||||||
port = 4444
|
port = 4444
|
||||||
## Optional keys file for proxy local destination
|
## Optional keys file for proxy local destination
|
||||||
# keys = http-proxy-keys.dat
|
# 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]
|
[socksproxy]
|
||||||
## Uncomment and set to 'false' to disable SOCKS Proxy
|
## Uncomment and set to 'false' to disable SOCKS Proxy
|
||||||
@ -135,13 +115,13 @@ address = 127.0.0.1
|
|||||||
port = 4447
|
port = 4447
|
||||||
## Optional keys file for proxy local destination
|
## Optional keys file for proxy local destination
|
||||||
# keys = socks-proxy-keys.dat
|
# keys = socks-proxy-keys.dat
|
||||||
|
|
||||||
## Socks outproxy. Example below is set to use Tor for all connections except i2p
|
## 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
|
## Uncomment and set to 'true' to enable using of SOCKS outproxy
|
||||||
# outproxy.enabled = false
|
# outproxy.enabled = false
|
||||||
## Address and port of outproxy
|
## Address and port of outproxy
|
||||||
# outproxy = 127.0.0.1
|
# outproxy = 127.0.0.1
|
||||||
# outproxyport = 9050
|
# outproxyport = 9050
|
||||||
|
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||||
|
|
||||||
[sam]
|
[sam]
|
||||||
## Uncomment and set to 'true' to enable SAM Bridge
|
## Uncomment and set to 'true' to enable SAM Bridge
|
||||||
@ -170,3 +150,71 @@ enabled = true
|
|||||||
## Address and port service will listen on
|
## Address and port service will listen on
|
||||||
# address = 127.0.0.1
|
# address = 127.0.0.1
|
||||||
# port = 7650
|
# 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
|
||||||
|
@ -10,7 +10,7 @@ RuntimeDirectory=i2pd
|
|||||||
RuntimeDirectoryMode=0700
|
RuntimeDirectoryMode=0700
|
||||||
LogsDirectory=i2pd
|
LogsDirectory=i2pd
|
||||||
LogsDirectoryMode=0700
|
LogsDirectoryMode=0700
|
||||||
Type=simple
|
Type=forking
|
||||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||||
ExecReload=/bin/kill -HUP $MAINPID
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
PIDFile=/var/run/i2pd/i2pd.pid
|
PIDFile=/var/run/i2pd/i2pd.pid
|
||||||
@ -24,7 +24,7 @@ KillSignal=SIGQUIT
|
|||||||
#TimeoutStopSec=10m
|
#TimeoutStopSec=10m
|
||||||
|
|
||||||
# If you have problems with hanging i2pd, you can try enable this
|
# If you have problems with hanging i2pd, you can try enable this
|
||||||
#LimitNOFILE=4096
|
LimitNOFILE=4096
|
||||||
PrivateDevices=yes
|
PrivateDevices=yes
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||||
|
|
||||||
Name: i2pd-git
|
Name: i2pd-git
|
||||||
Version: 2.18.0
|
Version: 2.19.0
|
||||||
Release: git%{git_hash}%{?dist}
|
Release: git%{git_hash}%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd
|
Conflicts: i2pd
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.18.0
|
Version: 2.19.0
|
||||||
Release: 2%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd-git
|
Conflicts: i2pd-git
|
||||||
|
|
||||||
@ -96,6 +96,9 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Jun 26 2018 orignal <i2porignal@yandex.ru> - 2.19.0
|
||||||
|
- update to 2.19.0
|
||||||
|
|
||||||
* Mon Feb 05 2018 r4sas <r4sas@i2pmail.org> - 2.18.0-2
|
* Mon Feb 05 2018 r4sas <r4sas@i2pmail.org> - 2.18.0-2
|
||||||
- Fixed blocking system shutdown for 10 minutes (#1089)
|
- Fixed blocking system shutdown for 10 minutes (#1089)
|
||||||
|
|
||||||
|
@ -30,4 +30,4 @@ keys = irc-keys.dat
|
|||||||
#destinationport = 110
|
#destinationport = 110
|
||||||
#keys = pop3-keys.dat
|
#keys = pop3-keys.dat
|
||||||
|
|
||||||
# see more examples in /usr/share/doc/i2pd/configuration.md.gz
|
# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/
|
||||||
|
@ -60,7 +60,11 @@ namespace i2p
|
|||||||
return service;
|
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<std::ostream> logstream)
|
||||||
{
|
{
|
||||||
i2p::config::Init();
|
i2p::config::Init();
|
||||||
i2p::config::ParseCmdline(argc, argv);
|
i2p::config::ParseCmdline(argc, argv);
|
||||||
@ -104,7 +108,10 @@ namespace i2p
|
|||||||
logs = "file";
|
logs = "file";
|
||||||
|
|
||||||
i2p::log::Logger().SetLogLevel(loglevel);
|
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 == "")
|
if (logfile == "")
|
||||||
logfile = i2p::fs::DataDirPath("i2pd.log");
|
logfile = i2p::fs::DataDirPath("i2pd.log");
|
||||||
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
|
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -12,6 +13,7 @@ namespace util
|
|||||||
class Daemon_Singleton
|
class Daemon_Singleton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
|
||||||
virtual bool init(int argc, char* argv[]);
|
virtual bool init(int argc, char* argv[]);
|
||||||
virtual bool start();
|
virtual bool start();
|
||||||
virtual bool stop();
|
virtual bool stop();
|
||||||
@ -44,19 +46,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)
|
#elif defined(_WIN32)
|
||||||
#define Daemon i2p::util::DaemonWin32::Instance()
|
#define Daemon i2p::util::DaemonWin32::Instance()
|
||||||
class DaemonWin32 : public Daemon_Singleton
|
class DaemonWin32 : public Daemon_Singleton
|
||||||
@ -77,7 +66,18 @@ namespace util
|
|||||||
|
|
||||||
DaemonWin32 ():isGraceful(false) {}
|
DaemonWin32 ():isGraceful(false) {}
|
||||||
};
|
};
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static DaemonAndroid& Instance()
|
||||||
|
{
|
||||||
|
static DaemonAndroid instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
#else
|
#else
|
||||||
#define Daemon i2p::util::DaemonLinux::Instance()
|
#define Daemon i2p::util::DaemonLinux::Instance()
|
||||||
class DaemonLinux : public Daemon_Singleton
|
class DaemonLinux : public Daemon_Singleton
|
||||||
|
@ -198,7 +198,10 @@ namespace http {
|
|||||||
s << "<b>ERROR:</b> " << string << "<br>\r\n";
|
s << "<b>ERROR:</b> " << string << "<br>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowStatus (std::stringstream& s, bool includeHiddenContent)
|
void ShowStatus (
|
||||||
|
std::stringstream& s,
|
||||||
|
bool includeHiddenContent,
|
||||||
|
i2p::http::OutputFormatEnum outputFormat)
|
||||||
{
|
{
|
||||||
s << "<b>Uptime:</b> ";
|
s << "<b>Uptime:</b> ";
|
||||||
ShowUptime(s, i2p::context.GetUptime ());
|
ShowUptime(s, i2p::context.GetUptime ());
|
||||||
@ -224,7 +227,7 @@ namespace http {
|
|||||||
default: s << "Unknown";
|
default: s << "Unknown";
|
||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "<br>\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) {
|
if (auto remains = Daemon.gracefulShutdownInterval) {
|
||||||
s << "<b>Stopping in:</b> ";
|
s << "<b>Stopping in:</b> ";
|
||||||
s << remains << " seconds";
|
s << remains << " seconds";
|
||||||
@ -245,7 +248,10 @@ namespace http {
|
|||||||
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
||||||
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
|
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
|
||||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
||||||
s << "<div class='slide'><label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<p class='content'>\r\n";
|
s << "<div class='slide'>";
|
||||||
|
if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
|
||||||
|
s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<p class='content'>\r\n";
|
||||||
|
}
|
||||||
if(includeHiddenContent) {
|
if(includeHiddenContent) {
|
||||||
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||||
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||||
@ -274,6 +280,9 @@ namespace http {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
s << "</p>\r\n</div>\r\n";
|
s << "</p>\r\n</div>\r\n";
|
||||||
|
if(outputFormat==OutputFormatEnum::forQtUi) {
|
||||||
|
s << "<br>";
|
||||||
|
}
|
||||||
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||||
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||||
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
||||||
@ -285,6 +294,7 @@ namespace http {
|
|||||||
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
||||||
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
|
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
|
||||||
|
|
||||||
|
if(outputFormat==OutputFormatEnum::forWebConsole) {
|
||||||
s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
|
s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
|
||||||
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
@ -295,6 +305,7 @@ namespace http {
|
|||||||
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "</table>\r\n";
|
s << "</table>\r\n";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ShowLocalDestinations (std::stringstream& s)
|
void ShowLocalDestinations (std::stringstream& s)
|
||||||
{
|
{
|
||||||
@ -493,7 +504,7 @@ namespace http {
|
|||||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n";
|
||||||
else
|
else
|
||||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\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)
|
if (Daemon.gracefulShutdownInterval)
|
||||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
|
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
|
||||||
else
|
else
|
||||||
@ -649,7 +660,7 @@ namespace http {
|
|||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n";
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n";
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
s << "<b>Streams:</b><br>\r\n";
|
s << "<b>Streams:</b><br>\r\n";
|
||||||
for (const auto& it: session->ListSockets())
|
for (const auto& it: sam->ListSockets(id))
|
||||||
{
|
{
|
||||||
switch (it->GetSocketType ())
|
switch (it->GetSocketType ())
|
||||||
{
|
{
|
||||||
@ -863,7 +874,7 @@ namespace http {
|
|||||||
} else if (req.uri.find("cmd=") != std::string::npos) {
|
} else if (req.uri.find("cmd=") != std::string::npos) {
|
||||||
HandleCommand (req, res, s);
|
HandleCommand (req, res, s);
|
||||||
} else {
|
} else {
|
||||||
ShowStatus (s, true);
|
ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
|
||||||
res.add_header("Refresh", "10");
|
res.add_header("Refresh", "10");
|
||||||
}
|
}
|
||||||
ShowPageTail (s);
|
ShowPageTail (s);
|
||||||
@ -953,14 +964,14 @@ namespace http {
|
|||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
|
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
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;
|
Daemon.gracefulShutdownInterval = 10*60;
|
||||||
#elif defined(WIN32_APP)
|
#elif defined(WIN32_APP)
|
||||||
i2p::win32::GracefulShutdown ();
|
i2p::win32::GracefulShutdown ();
|
||||||
#endif
|
#endif
|
||||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
|
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
|
||||||
i2p::context.SetAcceptsTunnels (true);
|
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;
|
Daemon.gracefulShutdownInterval = 0;
|
||||||
#elif defined(WIN32_APP)
|
#elif defined(WIN32_APP)
|
||||||
i2p::win32::StopGracefulShutdown ();
|
i2p::win32::StopGracefulShutdown ();
|
||||||
|
@ -80,7 +80,8 @@ namespace http
|
|||||||
};
|
};
|
||||||
|
|
||||||
//all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml
|
//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 ShowLocalDestinations (std::stringstream& s);
|
||||||
void ShowLeasesSets(std::stringstream& s);
|
void ShowLeasesSets(std::stringstream& s);
|
||||||
void ShowTunnels (std::stringstream& s);
|
void ShowTunnels (std::stringstream& s);
|
||||||
|
@ -727,7 +727,7 @@ namespace client
|
|||||||
sam_session.put("name", name);
|
sam_session.put("name", name);
|
||||||
sam_session.put("address", i2p::client::context.GetAddressBook ().ToAddress(ident));
|
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;
|
boost::property_tree::ptree stream;
|
||||||
stream.put("type", socket->GetSocketType ());
|
stream.put("type", socket->GetSocketType ());
|
||||||
|
@ -138,11 +138,14 @@ namespace i2p
|
|||||||
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno));
|
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ANDROID
|
||||||
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
||||||
{
|
{
|
||||||
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
|
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
char pid[10];
|
char pid[10];
|
||||||
sprintf(pid, "%d\n", getpid());
|
sprintf(pid, "%d\n", getpid());
|
||||||
ftruncate(pidFH, 0);
|
ftruncate(pidFH, 0);
|
||||||
|
11
debian/changelog
vendored
11
debian/changelog
vendored
@ -1,3 +1,14 @@
|
|||||||
|
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 <r4sas@i2pmail.org> Tue, 26 Jun 2018 16:27:45 +0000
|
||||||
|
|
||||||
i2pd (2.18.0-1) unstable; urgency=low
|
i2pd (2.18.0-1) unstable; urgency=low
|
||||||
|
|
||||||
* updated to version 2.18.0/0.9.33
|
* updated to version 2.18.0/0.9.33
|
||||||
|
8
debian/control
vendored
8
debian/control
vendored
@ -2,7 +2,7 @@ Source: i2pd
|
|||||||
Section: net
|
Section: net
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: R4SAS <r4sas@i2pmail.org>
|
Maintainer: R4SAS <r4sas@i2pmail.org>
|
||||||
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
|
Standards-Version: 3.9.6
|
||||||
Homepage: http://i2pd.website/
|
Homepage: http://i2pd.website/
|
||||||
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
|
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
|
||||||
@ -11,9 +11,8 @@ Vcs-Browser: https://github.com/PurpleI2P/i2pd
|
|||||||
Package: i2pd
|
Package: i2pd
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Pre-Depends: adduser
|
Pre-Depends: adduser
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
|
||||||
Suggests: tor, privoxy, apparmor
|
Description: Full-featured C++ implementation of I2P client.
|
||||||
Description: A full-featured C++ implementation of I2P client.
|
|
||||||
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
||||||
communications over I2P are anonymous and end-to-end encrypted, participants
|
communications over I2P are anonymous and end-to-end encrypted, participants
|
||||||
don't reveal their real IP addresses.
|
don't reveal their real IP addresses.
|
||||||
@ -25,7 +24,6 @@ Architecture: any
|
|||||||
Priority: extra
|
Priority: extra
|
||||||
Section: debug
|
Section: debug
|
||||||
Depends: i2pd (= ${binary:Version}), ${misc:Depends}
|
Depends: i2pd (= ${binary:Version}), ${misc:Depends}
|
||||||
Suggests: gdb
|
|
||||||
Description: i2pd debugging symbols
|
Description: i2pd debugging symbols
|
||||||
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
||||||
communications over I2P are anonymous and end-to-end encrypted, participants
|
communications over I2P are anonymous and end-to-end encrypted, participants
|
||||||
|
3
debian/docs
vendored
3
debian/docs
vendored
@ -1 +1,4 @@
|
|||||||
README.md
|
README.md
|
||||||
|
contrib/i2pd.conf
|
||||||
|
contrib/subscriptions.txt
|
||||||
|
contrib/tunnels.conf
|
||||||
|
90
debian/i2pd.1
vendored
90
debian/i2pd.1
vendored
@ -1,22 +1,19 @@
|
|||||||
.TH I2PD "1" "March 31, 2015"
|
.TH "I2PD" "1" "June 20, 2018"
|
||||||
|
|
||||||
.SH NAME
|
.SH "NAME"
|
||||||
i2pd \- Load-balanced unspoofable packet switching network
|
i2pd \- Full-featured C++ implementation of I2P client.
|
||||||
|
.SH "SYNOPSIS"
|
||||||
.SH SYNOPSIS
|
|
||||||
.B i2pd
|
.B i2pd
|
||||||
[\fIOPTION1\fR] [\fIOPTION2\fR]...
|
[\fIOPTION1\fR] [\fIOPTION2\fR]...
|
||||||
|
.SH "DESCRIPTION"
|
||||||
.SH DESCRIPTION
|
|
||||||
i2pd
|
i2pd
|
||||||
is a C++ implementation of the router for the I2P anonymizing network, offering
|
is a C++ implementation of the router for the I2P anonymizing network, offering
|
||||||
a simple layer that identity-sensitive applications can use to securely
|
a simple layer that identity-sensitive applications can use to securely
|
||||||
communicate. All data is wrapped with several layers of encryption, and the
|
communicate. All data is wrapped with several layers of encryption, and the
|
||||||
network is both distributed and dynamic, with no trusted parties.
|
network is both distributed and dynamic, with no trusted parties.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Any of the configuration options below can be used in the \fBDAEMON_ARGS\fR variable in \fI/etc/default/i2pd\fR.
|
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
|
.TP
|
||||||
\fB\-\-help\fR
|
\fB\-\-help\fR
|
||||||
Show available options.
|
Show available options.
|
||||||
@ -36,11 +33,14 @@ Where to write pidfile (don\'t write by default)
|
|||||||
\fB\-\-log=\fR
|
\fB\-\-log=\fR
|
||||||
Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not set, \fIfile\fR - otherwise, for compatibility)
|
Logs destination: \fIstdout\fR, \fIfile\fR, \fIsyslog\fR (\fIstdout\fR if not set, \fIfile\fR - otherwise, for compatibility)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-logfile\fR
|
\fB\-\-logfile=\fR
|
||||||
Path to logfile (default - autodetect)
|
Path to logfile (default - autodetect)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-loglevel=\fR
|
\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 (\fIdisabled\fR by default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-datadir=\fR
|
\fB\-\-datadir=\fR
|
||||||
Path to storage of i2pd data (RI, keys, peer profiles, ...)
|
Path to storage of i2pd data (RI, keys, peer profiles, ...)
|
||||||
@ -51,35 +51,58 @@ The external IP address
|
|||||||
\fB\-\-port=\fR
|
\fB\-\-port=\fR
|
||||||
The port to listen on for incoming connections
|
The port to listen on for incoming connections
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-daemon\fR
|
\fB\-\-ifname=\fR
|
||||||
Router will go to background after start
|
The network interface to bind to
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-service\fR
|
\fB\-\-ifname4=\fR
|
||||||
Router will use system folders like \fI/var/lib/i2pd\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\-\-ipv4=\fR
|
||||||
|
Enable communication through ipv6 (\fIenabled\fR by default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-ipv6\fR
|
\fB\-\-ipv6\fR
|
||||||
Enable communication through ipv6. false by default
|
Enable communication through ipv6 (\fIdisabled\fR by default)
|
||||||
|
.TP
|
||||||
|
\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
|
||||||
|
Enable usage of SSU transport (\fIenabled\fR by default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-notransit\fR
|
\fB\-\-notransit\fR
|
||||||
Router will not accept transit tunnels at startup
|
Router will not accept transit tunnels at startup (\fIdisabled\fR by default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-floodfill\fR
|
\fB\-\-floodfill\fR
|
||||||
Router will be floodfill
|
Router will be floodfill (\fIdisabled\fR by default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-bandwidth=\fR
|
\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 (\fIdisabled\fR by default)
|
||||||
|
.TP
|
||||||
|
\fB\-\-service\fR
|
||||||
|
Router will use system folders like \fI/var/lib/i2pd\fR (\fIdisabled\fR by default)
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-family=\fR
|
\fB\-\-family=\fR
|
||||||
Name of a family, router belongs to.
|
Name of a family, router belongs to.
|
||||||
.PP
|
.PP
|
||||||
See service-specific parameters in example config file \fIcontrib/i2pd.conf\fR
|
Switchs, which enabled by default (like \fB\-\-ssu\fR, \fB\-\-ntcp\fR, etc.), can be disabled in config file.
|
||||||
|
.RE
|
||||||
.SH FILES
|
See service-specific parameters in example config file \fI/usr/share/doc/i2pd/i2pd.conf.gz\fR
|
||||||
.PP
|
.SH "FILES"
|
||||||
/etc/i2pd/i2pd.conf, /etc/i2pd/tunnels.conf, /etc/default/i2pd
|
/etc/i2pd/i2pd.conf, /etc/i2pd/tunnels.conf, /etc/default/i2pd
|
||||||
.RS 4
|
.RS 4
|
||||||
i2pd configuration files (when running as a system service)
|
i2pd configuration files (when running as a system service)
|
||||||
|
|
||||||
.RE
|
.RE
|
||||||
.PP
|
.PP
|
||||||
/var/lib/i2pd/
|
/var/lib/i2pd/
|
||||||
@ -90,16 +113,15 @@ i2pd profile directory (when running as a system service, see \fB\-\-service\fR
|
|||||||
$HOME/.i2pd/
|
$HOME/.i2pd/
|
||||||
.RS 4
|
.RS 4
|
||||||
i2pd profile directory (when running as a normal user)
|
i2pd profile directory (when running as a normal user)
|
||||||
|
.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
|
.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
|
.PP
|
||||||
/usr/share/doc/i2pd/examples/hosts.txt.gz
|
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.
|
||||||
.RS 4
|
.RE
|
||||||
default I2P hosts file
|
|
||||||
.SH AUTHOR
|
|
||||||
This manual page was written by kytv <killyourtv@i2pmail.org> for the Debian system (but may be used by others).
|
|
||||||
.PP
|
|
||||||
Updated by hagen <hagen@i2pmail.org> in 2016.
|
|
||||||
.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
|
On Debian systems, the complete text of the GNU General Public License can be found in \fI/usr/share/common-licenses/GPL\fR
|
||||||
|
1
debian/i2pd.service
vendored
Symbolic link
1
debian/i2pd.service
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../contrib/debian/i2pd.service
|
1
debian/i2pd.tmpfile
vendored
Symbolic link
1
debian/i2pd.tmpfile
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../contrib/debian/i2pd.tmpfile
|
15
debian/rules
vendored
15
debian/rules
vendored
@ -5,17 +5,18 @@
|
|||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow
|
DEB_BUILD_MAINT_OPTIONS=hardening=+bindnow
|
||||||
DPKG_EXPORT_BUILDFLAGS = 1
|
#DPKG_EXPORT_BUILDFLAGS = 1
|
||||||
include /usr/share/dpkg/buildflags.mk
|
#include /usr/share/dpkg/buildflags.mk
|
||||||
CXXFLAGS+=$(CPPFLAGS)
|
#CXXFLAGS+=$(CPPFLAGS)
|
||||||
PREFIX=/usr
|
#PREFIX=/usr
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@ --parallel
|
dh $@ --parallel
|
||||||
dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd
|
# dh_apparmor --profile-name=usr.sbin.i2pd -pi2pd
|
||||||
|
|
||||||
override_dh_strip:
|
override_dh_strip:
|
||||||
dh_strip --dbg-package=i2pd-dbg
|
dh_strip --dbg-package=i2pd-dbg
|
||||||
|
|
||||||
override_dh_shlibdeps:
|
## uncoment this if you have "missing info" problem when building package
|
||||||
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
|
#override_dh_shlibdeps:
|
||||||
|
# dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
|
||||||
|
@ -210,6 +210,21 @@ namespace data
|
|||||||
return 4*d.quot;
|
return 4*d.quot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ToBase64Standard (const std::string& in)
|
||||||
|
{
|
||||||
|
auto len = Base64EncodingBufferSize (in.length ());
|
||||||
|
char * str = new char[len+1];
|
||||||
|
auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len);
|
||||||
|
str[l] = 0;
|
||||||
|
// replace '-' by '+' and '~' by '/'
|
||||||
|
for (size_t i = 0; i < l; i++)
|
||||||
|
if (str[i] == '-') str[i] = '+';
|
||||||
|
else if (str[i] == '~') str[i] = '/';
|
||||||
|
std::string s(str);
|
||||||
|
delete[] str;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* iT64
|
* iT64
|
||||||
|
@ -19,6 +19,9 @@ namespace data {
|
|||||||
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
||||||
*/
|
*/
|
||||||
size_t Base64EncodingBufferSize(const size_t input_size);
|
size_t Base64EncodingBufferSize(const size_t input_size);
|
||||||
|
|
||||||
|
std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization
|
||||||
|
|
||||||
} // data
|
} // data
|
||||||
} // i2p
|
} // i2p
|
||||||
|
|
||||||
|
147
libi2pd/ChaCha20.cpp
Normal file
147
libi2pd/ChaCha20.cpp
Normal file
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
26
libi2pd/ChaCha20.h
Normal file
26
libi2pd/ChaCha20.h
Normal file
@ -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 <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
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
|
@ -37,32 +37,33 @@ namespace config {
|
|||||||
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
|
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
|
||||||
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)")
|
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)")
|
||||||
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
|
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
|
||||||
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
|
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)")
|
||||||
("logclftime", value<bool>()->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<std::string>()->default_value(""), "Specify a family, router belongs to")
|
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
|
||||||
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
|
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
|
||||||
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
|
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
|
||||||
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
|
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
|
||||||
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
|
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
|
||||||
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
|
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
|
||||||
("nat", value<bool>()->default_value(true), "Should we assume we are behind NAT?")
|
("nat", value<bool>()->default_value(true), "Should we assume we are behind NAT? (default: enabled)")
|
||||||
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
||||||
("ipv4", value<bool>()->default_value(true), "Enable communication through ipv4")
|
("ipv4", value<bool>()->default_value(true), "Enable communication through ipv4 (default: enabled)")
|
||||||
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
|
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)")
|
||||||
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
|
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
|
||||||
("daemon", value<bool>()->zero_tokens()->default_value(false), "Router will go to background after start")
|
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)")
|
||||||
("service", value<bool>()->zero_tokens()->default_value(false), "Router will use system folders like '/var/lib/i2pd'")
|
("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)")
|
||||||
("notransit", value<bool>()->zero_tokens()->default_value(false), "Router will not accept transit tunnels at startup")
|
("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)")
|
||||||
("floodfill", value<bool>()->zero_tokens()->default_value(false), "Router will be floodfill")
|
("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)")
|
||||||
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
||||||
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100")
|
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
|
||||||
("ntcp", value<bool>()->default_value(true), "Enable NTCP transport")
|
("ntcp", value<bool>()->default_value(true), "Enable NTCP transport (default: enabled)")
|
||||||
("ssu", value<bool>()->default_value(true), "Enable SSU transport")
|
("ssu", value<bool>()->default_value(true), "Enable SSU transport (default: enabled)")
|
||||||
("ntcpproxy", value<std::string>()->default_value(""), "Proxy URL for NTCP transport")
|
("ntcpproxy", value<std::string>()->default_value(""), "Proxy URL for NTCP transport")
|
||||||
|
("ntcp2", value<bool>()->default_value(false), "Enable NTCP2 (experimental, default: disabled)")
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
||||||
("insomnia", value<bool>()->zero_tokens()->default_value(false), "Prevent system from sleeping")
|
("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)")
|
||||||
("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask") // TODO: add custom validator or something
|
("close", value<std::string>()->default_value("ask"), "Action on close: minimize, exit, ask")
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ namespace config {
|
|||||||
("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth")
|
("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth")
|
||||||
("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)")
|
("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)")
|
||||||
("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI")
|
("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI")
|
||||||
("http.hostname", value<std::string>()->default_value("localhost"),"Expected hostname for WebUI")
|
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description httpproxy("HTTP Proxy options");
|
options_description httpproxy("HTTP Proxy options");
|
||||||
@ -191,7 +192,7 @@ namespace config {
|
|||||||
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
||||||
"https://i2p-0.manas.ca:8443/,"
|
"https://i2p-0.manas.ca:8443/,"
|
||||||
"https://download.xxlspeed.com/,"
|
"https://download.xxlspeed.com/,"
|
||||||
"https://reseed-ru.lngserv.ru/,"
|
"https://reseed-fr.i2pd.xyz/,"
|
||||||
"https://reseed.atomike.ninja/,"
|
"https://reseed.atomike.ninja/,"
|
||||||
"https://reseed.memcpy.io/,"
|
"https://reseed.memcpy.io/,"
|
||||||
"https://reseed.onion.im/,"
|
"https://reseed.onion.im/,"
|
||||||
@ -330,4 +331,3 @@ namespace config {
|
|||||||
|
|
||||||
} // namespace config
|
} // namespace config
|
||||||
} // namespace i2p
|
} // namespace i2p
|
||||||
|
|
||||||
|
@ -8,8 +8,15 @@
|
|||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include "TunnelBase.h"
|
#include "TunnelBase.h"
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include "Log.h"
|
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
|
#if LEGACY_OPENSSL
|
||||||
|
#include "ChaCha20.h"
|
||||||
|
#include "Poly1305.h"
|
||||||
|
#else
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#endif
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@ -594,6 +601,13 @@ namespace crypto
|
|||||||
|
|
||||||
// AES
|
// AES
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
|
#ifdef ARM64AES
|
||||||
|
void init_aesenc(void){
|
||||||
|
// TODO: Implementation
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define KeyExpansion256(round0,round1) \
|
#define KeyExpansion256(round0,round1) \
|
||||||
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
||||||
"movaps %%xmm1, %%xmm4 \n" \
|
"movaps %%xmm1, %%xmm4 \n" \
|
||||||
@ -1050,6 +1064,91 @@ 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)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
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;
|
||||||
|
std::vector<uint8_t> 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)
|
||||||
|
{
|
||||||
|
// padding1
|
||||||
|
rem = 16 - 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)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
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)) ret = false; // compare with provided
|
||||||
|
}
|
||||||
|
#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
|
||||||
|
|
||||||
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
||||||
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
|
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
|
||||||
{
|
{
|
||||||
|
@ -124,6 +124,9 @@ namespace crypto
|
|||||||
|
|
||||||
|
|
||||||
#ifdef AESNI
|
#ifdef AESNI
|
||||||
|
#ifdef ARM64AES
|
||||||
|
void init_aesenc(void) __attribute__((constructor));
|
||||||
|
#endif
|
||||||
class ECBCryptoAESNI
|
class ECBCryptoAESNI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -178,6 +181,7 @@ namespace crypto
|
|||||||
|
|
||||||
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
|
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 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 (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
||||||
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
||||||
@ -200,6 +204,7 @@ namespace crypto
|
|||||||
|
|
||||||
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
|
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 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 (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
|
||||||
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
|
||||||
@ -249,6 +254,10 @@ namespace crypto
|
|||||||
CBCDecryption m_LayerDecryption;
|
CBCDecryption m_LayerDecryption;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// init and terminate
|
||||||
void InitCrypto (bool precomputation);
|
void InitCrypto (bool precomputation);
|
||||||
void TerminateCrypto ();
|
void TerminateCrypto ();
|
||||||
}
|
}
|
||||||
@ -256,7 +265,8 @@ namespace crypto
|
|||||||
|
|
||||||
// take care about openssl version
|
// take care about openssl version
|
||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
#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
|
// define getters and setters introduced in 1.1.0
|
||||||
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
||||||
{
|
{
|
||||||
|
@ -12,9 +12,9 @@ namespace crypto
|
|||||||
memcpy (m_PublicKey, pub, 256);
|
memcpy (m_PublicKey, pub, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
|
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, true);
|
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv)
|
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv)
|
||||||
@ -22,9 +22,9 @@ namespace crypto
|
|||||||
memcpy (m_PrivateKey, priv, 256);
|
memcpy (m_PrivateKey, priv, 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
|
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, true);
|
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub)
|
ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub)
|
||||||
@ -44,10 +44,10 @@ namespace crypto
|
|||||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
|
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
if (m_Curve && m_PublicKey)
|
if (m_Curve && m_PublicKey)
|
||||||
ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx, true);
|
ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv)
|
ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv)
|
||||||
@ -62,10 +62,10 @@ namespace crypto
|
|||||||
if (m_PrivateKey) BN_free (m_PrivateKey);
|
if (m_PrivateKey) BN_free (m_PrivateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
|
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
if (m_Curve && m_PrivateKey)
|
if (m_Curve && m_PrivateKey)
|
||||||
return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx, true);
|
return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,10 +104,10 @@ namespace crypto
|
|||||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx)
|
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
if (m_PublicKey)
|
if (m_PublicKey)
|
||||||
ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx, true);
|
ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv)
|
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv)
|
||||||
@ -120,10 +120,10 @@ namespace crypto
|
|||||||
if (m_PrivateKey) BN_free (m_PrivateKey);
|
if (m_PrivateKey) BN_free (m_PrivateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
|
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
if (m_PrivateKey)
|
if (m_PrivateKey)
|
||||||
return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx, true);
|
return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ namespace crypto
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~CryptoKeyEncryptor () {};
|
virtual ~CryptoKeyEncryptor () {};
|
||||||
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted
|
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) = 0; // 222 bytes data, 512/514 bytes encrypted
|
||||||
};
|
};
|
||||||
|
|
||||||
class CryptoKeyDecryptor
|
class CryptoKeyDecryptor
|
||||||
@ -21,7 +21,7 @@ namespace crypto
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~CryptoKeyDecryptor () {};
|
virtual ~CryptoKeyDecryptor () {};
|
||||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) = 0; // 512 bytes encrypted, 222 bytes data
|
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) = 0; // 512/514 bytes encrypted, 222 bytes data
|
||||||
};
|
};
|
||||||
|
|
||||||
// ElGamal
|
// ElGamal
|
||||||
@ -30,7 +30,7 @@ namespace crypto
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
ElGamalEncryptor (const uint8_t * pub);
|
ElGamalEncryptor (const uint8_t * pub);
|
||||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
|
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ namespace crypto
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
ElGamalDecryptor (const uint8_t * priv);
|
ElGamalDecryptor (const uint8_t * priv);
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ namespace crypto
|
|||||||
|
|
||||||
ECIESP256Encryptor (const uint8_t * pub);
|
ECIESP256Encryptor (const uint8_t * pub);
|
||||||
~ECIESP256Encryptor ();
|
~ECIESP256Encryptor ();
|
||||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
|
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ namespace crypto
|
|||||||
|
|
||||||
ECIESP256Decryptor (const uint8_t * priv);
|
ECIESP256Decryptor (const uint8_t * priv);
|
||||||
~ECIESP256Decryptor ();
|
~ECIESP256Decryptor ();
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ namespace crypto
|
|||||||
|
|
||||||
ECIESGOSTR3410Encryptor (const uint8_t * pub);
|
ECIESGOSTR3410Encryptor (const uint8_t * pub);
|
||||||
~ECIESGOSTR3410Encryptor ();
|
~ECIESGOSTR3410Encryptor ();
|
||||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
|
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ namespace crypto
|
|||||||
|
|
||||||
ECIESGOSTR3410Decryptor (const uint8_t * priv);
|
ECIESGOSTR3410Decryptor (const uint8_t * priv);
|
||||||
~ECIESGOSTR3410Decryptor ();
|
~ECIESGOSTR3410Decryptor ();
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -281,8 +281,12 @@ namespace client
|
|||||||
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
|
i2p::garlic::GarlicDestination::SetLeaseSetUpdated ();
|
||||||
if (m_IsPublic)
|
if (m_IsPublic)
|
||||||
{
|
{
|
||||||
m_PublishVerificationTimer.cancel ();
|
auto s = shared_from_this ();
|
||||||
Publish ();
|
m_Service.post ([s](void)
|
||||||
|
{
|
||||||
|
s->m_PublishVerificationTimer.cancel ();
|
||||||
|
s->Publish ();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,17 +329,17 @@ namespace client
|
|||||||
switch (typeID)
|
switch (typeID)
|
||||||
{
|
{
|
||||||
case eI2NPData:
|
case eI2NPData:
|
||||||
HandleDataMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
|
HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
||||||
break;
|
break;
|
||||||
case eI2NPDeliveryStatus:
|
case eI2NPDeliveryStatus:
|
||||||
// we assume tunnel tests non-encrypted
|
// we assume tunnel tests non-encrypted
|
||||||
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseStore:
|
case eI2NPDatabaseStore:
|
||||||
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
|
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseSearchReply:
|
case eI2NPDatabaseSearchReply:
|
||||||
HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, bufbe16toh (buf + I2NP_HEADER_SIZE_OFFSET));
|
HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
||||||
@ -855,6 +859,11 @@ namespace client
|
|||||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
uint32_t length = bufbe32toh (buf);
|
uint32_t length = bufbe32toh (buf);
|
||||||
|
if(length > len - 4)
|
||||||
|
{
|
||||||
|
LogPrint(eLogError, "Destination: Data message length ", length, " exceeds buffer length ", len);
|
||||||
|
return;
|
||||||
|
}
|
||||||
buf += 4;
|
buf += 4;
|
||||||
// we assume I2CP payload
|
// we assume I2CP payload
|
||||||
uint16_t fromPort = bufbe16toh (buf + 4), // source
|
uint16_t fromPort = bufbe16toh (buf + 4), // source
|
||||||
@ -1024,7 +1033,7 @@ namespace client
|
|||||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||||
{
|
{
|
||||||
if (m_Decryptor)
|
if (m_Decryptor)
|
||||||
return m_Decryptor->Decrypt (encrypted, data, ctx);
|
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "Destinations: decryptor is not set");
|
LogPrint (eLogError, "Destinations: decryptor is not set");
|
||||||
return false;
|
return false;
|
||||||
|
515
libi2pd/Ed25519.cpp
Normal file
515
libi2pd/Ed25519.cpp
Normal file
@ -0,0 +1,515 @@
|
|||||||
|
#include <openssl/sha.h>
|
||||||
|
#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<EDDSA25519_PRIVATE_KEY_LENGTH> (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<int len>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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 (x3, u);
|
||||||
|
auto z3 = BN_CTX_get (ctx); BN_one (z3);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
--bits;
|
||||||
|
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
|
||||||
|
swap ^= k_t;
|
||||||
|
if (swap)
|
||||||
|
{
|
||||||
|
std::swap (x2, x3);
|
||||||
|
std::swap (z2, z3);
|
||||||
|
}
|
||||||
|
swap = k_t;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
BN_mod_inverse (z2, z2, q, ctx);
|
||||||
|
BIGNUM * res = BN_new (); // not from ctx
|
||||||
|
BN_mod_mul(res, x2, z2, 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)
|
||||||
|
{
|
||||||
|
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<Ed25519> g_Ed25519;
|
||||||
|
std::unique_ptr<Ed25519>& 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
124
libi2pd/Ed25519.h
Normal file
124
libi2pd/Ed25519.h
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#ifndef ED25519_H__
|
||||||
|
#define ED25519_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
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<int len>
|
||||||
|
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;
|
||||||
|
// 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<Ed25519>& GetEd25519 ();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -96,7 +96,7 @@ namespace http {
|
|||||||
pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */
|
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)) {
|
if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) {
|
||||||
std::size_t delim = url.find(':', pos_p);
|
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);
|
user = url.substr(pos_p, delim - pos_p);
|
||||||
delim += 1;
|
delim += 1;
|
||||||
pass = url.substr(delim, pos_c - delim);
|
pass = url.substr(delim, pos_c - delim);
|
||||||
|
@ -327,7 +327,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
|
i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
// replace record to reply
|
// replace record to reply
|
||||||
if (i2p::context.AcceptsTunnels () &&
|
if (i2p::context.AcceptsTunnels () &&
|
||||||
|
@ -113,7 +113,20 @@ inline void htobe64buf(void *buf, uint64_t big64)
|
|||||||
htobuf64(buf, htobe64(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__
|
#endif // I2PENDIAN_H__
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey);
|
auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey);
|
||||||
if (encryptor)
|
if (encryptor)
|
||||||
encryptor->Encrypt (data, encrypted, ctx);
|
encryptor->Encrypt (data, encrypted, ctx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
|
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
//for std::transform
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace i2p {
|
namespace i2p {
|
||||||
namespace log {
|
namespace log {
|
||||||
static Log logger;
|
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<int(*)(int)>(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; }
|
if (level == "none") { m_MinLevel = eLogNone; }
|
||||||
else if (level == "error") { m_MinLevel = eLogError; }
|
else if (level == "error") { m_MinLevel = eLogError; }
|
||||||
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
||||||
|
623
libi2pd/NTCP2.cpp
Normal file
623
libi2pd/NTCP2.cpp
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/hmac.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "Log.h"
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "Ed25519.h"
|
||||||
|
#include "Siphash.h"
|
||||||
|
#include "RouterContext.h"
|
||||||
|
#include "NTCP2.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
|
||||||
|
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_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr),
|
||||||
|
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0)
|
||||||
|
{
|
||||||
|
auto addr = in_RemoteRouter->GetNTCPAddress ();
|
||||||
|
if (addr->ntcp2)
|
||||||
|
{
|
||||||
|
memcpy (m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
|
||||||
|
memcpy (m_IV, addr->ntcp2->iv, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "NTCP2: Missing NTCP2 parameters");
|
||||||
|
}
|
||||||
|
|
||||||
|
NTCP2Session::~NTCP2Session ()
|
||||||
|
{
|
||||||
|
delete[] m_SessionRequestBuffer;
|
||||||
|
delete[] m_SessionCreatedBuffer;
|
||||||
|
delete[] m_SessionConfirmedBuffer;
|
||||||
|
delete[] m_NextReceivedBuffer;
|
||||||
|
delete[] m_NextSendBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::Terminate ()
|
||||||
|
{
|
||||||
|
if (!m_IsTerminated)
|
||||||
|
{
|
||||||
|
m_IsTerminated = true;
|
||||||
|
m_IsEstablished = false;
|
||||||
|
m_Socket.close ();
|
||||||
|
LogPrint (eLogDebug, "NTCP2: session terminated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::Done ()
|
||||||
|
{
|
||||||
|
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<uint8_t> 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);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
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)
|
||||||
|
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))
|
||||||
|
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_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)
|
||||||
|
{
|
||||||
|
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 ()
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
// generate key pair (X)
|
||||||
|
uint8_t x[32];
|
||||||
|
CreateEphemeralKey (x);
|
||||||
|
// encrypt X
|
||||||
|
i2p::crypto::CBCEncryption encryption;
|
||||||
|
encryption.SetKey (GetRemoteIdentity ()->GetIdentHash ());
|
||||||
|
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];
|
||||||
|
KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralPrivateKey, x, key);
|
||||||
|
// 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
|
||||||
|
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
|
||||||
|
// 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
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
(void) bytes_transferred;
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
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 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
if (options[1] == 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 ", (int)options[1]);
|
||||||
|
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 - 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, 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 + 64), 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)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionCreated read error: ", ecode.message ());
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
|
||||||
|
m_SessionCreatedBufferLen = 64;
|
||||||
|
// decrypt Y
|
||||||
|
i2p::crypto::CBCDecryption decryption;
|
||||||
|
decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ());
|
||||||
|
decryption.SetIV (m_IV);
|
||||||
|
decryption.Decrypt (m_SessionCreatedBuffer, 32, m_Y);
|
||||||
|
// 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[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
|
||||||
|
{
|
||||||
|
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 (),
|
||||||
|
std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SendSessionConfirmed ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed ");
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 32); // encrypted payload
|
||||||
|
SHA256 (h, 64, h);
|
||||||
|
int paddingLength = m_SessionCreatedBufferLen - 64;
|
||||||
|
if (paddingLength > 0)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> h1(paddingLength + 32);
|
||||||
|
memcpy (h1.data (), h, 32);
|
||||||
|
memcpy (h1.data () + 32, m_SessionCreatedBuffer + 64, paddingLength);
|
||||||
|
SHA256 (h1.data (), paddingLength + 32, h);
|
||||||
|
}
|
||||||
|
// 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_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 = i2p::context.GetRouterInfo ().GetBufferLen () + 20;
|
||||||
|
std::vector<uint8_t> 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 (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 (),
|
||||||
|
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");
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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];
|
||||||
|
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 ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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<NTCP2Session> 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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn)
|
||||||
|
{
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ());
|
||||||
|
conn->Terminate ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetSocket ().remote_endpoint ());
|
||||||
|
conn->ClientLogin ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
111
libi2pd/NTCP2.h
Normal file
111
libi2pd/NTCP2.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#ifndef NTCP2_H__
|
||||||
|
#define NTCP2_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include "RouterInfo.h"
|
||||||
|
#include "TransportSession.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace transport
|
||||||
|
{
|
||||||
|
class NTCP2Server;
|
||||||
|
class NTCP2Session: public TransportSession, public std::enable_shared_from_this<NTCP2Session>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
|
||||||
|
~NTCP2Session ();
|
||||||
|
void Terminate ();
|
||||||
|
void Done ();
|
||||||
|
|
||||||
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
|
|
||||||
|
void ClientLogin (); // Alice
|
||||||
|
void ServerLogin (); // Bob
|
||||||
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) {}; // TODO
|
||||||
|
|
||||||
|
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 ();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
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;
|
||||||
|
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 */;
|
||||||
|
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];
|
||||||
|
uint16_t m_NextReceivedLen;
|
||||||
|
uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer;
|
||||||
|
uint8_t m_ReceiveIV[8], m_SendIV[8];
|
||||||
|
uint64_t m_ReceiveSequenceNumber, m_SendSequenceNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NTCP2Server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
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<NTCP2Session> conn);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Run ();
|
||||||
|
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool m_IsRunning;
|
||||||
|
std::thread * m_Thread;
|
||||||
|
boost::asio::io_service m_Service;
|
||||||
|
boost::asio::io_service::work m_Work;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -24,6 +24,12 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct NTCPWork
|
||||||
|
{
|
||||||
|
std::shared_ptr<NTCPSession> session;
|
||||||
|
};
|
||||||
|
|
||||||
NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
|
NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
|
||||||
TransportSession (in_RemoteRouter, NTCP_ESTABLISH_TIMEOUT),
|
TransportSession (in_RemoteRouter, NTCP_ESTABLISH_TIMEOUT),
|
||||||
m_Server (server), m_Socket (m_Server.GetService ()),
|
m_Server (server), m_Socket (m_Server.GetService ()),
|
||||||
@ -177,18 +183,20 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: check for number of pending keys
|
// TODO: check for number of pending keys
|
||||||
auto s = shared_from_this ();
|
auto work = new NTCPWork{shared_from_this()};
|
||||||
m_Server.Work(s, [s]() -> std::function<void(void)> {
|
m_Server.Work(work->session, [work, this]() -> std::function<void(void)> {
|
||||||
if (!s->m_DHKeysPair)
|
if (!work->session->m_DHKeysPair)
|
||||||
s->m_DHKeysPair = transports.GetNextDHKeysPair ();
|
work->session->m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||||
s->CreateAESKey (s->m_Establisher->phase1.pubKey);
|
work->session->CreateAESKey (work->session->m_Establisher->phase1.pubKey);
|
||||||
return std::bind(&NTCPSession::SendPhase2, s);
|
return std::bind(&NTCPSession::SendPhase2, work->session, work);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCPSession::SendPhase2 ()
|
void NTCPSession::SendPhase2 (NTCPWork * work)
|
||||||
{
|
{
|
||||||
|
if(work)
|
||||||
|
delete work;
|
||||||
const uint8_t * y = m_DHKeysPair->GetPublicKey ();
|
const uint8_t * y = m_DHKeysPair->GetPublicKey ();
|
||||||
memcpy (m_Establisher->phase2.pubKey, y, 256);
|
memcpy (m_Establisher->phase2.pubKey, y, 256);
|
||||||
uint8_t xy[512];
|
uint8_t xy[512];
|
||||||
@ -241,16 +249,17 @@ namespace transport
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto s = shared_from_this ();
|
auto work = new NTCPWork{shared_from_this()};
|
||||||
m_Server.Work(s, [s]() -> std::function<void(void)> {
|
m_Server.Work(work->session, [work, this]() -> std::function<void(void)> {
|
||||||
s->CreateAESKey (s->m_Establisher->phase2.pubKey);
|
work->session->CreateAESKey (work->session->m_Establisher->phase2.pubKey);
|
||||||
return std::bind(&NTCPSession::HandlePhase2, s);
|
return std::bind(&NTCPSession::HandlePhase2, work->session, work);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCPSession::HandlePhase2 ()
|
void NTCPSession::HandlePhase2 (NTCPWork * work)
|
||||||
{
|
{
|
||||||
|
if(work) delete work;
|
||||||
m_Decryption.SetIV (m_Establisher->phase2.pubKey + 240);
|
m_Decryption.SetIV (m_Establisher->phase2.pubKey + 240);
|
||||||
m_Encryption.SetIV (m_Establisher->phase1.HXxorHI + 16);
|
m_Encryption.SetIV (m_Establisher->phase1.HXxorHI + 16);
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ namespace transport
|
|||||||
} encrypted;
|
} encrypted;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NTCPWork;
|
||||||
|
|
||||||
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
|
const size_t NTCP_MAX_MESSAGE_SIZE = 16384;
|
||||||
const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message
|
const size_t NTCP_BUFFER_SIZE = 1028; // fits 1 tunnel data message
|
||||||
const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int NTCP_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
@ -77,12 +79,12 @@ namespace transport
|
|||||||
void SendPhase3 ();
|
void SendPhase3 ();
|
||||||
void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandlePhase1Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandlePhase2Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandlePhase2 ();
|
void HandlePhase2 (NTCPWork * work=nullptr);
|
||||||
void HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
void HandlePhase3Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
||||||
void HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
void HandlePhase4Received (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsA);
|
||||||
|
|
||||||
//server
|
//server
|
||||||
void SendPhase2 ();
|
void SendPhase2 (NTCPWork * work=nullptr);
|
||||||
void SendPhase4 (uint32_t tsA, uint32_t tsB);
|
void SendPhase4 (uint32_t tsA, uint32_t tsB);
|
||||||
void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandlePhase1Received (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
|
void HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB);
|
||||||
|
246
libi2pd/Poly1305.cpp
Normal file
246
libi2pd/Poly1305.cpp
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
#include "Poly1305.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 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)
|
||||||
|
{
|
||||||
|
const uint8_t * k = (const uint8_t *) key;
|
||||||
|
Poly1305 p(k);
|
||||||
|
p.Update(buf, sz);
|
||||||
|
p.Finish(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
libi2pd/Poly1305.h
Normal file
28
libi2pd/Poly1305.h
Normal file
@ -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 <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
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
|
@ -1,6 +1,8 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <openssl/rand.h>
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
|
#include "Ed25519.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
@ -34,11 +36,7 @@ namespace i2p
|
|||||||
|
|
||||||
void RouterContext::CreateNewRouter ()
|
void RouterContext::CreateNewRouter ()
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
|
|
||||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
||||||
#else
|
|
||||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_DSA_SHA1);
|
|
||||||
#endif
|
|
||||||
SaveKeys ();
|
SaveKeys ();
|
||||||
NewRouterInfo ();
|
NewRouterInfo ();
|
||||||
}
|
}
|
||||||
@ -52,6 +50,7 @@ namespace i2p
|
|||||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||||
|
bool ntcp2; i2p::config::GetOption("ntcp2", ntcp2);
|
||||||
bool nat; i2p::config::GetOption("nat", nat);
|
bool nat; i2p::config::GetOption("nat", nat);
|
||||||
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
||||||
std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
|
std::string ifname4; i2p::config::GetOption("ifname4", ifname4);
|
||||||
@ -93,6 +92,12 @@ namespace i2p
|
|||||||
routerInfo.CreateBuffer (m_Keys);
|
routerInfo.CreateBuffer (m_Keys);
|
||||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
||||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
|
|
||||||
|
if (ntcp2)
|
||||||
|
{
|
||||||
|
NewNTCP2Keys ();
|
||||||
|
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::UpdateRouterInfo ()
|
void RouterContext::UpdateRouterInfo ()
|
||||||
@ -102,6 +107,19 @@ namespace i2p
|
|||||||
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RouterContext::NewNTCP2Keys ()
|
||||||
|
{
|
||||||
|
m_NTCP2Keys.reset (new NTCP2PrivateKeys ());
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
void RouterContext::SetStatus (RouterStatus status)
|
void RouterContext::SetStatus (RouterStatus status)
|
||||||
{
|
{
|
||||||
if (status != m_Status)
|
if (status != m_Status)
|
||||||
@ -433,6 +451,30 @@ namespace i2p
|
|||||||
if (IsUnreachable ())
|
if (IsUnreachable ())
|
||||||
SetReachable (); // we assume reachable until we discover firewall through peer tests
|
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));
|
||||||
|
}
|
||||||
|
n2k.close ();
|
||||||
|
}
|
||||||
|
if (!m_NTCP2Keys)
|
||||||
|
{
|
||||||
|
NewNTCP2Keys ();
|
||||||
|
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,6 +524,11 @@ namespace i2p
|
|||||||
|
|
||||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||||
{
|
{
|
||||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx) : false;
|
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||||
|
{
|
||||||
|
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, false) : false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
const char ROUTER_INFO[] = "router.info";
|
const char ROUTER_INFO[] = "router.info";
|
||||||
const char ROUTER_KEYS[] = "router.keys";
|
const char ROUTER_KEYS[] = "router.keys";
|
||||||
|
const char NTCP2_KEYS[] = "ntcp2.keys";
|
||||||
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
||||||
|
|
||||||
enum RouterStatus
|
enum RouterStatus
|
||||||
@ -32,6 +33,15 @@ namespace i2p
|
|||||||
|
|
||||||
class RouterContext: public i2p::garlic::GarlicDestination
|
class RouterContext: public i2p::garlic::GarlicDestination
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct NTCP2PrivateKeys
|
||||||
|
{
|
||||||
|
uint8_t staticPublicKey[32];
|
||||||
|
uint8_t staticPrivateKey[32];
|
||||||
|
uint8_t iv[16];
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RouterContext ();
|
RouterContext ();
|
||||||
@ -49,6 +59,9 @@ namespace i2p
|
|||||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||||
[](i2p::garlic::GarlicDestination *) {});
|
[](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 GetUptime () const;
|
||||||
uint32_t GetStartupTime () const { return m_StartupTime; };
|
uint32_t GetStartupTime () const { return m_StartupTime; };
|
||||||
@ -61,6 +74,7 @@ namespace i2p
|
|||||||
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
||||||
int GetNetID () const { return m_NetID; };
|
int GetNetID () const { return m_NetID; };
|
||||||
void SetNetID (int netID) { m_NetID = netID; };
|
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 UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||||
@ -107,6 +121,7 @@ namespace i2p
|
|||||||
void CreateNewRouter ();
|
void CreateNewRouter ();
|
||||||
void NewRouterInfo ();
|
void NewRouterInfo ();
|
||||||
void UpdateRouterInfo ();
|
void UpdateRouterInfo ();
|
||||||
|
void NewNTCP2Keys ();
|
||||||
bool Load ();
|
bool Load ();
|
||||||
void SaveKeys ();
|
void SaveKeys ();
|
||||||
|
|
||||||
@ -124,6 +139,7 @@ namespace i2p
|
|||||||
RouterError m_Error;
|
RouterError m_Error;
|
||||||
int m_NetID;
|
int m_NetID;
|
||||||
std::mutex m_GarlicMutex;
|
std::mutex m_GarlicMutex;
|
||||||
|
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern RouterContext context;
|
extern RouterContext context;
|
||||||
|
@ -176,10 +176,14 @@ namespace data
|
|||||||
auto address = std::make_shared<Address>();
|
auto address = std::make_shared<Address>();
|
||||||
s.read ((char *)&address->cost, sizeof (address->cost));
|
s.read ((char *)&address->cost, sizeof (address->cost));
|
||||||
s.read ((char *)&address->date, sizeof (address->date));
|
s.read ((char *)&address->date, sizeof (address->date));
|
||||||
char transportStyle[5];
|
bool isNtcp2 = false;
|
||||||
ReadString (transportStyle, 5, s);
|
char transportStyle[6];
|
||||||
if (!strcmp (transportStyle, "NTCP"))
|
auto transportStyleLen = ReadString (transportStyle, 6, s) - 1;
|
||||||
|
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
|
||||||
|
{
|
||||||
address->transportStyle = eTransportNTCP;
|
address->transportStyle = eTransportNTCP;
|
||||||
|
if (transportStyleLen > 4 || transportStyle[4] == '2') isNtcp2= true;
|
||||||
|
}
|
||||||
else if (!strcmp (transportStyle, "SSU"))
|
else if (!strcmp (transportStyle, "SSU"))
|
||||||
{
|
{
|
||||||
address->transportStyle = eTransportSSU;
|
address->transportStyle = eTransportSSU;
|
||||||
@ -244,6 +248,18 @@ namespace data
|
|||||||
}
|
}
|
||||||
else if (!strcmp (key, "caps"))
|
else if (!strcmp (key, "caps"))
|
||||||
ExtractCaps (value);
|
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')
|
else if (key[0] == 'i')
|
||||||
{
|
{
|
||||||
// introducers
|
// introducers
|
||||||
@ -276,7 +292,7 @@ namespace data
|
|||||||
if (!s) return;
|
if (!s) return;
|
||||||
}
|
}
|
||||||
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
|
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);
|
addresses->push_back(address);
|
||||||
m_SupportedTransports |= supportedTransports;
|
m_SupportedTransports |= supportedTransports;
|
||||||
@ -423,7 +439,7 @@ namespace data
|
|||||||
s.write ((const char *)&address.date, sizeof (address.date));
|
s.write ((const char *)&address.date, sizeof (address.date));
|
||||||
std::stringstream properties;
|
std::stringstream properties;
|
||||||
if (address.transportStyle == eTransportNTCP)
|
if (address.transportStyle == eTransportNTCP)
|
||||||
WriteString ("NTCP", s);
|
WriteString (address.IsNTCP2 () ? "NTCP2" : "NTCP", s);
|
||||||
else if (address.transportStyle == eTransportSSU)
|
else if (address.transportStyle == eTransportSSU)
|
||||||
{
|
{
|
||||||
WriteString ("SSU", s);
|
WriteString ("SSU", s);
|
||||||
@ -439,10 +455,13 @@ namespace data
|
|||||||
else
|
else
|
||||||
WriteString ("", s);
|
WriteString ("", s);
|
||||||
|
|
||||||
|
if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement
|
||||||
|
{
|
||||||
WriteString ("host", properties);
|
WriteString ("host", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
WriteString (address.host.to_string (), properties);
|
WriteString (address.host.to_string (), properties);
|
||||||
properties << ';';
|
properties << ';';
|
||||||
|
}
|
||||||
if (address.transportStyle == eTransportSSU)
|
if (address.transportStyle == eTransportSSU)
|
||||||
{
|
{
|
||||||
// write introducers if any
|
// write introducers if any
|
||||||
@ -517,10 +536,23 @@ namespace data
|
|||||||
properties << ';';
|
properties << ';';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!address.IsNTCP2 ()) // we don't publish NTCP2 address fow now. TODO: implement
|
||||||
|
{
|
||||||
WriteString ("port", properties);
|
WriteString ("port", properties);
|
||||||
properties << '=';
|
properties << '=';
|
||||||
WriteString (boost::lexical_cast<std::string>(address.port), properties);
|
WriteString (boost::lexical_cast<std::string>(address.port), properties);
|
||||||
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 ());
|
uint16_t size = htobe16 (properties.str ().size ());
|
||||||
s.write ((char *)&size, sizeof (size));
|
s.write ((char *)&size, sizeof (size));
|
||||||
@ -656,6 +688,21 @@ namespace data
|
|||||||
m_Caps |= eSSUIntroducer;
|
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<Address>();
|
||||||
|
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, 16);
|
||||||
|
m_Addresses->push_back(std::move(addr));
|
||||||
|
}
|
||||||
|
|
||||||
bool RouterInfo::AddIntroducer (const Introducer& introducer)
|
bool RouterInfo::AddIntroducer (const Introducer& introducer)
|
||||||
{
|
{
|
||||||
for (auto& addr : *m_Addresses)
|
for (auto& addr : *m_Addresses)
|
||||||
@ -735,6 +782,14 @@ namespace data
|
|||||||
return m_SupportedTransports & (eSSUV4 | eSSUV6);
|
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
|
bool RouterInfo::IsV6 () const
|
||||||
{
|
{
|
||||||
return m_SupportedTransports & (eNTCPV6 | eSSUV6);
|
return m_SupportedTransports & (eNTCPV6 | eSSUV6);
|
||||||
@ -742,19 +797,19 @@ namespace data
|
|||||||
|
|
||||||
bool RouterInfo::IsV4 () const
|
bool RouterInfo::IsV4 () const
|
||||||
{
|
{
|
||||||
return m_SupportedTransports & (eNTCPV4 | eSSUV4);
|
return m_SupportedTransports & (eNTCPV4 | eSSUV4 | eNTCP2V4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterInfo::EnableV6 ()
|
void RouterInfo::EnableV6 ()
|
||||||
{
|
{
|
||||||
if (!IsV6 ())
|
if (!IsV6 ())
|
||||||
m_SupportedTransports |= eNTCPV6 | eSSUV6;
|
m_SupportedTransports |= eNTCPV6 | eSSUV6 | eNTCP2V6;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterInfo::EnableV4 ()
|
void RouterInfo::EnableV4 ()
|
||||||
{
|
{
|
||||||
if (!IsV4 ())
|
if (!IsV4 ())
|
||||||
m_SupportedTransports |= eNTCPV4 | eSSUV4;
|
m_SupportedTransports |= eNTCPV4 | eSSUV4 | eNTCP2V4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -762,7 +817,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (IsV6 ())
|
if (IsV6 ())
|
||||||
{
|
{
|
||||||
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6);
|
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6 | eNTCP2V6);
|
||||||
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
|
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
|
||||||
{
|
{
|
||||||
auto addr = *it;
|
auto addr = *it;
|
||||||
@ -778,7 +833,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (IsV4 ())
|
if (IsV4 ())
|
||||||
{
|
{
|
||||||
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4);
|
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4 | eNTCP2V4);
|
||||||
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
|
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
|
||||||
{
|
{
|
||||||
auto addr = *it;
|
auto addr = *it;
|
||||||
@ -840,7 +895,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr);
|
auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr);
|
||||||
if (encryptor)
|
if (encryptor)
|
||||||
encryptor->Encrypt (data, encrypted, ctx);
|
encryptor->Encrypt (data, encrypted, ctx, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,9 @@ namespace data
|
|||||||
eNTCPV4 = 0x01,
|
eNTCPV4 = 0x01,
|
||||||
eNTCPV6 = 0x02,
|
eNTCPV6 = 0x02,
|
||||||
eSSUV4 = 0x04,
|
eSSUV4 = 0x04,
|
||||||
eSSUV6 = 0x08
|
eSSUV6 = 0x08,
|
||||||
|
eNTCP2V4 = 0x10,
|
||||||
|
eNTCP2V6 = 0x20
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Caps
|
enum Caps
|
||||||
@ -88,6 +90,12 @@ namespace data
|
|||||||
std::vector<Introducer> introducers;
|
std::vector<Introducer> introducers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NTCP2Ext
|
||||||
|
{
|
||||||
|
Tag<32> staticKey;
|
||||||
|
Tag<16> iv;
|
||||||
|
};
|
||||||
|
|
||||||
struct Address
|
struct Address
|
||||||
{
|
{
|
||||||
TransportStyle transportStyle;
|
TransportStyle transportStyle;
|
||||||
@ -97,6 +105,7 @@ namespace data
|
|||||||
uint64_t date;
|
uint64_t date;
|
||||||
uint8_t cost;
|
uint8_t cost;
|
||||||
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
||||||
|
std::unique_ptr<NTCP2Ext> ntcp2; // not null for NTCP2
|
||||||
|
|
||||||
bool IsCompatible (const boost::asio::ip::address& other) const
|
bool IsCompatible (const boost::asio::ip::address& other) const
|
||||||
{
|
{
|
||||||
@ -113,6 +122,8 @@ namespace data
|
|||||||
{
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsNTCP2 () const { return (bool)ntcp2; };
|
||||||
};
|
};
|
||||||
typedef std::list<std::shared_ptr<Address> > Addresses;
|
typedef std::list<std::shared_ptr<Address> > Addresses;
|
||||||
|
|
||||||
@ -134,6 +145,7 @@ namespace data
|
|||||||
|
|
||||||
void AddNTCPAddress (const char * host, int port);
|
void AddNTCPAddress (const char * host, int port);
|
||||||
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
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 AddIntroducer (const Introducer& introducer);
|
||||||
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||||
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
|
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
|
||||||
@ -144,6 +156,7 @@ namespace data
|
|||||||
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
||||||
bool IsNTCP (bool v4only = true) const;
|
bool IsNTCP (bool v4only = true) const;
|
||||||
bool IsSSU (bool v4only = true) const;
|
bool IsSSU (bool v4only = true) const;
|
||||||
|
bool IsNTCP2 (bool v4only = true) const;
|
||||||
bool IsV6 () const;
|
bool IsV6 () const;
|
||||||
bool IsV4 () const;
|
bool IsV4 () const;
|
||||||
void EnableV6 ();
|
void EnableV6 ();
|
||||||
|
@ -6,442 +6,6 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace crypto
|
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<EDDSA25519_PRIVATE_KEY_LENGTH> (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<int len>
|
|
||||||
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<Ed25519> g_Ed25519;
|
|
||||||
std::unique_ptr<Ed25519>& 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)
|
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
|
||||||
{
|
{
|
||||||
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||||
@ -466,11 +30,7 @@ namespace crypto
|
|||||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||||
{
|
{
|
||||||
// expand key
|
// expand key
|
||||||
SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey);
|
Ed25519::ExpandPrivateKey (signingPrivateKey, 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
|
|
||||||
|
|
||||||
// generate and encode public key
|
// generate and encode public key
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
|
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
|
#include "Ed25519.h"
|
||||||
#include "Gost.h"
|
#include "Gost.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@ -361,62 +362,6 @@ namespace crypto
|
|||||||
typedef RSASigner<SHA512Hash, NID_sha512, RSASHA5124096_KEY_LENGTH> RSASHA5124096Signer;
|
typedef RSASigner<SHA512Hash, NID_sha512, RSASHA5124096_KEY_LENGTH> RSASHA5124096Signer;
|
||||||
|
|
||||||
// EdDSA
|
// 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
|
class EDDSA25519Verifier: public Verifier
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
152
libi2pd/Siphash.h
Normal file
152
libi2pd/Siphash.h
Normal file
@ -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 <cstdint>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace crypto
|
||||||
|
{
|
||||||
|
namespace siphash
|
||||||
|
{
|
||||||
|
constexpr int crounds = 2;
|
||||||
|
constexpr int drounds = 4;
|
||||||
|
|
||||||
|
inline uint64_t rotl(const uint64_t & x, int b)
|
||||||
|
{
|
||||||
|
uint64_t ret = x << b;
|
||||||
|
ret |= x >> (64 - b);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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<std::size_t hashsz>
|
||||||
|
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;
|
||||||
|
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
|
@ -578,9 +578,7 @@ namespace stream
|
|||||||
if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) // nothing to send
|
if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) // nothing to send
|
||||||
{
|
{
|
||||||
m_Status = eStreamStatusClosed;
|
m_Status = eStreamStatusClosed;
|
||||||
// close could be called from another thread so do SendClose from the destination thread
|
SendClose();
|
||||||
// this is so m_LocalDestination.NewPacket () does not trigger a race condition
|
|
||||||
m_Service.post(std::bind(&Stream::SendClose, shared_from_this()));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case eStreamStatusClosed:
|
case eStreamStatusClosed:
|
||||||
@ -903,11 +901,7 @@ namespace stream
|
|||||||
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
|
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
|
||||||
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
||||||
m_LastIncomingReceiveStreamID (0),
|
m_LastIncomingReceiveStreamID (0),
|
||||||
m_PendingIncomingTimer (m_Owner->GetService ()),
|
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)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -923,7 +917,6 @@ namespace stream
|
|||||||
|
|
||||||
void StreamingDestination::Start ()
|
void StreamingDestination::Start ()
|
||||||
{
|
{
|
||||||
ScheduleConnTrack();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamingDestination::Stop ()
|
void StreamingDestination::Stop ()
|
||||||
@ -931,15 +924,10 @@ namespace stream
|
|||||||
ResetAcceptor ();
|
ResetAcceptor ();
|
||||||
m_PendingIncomingTimer.cancel ();
|
m_PendingIncomingTimer.cancel ();
|
||||||
m_PendingIncomingStreams.clear ();
|
m_PendingIncomingStreams.clear ();
|
||||||
m_ConnTrackTimer.cancel();
|
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||||
m_Streams.clear ();
|
m_Streams.clear ();
|
||||||
}
|
}
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> l(m_ConnsMutex);
|
|
||||||
m_Conns.clear ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamingDestination::HandleNextPacket (Packet * packet)
|
void StreamingDestination::HandleNextPacket (Packet * packet)
|
||||||
@ -971,17 +959,7 @@ namespace stream
|
|||||||
auto incomingStream = CreateNewIncomingStream ();
|
auto incomingStream = CreateNewIncomingStream ();
|
||||||
incomingStream->HandleNextPacket (packet); // SYN
|
incomingStream->HandleNextPacket (packet); // SYN
|
||||||
auto ident = incomingStream->GetRemoteIdentity();
|
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;
|
m_LastIncomingReceiveStreamID = receiveStreamID;
|
||||||
|
|
||||||
// handle saved packets if any
|
// handle saved packets if any
|
||||||
@ -1176,63 +1154,5 @@ namespace stream
|
|||||||
return msg;
|
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<std::mutex> 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<std::mutex> 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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,22 +53,6 @@ namespace stream
|
|||||||
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
|
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
|
||||||
const int MAX_RECEIVE_TIMEOUT = 30; // 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
|
struct Packet
|
||||||
{
|
{
|
||||||
size_t len, offset;
|
size_t len, offset;
|
||||||
@ -181,6 +165,9 @@ namespace stream
|
|||||||
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
||||||
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
|
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 Close ();
|
||||||
void Cancel () { m_ReceiveTimer.cancel (); };
|
void Cancel () { m_ReceiveTimer.cancel (); };
|
||||||
|
|
||||||
@ -273,9 +260,6 @@ namespace stream
|
|||||||
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
void HandleDataMessagePayload (const uint8_t * buf, size_t len);
|
||||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort);
|
std::shared_ptr<I2NPMessage> 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(); }
|
Packet * NewPacket () { return m_PacketsPool.Acquire(); }
|
||||||
void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); }
|
void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); }
|
||||||
|
|
||||||
@ -286,13 +270,6 @@ namespace stream
|
|||||||
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
||||||
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
|
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:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
||||||
@ -306,17 +283,7 @@ namespace stream
|
|||||||
boost::asio::deadline_timer m_PendingIncomingTimer;
|
boost::asio::deadline_timer m_PendingIncomingTimer;
|
||||||
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
|
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
|
||||||
|
|
||||||
std::mutex m_ConnsMutex;
|
|
||||||
/** how many connections per minute did each identity have */
|
|
||||||
std::map<i2p::data::IdentHash, uint32_t> m_Conns;
|
|
||||||
boost::asio::deadline_timer m_ConnTrackTimer;
|
|
||||||
uint32_t m_ConnsPerMinute;
|
|
||||||
/** banned identities */
|
|
||||||
std::vector<i2p::data::IdentHash> m_Banned;
|
|
||||||
uint64_t m_LastBanClear;
|
|
||||||
|
|
||||||
i2p::util::MemoryPool<Packet> m_PacketsPool;
|
i2p::util::MemoryPool<Packet> m_PacketsPool;
|
||||||
bool m_EnableDrop;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Crypto.h"
|
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
@ -103,7 +102,9 @@ namespace tunnel
|
|||||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
|
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
|
||||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
|
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
|
||||||
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
|
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
|
||||||
i2p::crypto::ElGamalEncrypt (ident->GetEncryptionPublicKey (), clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx);
|
auto encryptor = ident->CreateEncryptor (nullptr);
|
||||||
|
if (encryptor)
|
||||||
|
encryptor->Encrypt (clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx, false);
|
||||||
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
|
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 18
|
#define I2PD_VERSION_MINOR 19
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
#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_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 33
|
#define I2P_VERSION_MICRO 35
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|
||||||
|
@ -362,8 +362,6 @@ namespace client
|
|||||||
{
|
{
|
||||||
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
|
m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA
|
||||||
m_SharedLocalDestination->Acquire ();
|
m_SharedLocalDestination->Acquire ();
|
||||||
m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination;
|
|
||||||
m_SharedLocalDestination->Start ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const
|
||||||
@ -488,8 +486,8 @@ namespace client
|
|||||||
{
|
{
|
||||||
localDestination = m_SharedLocalDestination;
|
localDestination = m_SharedLocalDestination;
|
||||||
}
|
}
|
||||||
auto clientTunnel = new I2PUDPClientTunnel(name, dest, end, localDestination, destinationPort);
|
auto clientTunnel = std::make_shared<I2PUDPClientTunnel>(name, dest, end, localDestination, destinationPort);
|
||||||
if(m_ClientForwards.insert(std::make_pair(end, std::unique_ptr<I2PUDPClientTunnel>(clientTunnel))).second)
|
if(m_ClientForwards.insert(std::make_pair(end, clientTunnel)).second)
|
||||||
{
|
{
|
||||||
clientTunnel->Start();
|
clientTunnel->Start();
|
||||||
}
|
}
|
||||||
@ -498,31 +496,35 @@ namespace client
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
boost::asio::ip::tcp::endpoint clientEndpoint;
|
boost::asio::ip::tcp::endpoint clientEndpoint;
|
||||||
I2PService * clientTunnel = nullptr;
|
std::shared_ptr<I2PService> clientTunnel;
|
||||||
if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
|
if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
|
||||||
{
|
{
|
||||||
// socks proxy
|
// socks proxy
|
||||||
clientTunnel = new i2p::proxy::SOCKSProxy(name, address, port, false, "", destinationPort, localDestination);
|
auto tun = std::make_shared<i2p::proxy::SOCKSProxy>(name, address, port, false, "", destinationPort, localDestination);
|
||||||
clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint ();
|
clientTunnel = tun;
|
||||||
|
clientEndpoint = tun->GetLocalEndpoint ();
|
||||||
}
|
}
|
||||||
else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)
|
else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)
|
||||||
{
|
{
|
||||||
// http proxy
|
// http proxy
|
||||||
std::string outproxy = section.second.get("outproxy", "");
|
std::string outproxy = section.second.get("outproxy", "");
|
||||||
clientTunnel = new i2p::proxy::HTTPProxy(name, address, port, outproxy, localDestination);
|
auto tun = std::make_shared<i2p::proxy::HTTPProxy>(name, address, port, outproxy, localDestination);
|
||||||
clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint ();
|
clientTunnel = tun;
|
||||||
|
clientEndpoint = tun->GetLocalEndpoint ();
|
||||||
}
|
}
|
||||||
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
|
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
|
||||||
{
|
{
|
||||||
// websocks proxy
|
// websocks proxy
|
||||||
clientTunnel = new WebSocks(address, port, localDestination);;
|
auto tun = std::make_shared<WebSocks>(address, port, localDestination);
|
||||||
clientEndpoint = ((WebSocks*)clientTunnel)->GetLocalEndpoint();
|
clientTunnel = tun;
|
||||||
|
clientEndpoint = tun->GetLocalEndpoint();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// tcp client
|
// tcp client
|
||||||
clientTunnel = new I2PClientTunnel (name, dest, address, port, localDestination, destinationPort);
|
auto tun = std::make_shared<I2PClientTunnel> (name, dest, address, port, localDestination, destinationPort);
|
||||||
clientEndpoint = ((I2PClientTunnel*)clientTunnel)->GetLocalEndpoint ();
|
clientTunnel = tun;
|
||||||
|
clientEndpoint = tun->GetLocalEndpoint ();
|
||||||
}
|
}
|
||||||
uint32_t timeout = section.second.get<uint32_t>(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0);
|
uint32_t timeout = section.second.get<uint32_t>(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0);
|
||||||
if(timeout)
|
if(timeout)
|
||||||
@ -531,7 +533,7 @@ namespace client
|
|||||||
LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout);
|
LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, std::unique_ptr<I2PService>(clientTunnel)));
|
auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, clientTunnel));
|
||||||
if (ins.second)
|
if (ins.second)
|
||||||
{
|
{
|
||||||
clientTunnel->Start ();
|
clientTunnel->Start ();
|
||||||
@ -567,7 +569,7 @@ namespace client
|
|||||||
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
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::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);
|
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<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
||||||
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
||||||
|
|
||||||
@ -588,7 +590,7 @@ namespace client
|
|||||||
// TODO: hostnames
|
// TODO: hostnames
|
||||||
auto localAddress = boost::asio::ip::address::from_string(address);
|
auto localAddress = boost::asio::ip::address::from_string(address);
|
||||||
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
|
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<I2PUDPServerTunnel>(name, localDestination, localAddress, endpoint, port);
|
||||||
if(!isUniqueLocal)
|
if(!isUniqueLocal)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
||||||
@ -599,7 +601,7 @@ namespace client
|
|||||||
std::make_pair(
|
std::make_pair(
|
||||||
std::make_pair(
|
std::make_pair(
|
||||||
localDestination->GetIdentHash(), port),
|
localDestination->GetIdentHash(), port),
|
||||||
std::unique_ptr<I2PUDPServerTunnel>(serverTunnel))).second)
|
serverTunnel)).second)
|
||||||
{
|
{
|
||||||
serverTunnel->Start();
|
serverTunnel->Start();
|
||||||
LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32());
|
LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32());
|
||||||
@ -610,16 +612,14 @@ namespace client
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PServerTunnel * serverTunnel;
|
std::shared_ptr<I2PServerTunnel> serverTunnel;
|
||||||
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
|
||||||
serverTunnel = new I2PServerTunnelHTTP (name, host, port, localDestination, hostOverride, inPort, gzip);
|
serverTunnel = std::make_shared<I2PServerTunnelHTTP> (name, host, port, localDestination, hostOverride, inPort, gzip);
|
||||||
else if (type == I2P_TUNNELS_SECTION_TYPE_IRC)
|
else if (type == I2P_TUNNELS_SECTION_TYPE_IRC)
|
||||||
serverTunnel = new I2PServerTunnelIRC (name, host, port, localDestination, webircpass, inPort, gzip);
|
serverTunnel = std::make_shared<I2PServerTunnelIRC> (name, host, port, localDestination, webircpass, inPort, gzip);
|
||||||
else // regular server tunnel by default
|
else // regular server tunnel by default
|
||||||
serverTunnel = new I2PServerTunnel (name, host, port, localDestination, inPort, gzip);
|
serverTunnel = std::make_shared<I2PServerTunnel> (name, host, port, localDestination, inPort, gzip);
|
||||||
|
|
||||||
LogPrint(eLogInfo, "Clients: Set Max Conns To ", maxConns);
|
|
||||||
serverTunnel->SetMaxConnsPerMinute(maxConns);
|
|
||||||
if(!isUniqueLocal)
|
if(!isUniqueLocal)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
LogPrint(eLogInfo, "Clients: disabling loopback address mapping");
|
||||||
@ -643,7 +643,7 @@ namespace client
|
|||||||
}
|
}
|
||||||
auto ins = m_ServerTunnels.insert (std::make_pair (
|
auto ins = m_ServerTunnels.insert (std::make_pair (
|
||||||
std::make_pair (localDestination->GetIdentHash (), inPort),
|
std::make_pair (localDestination->GetIdentHash (), inPort),
|
||||||
std::unique_ptr<I2PServerTunnel>(serverTunnel)));
|
serverTunnel));
|
||||||
if (ins.second)
|
if (ins.second)
|
||||||
{
|
{
|
||||||
serverTunnel->Start ();
|
serverTunnel->Start ();
|
||||||
|
@ -113,12 +113,12 @@ namespace client
|
|||||||
|
|
||||||
i2p::proxy::HTTPProxy * m_HttpProxy;
|
i2p::proxy::HTTPProxy * m_HttpProxy;
|
||||||
i2p::proxy::SOCKSProxy * m_SocksProxy;
|
i2p::proxy::SOCKSProxy * m_SocksProxy;
|
||||||
std::map<boost::asio::ip::tcp::endpoint, std::unique_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
|
std::map<boost::asio::ip::tcp::endpoint, std::shared_ptr<I2PService> > m_ClientTunnels; // local endpoint->tunnel
|
||||||
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
|
std::map<std::pair<i2p::data::IdentHash, int>, std::shared_ptr<I2PServerTunnel> > m_ServerTunnels; // <destination,port>->tunnel
|
||||||
|
|
||||||
std::mutex m_ForwardsMutex;
|
std::mutex m_ForwardsMutex;
|
||||||
std::map<boost::asio::ip::udp::endpoint, std::unique_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
|
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<I2PUDPClientTunnel> > m_ClientForwards; // local endpoint -> udp tunnel
|
||||||
std::map<std::pair<i2p::data::IdentHash, int>, std::unique_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
|
std::map<std::pair<i2p::data::IdentHash, int>, std::shared_ptr<I2PUDPServerTunnel> > m_ServerForwards; // <destination,port> -> udp tunnel
|
||||||
|
|
||||||
SAMBridge * m_SamBridge;
|
SAMBridge * m_SamBridge;
|
||||||
BOBCommandChannel * m_BOBCommandChannel;
|
BOBCommandChannel * m_BOBCommandChannel;
|
||||||
|
@ -219,7 +219,7 @@ namespace proxy {
|
|||||||
/* replace headers */
|
/* replace headers */
|
||||||
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
|
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
|
||||||
/* add headers */
|
/* add headers */
|
||||||
req.AddHeader("Connection", "close"); /* keep-alive conns not supported yet */
|
req.UpdateHeader("Connection", "close"); /* keep-alive conns not supported yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -387,18 +387,31 @@ namespace proxy {
|
|||||||
LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host);
|
LogPrint(eLogDebug, "HTTPProxy: ", m_ClientRequestURL.host);
|
||||||
m_ClientRequestURL.schema = "";
|
m_ClientRequestURL.schema = "";
|
||||||
m_ClientRequestURL.host = "";
|
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.uri = m_ClientRequestURL.to_string();
|
||||||
|
|
||||||
m_ClientRequest.write(m_ClientRequestBuffer);
|
m_ClientRequest.write(m_ClientRequestBuffer);
|
||||||
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
|
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
|
||||||
|
|
||||||
// assume http if empty schema
|
// assume http if empty schema
|
||||||
if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http") {
|
if (m_ProxyURL.schema == "" || m_ProxyURL.schema == "http")
|
||||||
|
{
|
||||||
// handle upstream http proxy
|
// handle upstream http proxy
|
||||||
if (!m_ProxyURL.port) m_ProxyURL.port = 80;
|
if (!m_ProxyURL.port) m_ProxyURL.port = 80;
|
||||||
if (m_ProxyURL.is_i2p())
|
if (m_ProxyURL.is_i2p())
|
||||||
{
|
{
|
||||||
m_send_buf = m_recv_buf;
|
m_ClientRequest.uri = origURI;
|
||||||
|
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,
|
GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete,
|
||||||
shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port);
|
shared_from_this(), std::placeholders::_1), m_ProxyURL.host, m_ProxyURL.port);
|
||||||
}
|
}
|
||||||
@ -409,14 +422,18 @@ namespace proxy {
|
|||||||
m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1));
|
m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamHTTPProxyConnect, this, std::placeholders::_1));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else if (m_ProxyURL.schema == "socks") {
|
}
|
||||||
|
else if (m_ProxyURL.schema == "socks")
|
||||||
|
{
|
||||||
// handle upstream socks proxy
|
// handle upstream socks proxy
|
||||||
if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified
|
if (!m_ProxyURL.port) m_ProxyURL.port = 9050; // default to tor default if not specified
|
||||||
boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port));
|
boost::asio::ip::tcp::resolver::query q(m_ProxyURL.host, std::to_string(m_ProxyURL.port));
|
||||||
m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) {
|
m_proxy_resolver.async_resolve(q, std::bind(&HTTPReqHandler::HandleUpstreamProxyResolved, this, std::placeholders::_1, std::placeholders::_2, [&](boost::asio::ip::tcp::endpoint ep) {
|
||||||
m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamSocksProxyConnect, this, std::placeholders::_1));
|
m_proxysock->async_connect(ep, std::bind(&HTTPReqHandler::HandleUpstreamSocksProxyConnect, this, std::placeholders::_1));
|
||||||
}));
|
}));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// unknown type, complain
|
// unknown type, complain
|
||||||
GenericProxyError("unknown outproxy url", m_ProxyURL.to_string().c_str());
|
GenericProxyError("unknown outproxy url", m_ProxyURL.to_string().c_str());
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ namespace client
|
|||||||
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||||
{
|
{
|
||||||
if (m_Decryptor)
|
if (m_Decryptor)
|
||||||
return m_Decryptor->Decrypt (encrypted, data, ctx);
|
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2CP: decryptor is not set");
|
LogPrint (eLogError, "I2CP: decryptor is not set");
|
||||||
return false;
|
return false;
|
||||||
|
@ -14,6 +14,7 @@ namespace client
|
|||||||
m_LocalDestination (localDestination ? localDestination :
|
m_LocalDestination (localDestination ? localDestination :
|
||||||
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)),
|
i2p::client::context.CreateNewLocalDestination (false, I2P_SERVICE_DEFAULT_KEY_TYPE)),
|
||||||
m_ReadyTimer(m_LocalDestination->GetService()),
|
m_ReadyTimer(m_LocalDestination->GetService()),
|
||||||
|
m_ReadyTimerTriggered(false),
|
||||||
m_ConnectTimeout(0),
|
m_ConnectTimeout(0),
|
||||||
isUpdated (true)
|
isUpdated (true)
|
||||||
{
|
{
|
||||||
@ -47,29 +48,25 @@ namespace client
|
|||||||
|
|
||||||
void I2PService::SetConnectTimeout(uint32_t timeout)
|
void I2PService::SetConnectTimeout(uint32_t timeout)
|
||||||
{
|
{
|
||||||
if(timeout && !m_ConnectTimeout)
|
|
||||||
{
|
|
||||||
TriggerReadyCheckTimer();
|
|
||||||
}
|
|
||||||
else if (m_ConnectTimeout && !timeout)
|
|
||||||
{
|
|
||||||
m_ReadyTimer.cancel();
|
|
||||||
}
|
|
||||||
m_ConnectTimeout = timeout;
|
m_ConnectTimeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PService::AddReadyCallback(ReadyCallback cb)
|
void I2PService::AddReadyCallback(ReadyCallback cb)
|
||||||
{
|
{
|
||||||
uint32_t now = i2p::util::GetSecondsSinceEpoch();
|
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);
|
LogPrint(eLogDebug, "I2PService::AddReadyCallback() ", tm, " ", now);
|
||||||
m_ReadyCallbacks.push_back({cb, tm});
|
m_ReadyCallbacks.push_back({cb, tm});
|
||||||
|
if (!m_ReadyTimerTriggered) TriggerReadyCheckTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PService::TriggerReadyCheckTimer()
|
void I2PService::TriggerReadyCheckTimer()
|
||||||
{
|
{
|
||||||
m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1));
|
m_ReadyTimer.expires_from_now(boost::posix_time::seconds (1));
|
||||||
m_ReadyTimer.async_wait(std::bind(&I2PService::HandleReadyCheckTimer, this, std::placeholders::_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)
|
void I2PService::HandleReadyCheckTimer(const boost::system::error_code &ec)
|
||||||
@ -87,7 +84,7 @@ namespace client
|
|||||||
auto itr = m_ReadyCallbacks.begin();
|
auto itr = m_ReadyCallbacks.begin();
|
||||||
while(itr != m_ReadyCallbacks.end())
|
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->first(boost::asio::error::timed_out);
|
||||||
itr = m_ReadyCallbacks.erase(itr);
|
itr = m_ReadyCallbacks.erase(itr);
|
||||||
@ -96,8 +93,10 @@ namespace client
|
|||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!ec)
|
if(!ec && m_ReadyCallbacks.size())
|
||||||
TriggerReadyCheckTimer();
|
TriggerReadyCheckTimer();
|
||||||
|
else
|
||||||
|
m_ReadyTimerTriggered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
void I2PService::CreateStream (StreamRequestComplete streamRequestComplete, const std::string& dest, int port) {
|
||||||
|
@ -67,8 +67,11 @@ namespace client
|
|||||||
std::mutex m_HandlersMutex;
|
std::mutex m_HandlersMutex;
|
||||||
std::vector<std::pair<ReadyCallback, uint32_t> > m_ReadyCallbacks;
|
std::vector<std::pair<ReadyCallback, uint32_t> > m_ReadyCallbacks;
|
||||||
boost::asio::deadline_timer m_ReadyTimer;
|
boost::asio::deadline_timer m_ReadyTimer;
|
||||||
|
bool m_ReadyTimerTriggered;
|
||||||
uint32_t m_ConnectTimeout;
|
uint32_t m_ConnectTimeout;
|
||||||
|
|
||||||
|
const size_t NEVER_TIMES_OUT = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool isUpdated; // transient, used during reload only
|
bool isUpdated; // transient, used during reload only
|
||||||
};
|
};
|
||||||
|
@ -280,8 +280,6 @@ namespace client
|
|||||||
|
|
||||||
const char* GetName() { return m_Name.c_str (); }
|
const char* GetName() { return m_Name.c_str (); }
|
||||||
|
|
||||||
void SetMaxConnsPerMinute(const uint32_t conns) { m_PortDestination->SetMaxConnsPerMinute(conns); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
void HandleResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
|
||||||
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
|
||||||
|
@ -15,8 +15,8 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
SAMSocket::SAMSocket (SAMBridge& owner, std::shared_ptr<Socket_t> socket):
|
SAMSocket::SAMSocket (SAMBridge& owner):
|
||||||
m_Owner (owner), m_Socket(socket), m_Timer (m_Owner.GetService ()),
|
m_Owner (owner), m_Socket(owner.GetService()), m_Timer (m_Owner.GetService ()),
|
||||||
m_BufferOffset (0),
|
m_BufferOffset (0),
|
||||||
m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false),
|
m_SocketType (eSAMSocketTypeUnknown), m_IsSilent (false),
|
||||||
m_IsAccepting (false), m_Stream (nullptr)
|
m_IsAccepting (false), m_Stream (nullptr)
|
||||||
@ -25,51 +25,17 @@ namespace client
|
|||||||
|
|
||||||
SAMSocket::~SAMSocket ()
|
SAMSocket::~SAMSocket ()
|
||||||
{
|
{
|
||||||
if(m_Stream)
|
m_Stream = nullptr;
|
||||||
{
|
|
||||||
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 ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::Terminate (const char* reason)
|
void SAMSocket::Terminate (const char* reason)
|
||||||
{
|
{
|
||||||
if(m_Stream)
|
if(m_Stream)
|
||||||
{
|
{
|
||||||
m_Stream->Close ();
|
m_Stream->AsyncClose ();
|
||||||
m_Stream.reset ();
|
m_Stream = nullptr;
|
||||||
}
|
}
|
||||||
auto Session = m_Owner.FindSession(m_ID);
|
auto Session = m_Owner.FindSession(m_ID);
|
||||||
|
|
||||||
switch (m_SocketType)
|
switch (m_SocketType)
|
||||||
{
|
{
|
||||||
case eSAMSocketTypeSession:
|
case eSAMSocketTypeSession:
|
||||||
@ -77,15 +43,12 @@ namespace client
|
|||||||
break;
|
break;
|
||||||
case eSAMSocketTypeStream:
|
case eSAMSocketTypeStream:
|
||||||
{
|
{
|
||||||
if (Session)
|
|
||||||
Session->DelSocket (this);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eSAMSocketTypeAcceptor:
|
case eSAMSocketTypeAcceptor:
|
||||||
{
|
{
|
||||||
if (Session)
|
if (Session)
|
||||||
{
|
{
|
||||||
Session->DelSocket (this);
|
|
||||||
if (m_IsAccepting && Session->localDestination)
|
if (m_IsAccepting && Session->localDestination)
|
||||||
Session->localDestination->StopAcceptingStreams ();
|
Session->localDestination->StopAcceptingStreams ();
|
||||||
}
|
}
|
||||||
@ -95,14 +58,18 @@ namespace client
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
m_SocketType = eSAMSocketTypeTerminated;
|
m_SocketType = eSAMSocketTypeTerminated;
|
||||||
if (m_Socket && m_Socket->is_open()) m_Socket->close ();
|
if (m_Socket.is_open ())
|
||||||
m_Socket.reset ();
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
m_Socket.shutdown (boost::asio::ip::tcp::socket::shutdown_both, ec);
|
||||||
|
m_Socket.close ();
|
||||||
|
}
|
||||||
|
m_Owner.RemoveSocket(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::ReceiveHandshake ()
|
void SAMSocket::ReceiveHandshake ()
|
||||||
{
|
{
|
||||||
if(m_Socket)
|
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::HandleHandshakeReceived, shared_from_this (),
|
std::bind(&SAMSocket::HandleHandshakeReceived, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
@ -184,7 +151,7 @@ namespace client
|
|||||||
#else
|
#else
|
||||||
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
|
size_t l = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_HANDSHAKE_REPLY, version.c_str ());
|
||||||
#endif
|
#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::bind(&SAMSocket::HandleHandshakeReplySent, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
@ -199,6 +166,11 @@ 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)
|
void SAMSocket::HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
{
|
{
|
||||||
if (ecode)
|
if (ecode)
|
||||||
@ -207,9 +179,9 @@ namespace client
|
|||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
Terminate ("SAM: handshake reply send error");
|
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::bind(&SAMSocket::HandleMessage, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2));
|
std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
@ -220,7 +192,7 @@ namespace client
|
|||||||
LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg);
|
LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg);
|
||||||
|
|
||||||
if (!m_IsSilent)
|
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::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2, close));
|
std::placeholders::_1, std::placeholders::_2, close));
|
||||||
else
|
else
|
||||||
@ -501,7 +473,6 @@ namespace client
|
|||||||
if(session)
|
if(session)
|
||||||
{
|
{
|
||||||
m_SocketType = eSAMSocketTypeStream;
|
m_SocketType = eSAMSocketTypeStream;
|
||||||
session->AddSocket (shared_from_this ());
|
|
||||||
m_Stream = session->localDestination->CreateStream (remote);
|
m_Stream = session->localDestination->CreateStream (remote);
|
||||||
m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
|
m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
|
||||||
m_BufferOffset = 0;
|
m_BufferOffset = 0;
|
||||||
@ -534,7 +505,6 @@ namespace client
|
|||||||
if (session)
|
if (session)
|
||||||
{
|
{
|
||||||
m_SocketType = eSAMSocketTypeAcceptor;
|
m_SocketType = eSAMSocketTypeAcceptor;
|
||||||
session->AddSocket (shared_from_this ());
|
|
||||||
if (!session->localDestination->IsAcceptingStreams ())
|
if (!session->localDestination->IsAcceptingStreams ())
|
||||||
{
|
{
|
||||||
m_IsAccepting = true;
|
m_IsAccepting = true;
|
||||||
@ -704,17 +674,9 @@ namespace client
|
|||||||
|
|
||||||
void SAMSocket::Receive ()
|
void SAMSocket::Receive ()
|
||||||
{
|
{
|
||||||
if (m_BufferOffset >= SAM_SOCKET_BUFFER_SIZE)
|
m_Socket.async_read_some (boost::asio::buffer(m_Buffer + m_BufferOffset, SAM_SOCKET_BUFFER_SIZE - m_BufferOffset),
|
||||||
{
|
|
||||||
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,
|
std::bind((m_SocketType == eSAMSocketTypeStream) ? &SAMSocket::HandleReceived : &SAMSocket::HandleMessage,
|
||||||
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
else
|
|
||||||
LogPrint(eLogError, "SAM: receive with no native socket");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
void SAMSocket::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
@ -731,15 +693,12 @@ namespace client
|
|||||||
{
|
{
|
||||||
bytes_transferred += m_BufferOffset;
|
bytes_transferred += m_BufferOffset;
|
||||||
m_BufferOffset = 0;
|
m_BufferOffset = 0;
|
||||||
auto s = shared_from_this ();
|
|
||||||
m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred,
|
m_Stream->AsyncSend ((uint8_t *)m_Buffer, bytes_transferred,
|
||||||
[s](const boost::system::error_code& ecode)
|
std::bind(&SAMSocket::HandleStreamSend, shared_from_this(), std::placeholders::_1));
|
||||||
{
|
}
|
||||||
if (!ecode)
|
|
||||||
s->m_Owner.GetService ().post ([s] { s->Receive (); });
|
|
||||||
else
|
else
|
||||||
s->m_Owner.GetService ().post ([s] { s->Terminate ("AsyncSend failed"); });
|
{
|
||||||
});
|
Terminate("No Stream Remaining");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -766,21 +725,21 @@ namespace client
|
|||||||
WriteI2PDataImmediate(buff, len);
|
WriteI2PDataImmediate(buff, len);
|
||||||
}
|
}
|
||||||
else // no more data
|
else // no more data
|
||||||
|
{
|
||||||
|
delete [] buff;
|
||||||
Terminate ("no more data");
|
Terminate ("no more data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SAMSocket::WriteI2PDataImmediate(uint8_t * buff, size_t sz)
|
void SAMSocket::WriteI2PDataImmediate(uint8_t * buff, size_t sz)
|
||||||
{
|
{
|
||||||
if(m_Socket)
|
|
||||||
boost::asio::async_write (
|
boost::asio::async_write (
|
||||||
*m_Socket,
|
m_Socket,
|
||||||
boost::asio::buffer (buff, sz),
|
boost::asio::buffer (buff, sz),
|
||||||
boost::asio::transfer_all(),
|
boost::asio::transfer_all(),
|
||||||
std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination
|
std::bind (&SAMSocket::HandleWriteI2PDataImmediate, shared_from_this (), std::placeholders::_1, buff)); // postpone termination
|
||||||
else
|
|
||||||
LogPrint(eLogError, "SAM: no native socket");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff)
|
void SAMSocket::HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff)
|
||||||
@ -790,9 +749,11 @@ namespace client
|
|||||||
|
|
||||||
void SAMSocket::WriteI2PData(size_t sz)
|
void SAMSocket::WriteI2PData(size_t sz)
|
||||||
{
|
{
|
||||||
uint8_t * sendbuff = new uint8_t[sz];
|
boost::asio::async_write (
|
||||||
memcpy(sendbuff, m_StreamBuffer, sz);
|
m_Socket,
|
||||||
WriteI2PDataImmediate(sendbuff, sz);
|
boost::asio::buffer (m_StreamBuffer, sz),
|
||||||
|
boost::asio::transfer_all(),
|
||||||
|
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)
|
void SAMSocket::HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
@ -826,6 +787,7 @@ namespace client
|
|||||||
{
|
{
|
||||||
WriteI2PData(bytes_transferred);
|
WriteI2PData(bytes_transferred);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
I2PReceive();
|
I2PReceive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,7 +820,7 @@ namespace client
|
|||||||
if (session)
|
if (session)
|
||||||
{
|
{
|
||||||
// find more pending acceptors
|
// find more pending acceptors
|
||||||
for (auto it: session->ListSockets ())
|
for (auto & it: m_Owner.ListSockets (m_ID))
|
||||||
if (it->m_SocketType == eSAMSocketTypeAcceptor)
|
if (it->m_SocketType == eSAMSocketTypeAcceptor)
|
||||||
{
|
{
|
||||||
it->m_IsAccepting = true;
|
it->m_IsAccepting = true;
|
||||||
@ -930,30 +892,31 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMSession::SAMSession (std::shared_ptr<ClientDestination> 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<ClientDestination> dest):
|
||||||
|
m_Bridge(parent),
|
||||||
localDestination (dest),
|
localDestination (dest),
|
||||||
UDPEndpoint(nullptr)
|
UDPEndpoint(nullptr),
|
||||||
|
Name(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMSession::~SAMSession ()
|
SAMSession::~SAMSession ()
|
||||||
{
|
{
|
||||||
CloseStreams();
|
|
||||||
i2p::client::context.DeleteLocalDestination (localDestination);
|
i2p::client::context.DeleteLocalDestination (localDestination);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSession::CloseStreams ()
|
void SAMSession::CloseStreams ()
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<SAMSocket> > socks;
|
for(const auto & itr : m_Bridge.ListSockets(Name))
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
itr->Terminate(nullptr);
|
||||||
for (const auto& sock : m_Sockets) {
|
|
||||||
socks.push_back(sock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto & sock : socks ) sock->Terminate("SAMSession::CloseStreams()");
|
|
||||||
m_Sockets.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
SAMBridge::SAMBridge (const std::string& address, int port):
|
SAMBridge::SAMBridge (const std::string& address, int port):
|
||||||
m_IsRunning (false), m_Thread (nullptr),
|
m_IsRunning (false), m_Thread (nullptr),
|
||||||
@ -1009,12 +972,17 @@ namespace client
|
|||||||
|
|
||||||
void SAMBridge::Accept ()
|
void SAMBridge::Accept ()
|
||||||
{
|
{
|
||||||
auto native = std::make_shared<boost::asio::ip::tcp::socket>(m_Service);
|
auto newSocket = std::make_shared<SAMSocket>(*this);
|
||||||
auto newSocket = std::make_shared<SAMSocket> (*this, native);
|
m_Acceptor.async_accept (newSocket->GetSocket(), std::bind (&SAMBridge::HandleAccept, this,
|
||||||
m_Acceptor.async_accept (*native, std::bind (&SAMBridge::HandleAccept, this,
|
|
||||||
std::placeholders::_1, newSocket));
|
std::placeholders::_1, newSocket));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SAMBridge::RemoveSocket(const std::shared_ptr<SAMSocket> & socket)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
|
||||||
|
m_OpenSockets.remove_if([socket](const std::shared_ptr<SAMSocket> & item) -> bool { return item == socket; });
|
||||||
|
}
|
||||||
|
|
||||||
void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
|
void SAMBridge::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<SAMSocket> socket)
|
||||||
{
|
{
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
@ -1024,6 +992,10 @@ namespace client
|
|||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: new connection from ", ep);
|
LogPrint (eLogDebug, "SAM: new connection from ", ep);
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_OpenSocketsMutex);
|
||||||
|
m_OpenSockets.push_back(socket);
|
||||||
|
}
|
||||||
socket->ReceiveHandshake ();
|
socket->ReceiveHandshake ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1066,7 +1038,7 @@ namespace client
|
|||||||
if (localDestination)
|
if (localDestination)
|
||||||
{
|
{
|
||||||
localDestination->Acquire ();
|
localDestination->Acquire ();
|
||||||
auto session = std::make_shared<SAMSession>(localDestination);
|
auto session = std::make_shared<SAMSession>(*this, id, localDestination);
|
||||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||||
auto ret = m_Sessions.insert (std::make_pair(id, session));
|
auto ret = m_Sessions.insert (std::make_pair(id, session));
|
||||||
if (!ret.second)
|
if (!ret.second)
|
||||||
@ -1105,6 +1077,18 @@ namespace client
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<SAMSocket> > SAMBridge::ListSockets(const std::string & id) const
|
||||||
|
{
|
||||||
|
std::list<std::shared_ptr<SAMSocket > > list;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_OpenSocketsMutex);
|
||||||
|
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<boost::asio::ip::udp::endpoint> remote)
|
void SAMBridge::SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote)
|
||||||
{
|
{
|
||||||
if(remote)
|
if(remote)
|
||||||
@ -1127,6 +1111,8 @@ namespace client
|
|||||||
{
|
{
|
||||||
m_DatagramReceiveBuffer[bytes_transferred] = 0;
|
m_DatagramReceiveBuffer[bytes_transferred] = 0;
|
||||||
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
|
char * eol = strchr ((char *)m_DatagramReceiveBuffer, '\n');
|
||||||
|
if(eol)
|
||||||
|
{
|
||||||
*eol = 0; eol++;
|
*eol = 0; eol++;
|
||||||
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
|
size_t payloadLen = bytes_transferred - ((uint8_t *)eol - m_DatagramReceiveBuffer);
|
||||||
LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
|
LogPrint (eLogDebug, "SAM: datagram received ", m_DatagramReceiveBuffer," size=", payloadLen);
|
||||||
@ -1154,6 +1140,9 @@ namespace client
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "SAM: Missing sessionID");
|
LogPrint (eLogError, "SAM: Missing sessionID");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogError, "SAM: invalid datagram");
|
||||||
ReceiveDatagram ();
|
ReceiveDatagram ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -82,17 +82,20 @@ namespace client
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
typedef boost::asio::ip::tcp::socket Socket_t;
|
typedef boost::asio::ip::tcp::socket Socket_t;
|
||||||
SAMSocket (SAMBridge& owner, std::shared_ptr<Socket_t> socket);
|
SAMSocket (SAMBridge& owner);
|
||||||
~SAMSocket ();
|
~SAMSocket ();
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& GetSocket () { return *m_Socket; };
|
Socket_t& GetSocket () { return m_Socket; };
|
||||||
void ReceiveHandshake ();
|
void ReceiveHandshake ();
|
||||||
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
|
void SetSocketType (SAMSocketType socketType) { m_SocketType = socketType; };
|
||||||
SAMSocketType GetSocketType () const { return m_SocketType; };
|
SAMSocketType GetSocketType () const { return m_SocketType; };
|
||||||
|
|
||||||
void Terminate (const char* reason);
|
void Terminate (const char* reason);
|
||||||
|
|
||||||
|
bool IsSession(const std::string & id) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void TerminateClose() { Terminate(nullptr); }
|
||||||
|
|
||||||
void HandleHandshakeReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
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 HandleHandshakeReplySent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
@ -128,10 +131,12 @@ namespace client
|
|||||||
void WriteI2PDataImmediate(uint8_t * ptr, size_t sz);
|
void WriteI2PDataImmediate(uint8_t * ptr, size_t sz);
|
||||||
|
|
||||||
void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff);
|
void HandleWriteI2PDataImmediate(const boost::system::error_code & ec, uint8_t * buff);
|
||||||
|
void HandleStreamSend(const boost::system::error_code & ec);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SAMBridge& m_Owner;
|
SAMBridge& m_Owner;
|
||||||
std::shared_ptr<Socket_t> m_Socket;
|
Socket_t m_Socket;
|
||||||
boost::asio::deadline_timer m_Timer;
|
boost::asio::deadline_timer m_Timer;
|
||||||
char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1];
|
char m_Buffer[SAM_SOCKET_BUFFER_SIZE + 1];
|
||||||
size_t m_BufferOffset;
|
size_t m_BufferOffset;
|
||||||
@ -145,34 +150,12 @@ namespace client
|
|||||||
|
|
||||||
struct SAMSession
|
struct SAMSession
|
||||||
{
|
{
|
||||||
|
SAMBridge & m_Bridge;
|
||||||
std::shared_ptr<ClientDestination> localDestination;
|
std::shared_ptr<ClientDestination> localDestination;
|
||||||
std::list<std::shared_ptr<SAMSocket> > m_Sockets;
|
|
||||||
std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint;
|
std::shared_ptr<boost::asio::ip::udp::endpoint> UDPEndpoint;
|
||||||
std::mutex m_SocketsMutex;
|
std::string Name;
|
||||||
|
|
||||||
/** safely add a socket to this session */
|
SAMSession (SAMBridge & parent, const std::string & name, std::shared_ptr<ClientDestination> dest);
|
||||||
void AddSocket(std::shared_ptr<SAMSocket> sock) {
|
|
||||||
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
|
||||||
m_Sockets.push_back(sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** safely remove a socket from this session */
|
|
||||||
void DelSocket(SAMSocket * sock) {
|
|
||||||
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
|
||||||
m_Sockets.remove_if([sock](const std::shared_ptr<SAMSocket> s) -> bool { return s.get() == sock; });
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get a list holding a copy of all sam sockets from this session */
|
|
||||||
std::list<std::shared_ptr<SAMSocket> > ListSockets() {
|
|
||||||
std::list<std::shared_ptr<SAMSocket> > l;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(m_SocketsMutex);
|
|
||||||
for(const auto& sock : m_Sockets ) l.push_back(sock);
|
|
||||||
}
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
SAMSession (std::shared_ptr<ClientDestination> dest);
|
|
||||||
~SAMSession ();
|
~SAMSession ();
|
||||||
|
|
||||||
void CloseStreams ();
|
void CloseStreams ();
|
||||||
@ -194,9 +177,13 @@ namespace client
|
|||||||
void CloseSession (const std::string& id);
|
void CloseSession (const std::string& id);
|
||||||
std::shared_ptr<SAMSession> FindSession (const std::string& id) const;
|
std::shared_ptr<SAMSession> FindSession (const std::string& id) const;
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<SAMSocket> > ListSockets(const std::string & id) const;
|
||||||
|
|
||||||
/** send raw data to remote endpoint from our UDP Socket */
|
/** send raw data to remote endpoint from our UDP Socket */
|
||||||
void SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote);
|
void SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote);
|
||||||
|
|
||||||
|
void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
@ -217,6 +204,8 @@ namespace client
|
|||||||
boost::asio::ip::udp::socket m_DatagramSocket;
|
boost::asio::ip::udp::socket m_DatagramSocket;
|
||||||
mutable std::mutex m_SessionsMutex;
|
mutable std::mutex m_SessionsMutex;
|
||||||
std::map<std::string, std::shared_ptr<SAMSession> > m_Sessions;
|
std::map<std::string, std::shared_ptr<SAMSession> > m_Sessions;
|
||||||
|
mutable std::mutex m_OpenSocketsMutex;
|
||||||
|
std::list<std::shared_ptr<SAMSocket> > m_OpenSockets;
|
||||||
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
|
uint8_t m_DatagramReceiveBuffer[i2p::datagram::MAX_DATAGRAM_SIZE+1];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "DaemonQT.h"
|
#include "DaemonQT.h"
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
@ -90,12 +95,12 @@ namespace qt
|
|||||||
delete mutex;
|
delete mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DaemonQTImpl::init(int argc, char* argv[])
|
bool DaemonQTImpl::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
|
||||||
{
|
{
|
||||||
mutex=new QMutex(QMutex::Recursive);
|
mutex=new QMutex(QMutex::Recursive);
|
||||||
setRunningCallback(0);
|
setRunningCallback(0);
|
||||||
m_IsRunning=false;
|
m_IsRunning=false;
|
||||||
return Daemon.init(argc,argv);
|
return Daemon.init(argc,argv,logstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DaemonQTImpl::start()
|
void DaemonQTImpl::start()
|
||||||
@ -146,33 +151,35 @@ namespace qt
|
|||||||
int result;
|
int result;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
std::shared_ptr<std::iostream> logstreamptr=std::make_shared<std::stringstream>();
|
||||||
|
//TODO move daemon init deinit to a bg thread
|
||||||
DaemonQTImpl daemon;
|
DaemonQTImpl daemon;
|
||||||
qDebug("Initialising the daemon...");
|
(*logstreamptr) << "Initialising the daemon..." << std::endl;
|
||||||
bool daemonInitSuccess = daemon.init(argc, argv);
|
bool daemonInitSuccess = daemon.init(argc, argv, logstreamptr);
|
||||||
if(!daemonInitSuccess)
|
if(!daemonInitSuccess)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(0, "Error", "Daemon init failed");
|
QMessageBox::critical(0, "Error", "Daemon init failed");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
qDebug("Initialised, creating the main window...");
|
LogPrint(eLogDebug, "Initialised, creating the main window...");
|
||||||
MainWindow w;
|
MainWindow w(logstreamptr);
|
||||||
qDebug("Before main window.show()...");
|
LogPrint(eLogDebug, "Before main window.show()...");
|
||||||
w.show ();
|
w.show ();
|
||||||
|
|
||||||
{
|
{
|
||||||
i2p::qt::Controller daemonQtController(daemon);
|
i2p::qt::Controller daemonQtController(daemon);
|
||||||
w.setI2PController(&daemonQtController);
|
w.setI2PController(&daemonQtController);
|
||||||
qDebug("Starting the daemon...");
|
LogPrint(eLogDebug, "Starting the daemon...");
|
||||||
emit daemonQtController.startDaemon();
|
emit daemonQtController.startDaemon();
|
||||||
//daemon.start ();
|
//daemon.start ();
|
||||||
qDebug("Starting GUI event loop...");
|
LogPrint(eLogDebug, "Starting GUI event loop...");
|
||||||
result = app.exec();
|
result = app.exec();
|
||||||
//daemon.stop ();
|
//daemon.stop ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//QMessageBox::information(&w, "Debug", "demon stopped");
|
//QMessageBox::information(&w, "Debug", "demon stopped");
|
||||||
qDebug("Exiting the application");
|
LogPrint(eLogDebug, "Exiting the application");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef DAEMONQT_H
|
#ifndef DAEMONQT_H
|
||||||
#define DAEMONQT_H
|
#define DAEMONQT_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
@ -25,7 +26,7 @@ namespace qt
|
|||||||
* @param argv
|
* @param argv
|
||||||
* @return success
|
* @return success
|
||||||
*/
|
*/
|
||||||
bool init(int argc, char* argv[]);
|
bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
void restart();
|
void restart();
|
||||||
|
@ -204,24 +204,6 @@ int ServerTunnelPane::appendServerTunnelForm(
|
|||||||
horizontalLayout_2->addItem(horizontalSpacer);
|
horizontalLayout_2->addItem(horizontalSpacer);
|
||||||
tunnelGridLayout->addLayout(horizontalLayout_2);
|
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();
|
std::string address = tunnelConfig->getaddress();
|
||||||
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
QHBoxLayout *horizontalLayout_2 = new QHBoxLayout();
|
||||||
|
@ -81,10 +81,6 @@ private:
|
|||||||
QLabel * addressLabel;
|
QLabel * addressLabel;
|
||||||
QLineEdit * addressLineEdit;
|
QLineEdit * addressLineEdit;
|
||||||
|
|
||||||
//maxConns
|
|
||||||
QLabel * maxConnsLabel;
|
|
||||||
QLineEdit * maxConnsLineEdit;
|
|
||||||
|
|
||||||
//gzip
|
//gzip
|
||||||
QCheckBox * gzipCheckBox;
|
QCheckBox * gzipCheckBox;
|
||||||
|
|
||||||
@ -109,7 +105,6 @@ private:
|
|||||||
hostOverrideLabel->setText(QApplication::translate("srvTunForm", "Host override:", 0));
|
hostOverrideLabel->setText(QApplication::translate("srvTunForm", "Host override:", 0));
|
||||||
webIRCPassLabel->setText(QApplication::translate("srvTunForm", "WebIRC password:", 0));
|
webIRCPassLabel->setText(QApplication::translate("srvTunForm", "WebIRC password:", 0));
|
||||||
addressLabel->setText(QApplication::translate("srvTunForm", "Address:", 0));
|
addressLabel->setText(QApplication::translate("srvTunForm", "Address:", 0));
|
||||||
maxConnsLabel->setText(QApplication::translate("srvTunForm", "Max connections:", 0));
|
|
||||||
|
|
||||||
gzipCheckBox->setText(QApplication::translate("srvTunForm", "GZip", 0));
|
gzipCheckBox->setText(QApplication::translate("srvTunForm", "GZip", 0));
|
||||||
isUniqueLocalCheckBox->setText(QApplication::translate("srvTunForm", "Is unique local", 0));
|
isUniqueLocalCheckBox->setText(QApplication::translate("srvTunForm", "Is unique local", 0));
|
||||||
@ -152,14 +147,6 @@ protected:
|
|||||||
|
|
||||||
stc->setaddress(addressLineEdit->text().toStdString());
|
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->setgzip(gzipCheckBox->isChecked());
|
||||||
|
|
||||||
stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked());
|
stc->setisUniqueLocal(isUniqueLocalCheckBox->isChecked());
|
||||||
|
@ -18,7 +18,7 @@ class SignatureTypeComboBoxFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint16_t getSigType(const QVariant& var) {
|
static uint16_t getSigType(const QVariant& var) {
|
||||||
return (uint16_t)var.toInt();
|
return (uint16_t)var.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ void ServerTunnelConfig::saveToStringStream(std::stringstream& out) {
|
|||||||
<< "enableuniquelocal=" << (isUniqueLocal?"true":"false") << "\n"
|
<< "enableuniquelocal=" << (isUniqueLocal?"true":"false") << "\n"
|
||||||
<< "address=" << address << "\n"
|
<< "address=" << address << "\n"
|
||||||
<< "hostoverride=" << hostOverride << "\n"
|
<< "hostoverride=" << hostOverride << "\n"
|
||||||
<< "webircpassword=" << webircpass << "\n"
|
<< "webircpassword=" << webircpass << "\n";
|
||||||
<< "maxconns=" << maxConns << "\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,6 @@ public:
|
|||||||
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
||||||
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
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::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<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
||||||
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
||||||
# * inport -- optional, i2p service port, if unset - the same as 'port'
|
# * inport -- optional, i2p service port, if unset - the same as 'port'
|
||||||
@ -170,7 +169,6 @@ class ServerTunnelConfig : public TunnelConfig {
|
|||||||
std::string webircpass;
|
std::string webircpass;
|
||||||
bool gzip;
|
bool gzip;
|
||||||
i2p::data::SigningKeyType sigType;
|
i2p::data::SigningKeyType sigType;
|
||||||
uint32_t maxConns;
|
|
||||||
std::string address;
|
std::string address;
|
||||||
bool isUniqueLocal;
|
bool isUniqueLocal;
|
||||||
public:
|
public:
|
||||||
@ -184,7 +182,6 @@ public:
|
|||||||
std::string webircpass_,
|
std::string webircpass_,
|
||||||
bool gzip_,
|
bool gzip_,
|
||||||
i2p::data::SigningKeyType sigType_,
|
i2p::data::SigningKeyType sigType_,
|
||||||
uint32_t maxConns_,
|
|
||||||
std::string address_,
|
std::string address_,
|
||||||
bool isUniqueLocal_): TunnelConfig(name_, type_, i2cpParameters_),
|
bool isUniqueLocal_): TunnelConfig(name_, type_, i2cpParameters_),
|
||||||
host(host_),
|
host(host_),
|
||||||
@ -196,7 +193,6 @@ public:
|
|||||||
webircpass(webircpass_),
|
webircpass(webircpass_),
|
||||||
gzip(gzip_),
|
gzip(gzip_),
|
||||||
sigType(sigType_),
|
sigType(sigType_),
|
||||||
maxConns(maxConns_),
|
|
||||||
address(address_),
|
address(address_),
|
||||||
isUniqueLocal(isUniqueLocal_) {}
|
isUniqueLocal(isUniqueLocal_) {}
|
||||||
std::string& gethost(){return host;}
|
std::string& gethost(){return host;}
|
||||||
@ -208,7 +204,6 @@ public:
|
|||||||
std::string& getwebircpass(){return webircpass;}
|
std::string& getwebircpass(){return webircpass;}
|
||||||
bool getgzip(){return gzip;}
|
bool getgzip(){return gzip;}
|
||||||
i2p::data::SigningKeyType getsigType(){return sigType;}
|
i2p::data::SigningKeyType getsigType(){return sigType;}
|
||||||
uint32_t getmaxConns(){return maxConns;}
|
|
||||||
std::string& getaddress(){return address;}
|
std::string& getaddress(){return address;}
|
||||||
bool getisUniqueLocal(){return isUniqueLocal;}
|
bool getisUniqueLocal(){return isUniqueLocal;}
|
||||||
void sethost(const std::string& host_){host=host_;}
|
void sethost(const std::string& host_){host=host_;}
|
||||||
@ -220,7 +215,6 @@ public:
|
|||||||
void setwebircpass(const std::string& webircpass_){webircpass=webircpass_;}
|
void setwebircpass(const std::string& webircpass_){webircpass=webircpass_;}
|
||||||
void setgzip(bool gzip_){gzip=gzip_;}
|
void setgzip(bool gzip_){gzip=gzip_;}
|
||||||
void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;}
|
void setsigType(i2p::data::SigningKeyType sigType_){sigType=sigType_;}
|
||||||
void setmaxConns(uint32_t maxConns_){maxConns=maxConns_;}
|
|
||||||
void setaddress(const std::string& address_){address=address_;}
|
void setaddress(const std::string& address_){address=address_;}
|
||||||
void setisUniqueLocal(bool isUniqueLocal_){isUniqueLocal=isUniqueLocal_;}
|
void setisUniqueLocal(bool isUniqueLocal_){isUniqueLocal=isUniqueLocal_;}
|
||||||
virtual void saveToStringStream(std::stringstream& out);
|
virtual void saveToStringStream(std::stringstream& out);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.18.0" android:versionCode="2" android:installLocation="auto">
|
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.19.0" android:versionCode="2" android:installLocation="auto">
|
||||||
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
|
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
|
||||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
<!-- <application android:hardwareAccelerated="true" -->
|
<!-- <application android:hardwareAccelerated="true" -->
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<!DOCTYPE RCC><RCC version="1.0">
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
<qresource prefix="/">
|
<qresource prefix="/icons">
|
||||||
<file>images/icon.png</file>
|
<file alias="mask">resources/icons/mask.ico</file>
|
||||||
</qresource>
|
<file alias="icon">resources/images/icon.png</file>
|
||||||
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
32
qt/i2pd_qt/i2pd.rc
Normal file
32
qt/i2pd_qt/i2pd.rc
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
IDI_ICON1 ICON DISCARDABLE "resources/icons/mask.ico"
|
||||||
|
|
||||||
|
#include <windows.h> // 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
|
@ -4,7 +4,7 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
|||||||
|
|
||||||
TARGET = i2pd_qt
|
TARGET = i2pd_qt
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
QMAKE_CXXFLAGS *= -std=c++11
|
QMAKE_CXXFLAGS *= -std=c++11 -ggdb
|
||||||
DEFINES += USE_UPNP
|
DEFINES += USE_UPNP
|
||||||
|
|
||||||
# change to your own path, where you will store all needed libraries with 'git clone' commands below.
|
# change to your own path, where you will store all needed libraries with 'git clone' commands below.
|
||||||
@ -66,6 +66,9 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||||||
../../libi2pd/TunnelGateway.cpp \
|
../../libi2pd/TunnelGateway.cpp \
|
||||||
../../libi2pd/TunnelPool.cpp \
|
../../libi2pd/TunnelPool.cpp \
|
||||||
../../libi2pd/util.cpp \
|
../../libi2pd/util.cpp \
|
||||||
|
../../libi2pd/Ed25519.cpp \
|
||||||
|
../../libi2pd/Chacha20.cpp \
|
||||||
|
../../libi2pd/Poly1305.cpp \
|
||||||
../../libi2pd_client/AddressBook.cpp \
|
../../libi2pd_client/AddressBook.cpp \
|
||||||
../../libi2pd_client/BOB.cpp \
|
../../libi2pd_client/BOB.cpp \
|
||||||
../../libi2pd_client/ClientContext.cpp \
|
../../libi2pd_client/ClientContext.cpp \
|
||||||
@ -93,7 +96,8 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
|||||||
textbrowsertweaked1.cpp \
|
textbrowsertweaked1.cpp \
|
||||||
pagewithbackbutton.cpp \
|
pagewithbackbutton.cpp \
|
||||||
widgetlock.cpp \
|
widgetlock.cpp \
|
||||||
widgetlockregistry.cpp
|
widgetlockregistry.cpp \
|
||||||
|
logviewermanager.cpp
|
||||||
|
|
||||||
#qt creator does not handle this well
|
#qt creator does not handle this well
|
||||||
#SOURCES += $$files(../../libi2pd/*.cpp)
|
#SOURCES += $$files(../../libi2pd/*.cpp)
|
||||||
@ -177,7 +181,10 @@ HEADERS += DaemonQT.h mainwindow.h \
|
|||||||
textbrowsertweaked1.h \
|
textbrowsertweaked1.h \
|
||||||
pagewithbackbutton.h \
|
pagewithbackbutton.h \
|
||||||
widgetlock.h \
|
widgetlock.h \
|
||||||
widgetlockregistry.h
|
widgetlockregistry.h \
|
||||||
|
i2pd.rc \
|
||||||
|
i2pd.rc \
|
||||||
|
logviewermanager.h
|
||||||
|
|
||||||
INCLUDEPATH += ../../libi2pd
|
INCLUDEPATH += ../../libi2pd
|
||||||
INCLUDEPATH += ../../libi2pd_client
|
INCLUDEPATH += ../../libi2pd_client
|
||||||
@ -272,6 +279,34 @@ linux:!android {
|
|||||||
LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc
|
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_RELEASE = -Os
|
||||||
|
QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows
|
||||||
|
|
||||||
|
#linker's -s means "strip"
|
||||||
|
QMAKE_LFLAGS_RELEASE += -s
|
||||||
|
|
||||||
|
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 {
|
!android:!symbian:!maemo5:!simulator {
|
||||||
message("Build with a system tray icon")
|
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*
|
# see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince*
|
||||||
|
45
qt/i2pd_qt/logviewermanager.cpp
Normal file
45
qt/i2pd_qt/logviewermanager.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include "logviewermanager.h"
|
||||||
|
|
||||||
|
LogViewerManager::LogViewerManager(std::shared_ptr<std::iostream> 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<std::iostream> 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*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
qt/i2pd_qt/logviewermanager.h
Normal file
130
qt/i2pd_qt/logviewermanager.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#ifndef LOGVIEWERMANAGER_H
|
||||||
|
#define LOGVIEWERMANAGER_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#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<std::iostream> 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<std::iostream> 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<std::iostream> 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
|
@ -27,15 +27,19 @@
|
|||||||
#include "DaemonQT.h"
|
#include "DaemonQT.h"
|
||||||
#include "SignatureTypeComboboxFactory.h"
|
#include "SignatureTypeComboboxFactory.h"
|
||||||
|
|
||||||
|
#include "logviewermanager.h"
|
||||||
|
|
||||||
std::string programOptionsWriterCurrentSection;
|
std::string programOptionsWriterCurrentSection;
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent) :
|
||||||
QMainWindow(parent)
|
QMainWindow(parent)
|
||||||
|
,logStream(logStream_)
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
,quitting(false)
|
,quitting(false)
|
||||||
#endif
|
#endif
|
||||||
,wasSelectingAtStatusMainPage(false)
|
,wasSelectingAtStatusMainPage(false)
|
||||||
,showHiddenInfoStatusMainPage(false)
|
,showHiddenInfoStatusMainPage(false)
|
||||||
|
,logViewerManagerPtr(nullptr)
|
||||||
,ui(new Ui::MainWindow)
|
,ui(new Ui::MainWindow)
|
||||||
,statusButtonsUI(new Ui::StatusButtonsForm)
|
,statusButtonsUI(new Ui::StatusButtonsForm)
|
||||||
,routerCommandsUI(new Ui::routerCommandsWidget)
|
,routerCommandsUI(new Ui::routerCommandsWidget)
|
||||||
@ -132,6 +136,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit()));
|
QObject::connect(routerCommandsUI->acceptTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(enableTransit()));
|
||||||
QObject::connect(routerCommandsUI->declineTransitTunnelsPushButton, SIGNAL(released()), this, SLOT(disableTransit()));
|
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->settingsPagePushButton, SIGNAL(released()), this, SLOT(showSettingsPage()));
|
||||||
|
|
||||||
QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage()));
|
QObject::connect(ui->tunnelsPagePushButton, SIGNAL(released()), this, SLOT(showTunnelsPage()));
|
||||||
@ -299,6 +305,9 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
trayIcon->show();
|
trayIcon->show();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
logViewerManagerPtr=new LogViewerManager(logStream_,ui->logViewerTextEdit,this);
|
||||||
|
assert(logViewerManagerPtr!=nullptr);
|
||||||
|
onLoggingOptionsChange();
|
||||||
//QMetaObject::connectSlotsByName(this);
|
//QMetaObject::connectSlotsByName(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,10 +342,11 @@ void MainWindow::showStatusPage(StatusPage newStatusPage){
|
|||||||
}
|
}
|
||||||
wasSelectingAtStatusMainPage=false;
|
wasSelectingAtStatusMainPage=false;
|
||||||
}
|
}
|
||||||
void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);}
|
void MainWindow::showLogViewerPage(){ui->stackedWidget->setCurrentIndex(1);setStatusButtonsVisible(false);}
|
||||||
void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);}
|
void MainWindow::showSettingsPage(){ui->stackedWidget->setCurrentIndex(2);setStatusButtonsVisible(false);}
|
||||||
void MainWindow::showRestartPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);}
|
void MainWindow::showTunnelsPage(){ui->stackedWidget->setCurrentIndex(3);setStatusButtonsVisible(false);}
|
||||||
void MainWindow::showQuitPage(){ui->stackedWidget->setCurrentIndex(4);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) {
|
void MainWindow::setStatusButtonsVisible(bool visible) {
|
||||||
ui->statusButtonsPane->setVisible(visible);
|
ui->statusButtonsPane->setVisible(visible);
|
||||||
@ -349,7 +359,9 @@ QString MainWindow::getStatusPageHtml(bool showHiddenInfo) {
|
|||||||
s << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">";
|
s << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">";
|
||||||
|
|
||||||
switch (statusPage) {
|
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 commands: break;
|
||||||
case local_destinations: i2p::http::ShowLocalDestinations(s);break;
|
case local_destinations: i2p::http::ShowLocalDestinations(s);break;
|
||||||
case leasesets: i2p::http::ShowLeasesSets(s); break;
|
case leasesets: i2p::http::ShowLeasesSets(s); break;
|
||||||
@ -449,7 +461,7 @@ void MainWindow::createTrayIcon() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setIcon() {
|
void MainWindow::setIcon() {
|
||||||
QIcon icon(":/images/icon.png");
|
QIcon icon(":icons/mask");
|
||||||
trayIcon->setIcon(icon);
|
trayIcon->setIcon(icon);
|
||||||
setWindowIcon(icon);
|
setWindowIcon(icon);
|
||||||
|
|
||||||
@ -629,6 +641,8 @@ void MainWindow::loadAllConfigs(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
ReadTunnelsConfig();
|
ReadTunnelsConfig();
|
||||||
|
|
||||||
|
onLoggingOptionsChange();
|
||||||
}
|
}
|
||||||
/** returns false iff not valid items present and save was aborted */
|
/** returns false iff not valid items present and save was aborted */
|
||||||
bool MainWindow::saveAllConfigs(){
|
bool MainWindow::saveAllConfigs(){
|
||||||
@ -666,6 +680,8 @@ bool MainWindow::saveAllConfigs(){
|
|||||||
|
|
||||||
SaveTunnelsConfig();
|
SaveTunnelsConfig();
|
||||||
|
|
||||||
|
onLoggingOptionsChange();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,6 +62,8 @@
|
|||||||
#include "widgetlockregistry.h"
|
#include "widgetlockregistry.h"
|
||||||
#include "widgetlock.h"
|
#include "widgetlock.h"
|
||||||
|
|
||||||
|
class LogViewerManager;
|
||||||
|
|
||||||
template<typename ValueType>
|
template<typename ValueType>
|
||||||
bool isType(boost::any& a) {
|
bool isType(boost::any& a) {
|
||||||
return
|
return
|
||||||
@ -215,7 +217,8 @@ public:
|
|||||||
};
|
};
|
||||||
class LogDestinationComboBoxItem : public ComboBoxItem {
|
class LogDestinationComboBoxItem : public ComboBoxItem {
|
||||||
public:
|
public:
|
||||||
LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) : ComboBoxItem(option_, comboBox_) {};
|
LogDestinationComboBoxItem(ConfigOption option_, QComboBox* comboBox_) :
|
||||||
|
ComboBoxItem(option_, comboBox_) {}
|
||||||
virtual ~LogDestinationComboBoxItem(){}
|
virtual ~LogDestinationComboBoxItem(){}
|
||||||
virtual void loadFromConfigOption(){
|
virtual void loadFromConfigOption(){
|
||||||
MainWindowItem::loadFromConfigOption();
|
MainWindowItem::loadFromConfigOption();
|
||||||
@ -228,6 +231,8 @@ public:
|
|||||||
MainWindowItem::saveToStringStream(out);
|
MainWindowItem::saveToStringStream(out);
|
||||||
}
|
}
|
||||||
virtual bool isValid() { return true; }
|
virtual bool isValid() { return true; }
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
};
|
};
|
||||||
class LogLevelComboBoxItem : public ComboBoxItem {
|
class LogLevelComboBoxItem : public ComboBoxItem {
|
||||||
public:
|
public:
|
||||||
@ -370,9 +375,10 @@ class Controller;
|
|||||||
|
|
||||||
class MainWindow : public QMainWindow {
|
class MainWindow : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
std::shared_ptr<std::iostream> logStream;
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget *parent=0);
|
explicit MainWindow(std::shared_ptr<std::iostream> logStream_, QWidget *parent=nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
void setI2PController(i2p::qt::Controller* controller_);
|
void setI2PController(i2p::qt::Controller* controller_);
|
||||||
@ -419,6 +425,7 @@ public slots:
|
|||||||
void showStatus_i2p_tunnels_Page();
|
void showStatus_i2p_tunnels_Page();
|
||||||
void showStatus_sam_sessions_Page();
|
void showStatus_sam_sessions_Page();
|
||||||
|
|
||||||
|
void showLogViewerPage();
|
||||||
void showSettingsPage();
|
void showSettingsPage();
|
||||||
void showTunnelsPage();
|
void showTunnelsPage();
|
||||||
void showRestartPage();
|
void showRestartPage();
|
||||||
@ -430,6 +437,8 @@ private:
|
|||||||
bool wasSelectingAtStatusMainPage;
|
bool wasSelectingAtStatusMainPage;
|
||||||
bool showHiddenInfoStatusMainPage;
|
bool showHiddenInfoStatusMainPage;
|
||||||
|
|
||||||
|
LogViewerManager *logViewerManagerPtr;
|
||||||
|
|
||||||
void showStatusPage(StatusPage newStatusPage);
|
void showStatusPage(StatusPage newStatusPage);
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
void createActions();
|
void createActions();
|
||||||
@ -522,13 +531,6 @@ private:
|
|||||||
void appendTunnelForms(std::string tunnelNameToFocus);
|
void appendTunnelForms(std::string tunnelNameToFocus);
|
||||||
void deleteTunnelForms();
|
void deleteTunnelForms();
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
TODO signaturetype
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename Section, typename Type>
|
template<typename Section, typename Type>
|
||||||
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
|
||||||
{
|
{
|
||||||
@ -628,7 +630,6 @@ private:
|
|||||||
std::string webircpass = "";
|
std::string webircpass = "";
|
||||||
bool gzip = true;
|
bool gzip = true;
|
||||||
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256;
|
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";
|
std::string address = "127.0.0.1";
|
||||||
bool isUniqueLocal = true;
|
bool isUniqueLocal = true;
|
||||||
|
|
||||||
@ -646,7 +647,6 @@ private:
|
|||||||
webircpass,
|
webircpass,
|
||||||
gzip,
|
gzip,
|
||||||
sigType,
|
sigType,
|
||||||
maxConns,
|
|
||||||
address,
|
address,
|
||||||
isUniqueLocal);
|
isUniqueLocal);
|
||||||
|
|
||||||
@ -734,7 +734,6 @@ private:
|
|||||||
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
||||||
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
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::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<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1");
|
||||||
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true);
|
||||||
|
|
||||||
@ -769,7 +768,6 @@ private:
|
|||||||
webircpass,
|
webircpass,
|
||||||
gzip,
|
gzip,
|
||||||
sigType,
|
sigType,
|
||||||
maxConns,
|
|
||||||
address,
|
address,
|
||||||
isUniqueLocal);
|
isUniqueLocal);
|
||||||
}
|
}
|
||||||
@ -794,6 +792,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener;
|
TunnelsPageUpdateListenerMainWindowImpl tunnelsPageUpdateListener;
|
||||||
|
|
||||||
|
void onLoggingOptionsChange() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
<enum>QLayout::SetMaximumSize</enum>
|
<enum>QLayout::SetMaximumSize</enum>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0,0,0">
|
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0,0,0,0,0,0">
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SetMinimumSize</enum>
|
<enum>QLayout::SetMinimumSize</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -96,6 +96,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="logViewerPushButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Log</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="settingsPagePushButton">
|
<widget class="QPushButton" name="settingsPagePushButton">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
@ -596,7 +603,7 @@
|
|||||||
</palette>
|
</palette>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>TextLabel</string>
|
<string>wrongInputMessageLabel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -627,7 +634,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>2</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="statusPage">
|
<widget class="QWidget" name="statusPage">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -671,6 +678,69 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="logViewerPage">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="verticalLayoutWidget_4_logViewer">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>711</width>
|
||||||
|
<height>531</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4_logViewer">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="logViewerTitleLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>15</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Log</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPlainTextEdit" name="logViewerTextEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollBarPolicy">
|
||||||
|
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QAbstractScrollArea::AdjustIgnored</enum>
|
||||||
|
</property>
|
||||||
|
<property name="maximumBlockCount">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
<property name="acceptRichText" stdset="0">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="widgetResizable" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
<widget class="QWidget" name="settingsPage">
|
<widget class="QWidget" name="settingsPage">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
@ -728,8 +798,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>689</width>
|
<width>81</width>
|
||||||
<height>496</height>
|
<height>28</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
BIN
qt/i2pd_qt/resources/icons/mask.ico
Normal file
BIN
qt/i2pd_qt/resources/icons/mask.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
@ -1,6 +1,6 @@
|
|||||||
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
|
TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305
|
||||||
|
|
||||||
all: $(TESTS) run
|
all: $(TESTS) run
|
||||||
|
|
||||||
@ -13,7 +13,13 @@ test-base-%: ../libi2pd/Base.cpp test-base-%.cpp
|
|||||||
test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp
|
test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto
|
$(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/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 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
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
|
||||||
|
|
||||||
run: $(TESTS)
|
run: $(TESTS)
|
||||||
|
54
tests/test-aeadchacha20poly1305.cpp
Normal file
54
tests/test-aeadchacha20poly1305.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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];
|
||||||
|
// 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);
|
||||||
|
// 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);
|
||||||
|
}
|
36
tests/test-x25519.cpp
Normal file
36
tests/test-x25519.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user