Merge pull request #1063 from PurpleI2P/openssl

recent changes
This commit is contained in:
orignal 2018-01-21 10:29:31 -05:00 committed by GitHub
commit df304fb38b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
134 changed files with 3331 additions and 3261 deletions

View file

@ -37,7 +37,7 @@
## [2.15.0] - 2017-08-17
### Added
- QT GUI
- QT GUI
- Ability to add and remove I2P tunnels without restart
- Ability to disable SOCKS outproxy option
### Changed
@ -81,7 +81,7 @@
- Some stats in a main window for Windows version
### Changed
- Reseed servers list
- MTU of 1488 for ipv6
- MTU of 1488 for ipv6
- Android and Mac OS X versions use OpenSSL 1.1
- New logo for Android
### Fixed
@ -111,7 +111,7 @@
## [2.10.2] - 2016-12-04
### Fixed
- Fixes UPnP discovery bug, producing excessive CPU usage
- Fixes sudden SSU thread stop for Windows.
- Fixes sudden SSU thread stop for Windows.
## [2.10.1] - 2016-11-07
### Fixed

View file

@ -13,13 +13,13 @@ RUN mkdir /user && adduser -S -h /user i2pd && chown -R i2pd:nobody /user
#
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
#
# 1. install deps, clone and build.
# 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory.
# 1. install deps, clone and build.
# 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory.
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \
&& mkdir -p /tmp/build \
&& cd /tmp/build && git clone -b ${GIT_BRANCH} https://github.com/PurpleI2P/i2pd.git \

View file

@ -1,9 +1,9 @@
UNAME := $(shell uname -s)
SYS := $(shell $(CXX) -dumpmachine)
SHLIB := libi2pd.so
ARLIB := libi2pd.a
SHLIB_CLIENT := libi2pdclient.so
ARLIB_CLIENT := libi2pdclient.a
I2PD := i2pd
I2PD := i2pd
GREP := grep
DEPS := obj/make.dep
@ -23,22 +23,24 @@ ifeq ($(WEBSOCKETS),1)
NEEDED_CXXFLAGS += -DWITH_EVENTS
endif
ifeq ($(UNAME),Darwin)
ifneq (, $(findstring darwin, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
ifeq ($(HOMEBREW),1)
include Makefile.homebrew
else
include Makefile.osx
endif
else ifeq ($(shell echo $(UNAME) | $(GREP) -Ec '(Free|Open)BSD'),1)
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.bsd
else ifeq ($(UNAME),Linux)
else ifneq (, $(findstring linux, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.linux
else
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp
include Makefile.mingw
else # not supported
$(error Not supported platform)
endif
ifeq ($(USE_MESHNET),yes)

View file

@ -1,5 +1,5 @@
CXX = clang++
CXXFLAGS = -O2
CXXFLAGS ?= -g -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation
## NOTE: NEEDED_CXXFLAGS is here so that custom CXXFLAGS can be specified at build time
## **without** overwriting the CXXFLAGS which we need in order to build.
## For example, when adding 'hardening flags' to the build

View file

@ -4,7 +4,7 @@ BOOSTROOT = ${BREWROOT}/opt/boost
SSLROOT = ${BREWROOT}/opt/libressl
UPNPROOT = ${BREWROOT}/opt/miniupnpc
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
ifndef TRAVIS
CXX = clang++

View file

@ -12,7 +12,7 @@ INCFLAGS ?=
# detect proper flag for c++11 support by compilers
CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match $(CXX) 'clang'),5)
NEEDED_CXXFLAGS += -std=c++11
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
@ -24,7 +24,7 @@ else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0
else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 ubuntu
NEEDED_CXXFLAGS += -std=c++11
else # not supported
$(error Compiler too old)
$(error Compiler too old)
endif
NEEDED_CXXFLAGS += -fPIC

View file

@ -1,7 +1,7 @@
CXX = clang++
CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11
INCFLAGS = -I/usr/local/include
INCFLAGS = -I/usr/local/include
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
ifeq ($(USE_STATIC),yes)

View file

@ -5,13 +5,13 @@ i2pd
i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client.
I2P (Invisible Internet Protocol) is a universal anonymous network layer.
I2P (Invisible Internet Protocol) is a universal anonymous network layer.
All communications over I2P are anonymous and end-to-end encrypted, participants
don't reveal their real IP addresses.
don't reveal their real IP addresses.
I2P client is a software used for building and using anonymous I2P
networks. Such networks are commonly used for anonymous peer-to-peer
applications (filesharing, cryptocurrencies) and anonymous client-server
I2P client is a software used for building and using anonymous I2P
networks. Such networks are commonly used for anonymous peer-to-peer
applications (filesharing, cryptocurrencies) and anonymous client-server
applications (websites, instant messengers, chat-servers).
I2P allows people from all around the world to communicate and share information
@ -38,9 +38,9 @@ Resources
Installing
----------
The easiest way to install i2pd is by using
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
The easiest way to install i2pd is by using
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
i2pd from source on your OS.
@ -58,25 +58,25 @@ Build instructions:
* Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd)
* Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
* FreeBSD
* Android
* Android
* iOS
Using i2pd
----------
See [documentation](https://i2pd.readthedocs.io/en/latest/user-guide/run/) and
See [documentation](https://i2pd.readthedocs.io/en/latest/user-guide/run/) and
[example config file](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/i2pd.conf).
Donations
---------
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
License
-------

View file

@ -23,4 +23,4 @@
</activity>
<service android:enabled="true" android:name=".ForegroundService"/>
</application>
</manifest>
</manifest>

View file

@ -1,7 +1,7 @@
<menu
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".I2PD">
<item
android:id="@+id/action_graceful_quit"

View file

@ -14,10 +14,10 @@ public class DaemonSingleton {
public static DaemonSingleton getInstance() {
return instance;
}
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
public synchronized void stopAcceptingTunnels() {
if(isStartedOkay()){
state=State.gracefulShutdownInProgress;
@ -25,19 +25,19 @@ public class DaemonSingleton {
I2PD_JNI.stopAcceptingTunnels();
}
}
public void onNetworkStateChange(boolean isConnected) {
I2PD_JNI.onNetworkStateChanged(isConnected);
}
private boolean startedOkay;
public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress};
private State state = State.uninitialized;
public State getState() { return state; }
public synchronized void start() {
if(state != State.uninitialized)return;
state = State.starting;
@ -76,9 +76,9 @@ public class DaemonSingleton {
fireStateUpdate();
}
return;
}
}
}
}, "i2pdDaemonStart").start();
}
private Throwable lastThrowable;
@ -87,10 +87,10 @@ public class DaemonSingleton {
private synchronized void fireStateUpdate() {
Log.i(TAG, "daemon state change: "+state);
for(StateUpdateListener listener : stateUpdateListeners) {
try {
listener.daemonStateUpdate();
} catch (Throwable tr) {
Log.e(TAG, "exception in listener ignored", tr);
try {
listener.daemonStateUpdate();
} catch (Throwable tr) {
Log.e(TAG, "exception in listener ignored", tr);
}
}
}
@ -102,7 +102,7 @@ public class DaemonSingleton {
public String getDaemonStartResult() {
return daemonStartResult;
}
private final Object startedOkayLock = new Object();
public boolean isStartedOkay() {

View file

@ -50,7 +50,7 @@ public class ForegroundService extends Service {
public void onDestroy() {
// Cancel the persistent notification.
notificationManager.cancel(NOTIFICATION);
stopForeground(true);
// Tell the user we stopped.
@ -91,7 +91,7 @@ public class ForegroundService extends Service {
//mNM.notify(NOTIFICATION, notification);
startForeground(NOTIFICATION, notification);
}
private final DaemonSingleton daemon = DaemonSingleton.getInstance();
}

View file

@ -24,12 +24,12 @@ public class I2PD extends Activity {
private static final String TAG = "i2pd";
private TextView textView;
private final DaemonSingleton daemon = DaemonSingleton.getInstance();
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() {
@Override
public void daemonStateUpdate() {
runOnUiThread(new Runnable(){
@ -53,7 +53,7 @@ public class I2PD extends Activity {
});
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -123,7 +123,7 @@ public class I2PD extends Activity {
}
};
private boolean mIsBound;
private void doBindService() {
@ -147,7 +147,7 @@ public class I2PD extends Activity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.options_main, menu);
getMenuInflater().inflate(R.menu.options_main, menu);
return true;
}
@ -216,9 +216,9 @@ public class I2PD extends Activity {
@Override
public void run() {
quit();
quit();
}
}, 10*60*1000/*milliseconds*/);
}else{
quit();
@ -227,7 +227,7 @@ public class I2PD extends Activity {
Log.e(TAG,"",tr);
}
}
},"gracQuitInit").start();
}

View file

@ -9,9 +9,9 @@ public class I2PD_JNI {
public static native String startDaemon();
//should only be called after startDaemon() success
public static native void stopDaemon();
public static native void stopAcceptingTunnels();
public static native void onNetworkStateChanged(boolean isConnected);
public static void loadLibraries() {

3
build/.gitignore vendored
View file

@ -8,6 +8,7 @@
/CPackConfig.cmake
/CPackSourceConfig.cmake
/install_manifest.txt
/arch.c
# windows build script
i2pd*.zip
build*.log
build*.log

View file

@ -26,6 +26,10 @@ option(WITH_WEBSOCKETS "Build with websocket ui" OFF)
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
set ( CMAKE_SOURCE_DIR ".." )
# architecture
include(TargetArch)
target_architecture(ARCHITECTURE)
set(LIBI2PD_SRC_DIR ../libi2pd)
set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client)
@ -79,7 +83,7 @@ if (WITH_WEBSOCKETS)
find_package(websocketpp REQUIRED)
endif ()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
if (WIN32 OR MSYS)
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
endif ()
@ -190,20 +194,14 @@ if (WITH_HARDENING AND MSVC)
endif ()
# compiler flags customization (by system)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
if (UNIX)
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp")
if (NOT (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR APPLE))
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
endif ()
elseif (WIN32 OR MSYS)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp")
if (WITH_GUI)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32App.cpp")
set_source_files_properties("${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp"
@ -259,6 +257,8 @@ if(THREADS_HAVE_PTHREAD_ARG) # compile time flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
include(CheckLibcxxAtomic)
if (WITH_STATIC)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON)
@ -366,11 +366,13 @@ if (NOT ZLIB_FOUND )
if (NOT WITH_STATIC)
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
endif ()
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib)
else()
link_directories(${ZLIB_ROOT}/lib)
endif ()
if (WITH_STATIC AND (MSVC OR MSYS))
set ( ZLIB_LIBRARY debug zlibstaticd optimized zlibstatic CACHE STRING "zlib libraries" FORCE)
endif ()
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib ${ZLIB_ROOT}/lib)
# load includes
include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
@ -382,6 +384,12 @@ if (WITH_MESHNET)
message(WARNING "This build will NOT work on mainline i2p")
endif()
if (ARCHITECTURE MATCHES "arm")
set(ATOMIC_LIB -latomic)
else()
set(ATMOIC_LIB "")
endif()
# show summary
message(STATUS "---------------------------------------")
@ -389,6 +397,7 @@ message(STATUS "Build type : ${CMAKE_BUILD_TYPE}")
message(STATUS "Compiler vendor : ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "Compiler version : ${CMAKE_CXX_COMPILER_VERSION}")
message(STATUS "Compiler path : ${CMAKE_CXX_COMPILER}")
message(STATUS "Architecture : ${ARCHITECTURE}")
message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}")
message(STATUS "Options:")
message(STATUS " AESNI : ${WITH_AESNI}")
@ -448,7 +457,7 @@ if (WITH_BINARY)
if (WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS})
endif()
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB})
target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${ATOMIC_LIB})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

View file

@ -0,0 +1,47 @@
INCLUDE(CheckCXXSourceCompiles)
# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.
#
# We could modify LLVM's CheckAtomic module and have it check for 64-bit
# atomics instead. However, we would like to avoid careless uses of 64-bit
# atomics inside LLVM over time on 32-bit platforms.
function(check_cxx_atomics varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(CMAKE_REQUIRED_FLAGS "-nodefaultlibs -std=c++11 -nostdinc++ -isystem ${LIBCXX_SOURCE_DIR}/include")
if (${LIBCXX_GCC_TOOLCHAIN})
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} --gcc-toolchain=${LIBCXX_GCC_TOOLCHAIN}")
endif()
if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all")
endif()
if (CMAKE_C_FLAGS MATCHES -fsanitize-coverage OR CMAKE_CXX_FLAGS MATCHES -fsanitize-coverage)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters")
endif()
check_cxx_source_compiles("
#include <cstdint>
#include <atomic>
std::atomic<uintptr_t> x;
std::atomic<uintmax_t> y;
int main() {
return x + y;
}
" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction(check_cxx_atomics)
check_cxx_atomics(LIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB)
check_library_exists(atomic __atomic_fetch_add_8 "" LIBCXX_HAS_ATOMIC_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT LIBCXX_HAVE_CXX_ATOMICS_WITHOUT_LIB)
if(LIBCXX_HAS_ATOMIC_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_cxx_atomics(LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT LIBCXX_HAVE_CXX_ATOMICS_WITH_LIB)
message(WARNING "Host compiler must support std::atomic!")
endif()
else()
message(WARNING "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()

View file

@ -24,5 +24,5 @@ else()
endif()
mark_as_advanced(MINIUPNPC_INCLUDE_DIR MINIUPNPC_LIBRARY)
endif()

View file

@ -0,0 +1,134 @@
# Based on the Qt 5 processor detection code, so should be very accurate
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
# Regarding POWER/PowerPC, just as is noted in the Qt source,
# "There are many more known variants/revisions that we do not handle/detect."
set(archdetect_c_code "
#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
#if defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
#error cmake_ARCH armv7
#elif defined(__ARM_ARCH_6__) \\
|| defined(__ARM_ARCH_6J__) \\
|| defined(__ARM_ARCH_6T2__) \\
|| defined(__ARM_ARCH_6Z__) \\
|| defined(__ARM_ARCH_6K__) \\
|| defined(__ARM_ARCH_6ZK__) \\
|| defined(__ARM_ARCH_6M__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
#error cmake_ARCH armv6
#elif defined(__ARM_ARCH_5TEJ__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
#error cmake_ARCH armv5
#else
#error cmake_ARCH arm
#endif
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
#error cmake_ARCH i386
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
#error cmake_ARCH x86_64
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
#error cmake_ARCH ia64
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|| defined(_M_MPPC) || defined(_M_PPC)
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
#error cmake_ARCH ppc64
#else
#error cmake_ARCH ppc
#endif
#endif
#error cmake_ARCH unknown
")
# Set ppc_support to TRUE before including this file or ppc and ppc64
# will be treated as invalid architectures since they are no longer supported by Apple
function(target_architecture output_var)
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
# First let's normalize the order of the values
# Note that it's not possible to compile PowerPC applications if you are using
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
# disable it by default
# See this page for more information:
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
set(osx_arch_ppc TRUE)
elseif("${osx_arch}" STREQUAL "i386")
set(osx_arch_i386 TRUE)
elseif("${osx_arch}" STREQUAL "x86_64")
set(osx_arch_x86_64 TRUE)
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
set(osx_arch_ppc64 TRUE)
else()
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
endif()
endforeach()
# Now add all the architectures in our normalized order
if(osx_arch_ppc)
list(APPEND ARCH ppc)
endif()
if(osx_arch_i386)
list(APPEND ARCH i386)
endif()
if(osx_arch_x86_64)
list(APPEND ARCH x86_64)
endif()
if(osx_arch_ppc64)
list(APPEND ARCH ppc64)
endif()
else()
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
enable_language(C)
# Detect the architecture in a rather creative way...
# This compiles a small C program which is a series of ifdefs that selects a
# particular #error preprocessor directive whose message string contains the
# target architecture. The program will always fail to compile (both because
# file is not a valid C program, and obviously because of the presence of the
# #error preprocessor directives... but by exploiting the preprocessor in this
# way, we can detect the correct target architecture even when cross-compiling,
# since the program itself never needs to be run (only the compiler/preprocessor)
try_run(
run_result_unused
compile_result_unused
"${CMAKE_BINARY_DIR}"
"${CMAKE_BINARY_DIR}/arch.c"
COMPILE_OUTPUT_VARIABLE ARCH
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
)
# Parse the architecture name from the compiler output
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
# Get rid of the value marker leaving just the architecture name
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
# If we are compiling with an unknown architecture this variable should
# already be set to "unknown" but in the case that it's empty (i.e. due
# to a typo in the code), then set it to unknown
if (NOT ARCH)
set(ARCH unknown)
endif()
endif()
set(${output_var} "${ARCH}" PARENT_SCOPE)
endfunction()

View file

@ -5,7 +5,7 @@ RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
libssl-dev git build-essential
RUN git clone https://github.com/PurpleI2P/i2pd.git
WORKDIR /i2pd
WORKDIR /i2pd
RUN make
CMD ./i2pd

View file

@ -1,4 +1,4 @@
# Basic profile for i2pd
# Basic profile for i2pd
# Should work without modifications with Ubuntu/Debian packages
# Author: Darknet Villain <supervillain@riseup.net>
#

View file

@ -1,33 +0,0 @@
-----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-----

View file

@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFhTCCA22gAwIBAgIELuRWgDANBgkqhkiG9w0BAQ0FADBzMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEcMBoGA1UEAwwTa2lsbHlvdXJ0dkBt
YWlsLmkycDAeFw0xMzEwMDYyMTM5MzFaFw0yMzEwMDYyMTM5MzFaMHMxCzAJBgNV
BAYTAlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBB
bm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRwwGgYDVQQDDBNraWxseW91
cnR2QG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAig3u
niLWm0y/TFJtciHgmWUt20FOdQrxkiSZ87G8xjuGfq7TbGIiVDn7pQZcHidpq+Dk
47sm+Swqhb4psSijj0AXUEVKlV39jF5IZE+VUgmEtMqQbnBkWudaTJPWcEe9T/Kd
8Oz2jgsnrD/EGVTMKBBjt/gk8VqTWvpCdCF1GhqcCeUTFHzjhN9jtoRCaJ2DClpO
Px+86+d3s9PqUFo8gcD/dbbyJCMqUCMBLtIy/Ooouxb9cfWtXfyOlphU+enmdvuA
0BDewb9pOJg2/kVd9/9moDWcBGChLOlfSlxpDwyUtcclcpvwnG7c6o4or6gqLeOf
AbCpse623utV7fWlFWG7M4AQ/2emhhe4YoMJQnflydzV8bPRJxRTeW1j/9UfpvLT
nO5LHp0oBXE0GqAPjxuAr+r5IDXFbkKYNjK5oWQB/Ul3LkexulYdCzHWbGd1Ja5b
sbiOy6t/hH6G8DD75HYb+PQZaNZWBv90EyOq1JDSUPw6nxVbhiBldi3ipc8/1X51
FbzBqJ+QO1XKrKqxWxBKoTekuy38KRzsmkSCpY+WJ9f0gLOKtxzVO2HNNqqVFGQf
RGIbrNA0JSRQ1fgelccfrcRIXIZ3B8Tk/wxCIzCY6Yvg2jezz2xJkVdqOUsznS2v
+xJe67PYIAeMVtcfO4kmuCvyIYhsUEpob2n/5lkCAwEAAaMhMB8wHQYDVR0OBBYE
FCLneov6QMtvra5FSoSLhdymi++rMA0GCSqGSIb3DQEBDQUAA4ICAQAIcqbiwjdQ
M9VlGBiHe5eVsL6OM9zfRqR1wnRg4Q6ce65XDfEOYleBWaaNJA4BdykcA4fkUN1h
M2D9FDQScsyPTOuzJ6o75TYh0JOtF51yCi9iuemcosxAwsm90ZXGuMDfDYeyND5c
PAkWfyCP+jwLYbNo/hkNqyv+XWHXPQmT2adRnPXINVUQuBxVPC//C9wv2uDYWhgS
f8M425VPp4/R/uks9mlzTx08DwacvouD0YOC+HZE4sWq+2smgeBInMiyr/THYzl+
baMtYgVs8IKUD2gtjfXZoaQNg3eq5SedSf/5F0S/LCdu9/ccQ8CzSEoVTiQFtO78
SaU37xai8+QTSVpPuINigxCoXmkubBd+voEmWRcBd/XB5L+u+MFU/jXyyBj2BXVj
6agqVzY53KVYt23/63QliAUWyxT+ns9gRxVN1jrMhHdiDwsdT4NbzHxg1Su4eiHv
C/wjD3Dga0BRTEGylpHZGzb1U1rZRHM3ho3f1QkmRPPLcBUMTyUTxJm+GEeuhPvp
+TBf3Kg/YkdpnEMlagqcyHuIrf3m8Z/pTmpOIbekJWbbA7tluvWbMWw2ARB7dUOE
fHYVISh0DTw2oVXxM82/q8XXHnhEXv2nW3K40x1VabxUN+sF4M/7YA8nJqwsPJei
749STYJRfZXdIe69M9zpM5unxENAsiPJgQ==
-----END CERTIFICATE-----

View file

@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFezCCA2OgAwIBAgIEHLJfZzANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc3RyNGRAbWFpbC5p
MnAwHhcNMTMxMDI2MTExODQxWhcNMjMxMDI2MTExODQxWjBuMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc3RyNGRAbWFpbC5p
MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvw0vTay1IPOgxvwe8
yt5jGakha20kw9qDb6zbEL87EWEkeOzdu7iUC69lkxVP9Ws8EbLtkeMf/CXg6CC1
e+w8WpOHj5prOsiOlrIO+2I1tKMaMUuJDX2wK4I5ZSw/Kieimh9xqOBZknDmtwjw
2HPW8rpxMqrScaGAP6sQD8Gh4XKKkLogfxYPzF8NnC6O8vBkFKVU2WSVZ0jPAQfv
6luPdA+5lES+5UPWr9Yhv/CX4siGKUTxchqJRf2VU4o5BzzXae4asVA/NY7lKgEw
eDDufbm0mRFWP4mbmXRlODuJ8GMnJbMQkNcAvZUnUcvpSTnGnIvxyxtXP5P6ic8V
3b9HV2eIsbfO1xrgyr6/9qgGpXcdDJejhvNg6fZgQeO40bOGQYwV8bNvsNQHqnZl
KsVhsMQkOubMxcHTBadcifi8PmdeJ5hxyyqJmyrwkmg2ijnN521M6YkoBzl+8VAi
zLmqKZfvN5t+pb9PZ3U3jHfkeIEwDRYRAOsvVqch5+ZfSv8x/Te6o15zDKPJQtWK
ty42GV1vERw30oSZQdrRRy/+4+HSRs3/Zb368OdAbcr+f/xPvwceYGWPeNNIoZ/x
xkIQE3xgEK+eJyPM9McjlCAezZZclT7fWfiEYNJAiS3fGALi+a+cGYWWULxCXpz+
y397OHhZBhnh7D9K8aPePB8tCwIDAQABoyEwHzAdBgNVHQ4EFgQUezvGHq3h1gbC
Hs2LLVoll5fIUWMwDQYJKoZIhvcNAQENBQADggIBAF7SG1WBcE1r5eyTp/BLFZfG
iPtvqu+B1L2HutPum/Xf8A5fxR4kcKAKpVdu6vnDzCRAsAC9YvyETgAzI2nfVgLk
l9YZ31tSi6qxnMsQsV5o9lt/q2Rvsf2Zi/Ir8AlWtvnP8YG0Aj/8AG8MyhMLaIdj
M2FuakPs8RqEjoJL9dTOC9VTQpNTwBH9guP9UalWYwlkaXDzMoyO4nswT/GpCpg8
4m4RO6grzdsEIamD/PCBM5f/vq+y08GaqfXpX9+8CbaX3tdzd3x48wPphmdpkptk
aRELIpLJZiK+Mos7W+0ZS8SHxGDIosjqVsgbZPmk12+VBcVgLOr8W1D7osS4OY59
2GMUVV/GhoDh8wR/Td5wpZlcPE0NWmljjVg9+1E8ePAyMZy+U1KCiMlRVdRy518O
dOzzUUQGqGQHosRrH0ypS3MGbMLmbuWFRiz7q/3mUmW2xikH9I1t/6ZMNUvh+IWL
kGAaEf2JIv/D8+QsC0Un1W09DgvYz7qmKSeHhBixlLe68vgXtz/Fa+rRMsmPrueo
4wk/u/VyILo0BJP860APJMZbm+DPfGhV9DF9L5Gx9+d/BlduBVGHc+AQSWbU70dS
eH4/rgUYRikWlgwUxjY8/QQTlfx5xl28tG0xdO9libN22z7UwTGfm48BQIdrTyER
hqQ7usTy3oaWD85MbJ0q
-----END CERTIFICATE-----

View file

@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFdzCCA1+gAwIBAgIEcwrwsjANBgkqhkiG9w0BAQ0FADBsMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEVMBMGA1UEAwwMenp6QG1haWwuaTJw
MB4XDTEzMDkzMDE3NDEyNVoXDTIzMDkzMDE3NDEyNVowbDELMAkGA1UEBhMCWFgx
CzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255bW91
cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxFTATBgNVBAMMDHp6ekBtYWlsLmkycDCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJV4ptvhlfrcize9/ARz4lUy
iLtLMSvSST1BdZjLJTwus05EUs0oiqnv9qXYIWGRB97aKlAmqSxsn4ZgBttCgmev
IkuiZ8kbdqI5YaT98yKW5P2Prt9p9cPbnz5/qjwZ5L9W+k/Itx7bv2pkNEP0NLYo
NrgHHTb1hsyRxc0lfPYk2BwsIi8hIWBHNrRpR41EWFXfqPcdsxS8cQhxVj4zLG/R
aMm4H8T+V1R1Khl4R4qqRgXBP305xqqRoawHmZ/S9/RkF0Ji6IYwBq9iWthWol6W
sMDn1xhZk9765fk+ohAC2XWuGSFCr02JOILRV3x/8OUxT1GYgYjc7FfyWIekg/pZ
yotlhL2I3SMWOH3PdG58iDY121hq/LsSKM9aP20rwtvssnw+8Aex01YDkI3bM6yO
HNi+tRojaJcJciBWv6cuiFKvQdxj/mOhOr0u0lHLlJ4jqES8uvVJkS7X/C4BB7ra
bJYQgumZMYvVQJFIjo8vZxMXue53o65FRidvAUT29ay54UTiL7jRV9w1wHnzLapU
xT1v7kWpWJcZ1zzC8coJjW+6ijkk38cVLb80u1Q4kEbmP2rDxw6jRvmqg6DcCKjK
oqDt+XQ6P5grxAxLT+VMfB404WHHwNs6BB841//4ZnXvy3msMONY/5y0fsblURgh
IS2UG1TAjR+x7+XikGx9AgMBAAGjITAfMB0GA1UdDgQWBBSvx/fCCP8UeHwjN65p
EoHjgRfiIzANBgkqhkiG9w0BAQ0FAAOCAgEAYgVE1Aa/Ok5k+Jvujbx72bktRWXo
Y4UfbWH/426VdgqXt3n9XtJUNM2oI4ODwITM4O15SyXQTLJhnvJz5ELcJV8nqviZ
RjK2HNX1BW7IEta3tacCvVnjzZ265kCT59uW+qmd+5PiaAYI5lYUn8P6pe+6neSa
HW6ecXCrdxJetSYfUUuKeV6YHpdzfjtZClLmwl91sJUBKcjK+Q9G/cE6HnwcDH1s
uXr7SgkBt/qc/OlNuu4fnTqUA58TAumdq9cD+eLBilDFrux1HsUZMuBUp64x5oPi
gme+3VewsczfFEtrxaG6+l6UA40Lerdx9XECZcDCcFsK6MS1uQ2HYjsyZcWnNT3l
6eDNUbjrllwxDdRAk0cbWiMuc21CFq/1v2QMXk88EiBjEajqzyXUPmKzwFhit6pr
5kfjfXNq+pxQSCoaqjpzVKjb3CqMhSlC8cLgrPw6HEgGnjCy4cTLFHlVmD64M778
tj6rE7CntcmUi8GKmZKyaMyUo3QQUcrjO5IQ4+3iGUgMkZuujyjrZiOJbvircPmK
4IQEXzJ/G00upqtqKstRybaWSbJ/k6iuturtA2n8MJiCBjhLy8dtTgDbFaDaNF7F
NHeqQjIJDLhYDy6mi4gya3A0ort777Inl/rWYLo067pYM+EWDw66GdpbEIB0Bp71
pwvcQcjIzbUzEK0=
-----END CERTIFICATE-----

View file

@ -17,13 +17,13 @@ RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
&& chown -R i2pd:nobody "$I2PD_HOME"
#
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
#
# 1. install deps, clone and build.
# 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory.
# 1. install deps, clone and build.
# 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory.
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \
&& mkdir -p /tmp/build \
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \

View file

@ -54,7 +54,7 @@ ipv4 = true
ipv6 = false
## Network interface to bind to
# ifname =
# ifname =
## Enable NTCP transport (default = true)
# ntcp = true
@ -88,18 +88,18 @@ ipv6 = false
[upnp]
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
# enabled = false
# enabled = false
## Name i2pd appears in UPnP forwardings list (default = I2Pd)
# name = I2Pd
[reseed]
## Enable or disable reseed data verification.
## 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
## 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

View file

@ -48,7 +48,7 @@ using dedicated user's permissions.
%build
cd build
%if 0%{?rhel} == 7
%if 0%{?rhel} == 7
%cmake3 \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
@ -133,7 +133,7 @@ getent passwd i2pd >/dev/null || \
- Fixed QT GUI issues
* Thu Aug 17 2017 orignal <i2porignal@yandex.ru> - 2.15.0
- Added QT GUI
- Added QT GUI
- Added ability add and remove I2P tunnels without restart
- Added ability to disable SOCKS outproxy option
- Changed strip-out Accept-* hedaers in HTTP proxy

View file

@ -123,7 +123,7 @@ namespace i2p
LogPrint(eLogInfo, "AESNI enabled");
#endif
#if defined(__AVX__)
LogPrint(eLogInfo, "AVX enabled");
LogPrint(eLogInfo, "AVX enabled");
#endif
LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir);

View file

@ -505,7 +505,7 @@ namespace http {
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
s << "<br>\r\n<b>Logging level</b><br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\">[none]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> ";

View file

@ -10,12 +10,12 @@
#include <sstream>
#include "HTTP.h"
namespace i2p
namespace i2p
{
namespace http
namespace http
{
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{
@ -23,7 +23,7 @@ namespace http
HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void Receive ();
private:
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -63,11 +63,11 @@ namespace http
private:
void Run ();
void Accept ();
void Accept ();
void HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
private:
bool m_IsRunning;

View file

@ -67,7 +67,7 @@ namespace client
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
// I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
// RouterInfo
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
@ -80,13 +80,13 @@ namespace client
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] =
&I2PControlService::TunnelsSuccessRateHandler;
&I2PControlService::TunnelsSuccessRateHandler;
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
// RouterManager
// RouterManager
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
// NetworkSetting
@ -133,8 +133,8 @@ namespace client
m_Service.run ();
} catch (std::exception& ex) {
LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ());
}
}
}
}
}
void I2PControlService::Accept ()
@ -160,7 +160,7 @@ namespace client
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
{
socket->async_handshake(boost::asio::ssl::stream_base::server,
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
}
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
@ -168,7 +168,7 @@ namespace client
if (ecode) {
LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ());
return;
}
}
//std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket);
}
@ -187,15 +187,15 @@ namespace client
}
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf)
{
if (ecode)
if (ecode)
{
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
return;
}
else
}
else
{
bool isHtml = !memcmp (buf->data (), "POST", 4);
try
@ -243,8 +243,8 @@ namespace client
response << "{\"id\":" << id << ",\"result\":{";
(this->*(it->second))(pt.get_child ("params"), response);
response << "},\"jsonrpc\":\"2.0\"}";
}
else
}
else
{
LogPrint (eLogWarning, "I2PControl: unknown method ", method);
response << "{\"id\":null,\"error\":";
@ -337,9 +337,9 @@ namespace client
InsertParam (results, "API", api);
results << ",";
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
m_Tokens.insert (token);
m_Tokens.insert (token);
InsertParam (results, "Token", token);
}
}
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{
@ -364,7 +364,7 @@ namespace client
}
else
LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first);
}
}
}
void I2PControlService::PasswordHandler (const std::string& value)
@ -394,28 +394,28 @@ namespace client
void I2PControlService::UptimeHandler (std::ostringstream& results)
{
InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000);
InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000);
}
void I2PControlService::VersionHandler (std::ostringstream& results)
{
InsertParam (results, "i2p.router.version", VERSION);
}
}
void I2PControlService::StatusHandler (std::ostringstream& results)
{
auto dest = i2p::client::context.GetSharedLocalDestination ();
InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
}
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
{
InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
}
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
{
InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
}
void I2PControlService::NetStatusHandler (std::ostringstream& results)
@ -463,11 +463,11 @@ namespace client
{
for (auto it = params.begin (); it != params.end (); it++)
{
if (it != params.begin ()) results << ",";
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
auto it1 = m_RouterManagerHandlers.find (it->first);
if (it1 != m_RouterManagerHandlers.end ()) {
(this->*(it1->second))(results);
(this->*(it1->second))(results);
} else
LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);
}
@ -516,7 +516,7 @@ namespace client
auto it1 = m_NetworkSettingHandlers.find (it->first);
if (it1 != m_NetworkSettingHandlers.end ()) {
if (it != params.begin ()) results << ",";
(this->*(it1->second))(it->second.data (), results);
(this->*(it1->second))(it->second.data (), results);
} else
LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
}
@ -538,7 +538,7 @@ namespace client
InsertParam (results, "i2p.router.net.bw.out", bw);
}
// certificate
// certificate
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
{
FILE *f = NULL;

View file

@ -10,7 +10,7 @@
#include <map>
#include <set>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp>
namespace i2p

View file

@ -42,13 +42,13 @@ namespace transport
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
private:
bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread;
std::condition_variable m_Started;
std::mutex m_StartedMutex;
std::condition_variable m_Started;
std::mutex m_StartedMutex;
boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer;
boost::asio::deadline_timer m_Timer;
struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData;

View file

@ -163,7 +163,7 @@ namespace i2p
sigaction(SIGABRT, &sa, 0);
sigaction(SIGTERM, &sa, 0);
sigaction(SIGINT, &sa, 0);
sigaction(SIGPIPE, &sa, 0);
sigaction(SIGPIPE, &sa, 0);
return Daemon_Singleton::start();
}

4
debian/changelog vendored
View file

@ -62,7 +62,7 @@ i2pd (2.10.0-1) unstable; urgency=low
* updated to version 2.10.0/0.9.27
* reseed.verify set to true by default
-- orignal <orignal@i2pmail.org> Sun, 16 Oct 2016 13:55:40 +0000
i2pd (2.9.0-1) unstable; urgency=low
@ -73,7 +73,7 @@ i2pd (2.9.0-1) unstable; urgency=low
* removed all port assigments in services files
* fixed logrotate
* subscriptions.txt and tunnels.conf taken from docs folder
-- orignal <orignal@i2pmail.org> Fri, 12 Aug 2016 14:25:40 +0000
i2pd (2.7.0-1) unstable; urgency=low

2
debian/i2pd.default vendored
View file

@ -7,5 +7,5 @@ I2PD_ENABLED="yes"
# see possible switches in /usr/share/doc/i2pd/configuration.md.gz
DAEMON_OPTS=""
# If you have problems with hunging i2pd, you can try enable this
# If you have problems with hunging i2pd, you can try enable this
ulimit -n 4096

View file

@ -1,12 +1,11 @@
diff --git a/Makefile b/Makefile
index bdadfe0..2f71eec 100644
--- a/Makefile
+++ b/Makefile
@@ -9,10 +9,10 @@ DEPS := obj/make.dep
include filelist.mk
-USE_AESNI := yes
+USE_AESNI := no
-USE_AVX := yes

View file

@ -43,8 +43,8 @@ namespace data
const char * GetBase64SubstitutionTable ()
{
return T64;
}
}
/*
* Reverse Substitution Table (built in run time)
*/
@ -53,10 +53,10 @@ namespace data
static int isFirstTime = 1;
/*
* Padding
* Padding
*/
static char P64 = '=';
static char P64 = '=';
/*
*
@ -68,11 +68,11 @@ namespace data
*/
size_t /* Number of bytes in the encoded buffer */
ByteStreamToBase64 (
ByteStreamToBase64 (
const uint8_t * InBuffer, /* Input buffer, binary data */
size_t InCount, /* Number of bytes in the input buffer */
size_t InCount, /* Number of bytes in the input buffer */
char * OutBuffer, /* output buffer */
size_t len /* length of output buffer */
size_t len /* length of output buffer */
)
{
@ -80,9 +80,9 @@ namespace data
unsigned char * pd;
unsigned char acc_1;
unsigned char acc_2;
int i;
int n;
int m;
int i;
int n;
int m;
size_t outCount;
ps = (unsigned char *)InBuffer;
@ -96,7 +96,7 @@ namespace data
pd = (unsigned char *)OutBuffer;
for ( i = 0; i<n; i++ ){
acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x30;
acc_2 = (acc_1<<4)&0x30;
acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1];
acc_1 = *ps++;
@ -109,7 +109,7 @@ namespace data
*pd++ = T64[acc_1];
acc_2 &= 0x3f; /* base64 digit #4 */
*pd++ = T64[acc_2];
}
}
if ( m == 1 ){
acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */
@ -122,7 +122,7 @@ namespace data
}
else if ( m == 2 ){
acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x3f;
acc_2 = (acc_1<<4)&0x3f;
acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1];
acc_1 = *ps++;
@ -133,7 +133,7 @@ namespace data
*pd++ = T64[acc_1];
*pd++ = P64;
}
return outCount;
}
@ -148,10 +148,10 @@ namespace data
*/
size_t /* Number of output bytes */
Base64ToByteStream (
Base64ToByteStream (
const char * InBuffer, /* BASE64 encoded buffer */
size_t InCount, /* Number of input bytes */
uint8_t * OutBuffer, /* output buffer length */
uint8_t * OutBuffer, /* output buffer length */
size_t len /* length of output buffer */
)
{
@ -159,28 +159,28 @@ namespace data
unsigned char * pd;
unsigned char acc_1;
unsigned char acc_2;
int i;
int n;
int m;
int i;
int n;
int m;
size_t outCount;
if (isFirstTime) iT64Build();
n = InCount/4;
m = InCount%4;
if (InCount && !m)
if (InCount && !m)
outCount = 3*n;
else {
outCount = 0;
return 0;
}
ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 ) outCount--;
ps = (unsigned char *)InBuffer;
if (outCount > len) return -1;
pd = OutBuffer;
auto endOfOutBuffer = OutBuffer + outCount;
auto endOfOutBuffer = OutBuffer + outCount;
for ( i = 0; i < n; i++ ){
acc_1 = iT64[*ps++];
acc_2 = iT64[*ps++];
@ -193,7 +193,7 @@ namespace data
acc_1 = iT64[*ps++];
acc_2 |= acc_1 >> 2;
*pd++ = acc_2;
if (pd >= endOfOutBuffer) break;
if (pd >= endOfOutBuffer) break;
acc_2 = iT64[*ps++];
acc_2 |= acc_1 << 6;
@ -203,13 +203,13 @@ namespace data
return outCount;
}
size_t Base64EncodingBufferSize (const size_t input_size)
size_t Base64EncodingBufferSize (const size_t input_size)
{
auto d = div (input_size, 3);
if (d.rem) d.quot++;
return 4*d.quot;
}
/*
*
* iT64
@ -228,20 +228,20 @@ namespace data
iT64[(int)P64] = 0;
}
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
{
int tmp = 0, bits = 0;
size_t ret = 0;
for (size_t i = 0; i < len; i++)
{
char ch = inBuf[i];
char ch = inBuf[i];
if (ch >= '2' && ch <= '7') // digit
ch = (ch - '2') + 26; // 26 means a-z
else if (ch >= 'a' && ch <= 'z')
ch = ch - 'a'; // a = 0
else
return 0; // unexpected character
tmp |= ch;
bits += 5;
if (bits >= 8)
@ -261,23 +261,23 @@ namespace data
size_t ret = 0, pos = 1;
int bits = 8, tmp = inBuf[0];
while (ret < outLen && (bits > 0 || pos < len))
{
{
if (bits < 5)
{
if (pos < len)
{
tmp <<= 8;
tmp |= inBuf[pos] & 0xFF;
tmp |= inBuf[pos] & 0xFF;
pos++;
bits += 8;
bits += 8;
}
else // last byte
{
tmp <<= (5 - bits);
bits = 5;
bits = 5;
}
}
}
bits -= 5;
int ind = (tmp >> bits) & 0x1F;
outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2');

View file

@ -10,8 +10,8 @@ namespace data {
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable ();
const char * GetBase64SubstitutionTable ();
const char * GetBase64SubstitutionTable ();
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);

View file

@ -79,10 +79,10 @@ namespace config {
}
template<typename T>
bool GetOption(const std::string& name, T& value)
bool GetOption(const std::string& name, T& value)
{
return GetOption (name.c_str (), value);
}
}
bool GetOptionAsAny(const char *name, boost::any& value);
bool GetOptionAsAny(const std::string& name, boost::any& value);

View file

@ -22,7 +22,7 @@ namespace crypto
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,

View file

@ -24,7 +24,7 @@ namespace crypto
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
// DSA
DSA * CreateDSA ();
DSA * CreateDSA ();
// RSA
const BIGNUM * GetRSAE ();
@ -33,20 +33,20 @@ namespace crypto
class DHKeys
{
public:
DHKeys ();
~DHKeys ();
void GenerateKeys ();
const uint8_t * GetPublicKey () const { return m_PublicKey; };
void Agree (const uint8_t * pub, uint8_t * shared);
private:
DH * m_DH;
uint8_t m_PublicKey[256];
};
};
// ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false);
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
@ -54,15 +54,15 @@ namespace crypto
// ECIES
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 514 bytes encrypted
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
// HMAC
typedef i2p::data::Tag<32> MACKey;
typedef i2p::data::Tag<32> MACKey;
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest);
// AES
struct ChipherBlock
struct ChipherBlock
{
uint8_t buf[16];
@ -71,40 +71,40 @@ namespace crypto
#if defined(__AVX__) // AVX
__asm__
(
"vmovups (%[buf]), %%xmm0 \n"
"vmovups (%[other]), %%xmm1 \n"
"vmovups (%[buf]), %%xmm0 \n"
"vmovups (%[other]), %%xmm1 \n"
"vxorps %%xmm0, %%xmm1, %%xmm0 \n"
"vmovups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
"vmovups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory"
);
);
#elif defined(__SSE__) // SSE
__asm__
(
"movups (%[buf]), %%xmm0 \n"
"movups (%[other]), %%xmm1 \n"
"movups (%[buf]), %%xmm0 \n"
"movups (%[other]), %%xmm1 \n"
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
:
: [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory"
);
);
#else
// TODO: implement it better
for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i];
#endif
}
}
};
typedef i2p::data::Tag<32> AESKey;
template<size_t sz>
class AESAlignedBuffer // 16 bytes alignment
{
public:
AESAlignedBuffer ()
{
m_Buf = m_UnalignedBuffer;
@ -112,22 +112,22 @@ namespace crypto
if (rem)
m_Buf += (16 - rem);
}
operator uint8_t * () { return m_Buf; };
operator const uint8_t * () const { return m_Buf; };
ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; };
const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; };
private:
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
uint8_t * m_Buf;
};
};
#ifdef AESNI
class ECBCryptoAESNI
{
{
public:
uint8_t * GetKeySchedule () { return m_KeySchedule; };
@ -135,27 +135,27 @@ namespace crypto
protected:
void ExpandKey (const AESKey& key);
private:
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
};
};
class ECBEncryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const AESKey& key) { ExpandKey (key); };
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
};
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
};
class ECBDecryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const AESKey& key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
};
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
};
typedef ECBEncryptionAESNI ECBEncryption;
typedef ECBDecryptionAESNI ECBDecryption;
@ -165,46 +165,46 @@ namespace crypto
class ECBEncryption
{
public:
void SetKey (const AESKey& key)
{
void SetKey (const AESKey& key)
{
AES_set_encrypt_key (key, 256, &m_Key);
}
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
{
AES_encrypt (in->buf, out->buf, &m_Key);
}
}
private:
AES_KEY m_Key;
};
};
class ECBDecryption
{
public:
void SetKey (const AESKey& key)
{
AES_set_decrypt_key (key, 256, &m_Key);
void SetKey (const AESKey& key)
{
AES_set_decrypt_key (key, 256, &m_Key);
}
void Decrypt (const ChipherBlock * in, ChipherBlock * out)
{
AES_decrypt (in->buf, out->buf, &m_Key);
}
}
private:
AES_KEY m_Key;
};
};
#endif
#endif
class CBCEncryption
{
public:
CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); };
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
@ -217,14 +217,14 @@ namespace crypto
private:
AESAlignedBuffer<16> m_LastBlock;
ECBEncryption m_ECBEncryption;
};
class CBCDecryption
{
public:
CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); };
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
@ -238,7 +238,7 @@ namespace crypto
AESAlignedBuffer<16> m_IV;
ECBDecryption m_ECBDecryption;
};
};
class TunnelEncryption // with double IV encryption
{
@ -248,9 +248,9 @@ namespace crypto
{
m_LayerEncryption.SetKey (layerKey);
m_IVEncryption.SetKey (ivKey);
}
}
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
private:
@ -270,9 +270,9 @@ namespace crypto
{
m_LayerDecryption.SetKey (layerKey);
m_IVDecryption.SetKey (ivKey);
}
}
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
private:
@ -282,72 +282,72 @@ namespace crypto
#else
CBCDecryption m_LayerDecryption;
#endif
};
};
void InitCrypto (bool precomputation);
void TerminateCrypto ();
}
}
}
}
// take care about openssl version
#include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL
// 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)
{
if (d->p) BN_free (d->p);
if (d->q) BN_free (d->q);
if (d->g) BN_free (d->g);
d->p = p; d->q = q; d->g = g; return 1;
d->p = p; d->q = q; d->g = g; return 1;
}
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{
if (d->pub_key) BN_free (d->pub_key);
if (d->priv_key) BN_free (d->priv_key);
d->pub_key = pub_key; d->priv_key = priv_key; return 1;
}
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
d->pub_key = pub_key; d->priv_key = priv_key; return 1;
}
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = d->pub_key; *priv_key = d->priv_key; }
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
if (sig->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s);
sig->r = r; sig->s = s; return 1;
sig->r = r; sig->s = s; return 1;
}
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; }
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{
{
if (sig->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s);
sig->r = r; sig->s = s; return 1;
sig->r = r; sig->s = s; return 1;
}
inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; }
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
if (r->n) BN_free (r->n);
if (r->e) BN_free (r->e);
if (r->d) BN_free (r->d);
r->n = n; r->e = e; r->d = d; return 1;
r->n = n; r->e = e; r->d = d; return 1;
}
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{ *n = r->n; *e = r->e; *d = r->d; }
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
{
if (dh->p) BN_free (dh->p);
if (dh->q) BN_free (dh->q);
if (dh->g) BN_free (dh->g);
dh->p = p; dh->q = q; dh->g = g; return 1;
dh->p = p; dh->q = q; dh->g = g; return 1;
}
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{
if (dh->pub_key) BN_free (dh->pub_key);
{
if (dh->pub_key) BN_free (dh->pub_key);
if (dh->priv_key) BN_free (dh->priv_key);
dh->pub_key = pub_key; dh->priv_key = priv_key; return 1;
dh->pub_key = pub_key; dh->priv_key = priv_key; return 1;
}
inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; }

View file

@ -72,7 +72,7 @@ namespace crypto
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub)
{
EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1);
EC_POINT * p = nullptr;
EC_POINT * p = nullptr;
BIGNUM * key = nullptr;
GenerateECIESKeyPair (curve, key, p);
bn2buf (key, priv, 32);
@ -81,11 +81,11 @@ namespace crypto
BIGNUM * x = BN_new (), * y = BN_new ();
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL);
bn2buf (x, pub, 32);
bn2buf (y, pub + 32, 32);
bn2buf (y, pub + 32, 32);
RAND_bytes (pub + 64, 192);
EC_POINT_free (p);
EC_POINT_free (p);
BN_free (x); BN_free (y);
EC_GROUP_free (curve);
EC_GROUP_free (curve);
}
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub)
@ -131,7 +131,7 @@ namespace crypto
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub)
{
auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA);
EC_POINT * p = nullptr;
EC_POINT * p = nullptr;
BIGNUM * key = nullptr;
GenerateECIESKeyPair (curve->GetGroup (), key, p);
bn2buf (key, priv, 32);
@ -140,9 +140,9 @@ namespace crypto
BIGNUM * x = BN_new (), * y = BN_new ();
EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL);
bn2buf (x, pub, 32);
bn2buf (y, pub + 32, 32);
bn2buf (y, pub + 32, 32);
RAND_bytes (pub + 64, 192);
EC_POINT_free (p);
EC_POINT_free (p);
BN_free (x); BN_free (y);
}

View file

@ -8,15 +8,15 @@ namespace i2p
{
namespace crypto
{
class CryptoKeyEncryptor
class CryptoKeyEncryptor
{
public:
virtual ~CryptoKeyEncryptor () {};
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted
};
};
class CryptoKeyDecryptor
class CryptoKeyDecryptor
{
public:
@ -30,7 +30,7 @@ namespace crypto
public:
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);
private:
@ -42,7 +42,7 @@ namespace crypto
public:
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);
private:
@ -51,13 +51,13 @@ namespace crypto
// ECIES P256
class ECIESP256Encryptor: public CryptoKeyEncryptor
class ECIESP256Encryptor: public CryptoKeyEncryptor
{
public:
ECIESP256Encryptor (const uint8_t * pub);
~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);
private:
@ -72,7 +72,7 @@ namespace crypto
ECIESP256Decryptor (const uint8_t * priv);
~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);
private:
@ -80,17 +80,17 @@ namespace crypto
BIGNUM * m_PrivateKey;
};
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub);
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub);
// ECIES GOST R 34.10
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor
{
public:
ECIESGOSTR3410Encryptor (const uint8_t * pub);
~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);
private:
@ -104,7 +104,7 @@ namespace crypto
ECIESGOSTR3410Decryptor (const uint8_t * priv);
~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);
private:

View file

@ -11,20 +11,20 @@ namespace i2p
{
namespace datagram
{
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner):
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner):
m_Owner (owner.get()),
m_Receiver (nullptr)
{
m_Identity.FromBase64 (owner->GetIdentity()->ToBase64());
}
DatagramDestination::~DatagramDestination ()
{
m_Sessions.clear();
}
void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
{
{
auto owner = m_Owner;
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
uint8_t * buf = v.data();
@ -33,11 +33,11 @@ namespace datagram
auto signatureLen = m_Identity.GetSignatureLen ();
uint8_t * buf1 = signature + signatureLen;
size_t headerLen = identityLen + signatureLen;
memcpy (buf1, payload, len);
memcpy (buf1, payload, len);
if (m_Identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{
uint8_t hash[32];
uint8_t hash[32];
SHA256(buf1, len, hash);
owner->Sign (hash, 32, signature);
}
@ -63,10 +63,10 @@ namespace datagram
uint8_t hash[32];
SHA256(buf + headerLen, len - headerLen, hash);
verified = identity.Verify (hash, 32, signature);
}
else
}
else
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
if (verified)
{
auto h = identity.GetIdentHash();
@ -79,7 +79,7 @@ namespace datagram
LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort);
}
else
LogPrint (eLogWarning, "Datagram signature verification failed");
LogPrint (eLogWarning, "Datagram signature verification failed");
}
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
@ -113,24 +113,24 @@ namespace datagram
{
htobe32buf (msg->GetPayload (), size); // length
htobe16buf (buf + 4, fromPort); // source port
htobe16buf (buf + 6, toPort); // destination port
htobe16buf (buf + 6, toPort); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
msg->len += size + 4;
msg->len += size + 4;
msg->FillI2NPMessageHeader (eI2NPData);
}
}
else
msg = nullptr;
return msg;
}
void DatagramDestination::CleanUp ()
{
{
if (m_Sessions.empty ()) return;
auto now = i2p::util::GetMillisecondsSinceEpoch();
LogPrint(eLogDebug, "DatagramDestination: clean up sessions");
std::unique_lock<std::mutex> lock(m_SessionsMutex);
// for each session ...
for (auto it = m_Sessions.begin (); it != m_Sessions.end (); )
for (auto it = m_Sessions.begin (); it != m_Sessions.end (); )
{
// check if expired
if (now - it->second->LastActivity() >= DATAGRAM_SESSION_MAX_IDLE)
@ -143,7 +143,7 @@ namespace datagram
it++;
}
}
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity)
{
std::shared_ptr<DatagramSession> session = nullptr;
@ -169,7 +169,7 @@ namespace datagram
}
return nullptr;
}
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
const i2p::data::IdentHash & remoteIdent) :
m_LocalDestination(localDestination),
@ -203,7 +203,7 @@ namespace datagram
{
if(!m_RoutingSession)
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
if (!routingPath)
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
@ -318,7 +318,7 @@ namespace datagram
m_RoutingSession->SetSharedRoutingPath(path);
}
return path;
}
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)

View file

@ -106,7 +106,7 @@ namespace datagram
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
~DatagramDestination ();
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };

View file

@ -24,9 +24,9 @@ namespace client
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
int numTags = DEFAULT_TAGS_TO_SEND;
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
try
try
{
if (params)
if (params)
{
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
if (it != params->end ())
@ -59,10 +59,16 @@ namespace client
}
}
it = params->find (I2CP_PARAM_INBOUND_NICKNAME);
if (it != params->end ()) m_Nickname = it->second; // otherwise we set deafult nickname in Start when we know local address
if (it != params->end ()) m_Nickname = it->second;
else // try outbound
{
it = params->find (I2CP_PARAM_OUTBOUND_NICKNAME);
if (it != params->end ()) m_Nickname = it->second;
// otherwise we set deafult nickname in Start when we know local address
}
}
}
catch (std::exception & ex)
}
catch (std::exception & ex)
{
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
}
@ -486,7 +492,7 @@ namespace client
m_PublishReplyToken = 0;
if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
{
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
Publish ();
}
else
@ -497,7 +503,7 @@ namespace client
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1));
}
}
}
@ -722,14 +728,14 @@ namespace client
if (isPublic)
PersistTemporaryKeys ();
else
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey);
m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey);
if (isPublic)
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
// extract streaming params
if (params)
if (params)
{
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
if (it != params->end ())
@ -774,7 +780,7 @@ namespace client
delete m_DatagramDestination;
m_DatagramDestination = nullptr;
}
return true;
return true;
}
else
return false;
@ -950,7 +956,7 @@ namespace client
}
LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
m_EncryptionPrivateKey, m_EncryptionPublicKey);
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);

View file

@ -51,6 +51,7 @@ namespace client
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
const int DEFAULT_TAGS_TO_SEND = 40;
const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname";
const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname";
// latency
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
@ -189,9 +190,9 @@ namespace client
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
// ref counter
int Acquire () { return ++m_RefCounter; };
int Acquire () { return ++m_RefCounter; };
int Release () { return --m_RefCounter; };
int GetRefCounter () const { return m_RefCounter; };
int GetRefCounter () const { return m_RefCounter; };
// streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
@ -238,7 +239,7 @@ namespace client
int m_StreamingAckDelay;
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
i2p::datagram::DatagramDestination * m_DatagramDestination;
i2p::datagram::DatagramDestination * m_DatagramDestination;
int m_RefCounter; // how many clients(tunnels) use this destination
boost::asio::deadline_timer m_ReadyChecker;

View file

@ -30,7 +30,7 @@ namespace i2p
}
m_collected[key].Val += val;
}
void EventCore::PumpCollected(EventListener * listener)
{
std::unique_lock<std::mutex> lock(m_collect_mutex);

View file

@ -29,7 +29,7 @@ namespace i2p
void CollectEvent(const std::string & type, const std::string & ident, uint64_t val);
void SetListener(EventListener * l);
void PumpCollected(EventListener * l);
private:
std::mutex m_collect_mutex;
struct CollectedEvent
@ -41,7 +41,7 @@ namespace i2p
std::map<std::string, CollectedEvent> m_collected;
EventListener * m_listener = nullptr;
};
#ifdef WITH_EVENTS
#ifdef WITH_EVENTS
extern EventCore core;
#endif
}

View file

@ -68,7 +68,7 @@ namespace fs {
#else /* other unix */
#if defined(ANDROID)
const char * ext = getenv("EXTERNAL_STORAGE");
if (!ext) ext = "/sdcard";
if (!ext) ext = "/sdcard";
if (boost::filesystem::exists(ext))
{
dataDir = std::string (ext) + "/" + appName;
@ -96,7 +96,7 @@ namespace fs {
boost::filesystem::create_directory(destinations);
std::string tags = DataDirPath("tags");
if (!boost::filesystem::exists(tags))
boost::filesystem::create_directory(tags);
boost::filesystem::create_directory(tags);
else
i2p::garlic::CleanUpTagsFiles ();
@ -123,12 +123,12 @@ namespace fs {
}
uint32_t GetLastUpdateTime (const std::string & path)
{
{
if (!boost::filesystem::exists(path)) return 0;
boost::system::error_code ec;
auto t = boost::filesystem::last_write_time (path, ec);
return ec ? 0 : t;
}
}
bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path))
@ -136,7 +136,7 @@ namespace fs {
return boost::filesystem::remove(path);
}
bool CreateDirectory (const std::string& path)
bool CreateDirectory (const std::string& path)
{
if (boost::filesystem::exists(path) &&
boost::filesystem::is_directory (boost::filesystem::status (path))) return true;

View file

@ -97,7 +97,7 @@ namespace fs {
* @param files Vector to store found files
* @return true on success and false if directory not exists
*/
bool ReadDir(const std::string & path, std::vector<std::string> & files);
bool ReadDir(const std::string & path, std::vector<std::string> & files);
/**
* @brief Remove file with given path
@ -113,9 +113,9 @@ namespace fs {
*/
bool Exists(const std::string & path);
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
bool CreateDirectory (const std::string& path);
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
bool CreateDirectory (const std::string& path);
template<typename T>
void _ExpandPath(std::stringstream & path, T c) {
@ -153,7 +153,7 @@ namespace fs {
_ExpandPath(s, filenames...);
return s.str();
}
}
} // fs
} // i2p

View file

@ -21,24 +21,24 @@ namespace data
void Families::LoadCertificate (const std::string& filename)
{
SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret)
{
{
SSL * ssl = SSL_new (ctx);
X509 * cert = SSL_get_certificate (ssl);
if (cert)
{
{
std::shared_ptr<i2p::crypto::Verifier> verifier;
// extract issuer name
char name[100];
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
char * cn = strstr (name, "CN=");
if (cn)
{
{
cn += 3;
char * family = strstr (cn, ".family");
if (family) family[0] = 0;
}
}
auto pkey = X509_get_pubkey (cert);
int keyType = EVP_PKEY_base_id (pkey);
switch (keyType)
@ -65,7 +65,7 @@ namespace data
i2p::crypto::bn2buf (y, signingKey + 32, 32);
BN_free (x); BN_free (y);
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(signingKey);
}
}
else
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
}
@ -79,12 +79,12 @@ namespace data
EVP_PKEY_free (pkey);
if (verifier && cn)
m_SigningKeys[cn] = verifier;
}
SSL_free (ssl);
}
}
SSL_free (ssl);
}
else
LogPrint (eLogError, "Family: Can't open certificate file ", filename);
SSL_CTX_free (ctx);
SSL_CTX_free (ctx);
}
void Families::LoadCertificates ()
@ -105,11 +105,11 @@ namespace data
}
LoadCertificate (file);
numCertificates++;
}
}
LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
}
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key)
{
uint8_t buf[50], signatureBuf[64];
@ -118,12 +118,12 @@ namespace data
{
LogPrint (eLogError, "Family: ", family, " is too long");
return false;
}
}
memcpy (buf, family.c_str (), len);
memcpy (buf + len, (const uint8_t *)ident, 32);
len += 32;
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
len += 32;
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ())
return it->second->Verify (buf, len, signatureBuf);
@ -136,7 +136,7 @@ namespace data
auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
std::string sig;
SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret)
{
SSL * ssl = SSL_new (ctx);
@ -167,15 +167,15 @@ namespace data
}
else
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
}
}
SSL_free (ssl);
}
}
}
SSL_free (ssl);
}
else
LogPrint (eLogError, "Family: Can't open keys file: ", filename);
SSL_CTX_free (ctx);
SSL_CTX_free (ctx);
return sig;
}
}
}
}

View file

@ -18,7 +18,7 @@ namespace data
Families ();
~Families ();
void LoadCertificates ();
bool VerifyFamily (const std::string& family, const IdentHash& ident,
bool VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key = nullptr);
private:
@ -28,7 +28,7 @@ namespace data
private:
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
};
};
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
// return base64 signature of empty string in case of failure

View file

@ -17,16 +17,16 @@ namespace i2p
{
namespace garlic
{
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
m_LeaseSetUpdateMsgID (0)
{
// create new session tags and session key
RAND_bytes (m_SessionKey, 32);
m_Encryption.SetKey (m_SessionKey);
}
}
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
@ -35,10 +35,10 @@ namespace garlic
m_Encryption.SetKey (m_SessionKey);
m_SessionTags.push_back (sessionTag);
m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch ();
}
}
GarlicRoutingSession::~GarlicRoutingSession ()
{
{
}
std::shared_ptr<GarlicRoutingPath> GarlicRoutingSession::GetSharedRoutingPath ()
@ -53,56 +53,56 @@ namespace garlic
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
return m_SharedRoutingPath;
}
void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path)
{
if (path && path->outboundTunnel && path->remoteLease)
{
{
if (path && path->outboundTunnel && path->remoteLease)
{
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
path->numTimesUsed = 0;
}
}
else
path = nullptr;
m_SharedRoutingPath = path;
}
GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags ()
{
auto tags = new UnconfirmedTags (m_NumTags);
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
for (int i = 0; i < m_NumTags; i++)
{
RAND_bytes (tags->sessionTags[i], 32);
tags->sessionTags[i].creationTime = tags->tagsCreationTime;
}
return tags;
}
return tags;
}
void GarlicRoutingSession::MessageConfirmed (uint32_t msgID)
{
TagsConfirmed (msgID);
if (msgID == m_LeaseSetUpdateMsgID)
{
{
m_LeaseSetUpdateStatus = eLeaseSetUpToDate;
m_LeaseSetUpdateMsgID = 0;
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
}
}
else
CleanupExpiredTags ();
}
void GarlicRoutingSession::TagsConfirmed (uint32_t msgID)
{
}
void GarlicRoutingSession::TagsConfirmed (uint32_t msgID)
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
auto it = m_UnconfirmedTagsMsgs.find (msgID);
if (it != m_UnconfirmedTagsMsgs.end ())
{
auto& tags = it->second;
if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
{
{
for (int i = 0; i < tags->numTags; i++)
m_SessionTags.push_back (tags->sessionTags[i]);
}
}
m_UnconfirmedTagsMsgs.erase (it);
}
}
@ -114,7 +114,7 @@ namespace garlic
{
if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
it = m_SessionTags.erase (it);
else
else
++it;
}
CleanupUnconfirmedTags ();
@ -123,9 +123,9 @@ namespace garlic
if (m_Owner)
m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
m_LeaseSetUpdateMsgID = 0;
}
}
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
}
}
bool GarlicRoutingSession::CleanupUnconfirmedTags ()
{
@ -140,10 +140,10 @@ namespace garlic
m_Owner->RemoveDeliveryStatusSession (it->first);
it = m_UnconfirmedTagsMsgs.erase (it);
ret = true;
}
}
else
++it;
}
}
return ret;
}
@ -155,10 +155,10 @@ namespace garlic
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
// find non-expired tag
bool tagFound = false;
SessionTag tag;
bool tagFound = false;
SessionTag tag;
if (m_NumTags > 0)
{
{
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
while (!m_SessionTags.empty ())
{
@ -168,11 +168,11 @@ namespace garlic
m_SessionTags.pop_front (); // use same tag only once
tagFound = true;
break;
}
}
else
m_SessionTags.pop_front (); // remove expired tag
}
}
}
// create message
if (!tagFound) // new session
{
@ -184,34 +184,34 @@ namespace garlic
}
// create ElGamal block
ElGamalBlock elGamal;
memcpy (elGamal.sessionKey, m_SessionKey, 32);
memcpy (elGamal.sessionKey, m_SessionKey, 32);
RAND_bytes (elGamal.preIV, 32); // Pre-IV
uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv);
SHA256(elGamal.preIV, 32, iv);
BN_CTX * ctx = BN_CTX_new ();
m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx);
BN_CTX_free (ctx);
m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx);
BN_CTX_free (ctx);
m_Encryption.SetIV (iv);
buf += 514;
len += 514;
len += 514;
}
else // existing session
{
{
// session tag
memcpy (buf, tag, 32);
memcpy (buf, tag, 32);
uint8_t iv[32]; // IV is first 16 bytes
SHA256(tag, 32, iv);
m_Encryption.SetIV (iv);
buf += 32;
len += 32;
}
len += 32;
}
// AES block
len += CreateAESBlock (buf, msg);
htobe32buf (m->GetPayload (), len);
m->len += len + 4;
m->FillI2NPMessageHeader (eI2NPGarlic);
return m;
}
}
size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg)
{
@ -221,13 +221,13 @@ namespace garlic
htobuf16 (buf, newTags ? htobe16 (newTags->numTags) : 0); // tag count
blockSize += 2;
if (newTags) // session tags recreated
{
{
for (int i = 0; i < newTags->numTags; i++)
{
memcpy (buf + blockSize, newTags->sessionTags[i], 32); // tags
blockSize += 32;
}
}
}
uint32_t * payloadSize = (uint32_t *)(buf + blockSize);
blockSize += 4;
uint8_t * payloadHash = buf + blockSize;
@ -243,7 +243,7 @@ namespace garlic
blockSize += (16-rem); //padding
m_Encryption.Encrypt(buf, blockSize, buf);
return blockSize;
}
}
size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags)
{
@ -256,7 +256,7 @@ namespace garlic
size++;
if (m_Owner)
{
{
// resubmit non-confirmed LeaseSet
if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
{
@ -267,7 +267,7 @@ namespace garlic
// attach DeviveryStatus if necessary
if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated
{
// clove is DeliveryStatus
// clove is DeliveryStatus
auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID);
if (cloveSize > 0) // successive?
{
@ -278,14 +278,14 @@ namespace garlic
newTags->msgID = msgID;
m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags)));
newTags = nullptr; // got acquired
}
}
m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
}
else
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
}
}
// attach LeaseSet
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
{
if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous
m_LeaseSetUpdateStatus = eLeaseSetSubmitted;
@ -293,25 +293,25 @@ namespace garlic
m_LeaseSetSubmissionTime = ts;
// clove if our leaseSet must be attached
auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ());
size += CreateGarlicClove (payload + size, leaseSet, false);
size += CreateGarlicClove (payload + size, leaseSet, false);
(*numCloves)++;
}
}
}
if (msg) // clove message ifself if presented
{
{
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
(*numCloves)++;
}
}
memset (payload + size, 0, 3); // certificate of message
size += 3;
htobe32buf (payload + size, msgID); // MessageID
size += 4;
htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec
size += 8;
if (newTags) delete newTags; // not acquired, delete
if (newTags) delete newTags; // not acquired, delete
return size;
}
}
size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination)
{
@ -323,13 +323,13 @@ namespace garlic
size++;
memcpy (buf + size, m_Destination->GetIdentHash (), 32);
size += 32;
}
else
{
}
else
{
buf[size] = 0;// delivery instructions flag local
size++;
}
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength ();
uint32_t cloveID;
@ -341,34 +341,34 @@ namespace garlic
memset (buf + size, 0, 3); // certificate of clove
size += 3;
return size;
}
}
size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID)
{
{
size_t size = 0;
if (m_Owner)
{
auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel ();
if (inboundTunnel)
{
{
buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel
size++;
// hash and tunnelID sequence is reversed for Garlic
// hash and tunnelID sequence is reversed for Garlic
memcpy (buf + size, inboundTunnel->GetNextIdentHash (), 32); // To Hash
size += 32;
htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
size += 4;
// create msg
size += 4;
// create msg
auto msg = CreateDeliveryStatusMsg (msgID);
if (m_Owner)
{
//encrypt
//encrypt
uint8_t key[32], tag[32];
RAND_bytes (key, 32); // random session key
RAND_bytes (key, 32); // random session key
RAND_bytes (tag, 32); // random session tag
m_Owner->SubmitSessionKey (key, tag);
GarlicRoutingSession garlic (key, tag);
msg = garlic.WrapSingleMessage (msg);
msg = garlic.WrapSingleMessage (msg);
}
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength ();
@ -383,7 +383,7 @@ namespace garlic
memset (buf + size, 0, 3); // certificate of clove
size += 3;
}
else
else
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
}
else
@ -395,19 +395,19 @@ namespace garlic
GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default
{
m_Ctx = BN_CTX_new ();
}
}
GarlicDestination::~GarlicDestination ()
{
BN_CTX_free (m_Ctx);
}
void GarlicDestination::CleanUp ()
{
{
m_Sessions.clear ();
m_DeliveryStatusSessions.clear ();
m_Tags.clear ();
}
}
void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
{
if (key)
@ -417,7 +417,7 @@ namespace garlic
}
}
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{
AddSessionKey (key, tag);
return true;
@ -431,22 +431,22 @@ namespace garlic
{
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
return;
}
}
buf += 4; // length
auto it = m_Tags.find (SessionTag(buf));
if (it != m_Tags.end ())
{
// tag found. Use AES
auto decryption = it->second;
m_Tags.erase (it); // tag might be used only once
m_Tags.erase (it); // tag might be used only once
if (length >= 32)
{
{
uint8_t iv[32]; // IV is first 16 bytes
SHA256(buf, 32, iv);
decryption->SetIV (iv);
decryption->Decrypt (buf + 32, length - 32, buf + 32);
HandleAESBlock (buf + 32, length - 32, decryption, msg->from);
}
}
else
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
}
@ -455,35 +455,35 @@ namespace garlic
// tag not found. Use ElGamal
ElGamalBlock elGamal;
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
{
{
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv);
SHA256(elGamal.preIV, 32, iv);
decryption->SetIV (iv);
decryption->Decrypt(buf + 514, length - 514, buf + 514);
HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
}
}
else
LogPrint (eLogError, "Garlic: Failed to decrypt message");
}
}
}
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{
uint16_t tagCount = bufbe16toh (buf);
buf += 2; len -= 2;
buf += 2; len -= 2;
if (tagCount > 0)
{
if (tagCount*32 > len)
{
if (tagCount*32 > len)
{
LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len);
return ;
}
}
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (int i = 0; i < tagCount; i++)
m_Tags[SessionTag(buf + i*32, ts)] = decryption;
}
m_Tags[SessionTag(buf + i*32, ts)] = decryption;
}
buf += tagCount*32;
len -= tagCount*32;
uint32_t payloadSize = bufbe32toh (buf);
@ -491,10 +491,10 @@ namespace garlic
{
LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize);
return;
}
}
buf += 4;
uint8_t * payloadHash = buf;
buf += 32;// payload hash.
buf += 32;// payload hash.
if (*buf) // session key?
buf += 32; // new session key
buf++; // flag
@ -506,9 +506,9 @@ namespace garlic
{
LogPrint (eLogError, "Garlic: wrong payload hash");
return;
}
}
HandleGarlicPayload (buf, payloadSize, from);
}
}
void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{
@ -530,8 +530,8 @@ namespace garlic
{
// TODO: implement
LogPrint (eLogWarning, "Garlic: clove encrypted");
buf += 32;
}
buf += 32;
}
ptrdiff_t offset = buf - buf1;
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
switch (deliveryType)
@ -542,27 +542,27 @@ namespace garlic
{
LogPrint (eLogError, "Garlic: message is too short");
break;
}
}
HandleI2NPMessage (buf, len - offset, from);
break;
case eGarlicDeliveryTypeDestination:
break;
case eGarlicDeliveryTypeDestination:
LogPrint (eLogDebug, "Garlic: type destination");
buf += 32; // destination. check it later or for multiple destinations
offset = buf1 - buf;
offset = buf - buf1;
if (offset > (int)len)
{
LogPrint (eLogError, "Garlic: message is too short");
break;
}
HandleI2NPMessage (buf, len - offset, from);
}
HandleI2NPMessage (buf, len - offset, from);
break;
case eGarlicDeliveryTypeTunnel:
{
{
LogPrint (eLogDebug, "Garlic: type tunnel");
// gwHash and gwTunnel sequence is reverted
uint8_t * gwHash = buf;
buf += 32;
offset = buf1 - buf;
offset = buf - buf1;
if (offset + 4 > (int)len)
{
LogPrint (eLogError, "Garlic: message is too short");
@ -591,7 +591,7 @@ namespace garlic
{
uint8_t * ident = buf;
buf += 32;
offset = buf1 - buf;
offset = buf - buf1;
if (!from) // received directly
{
if (offset > (int)len)
@ -604,7 +604,7 @@ namespace garlic
}
else
LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported");
break;
break;
}
default:
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
@ -618,28 +618,28 @@ namespace garlic
buf += 4; // CloveID
buf += 8; // Date
buf += 3; // Certificate
offset = buf1 - buf;
offset = buf - buf1;
if (offset > (int)len)
{
LogPrint (eLogError, "Garlic: clove is too long");
break;
}
}
len -= offset;
}
}
std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet)
}
}
std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet)
{
auto session = GetRoutingSession (destination, attachLeaseSet);
return session->WrapSingleMessage (msg);
auto session = GetRoutingSession (destination, attachLeaseSet);
return session->WrapSingleMessage (msg);
}
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
{
GarlicRoutingSessionPtr session;
{
{
std::unique_lock<std::mutex> l(m_SessionsMutex);
auto it = m_Sessions.find (destination->GetIdentHash ());
if (it != m_Sessions.end ())
@ -647,14 +647,14 @@ namespace garlic
}
if (!session)
{
session = std::make_shared<GarlicRoutingSession> (this, destination,
session = std::make_shared<GarlicRoutingSession> (this, destination,
attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests
std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[destination->GetIdentHash ()] = session;
}
}
return session;
}
}
void GarlicDestination::CleanupExpiredTags ()
{
// incoming
@ -666,7 +666,7 @@ namespace garlic
{
numExpiredTags++;
it = m_Tags.erase (it);
}
}
else
++it;
}
@ -690,7 +690,7 @@ namespace garlic
}
}
// delivery status sessions
{
{
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
for (auto it = m_DeliveryStatusSessions.begin (); it != m_DeliveryStatusSessions.end (); )
{
@ -699,7 +699,7 @@ namespace garlic
else
++it;
}
}
}
}
void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID)
@ -756,7 +756,7 @@ namespace garlic
if (m_Tags.empty ()) return;
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc);
std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc);
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
// 4 bytes timestamp, 32 bytes tag, 32 bytes key
for (auto it: m_Tags)
@ -766,7 +766,7 @@ namespace garlic
f.write ((char *)&it.first.creationTime, 4);
f.write ((char *)it.first.data (), 32);
f.write ((char *)it.second->GetKey ().data (), 32);
}
}
}
}
@ -775,11 +775,11 @@ namespace garlic
std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{
// might contain non-expired tags
std::ifstream f (path, std::ifstream::binary);
if (f)
if (f)
{
std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys;
// 4 bytes timestamp, 32 bytes tag, 32 bytes key
@ -794,7 +794,7 @@ namespace garlic
f.read ((char *)key, 32);
}
else
f.seekg (64, std::ios::cur); // skip
f.seekg (64, std::ios::cur); // skip
if (f.eof ()) break;
std::shared_ptr<AESDecryption> decryption;
@ -805,21 +805,21 @@ namespace garlic
decryption = std::make_shared<AESDecryption>(key);
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
}
if (!m_Tags.empty ())
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
if (!m_Tags.empty ())
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
}
}
i2p::fs::Remove (path);
i2p::fs::Remove (path);
}
void CleanUpTagsFiles ()
{
std::vector<std::string> files;
std::vector<std::string> files;
i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files);
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: files)
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
i2p::fs::Remove (it);
}
}
}
}

View file

@ -17,46 +17,46 @@
namespace i2p
{
namespace tunnel
{
{
class OutboundTunnel;
}
namespace garlic
{
enum GarlicDeliveryType
{
eGarlicDeliveryTypeLocal = 0,
enum GarlicDeliveryType
{
eGarlicDeliveryTypeLocal = 0,
eGarlicDeliveryTypeDestination = 1,
eGarlicDeliveryTypeRouter = 2,
eGarlicDeliveryTypeRouter = 2,
eGarlicDeliveryTypeTunnel = 3
};
};
struct ElGamalBlock
{
uint8_t sessionKey[32];
uint8_t preIV[32];
uint8_t padding[158];
};
};
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
struct SessionTag: public i2p::data::Tag<32>
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
struct SessionTag: public i2p::data::Tag<32>
{
SessionTag (const uint8_t * buf, uint32_t ts = 0): Tag<32>(buf), creationTime (ts) {};
SessionTag () = default;
SessionTag (const SessionTag& ) = default;
SessionTag& operator= (const SessionTag& ) = default;
#ifndef _WIN32
SessionTag (SessionTag&& ) = default;
SessionTag& operator= (SessionTag&& ) = default;
SessionTag (SessionTag&& ) = default;
SessionTag& operator= (SessionTag&& ) = default;
#endif
uint32_t creationTime; // seconds since epoch
uint32_t creationTime; // seconds since epoch
};
// AESDecryption is associated with session tags and store key
@ -67,7 +67,7 @@ namespace garlic
AESDecryption (const uint8_t * key): m_Key (key)
{
SetKey (key);
}
}
const i2p::crypto::AESKey& GetKey () const { return m_Key; };
private:
@ -81,8 +81,8 @@ namespace garlic
std::shared_ptr<const i2p::data::Lease> remoteLease;
int rtt; // RTT
uint32_t updateTime; // seconds since epoch
int numTimesUsed;
};
int numTimesUsed;
};
class GarlicDestination;
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
@ -94,7 +94,7 @@ namespace garlic
eLeaseSetSubmitted,
eLeaseSetDoNotSend
};
struct UnconfirmedTags
{
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
@ -107,23 +107,23 @@ namespace garlic
public:
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
int numTags, bool attachLeaseSet);
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
~GarlicRoutingSession ();
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
void MessageConfirmed (uint32_t msgID);
bool CleanupExpiredTags (); // returns true if something left
bool CleanupExpiredTags (); // returns true if something left
bool CleanupUnconfirmedTags (); // returns true if something has been deleted
void SetLeaseSetUpdated ()
{
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
void SetLeaseSetUpdated ()
{
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
};
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
@ -144,26 +144,26 @@ namespace garlic
GarlicDestination * m_Owner;
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
i2p::crypto::AESKey m_SessionKey;
std::list<SessionTag> m_SessionTags;
int m_NumTags;
std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags
std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags
LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
uint32_t m_LeaseSetUpdateMsgID;
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
i2p::crypto::CBCEncryption m_Encryption;
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
public:
// for HTTP only
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
};
};
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
class GarlicDestination: public i2p::data::LocalDestination
{
@ -173,36 +173,36 @@ namespace garlic
~GarlicDestination ();
void CleanUp ();
void SetNumTags (int numTags) { m_NumTags = numTags; };
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
void SetNumTags (int numTags) { m_NumTags = numTags; };
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
void CleanupExpiredTags ();
void RemoveDeliveryStatusSession (uint32_t msgID);
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated ();
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
protected:
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SaveTags ();
void LoadTags ();
void LoadTags ();
private:
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
@ -218,17 +218,17 @@ namespace garlic
// DeliveryStatus
std::mutex m_DeliveryStatusSessionsMutex;
std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
public:
// for HTTP only
size_t GetNumIncomingTags () const { return m_Tags.size (); }
size_t GetNumIncomingTags () const { return m_Tags.size (); }
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
};
void CleanUpTagsFiles ();
}
}
}
#endif

View file

@ -28,7 +28,7 @@ namespace crypto
GOSTR3410Curve::~GOSTR3410Curve ()
{
EC_GROUP_free (m_Group);
}
}
EC_POINT * GOSTR3410Curve::MulP (const BIGNUM * n) const
{
@ -81,12 +81,12 @@ namespace crypto
BN_mod_inverse (h, h, q, ctx); // 1/h mod q
BIGNUM * z1 = BN_CTX_get (ctx);
BN_mod_mul (z1, s, h, q, ctx); // z1 = s/h
BIGNUM * z2 = BN_CTX_get (ctx);
BIGNUM * z2 = BN_CTX_get (ctx);
BN_sub (z2, q, r); // z2 = -r
BN_mod_mul (z2, z2, h, q, ctx); // z2 = -r/h
EC_POINT * C = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub
BIGNUM * x = BN_CTX_get (ctx);
BIGNUM * x = BN_CTX_get (ctx);
GetXY (C, x, nullptr); // Cx
BN_mod (x, x, q, ctx); // Cx % q
bool ret = !BN_cmp (x, r); // Cx = r ?
@ -94,9 +94,9 @@ namespace crypto
BN_CTX_end (ctx);
BN_CTX_free (ctx);
return ret;
}
}
EC_POINT * GOSTR3410Curve::RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY) const
EC_POINT * GOSTR3410Curve::RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY) const
{
// s*P = r*Q + h*C
BN_CTX * ctx = BN_CTX_new ();
@ -104,7 +104,7 @@ namespace crypto
EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry)
EC_POINT * Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx))
{
{
EC_POINT * S = EC_POINT_new (m_Group); // S = s*P
EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx);
BIGNUM * q = BN_CTX_get (ctx);
@ -112,28 +112,28 @@ namespace crypto
BIGNUM * h = BN_CTX_get (ctx);
BN_mod (h, digest, q, ctx); // h = digest % q
BN_sub (h, q, h); // h = -h
EC_POINT * H = EC_POINT_new (m_Group);
EC_POINT * H = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, H, nullptr, C, h, ctx); // -h*C
EC_POINT_add (m_Group, C, S, H, ctx); // s*P - h*C
EC_POINT_free (H);
EC_POINT_free (S);
BIGNUM * r1 = BN_CTX_get (ctx);
BN_mod_inverse (r1, r, q, ctx);
Q = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
}
Q = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
}
EC_POINT_free (C);
BN_CTX_end (ctx);
BN_CTX_free (ctx);
return Q;
}
}
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet)
{
// a, b, p, q, x, y
static const char * params[eGOSTR3410NumParamSets][6] =
// a, b, p, q, x, y
static const char * params[eGOSTR3410NumParamSets][6] =
{
{
{
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
"A6",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
@ -147,10 +147,10 @@ namespace crypto
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",
"3",
"7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4"
"7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4"
} // tc26-2012-paramSetA-512
};
};
BIGNUM * a = nullptr, * b = nullptr, * p = nullptr, * q =nullptr, * x = nullptr, * y = nullptr;
BN_hex2bn(&a, params[paramSet][0]);
BN_hex2bn(&b, params[paramSet][1]);
@ -161,25 +161,25 @@ namespace crypto
auto curve = new GOSTR3410Curve (a, b, p, q, x, y);
BN_free (a); BN_free (b); BN_free (p); BN_free (q); BN_free (x); BN_free (y);
return curve;
}
}
static std::array<std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet)
{
if (!g_GOSTR3410Curves[paramSet])
{
auto c = CreateGOSTR3410Curve (paramSet);
auto c = CreateGOSTR3410Curve (paramSet);
if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already
g_GOSTR3410Curves[paramSet].reset (c);
else
delete c;
}
return g_GOSTR3410Curves[paramSet];
}
return g_GOSTR3410Curves[paramSet];
}
// ГОСТ 34.11-2012
static const uint64_t T0[256] =
static const uint64_t T0[256] =
{
0xE6F87E5C5B711FD0, 0x258377800924FA16, 0xC849E07E852EA4A8, 0x5B4686A18F06C16A,
0x0B32E9A2D77B416E, 0xABDA37A467815C66, 0xF61796A81A686676, 0xF5DC0B706391954B,
@ -246,7 +246,7 @@ namespace crypto
0x92BDE697D67F3422, 0xC78933E10514BC61, 0xE1C1D9B975C9B54A, 0xD2266160CF1BCD80,
0x9A4492ED78FD8671, 0xB3CCAB2A881A9793, 0x72CEBF667FE1D088, 0xD6D45B5D985A9427
};
static const uint64_t T1[256] =
static const uint64_t T1[256] =
{
0xC811A8058C3F55DE, 0x65F5B43196B50619, 0xF74F96B1D6706E43, 0x859D1E8BCB43D336,
0x5AAB8A85CCFA3D84, 0xF9C7BF99C295FCFD, 0xA21FD5A1DE4B630F, 0xCDB3EF763B8B456D,
@ -313,7 +313,7 @@ namespace crypto
0x57B69E77B57354A0, 0x3969441D8097D0B4, 0x3330CAFBF3E2F0CF, 0xE28E77DDE0BE8CC3,
0x62B12E259C494F46, 0xA6CE726FB9DBD1CA, 0x41E242C1EED14DBA, 0x76032FF47AA30FB0
};
static const uint64_t T2[256] =
static const uint64_t T2[256] =
{
0x45B268A93ACDE4CC, 0xAF7F0BE884549D08, 0x048354B3C1468263, 0x925435C2C80EFED2,
0xEE4E37F27FDFFBA7, 0x167A33920C60F14D, 0xFB123B52EA03E584, 0x4A0CAB53FDBB9007,
@ -380,7 +380,7 @@ namespace crypto
0xF9DD11850420A43B, 0x4BE5BEB68A243ED6, 0x5584255F19C8D65D, 0x3B67404E633FA006,
0xA68DB6766C472A1F, 0xF78AC79AB4C97E21, 0xC353442E1080AAEC, 0x9A4F9DB95782E714
};
static const uint64_t T3[256] =
static const uint64_t T3[256] =
{
0x05BA7BC82C9B3220, 0x31A54665F8B65E4F, 0xB1B651F77547F4D4, 0x8BFA0D857BA46682,
0x85A96C5AA16A98BB, 0x990FAEF908EB79C9, 0xA15E37A247F4A62D, 0x76857DCD5D27741E,
@ -447,7 +447,7 @@ namespace crypto
0x77059157F359DC47, 0x1D262E3907FF492B, 0xFB582233E59AC557, 0xDDB2BCE242F8B673,
0x2577B76248E096CF, 0x6F99C4A6D83DA74C, 0xC1147E41EB795701, 0xF48BAF76912A9337
};
static const uint64_t T4[256] =
static const uint64_t T4[256] =
{
0x3EF29D249B2C0A19, 0xE9E16322B6F8622F, 0x5536994047757F7A, 0x9F4D56D5A47B0B33,
0x822567466AA1174C, 0xB8F5057DEB082FB2, 0xCC48C10BF4475F53, 0x373088D4275DEC3A,
@ -514,7 +514,7 @@ namespace crypto
0x6853032B59F3EE6E, 0x65B3E9C4FF073AAA, 0x772AC3399AE5EBEC, 0x87816E97F842A75B,
0x110E2DB2E0484A4B, 0x331277CB3DD8DEDD, 0xBD510CAC79EB9FA5, 0x352179552A91F5C7
};
static const uint64_t T5[256] =
static const uint64_t T5[256] =
{
0x8AB0A96846E06A6D, 0x43C7E80B4BF0B33A, 0x08C9B3546B161EE5, 0x39F1C235EBA990BE,
0xC1BEF2376606C7B2, 0x2C209233614569AA, 0xEB01523B6FC3289A, 0x946953AB935ACEDD,
@ -581,7 +581,7 @@ namespace crypto
0xEFEB8511D4C82766, 0x961CB6BE40D147A3, 0xAAB35F25F7B812DE, 0x76154E407044329D,
0x513D76B64E570693, 0xF3479AC7D2F90AA8, 0x9B8B2E4477079C85, 0x297EB99D3D85AC69
};
static const uint64_t T6[256] =
static const uint64_t T6[256] =
{
0x7E37E62DFC7D40C3, 0x776F25A4EE939E5B, 0xE045C850DD8FB5AD, 0x86ED5BA711FF1952,
0xE91D0BD9CF616B35, 0x37E0AB256E408FFB, 0x9607F6C031025A7A, 0x0B02F5E116D23C9D,
@ -648,7 +648,7 @@ namespace crypto
0xE6AB92E8D1CB8EA2, 0x3354C7F5663856F1, 0xD93EE170AF7BAE4D, 0x616BD27BC22AE67C,
0x92B39A10397A8370, 0xABC8B3304B8E9890, 0xBF967287630B02B2, 0x5B67D607B6FC6E15
};
static uint64_t T7[256] =
static uint64_t T7[256] =
{
0xD031C397CE553FE6, 0x16BA5B01B006B525, 0xA89BADE6296E70C8, 0x6A1F525D77D3435B,
0x6E103570573DFA0B, 0x660EFB2A17FC95AB, 0x76327A9E97634BF6, 0x4BAD9D6462458BF5,
@ -716,59 +716,59 @@ namespace crypto
0x717E7067AF4F499A, 0x938290A9ECD1DBB3, 0x88E3B293344DD172, 0x2734158C250FA3D6
};
static const uint64_t C_[12][8] =
static const uint64_t C_[12][8] =
{
{
0xe9daca1eda5b08b1, 0x1f7c65c0812fcbeb, 0x16d0452e43766a2f, 0xfcc485758db84e71,
0x0169679291e07c4b, 0x15d360a4082a42a2, 0x234d74cc36747605, 0x0745a6f2596580dd
},
},
{
0x1a2f9da98ab5a36f, 0xd7b5700f469de34f, 0x982b230a72eafef3, 0x3101b5160f5ed561,
0x5899d6126b17b59a, 0xcaa70adbc261b55c, 0x56cdcbd71ba2dd55, 0xb79bb121700479e6
},
},
{
0xc72fce2bacdc74f5, 0x35843d6a28fc390a, 0x8b1f9c525f5ef106, 0x7b7b29b11475eaf2,
0xb19e3590e40fe2d3, 0x09db6260373ac9c1, 0x31db7a8643f4b6c2, 0xb20aba0af5961e99
},
},
{
0xd26615e8b3df1fef, 0xdde4715da0e148f9, 0x7d3c5c337e858e48, 0x3f355e68ad1c729d,
0x75d603ed822cd7a9, 0xbe0352933313b7d8, 0xf137e893a1ea5334, 0x2ed1e384bcbe0c22
},
},
{
0x994747adac6bea4b, 0x6323a96c0c413f9a, 0x4a1086161f1c157f, 0xbdff0f80d7359e35,
0xa3f53a254717cdbf, 0x161a2723b700ffdf, 0xf563eaa97ea2567a, 0x57fe6c7cfd581760
},
},
{
0xd9d33a1daeae4fae, 0xc039307a3bc3a46f, 0x6ca44251f9c4662d, 0xc68ef09ab49a7f18,
0xb4b79a1cb7a6facf, 0xb6c6bec2661ff20a, 0x354f903672c571bf, 0x6e7d64467a4068fa
},
},
{
0xecc5aaee160ec7f4, 0x540924bffe86ac51, 0xc987bfe6c7c69e39, 0xc9937a19333e47d3,
0x372c822dc5ab9209, 0x04054a2883694706, 0xf34a3ca24c451735, 0x93d4143a4d568688
},
},
{
0xa7c9934d425b1f9b, 0x41416e0c02aae703, 0x1ede369c71f8b74e, 0x9ac4db4d3b44b489,
0x90069b92cb2b89f4, 0x2fc4a5d12b8dd169, 0xd9a8515935c2ac36, 0x1ee702bfd40d7fa4
},
},
{
0x9b223116545a8f37, 0xde5f16ecd89a4c94, 0x244289251b3a7d3a, 0x84090de0b755d93c,
0xb1ceb2db0b440a80, 0x549c07a69a8a2b7b, 0x602a1fcb92dc380e, 0xdb5a238351446172
},
},
{
0x526f0580a6debeab, 0xf3f3e4b248e52a38, 0xdb788aff1ce74189, 0x0361331b8ae1ff1f,
0x4b3369af0267e79f, 0xf452763b306c1e7a, 0xc3b63b15d1fa9836, 0xed9c4598fbc7b474
},
},
{
0xfb89c8efd09ecd7b, 0x94fe5a63cdc60230, 0x6107abebbb6bfad8, 0x7966841421800120,
0xcab948eaef711d8a, 0x986e477d1dcdbaef, 0x5dd86fc04a59a2de, 0x1b2df381cda4ca6b
},
},
{
0xba3116f167e78e37, 0x7ab14904b08013d2, 0x771ddfbc323ca4cd, 0x9b9f2130d41220f8,
0x86cc91189def805d, 0x5228e188aaa41de7, 0x991bb2d9d517f4fa, 0x20d71bf14a92bc48
}
};
union GOST3411Block // 8 bytes aligned
{
uint8_t buf[64];
@ -780,15 +780,15 @@ namespace crypto
for (int i = 0; i < 8; i++)
ret.ll[i] = ll[i]^other.ll[i];
return ret;
}
}
GOST3411Block operator^(const uint64_t * other) const
{
GOST3411Block ret;
for (int i = 0; i < 8; i++)
ret.ll[i] = ll[i]^other[i];
return ret;
}
}
GOST3411Block operator+(const GOST3411Block& other) const
{
@ -799,7 +799,7 @@ namespace crypto
uint16_t sum = buf[i] + other.buf[i] + carry;
ret.buf[i] = sum;
carry = sum >> 8;
}
}
return ret;
}
@ -807,17 +807,17 @@ namespace crypto
{
for (int i = 63; i >= 0; i--)
{
if (!c) return;
if (!c) return;
c += buf[i];
buf[i] = c;
c >>= 8;
c >>= 8;
}
}
void F ()
{
uint64_t res[8];
for (int b=0; b<8; b++)
for (int b=0; b<8; b++)
{
uint64_t r;
r = T0[buf[b+56]];
@ -843,11 +843,11 @@ namespace crypto
k = k^C_[i];
k.F ();
res = k^res;
}
}
return res;
}
}
};
static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m)
{
GOST3411Block res = N ^ h;
@ -855,12 +855,12 @@ namespace crypto
res = res.E (m);
res = res^h;
res = res^m;
return res;
}
return res;
}
static void H (const uint8_t * iv, const uint8_t * buf, size_t len, uint8_t * digest)
{
// stage 1
// stage 1
GOST3411Block h, N, s, m;
memcpy (h.buf, iv, 64);
memset (N.buf, 0, 64);
@ -885,15 +885,15 @@ namespace crypto
memcpy (m.buf + padding, buf, l);
h = gN (N, h, m);
N.Add (l*8);
N.Add (l*8);
s = m + s;
GOST3411Block N0;
memset (N0.buf, 0, 64);
h = gN (N0, h, N);
h = gN (N0, h, s);
memcpy (digest, h.buf, 64);
memcpy (digest, h.buf, 64);
}
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest)
@ -919,7 +919,7 @@ namespace crypto
size_t len;
bool is512;
};
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ()
{
return new GOSTR3411_2012_CTX;
@ -949,7 +949,7 @@ namespace crypto
size_t l = 64 - ctx->len;
if (len < l) l = len;
for (size_t i = 0; i < l; i++)
ctx->m.buf[ctx->len + i] = buf[l-i-1]; // invert
ctx->m.buf[ctx->len + i] = buf[l-i-1]; // invert
ctx->len += l; len -= l; buf += l;
ctx->h = gN (ctx->N, ctx->h, ctx->m);
@ -959,7 +959,7 @@ namespace crypto
while (len >= 64)
{
for (size_t i = 0; i < 64; i++)
ctx->m.buf[i] = buf[63-i]; // invert
ctx->m.buf[i] = buf[63-i]; // invert
len -= 64; buf += 64;
ctx->h = gN (ctx->N, ctx->h, ctx->m);
ctx->N.Add (512);
@ -975,7 +975,7 @@ namespace crypto
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx)
{
GOST3411Block m;
GOST3411Block m;
size_t padding = 64 - ctx->len;
if (padding)
{
@ -985,14 +985,14 @@ namespace crypto
memcpy (m.buf + padding, ctx->m.buf, ctx->len);
ctx->h = gN (ctx->N, ctx->h, m);
ctx->N.Add (ctx->len*8);
ctx->N.Add (ctx->len*8);
ctx->s = m + ctx->s;
GOST3411Block N0;
memset (N0.buf, 0, 64);
ctx->h = gN (N0, ctx->h, ctx->N);
ctx->h = gN (N0, ctx->h, ctx->s);
size_t sz = ctx->is512 ? 64 : 32;
for (size_t i = 0; i < sz; i++)
digest[i] = ctx->h.buf[sz - i - 1];

View file

@ -10,25 +10,25 @@ namespace crypto
{
// ГОСТ Р 34.10
enum GOSTR3410ParamSet
{
eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1
// XchA = A, XchB = C
//eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0
//eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1
//eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1
eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1
eGOSTR3410NumParamSets
};
};
class GOSTR3410Curve
{
public:
GOSTR3410Curve (BIGNUM * a, BIGNUM * b, BIGNUM * p, BIGNUM * q, BIGNUM * x, BIGNUM * y);
~GOSTR3410Curve ();
~GOSTR3410Curve ();
size_t GetKeyLen () const { return m_KeyLen; };
size_t GetKeyLen () const { return m_KeyLen; };
const EC_GROUP * GetGroup () const { return m_Group; };
EC_POINT * MulP (const BIGNUM * n) const;
bool GetXY (const EC_POINT * p, BIGNUM * x, BIGNUM * y) const;
@ -36,7 +36,7 @@ namespace crypto
void Sign (const BIGNUM * priv, const BIGNUM * digest, BIGNUM * r, BIGNUM * s);
bool Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s);
EC_POINT * RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY = false) const;
private:
EC_GROUP * m_Group;
@ -47,14 +47,14 @@ namespace crypto
// Big Endian
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest);
void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest);
void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest);
// Little Endian
struct GOSTR3411_2012_CTX;
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ();
void GOSTR3411_2012_CTX_Init (GOSTR3411_2012_CTX * ctx, bool is512 = true);
void GOSTR3411_2012_CTX_Update (const uint8_t * buf, size_t len, GOSTR3411_2012_CTX * ctx);
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx);
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx);
void GOSTR3411_2012_CTX_free (GOSTR3411_2012_CTX * ctx);
}
}

View file

@ -12,9 +12,9 @@
#include "Log.h"
#include "Gzip.h"
namespace i2p
namespace i2p
{
namespace data
namespace data
{
const size_t GZIP_CHUNK_SIZE = 16384;
@ -38,7 +38,7 @@ namespace data
m_Inflator.next_out = out;
m_Inflator.avail_out = outLen;
int err;
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
return outLen - m_Inflator.avail_out;
// else
LogPrint (eLogError, "Gzip: Inflate error ", err);
@ -52,19 +52,19 @@ namespace data
m_Inflator.next_in = const_cast<uint8_t *>(in);
m_Inflator.avail_in = inLen;
int ret;
do
do
{
m_Inflator.next_out = out;
m_Inflator.avail_out = GZIP_CHUNK_SIZE;
ret = inflate (&m_Inflator, Z_NO_FLUSH);
if (ret < 0)
if (ret < 0)
{
inflateEnd (&m_Inflator);
os.setstate(std::ios_base::failbit);
break;
}
os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
}
}
while (!m_Inflator.avail_out); // more data to read
delete[] out;
}
@ -105,7 +105,7 @@ namespace data
m_Deflator.next_out = out;
m_Deflator.avail_out = outLen;
int err;
if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END)
if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END)
return outLen - m_Deflator.avail_out;
// else
LogPrint (eLogError, "Gzip: Deflate error ", err);

View file

@ -44,7 +44,7 @@ namespace http {
}
}
static std::pair<std::string, std::string> parse_header_line(const std::string& line)
static std::pair<std::string, std::string> parse_header_line(const std::string& line)
{
std::size_t pos = 0;
std::size_t len = 2; /* strlen(": ") */
@ -251,14 +251,14 @@ namespace http {
uri = tokens[1];
version = tokens[2];
expect = HEADER_LINE;
}
else
}
else
{
std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line);
if (p.first.length () > 0)
headers.push_back (p);
else
else
return -1;
}
pos = eol + strlen(CRLF);
@ -268,11 +268,11 @@ namespace http {
return eoh + strlen(HTTP_EOH);
}
void HTTPReq::write(std::ostream & o)
void HTTPReq::write(std::ostream & o)
{
o << method << " " << uri << " " << version << CRLF;
for (auto & h : headers)
o << h.first << ": " << h.second << CRLF;
for (auto & h : headers)
o << h.first << ": " << h.second << CRLF;
o << CRLF;
}
@ -284,7 +284,7 @@ namespace http {
}
void HTTPReq::AddHeader (const std::string& name, const std::string& value)
{
{
headers.push_back (std::make_pair(name, value));
}
@ -295,28 +295,28 @@ namespace http {
{
it.second = value;
break;
}
}
}
}
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt)
{
for (auto it = headers.begin (); it != headers.end ();)
{
if (!it->first.compare(0, name.length (), name) && it->first != exempt)
if (!it->first.compare(0, name.length (), name) && it->first != exempt)
it = headers.erase (it);
else
it++;
}
}
}
}
std::string HTTPReq::GetHeader (const std::string& name) const
std::string HTTPReq::GetHeader (const std::string& name) const
{
for (auto& it : headers)
if (it.first == name)
return it.second;
return it.second;
return "";
}
}
bool HTTPRes::is_chunked() const
{
auto it = headers.find("Transfer-Encoding");
@ -335,10 +335,10 @@ namespace http {
if (it->second.find("gzip") != std::string::npos)
return true; /* gotcha! */
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
return true;
return true;
return false;
}
long int HTTPMsg::content_length() const
{
unsigned long int length = 0;
@ -385,8 +385,8 @@ namespace http {
std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line);
if (p.first.length () > 0)
headers.insert (p);
else
headers.insert (p);
else
return -1;
}
pos = eol + strlen(CRLF);

View file

@ -16,16 +16,16 @@
#include <string>
#include <vector>
namespace i2p
namespace i2p
{
namespace http
namespace http
{
const char CRLF[] = "\r\n"; /**< HTTP line terminator */
const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */
extern const std::vector<std::string> HTTP_METHODS; /**< list of valid HTTP methods */
extern const std::vector<std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */
struct URL
struct URL
{
std::string schema;
std::string user;
@ -63,7 +63,7 @@ namespace http
bool is_i2p() const;
};
struct HTTPMsg
struct HTTPMsg
{
std::map<std::string, std::string> headers;
@ -75,9 +75,9 @@ namespace http
long int content_length() const;
};
struct HTTPReq
struct HTTPReq
{
std::list<std::pair<std::string, std::string> > headers;
std::list<std::pair<std::string, std::string> > headers;
std::string version;
std::string method;
std::string uri;
@ -97,10 +97,10 @@ namespace http
void write(std::ostream & o);
void AddHeader (const std::string& name, const std::string& value);
void UpdateHeader (const std::string& name, const std::string& value);
void UpdateHeader (const std::string& name, const std::string& value);
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); };
std::string GetHeader (const std::string& name) const;
std::string GetHeader (const std::string& name) const;
};
struct HTTPRes : HTTPMsg {

View file

@ -21,7 +21,7 @@ namespace i2p
{
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >();
}
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ()
{
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
@ -32,38 +32,38 @@ namespace i2p
auto msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12
msg->Align (12);
return std::shared_ptr<I2NPMessage>(msg);
}
}
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
{
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage ();
}
}
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID)
{
SetTypeID (msgType);
if (!replyMsgID) RAND_bytes ((uint8_t *)&replyMsgID, 4);
SetMsgID (replyMsgID);
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
SetMsgID (replyMsgID);
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
UpdateSize ();
UpdateChks ();
}
}
void I2NPMessage::RenewI2NPMessageHeader ()
{
uint32_t msgID;
RAND_bytes ((uint8_t *)&msgID, 4);
SetMsgID (msgID);
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
}
bool I2NPMessage::IsExpired () const
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
auto exp = GetExpiration ();
auto exp = GetExpiration ();
return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future
}
}
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
{
auto msg = NewI2NPMessage (len);
@ -71,7 +71,7 @@ namespace i2p
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen);
msg->FillI2NPMessageHeader (msgType, replyMsgID);
return msg;
}
}
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{
@ -85,7 +85,7 @@ namespace i2p
else
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length");
return msg;
}
}
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg)
{
@ -94,8 +94,8 @@ namespace i2p
newMsg->offset = msg->offset;
*newMsg = *msg;
return newMsg;
}
}
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
{
auto m = NewI2NPShortMessage ();
@ -109,14 +109,14 @@ namespace i2p
{
RAND_bytes ((uint8_t *)&msgID, 4);
htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID);
htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::context.GetNetID ());
}
htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::context.GetNetID ());
}
m->len += DELIVERY_STATUS_SIZE;
m->FillI2NPMessageHeader (eI2NPDeliveryStatus);
return m;
}
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
@ -125,7 +125,7 @@ namespace i2p
buf += 32;
memcpy (buf, from, 32); // from
buf += 32;
uint8_t flag = exploratory ? DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP : DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP;
uint8_t flag = exploratory ? DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP : DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP;
if (replyTunnelID)
{
*buf = flag | DATABASE_LOOKUP_DELIVERY_FLAG; // set delivery flag
@ -133,11 +133,11 @@ namespace i2p
buf += 5;
}
else
{
{
*buf = flag; // flag
buf++;
}
}
if (excludedPeers)
{
int cnt = excludedPeers->size ();
@ -147,21 +147,21 @@ namespace i2p
{
memcpy (buf, it, 32);
buf += 32;
}
}
}
else
{
{
// nothing to exclude
htobuf16 (buf, 0);
buf += 2;
}
m->len += (buf - m->GetPayload ());
m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m;
}
}
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
m->len += (buf - m->GetPayload ());
m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m;
}
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
{
@ -176,7 +176,7 @@ namespace i2p
buf ++;
htobe32buf (buf, replyTunnel->GetNextTunnelID ()); // reply tunnel ID
buf += 4;
// excluded
htobe16buf (buf, cnt);
buf += 2;
@ -187,19 +187,19 @@ namespace i2p
memcpy (buf, it, 32);
buf += 32;
}
}
}
// encryption
memcpy (buf, replyKey, 32);
buf[32] = uint8_t( 1 ); // 1 tag
memcpy (buf + 33, replyTag, 32);
buf += 65;
m->len += (buf - m->GetPayload ());
m->len += (buf - m->GetPayload ());
m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m;
}
return m;
}
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
std::vector<i2p::data::IdentHash> routers)
{
auto m = NewI2NPShortMessage ();
@ -207,27 +207,27 @@ namespace i2p
size_t len = 0;
memcpy (buf, ident, 32);
len += 32;
buf[len] = routers.size ();
buf[len] = routers.size ();
len++;
for (const auto& it: routers)
{
memcpy (buf + len, it, 32);
len += 32;
}
}
memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
len += 32;
len += 32;
m->len += len;
m->FillI2NPMessageHeader (eI2NPDatabaseSearchReply);
return m;
}
return m;
}
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, uint32_t replyToken)
{
if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo ();
auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload ();
uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo
@ -239,7 +239,7 @@ namespace i2p
buf += 4;
memcpy (buf, router->GetIdentHash (), 32);
buf += 32;
}
}
uint8_t * sizePtr = buf;
buf += 2;
@ -247,22 +247,22 @@ namespace i2p
i2p::data::GzipDeflator deflator;
size_t size = deflator.Deflate (router->GetBuffer (), router->GetBufferLen (), buf, m->maxLen -m->len);
if (size)
{
{
htobe16buf (sizePtr, size); // size
m->len += size;
}
}
else
m = nullptr;
if (m)
m->FillI2NPMessageHeader (eI2NPDatabaseStore);
return m;
}
}
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
{
if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload ();
uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
@ -278,7 +278,7 @@ namespace i2p
{
if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload ();
uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
@ -306,8 +306,8 @@ namespace i2p
{
if (!msg || msg->GetTypeID () != eI2NPDatabaseStore) return false;
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
}
}
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{
@ -321,37 +321,37 @@ namespace i2p
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{
for (int i = 0; i < num; i++)
{
{
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
{
{
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
BN_CTX * ctx = BN_CTX_new ();
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
BN_CTX_free (ctx);
// replace record to reply
if (i2p::context.AcceptsTunnels () &&
// replace record to reply
if (i2p::context.AcceptsTunnels () &&
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded () &&
!i2p::transport::transports.IsTransitBandwidthExceeded ())
{
{
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40);
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0;
}
else
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30)
//TODO: fill filler
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret
record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
// encrypt reply
i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++)
@ -359,23 +359,23 @@ namespace i2p
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
}
return true;
}
}
}
}
return false;
}
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{
{
int num = buf[0];
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
{
LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len);
return;
}
}
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
if (tunnel)
@ -385,34 +385,34 @@ namespace i2p
if (tunnel->HandleTunnelBuildResponse (buf, len))
{
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
}
else
{
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
}
}
else
{
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (HandleBuildRequestRecords (num, buf + 1, clearText))
{
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel
{
// so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
// so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
}
}
}
}
void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
@ -421,51 +421,51 @@ namespace i2p
{
LogPrint (eLogError, "TunnelBuild message is too short ", len);
return;
}
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
}
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, buf, clearText))
{
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outbound tunnel
{
// so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
// so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
eI2NPTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
}
}
}
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{
{
int num = buf[0];
LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
{
LogPrint (eLogError, "VaribleTunnelBuildReply message of ", num, " records is too short ", len);
return;
}
}
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
if (tunnel)
{
{
// reply for outbound tunnel
if (tunnel->HandleTunnelBuildResponse (buf, len))
{
{
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddOutboundTunnel (tunnel);
}
}
else
{
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
}
}
}
else
LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
}
@ -474,12 +474,12 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
{
auto msg = NewI2NPTunnelMessage ();
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg;
}
}
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
{
auto msg = NewI2NPTunnelMessage ();
htobe32buf (msg->GetPayload (), tunnelID);
@ -487,15 +487,15 @@ namespace i2p
msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg;
}
}
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ()
{
auto msg = NewI2NPTunnelMessage ();
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
return msg;
}
}
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
{
auto msg = NewI2NPMessage (len);
@ -504,10 +504,10 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg;
}
}
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg)
{
@ -520,14 +520,14 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE);
msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len;
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg;
}
else
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
}
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID)
{
auto msg = NewI2NPMessage (len);
@ -544,7 +544,7 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway); // gateway message
return msg;
}
}
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len)
{
@ -552,25 +552,25 @@ namespace i2p
{
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
return len;
}
}
auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE;
if (l > len)
{
LogPrint (eLogError, "I2NP: message length ", l, " exceeds buffer length ", len);
l = len;
}
}
return l;
}
}
void HandleI2NPMessage (uint8_t * msg, size_t len)
{
if (len < I2NP_HEADER_SIZE)
{
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
return;
}
}
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
uint8_t * buf = msg + I2NP_HEADER_SIZE;
auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
@ -581,35 +581,35 @@ namespace i2p
size = len;
}
switch (typeID)
{
{
case eI2NPVariableTunnelBuild:
HandleVariableTunnelBuildMsg (msgID, buf, size);
break;
break;
case eI2NPVariableTunnelBuildReply:
HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
break;
break;
case eI2NPTunnelBuild:
HandleTunnelBuildMsg (buf, size);
break;
break;
case eI2NPTunnelBuildReply:
// TODO:
break;
break;
default:
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
}
}
}
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
{
if (msg)
{
{
uint8_t typeID = msg->GetTypeID ();
LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID);
switch (typeID)
{
{
case eI2NPTunnelData:
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
break;
case eI2NPTunnelGateway:
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
@ -623,7 +623,7 @@ namespace i2p
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
}
else
i2p::context.ProcessGarlicMessage (msg);
i2p::context.ProcessGarlicMessage (msg);
break;
}
case eI2NPDatabaseStore:
@ -638,55 +638,55 @@ namespace i2p
msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg);
else
i2p::context.ProcessDeliveryStatusMessage (msg);
break;
break;
}
case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply:
case eI2NPTunnelBuildReply:
// forward to tunnel thread
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
break;
default:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
}
}
}
}
}
}
I2NPMessagesHandler::~I2NPMessagesHandler ()
{
Flush ();
}
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg)
{
if (msg)
{
switch (msg->GetTypeID ())
{
{
case eI2NPTunnelData:
m_TunnelMsgs.push_back (msg);
break;
case eI2NPTunnelGateway:
case eI2NPTunnelGateway:
m_TunnelGatewayMsgs.push_back (msg);
break;
break;
default:
HandleI2NPMessage (msg);
}
}
}
}
}
void I2NPMessagesHandler::Flush ()
{
if (!m_TunnelMsgs.empty ())
{
{
i2p::tunnel::tunnels.PostTunnelData (m_TunnelMsgs);
m_TunnelMsgs.clear ();
}
}
if (!m_TunnelGatewayMsgs.empty ())
{
{
i2p::tunnel::tunnels.PostTunnelData (m_TunnelGatewayMsgs);
m_TunnelGatewayMsgs.clear ();
}
}
}
}
}

View file

@ -12,7 +12,7 @@
#include "LeaseSet.h"
namespace i2p
{
{
// I2NP header
const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1;
@ -25,13 +25,13 @@ namespace i2p
const size_t I2NP_SHORT_HEADER_TYPEID_OFFSET = 0;
const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1;
const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
// Tunnel Gateway header
const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0;
const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4;
const size_t TUNNEL_GATEWAY_HEADER_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2;
// DeliveryStatus
// DeliveryStatus
const size_t DELIVERY_STATUS_MSGID_OFFSET = 0;
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8;
@ -42,7 +42,7 @@ namespace i2p
const size_t DATABASE_STORE_REPLY_TOKEN_OFFSET = DATABASE_STORE_TYPE_OFFSET + 1;
const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4;
// TunnelBuild
// TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
//BuildRequestRecordClearText
@ -59,11 +59,11 @@ namespace i2p
const size_t BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
const size_t BUILD_REQUEST_RECORD_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222;
// BuildRequestRecordEncrypted
// BuildRequestRecordEncrypted
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
// BuildResponseRecord
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
@ -83,40 +83,40 @@ namespace i2p
eI2NPTunnelBuild = 21,
eI2NPTunnelBuildReply = 22,
eI2NPVariableTunnelBuild = 23,
eI2NPVariableTunnelBuildReply = 24
};
eI2NPVariableTunnelBuildReply = 24
};
const int NUM_TUNNEL_BUILD_RECORDS = 8;
const int NUM_TUNNEL_BUILD_RECORDS = 8;
// DatabaseLookup flags
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02;
const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02;
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
namespace tunnel
{
{
class InboundTunnel;
class TunnelPool;
}
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
struct I2NPMessage
{
uint8_t * buf;
{
uint8_t * buf;
size_t len, offset, maxLen;
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
// header accessors
uint8_t * GetHeader () { return GetBuffer (); };
const uint8_t * GetHeader () const { return GetBuffer (); };
@ -128,24 +128,24 @@ namespace tunnel
uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); };
void UpdateSize () { SetSize (GetPayloadLength ()); };
void UpdateSize () { SetSize (GetPayloadLength ()); };
void SetChks (uint8_t chks) { GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = chks; };
void UpdateChks ()
void UpdateChks ()
{
uint8_t hash[32];
SHA256(GetPayload (), GetPayloadLength (), hash);
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
}
}
// payload
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
uint8_t * GetBuffer () { return buf + offset; };
const uint8_t * GetBuffer () const { return buf + offset; };
size_t GetLength () const { return len - offset; };
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
void Align (size_t alignment)
size_t GetLength () const { return len - offset; };
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
void Align (size_t alignment)
{
if (len + alignment > maxLen) return;
size_t rem = ((size_t)GetBuffer ()) % alignment;
@ -153,7 +153,7 @@ namespace tunnel
{
offset += (alignment - rem);
len += (alignment - rem);
}
}
}
size_t Concat (const uint8_t * buf1, size_t len1)
@ -171,10 +171,10 @@ namespace tunnel
len = offset + other.GetLength ();
from = other.from;
return *this;
}
}
// for SSU only
uint8_t * GetSSUHeader () { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; };
uint8_t * GetSSUHeader () { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; };
void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular
{
const uint8_t * ssu = GetSSUHeader ();
@ -193,12 +193,12 @@ namespace tunnel
htobe32buf (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET, bufbe64toh (header + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL);
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
}
}
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
void RenewI2NPMessageHeader ();
bool IsExpired () const;
};
};
template<int sz>
struct I2NPMessageBuffer: public I2NPMessage
@ -211,35 +211,35 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage ();
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ();
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
@ -254,7 +254,7 @@ namespace tunnel
~I2NPMessagesHandler ();
void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
void Flush ();
private:
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
@ -262,6 +262,6 @@ namespace tunnel
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
}
}
#endif

View file

@ -41,7 +41,7 @@ namespace data
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType):
m_IsVerifierCreated (false)
{
{
memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{
@ -450,7 +450,7 @@ namespace data
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (const uint8_t * key) const
{
if (!key) key = GetEncryptionPublicKey (); // use publicKey
if (!key) key = GetEncryptionPublicKey (); // use publicKey
switch (GetCryptoKeyType ())
{
case CRYPTO_KEY_TYPE_ELGAMAL:
@ -542,7 +542,7 @@ namespace data
void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
if (!m_Signer)
CreateSigner();
CreateSigner();
m_Signer->Sign (buf, len, signature);
}
@ -596,12 +596,12 @@ namespace data
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (const uint8_t * key) const
{
if (!key) key = m_PrivateKey; // use privateKey
if (!key) key = m_PrivateKey; // use privateKey
return CreateDecryptor (m_Public->GetCryptoKeyType (), key);
}
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key)
{
{
if (!key) return nullptr;
switch (cryptoType)
{
@ -618,7 +618,7 @@ namespace data
default:
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
};
return nullptr;
return nullptr;
}
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType)
@ -643,7 +643,7 @@ namespace data
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Create EdDSA");
// no break here
// no break here
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break;
@ -685,7 +685,7 @@ namespace data
break;
default:
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
}
}
}
Keys CreateRandomKeys ()

View file

@ -91,12 +91,12 @@ namespace data
size_t ToBuffer (uint8_t * buf, size_t len) const;
size_t FromBase64(const std::string& s);
std::string ToBase64 () const;
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
const IdentHash& GetIdentHash () const { return m_IdentHash; };
const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; };
uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; };
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; };
uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; };
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
size_t GetSigningPublicKeyLen () const;
size_t GetSigningPrivateKeyLen () const;
@ -141,7 +141,7 @@ namespace data
const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
uint8_t * GetPadding();
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); };

View file

@ -11,7 +11,7 @@ namespace i2p
{
namespace data
{
LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases):
m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0)
{
@ -22,13 +22,13 @@ namespace data
}
void LeaseSet::Update (const uint8_t * buf, size_t len)
{
{
if (len > m_BufferLen)
{
auto oldBuffer = m_Buffer;
m_Buffer = new uint8_t[len];
delete[] oldBuffer;
}
}
memcpy (m_Buffer, buf, len);
m_BufferLen = len;
ReadFromBuffer (false);
@ -38,10 +38,10 @@ namespace data
{
m_StoreLeases = true;
ReadFromBuffer (false);
}
void LeaseSet::ReadFromBuffer (bool readIdentity)
{
}
void LeaseSet::ReadFromBuffer (bool readIdentity)
{
if (readIdentity || !m_Identity)
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
size_t size = m_Identity->GetFullLen ();
@ -58,17 +58,17 @@ namespace data
size++; // num
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
if (!num || num > MAX_NUM_LEASES)
{
{
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num);
m_IsValid = false;
return;
}
}
// reset existing leases
if (m_StoreLeases)
for (auto& it: m_Leases)
it->isUpdated = false;
else
else
m_Leases.clear ();
// process leases
@ -82,14 +82,14 @@ namespace data
leases += 32; // gateway
lease.tunnelID = bufbe32toh (leases);
leases += 4; // tunnel ID
lease.endDate = bufbe64toh (leases);
lease.endDate = bufbe64toh (leases);
leases += 8; // end date
if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD)
{
{
if (lease.endDate > m_ExpirationTime)
m_ExpirationTime = lease.endDate;
if (m_StoreLeases)
{
{
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
(*ret.first)->isUpdated = true;
@ -100,28 +100,28 @@ namespace data
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
netdb.RequestDestination (lease.tunnelGateway);
}
}
}
}
else
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
}
}
if (!m_ExpirationTime)
{
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
m_IsValid = false;
return;
}
}
m_ExpirationTime += LEASE_ENDDATE_THRESHOLD;
// delete old leases
// delete old leases
if (m_StoreLeases)
{
{
for (auto it = m_Leases.begin (); it != m_Leases.end ();)
{
{
if (!(*it)->isUpdated)
{
(*it)->endDate = 0; // somebody might still hold it
m_Leases.erase (it++);
}
}
else
++it;
}
@ -133,9 +133,9 @@ namespace data
LogPrint (eLogWarning, "LeaseSet: verification failed");
m_IsValid = false;
}
}
}
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
{
if (!m_Identity) return 0;
size_t size = m_Identity->GetFullLen ();
@ -150,18 +150,18 @@ namespace data
for (int i = 0; i < num; i++)
{
size += 36; // gateway (32) + tunnelId(4)
auto endDate = bufbe64toh (buf + size);
auto endDate = bufbe64toh (buf + size);
size += 8; // end date
if (!timestamp || endDate < timestamp)
timestamp = endDate;
}
}
return timestamp;
}
}
bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const
{
return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen);
}
}
bool LeaseSet::ExpiresSoon(const uint64_t dlt, const uint64_t fudge) const
{
@ -175,7 +175,7 @@ namespace data
{
return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold);
}
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
@ -189,17 +189,17 @@ namespace data
endDate -= LEASE_ENDDATE_THRESHOLD;
if (ts < endDate && !exclude(*it))
leases.push_back (it);
}
return leases;
}
}
return leases;
}
bool LeaseSet::HasExpiredLeases () const
{
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (const auto& it: m_Leases)
if (ts >= it->endDate) return true;
return false;
}
}
bool LeaseSet::IsExpired () const
{
@ -222,15 +222,15 @@ namespace data
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
// identity
auto signingKeyLen = m_Identity->GetSigningPublicKeyLen ();
m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen ();
m_Buffer = new uint8_t[m_BufferLen];
m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen ();
m_Buffer = new uint8_t[m_BufferLen];
auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen);
memcpy (m_Buffer + offset, encryptionPublicKey, 256);
offset += 256;
memset (m_Buffer + offset, 0, signingKeyLen);
offset += signingKeyLen;
// num leases
m_Buffer[offset] = num;
m_Buffer[offset] = num;
offset++;
// leases
m_Leases = m_Buffer + offset;
@ -257,13 +257,13 @@ namespace data
{
m_BufferLen = len;
m_Buffer = new uint8_t[m_BufferLen];
memcpy (m_Buffer, buf, len);
memcpy (m_Buffer, buf, len);
}
bool LocalLeaseSet::IsExpired () const
{
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
return ts > m_ExpirationTime;
}
}
}
}
}
}

View file

@ -14,11 +14,11 @@ namespace i2p
namespace tunnel
{
class InboundTunnel;
class InboundTunnel;
}
namespace data
{
{
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
struct Lease
{
@ -33,24 +33,24 @@ namespace data
if (endDate < expire) return true;
return (endDate - expire) < t;
}
};
};
struct LeaseCmp
{
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
{
{
if (l1->tunnelID != l2->tunnelID)
return l1->tunnelID < l2->tunnelID;
return l1->tunnelID < l2->tunnelID;
else
return l1->tunnelGateway < l2->tunnelGateway;
return l1->tunnelGateway < l2->tunnelGateway;
};
};
};
typedef std::function<bool(const Lease & l)> LeaseInspectFunc;
const size_t MAX_LS_BUFFER_SIZE = 3072;
const size_t LEASE_SIZE = 44; // 32 + 4 + 8
const uint8_t MAX_NUM_LEASES = 16;
const uint8_t MAX_NUM_LEASES = 16;
class LeaseSet: public RoutingDestination
{
public:
@ -59,10 +59,10 @@ namespace data
~LeaseSet () { delete[] m_Buffer; };
void Update (const uint8_t * buf, size_t len);
bool IsNewer (const uint8_t * buf, size_t len) const;
void PopulateLeases (); // from buffer
void PopulateLeases (); // from buffer
const uint8_t * GetBuffer () const { return m_Buffer; };
size_t GetBufferLen () const { return m_BufferLen; };
size_t GetBufferLen () const { return m_BufferLen; };
bool IsValid () const { return m_IsValid; };
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const;
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold = true) const;
@ -71,8 +71,8 @@ namespace data
bool IsEmpty () const { return m_Leases.empty (); };
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
bool ExpiresSoon(const uint64_t dlt=1000 * 5, const uint64_t fudge = 0) const ;
bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
// implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
@ -83,7 +83,7 @@ namespace data
void ReadFromBuffer (bool readIdentity = true);
uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time
private:
bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill
@ -93,7 +93,7 @@ namespace data
uint8_t m_EncryptionKey[256];
uint8_t * m_Buffer;
size_t m_BufferLen;
};
};
class LocalLeaseSet
{
@ -104,27 +104,27 @@ namespace data
~LocalLeaseSet () { delete[] m_Buffer; };
const uint8_t * GetBuffer () const { return m_Buffer; };
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
size_t GetBufferLen () const { return m_BufferLen; };
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
size_t GetBufferLen () const { return m_BufferLen; };
size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); };
uint8_t * GetLeases () { return m_Leases; };
uint8_t * GetLeases () { return m_Leases; };
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
bool IsExpired () const;
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
private:
uint64_t m_ExpirationTime; // in milliseconds
std::shared_ptr<const IdentityEx> m_Identity;
uint8_t * m_Buffer, * m_Leases;
size_t m_BufferLen;
};
}
}
};
}
}
#endif

View file

@ -44,7 +44,7 @@ enum LogType {
namespace i2p {
namespace log {
struct LogMsg; /* forward declaration */
class Log
@ -146,7 +146,7 @@ namespace log {
std::string text; /**< message text as single string */
LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {};
};
@ -185,7 +185,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
std::stringstream ss("");
LogPrint (ss, std::forward<TArgs>(args)...);
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
msg->tid = std::this_thread::get_id();
log.Append(msg);

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
namespace i2p
{
namespace data
{
{
const int NETDB_MIN_ROUTERS = 90;
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60*60; // 1 hour, in seconds
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60;
@ -37,11 +37,11 @@ namespace data
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
/** function for visiting a router info we have locally */
typedef std::function<void(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoVisitor;
typedef std::function<void(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoVisitor;
/** function for visiting a router info and determining if we want to use it */
typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter;
class NetDb
{
public:
@ -51,7 +51,7 @@ namespace data
void Start ();
void Stop ();
bool AddRouterInfo (const uint8_t * buf, int len);
bool AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
bool AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
@ -59,12 +59,12 @@ namespace data
std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const;
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
@ -76,13 +76,13 @@ namespace data
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable);
void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide);
void SetHidden(bool hide);
void Reseed ();
Families& GetFamilies () { return m_Families; };
@ -108,28 +108,28 @@ namespace data
bool LoadRouterInfo (const std::string & path);
void SaveUpdated ();
void Run (); // exploratory thread
void Explore (int numDestinations);
void Explore (int numDestinations);
void Publish ();
void ManageLeaseSets ();
void ManageRequests ();
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
private:
mutable std::mutex m_LeaseSetsMutex;
std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
mutable std::mutex m_RouterInfosMutex;
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex;
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning;
uint64_t m_LastLoad;
std::thread * m_Thread;
std::thread * m_Thread;
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
GzipInflator m_Inflator;
@ -137,12 +137,12 @@ namespace data
Families m_Families;
i2p::fs::HashedStorage m_Storage;
friend class NetDbRequests;
friend class NetDbRequests;
NetDbRequests m_Requests;
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
/** true if in hidden mode */
bool m_HiddenMode;

View file

@ -13,8 +13,8 @@ namespace data
{
std::shared_ptr<I2NPMessage> msg;
if(replyTunnel)
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
&m_ExcludedPeers);
else
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
@ -22,22 +22,22 @@ namespace data
m_ExcludedPeers.insert (router->GetIdentHash ());
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return msg;
}
}
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
{
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
m_ExcludedPeers.insert (floodfill);
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return msg;
}
}
void RequestedDestination::ClearExcludedPeers ()
{
m_ExcludedPeers.clear ();
}
}
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
{
if (m_RequestComplete)
@ -69,15 +69,15 @@ namespace data
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
{
// request RouterInfo directly
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
dest->SetRequestComplete (requestComplete);
{
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
return nullptr;
return nullptr;
}
return dest;
}
}
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
{
@ -86,18 +86,18 @@ namespace data
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
auto it = m_RequestedDestinations.find (ident);
if (it != m_RequestedDestinations.end ())
{
{
request = it->second;
m_RequestedDestinations.erase (it);
}
}
}
}
if (request)
{
if (r)
request->Success (r);
else
request->Fail ();
}
}
}
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
@ -107,12 +107,12 @@ namespace data
if (it != m_RequestedDestinations.end ())
return it->second;
return nullptr;
}
}
void NetDbRequests::ManageRequests ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
{
auto& dest = it->second;
@ -126,7 +126,7 @@ namespace data
{
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool->GetNextOutboundTunnel ();
auto inbound = pool->GetNextInboundTunnel ();
auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound)
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
@ -138,15 +138,15 @@ namespace data
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
}
}
}
else
{
if (!dest->IsExploratory ())
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
done = true;
}
}
}
}
}
}
else // delete obsolete request
done = true;
@ -154,7 +154,7 @@ namespace data
it = m_RequestedDestinations.erase (it);
else
++it;
}
}
}
}
}

View file

@ -12,14 +12,14 @@ namespace i2p
namespace data
{
class RequestedDestination
{
{
public:
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
@ -30,12 +30,12 @@ namespace data
uint64_t GetCreationTime () const { return m_CreationTime; };
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
void Success (std::shared_ptr<RouterInfo> r);
void Fail ();
private:
IdentHash m_Destination;
@ -43,7 +43,7 @@ namespace data
std::set<IdentHash> m_ExcludedPeers;
uint64_t m_CreationTime;
RequestComplete m_RequestComplete;
};
};
class NetDbRequests
{

View file

@ -15,20 +15,20 @@ namespace data
RouterProfile::RouterProfile ():
m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
m_NumTimesTaken (0), m_NumTimesRejected (0)
m_NumTimesTaken (0), m_NumTimesRejected (0)
{
}
boost::posix_time::ptime RouterProfile::GetTime () const
{
return boost::posix_time::second_clock::local_time();
}
}
void RouterProfile::UpdateTime ()
{
m_LastUpdateTime = GetTime ();
}
}
void RouterProfile::Save (const IdentHash& identHash)
{
// fill sections
@ -63,57 +63,57 @@ namespace data
std::string path = m_ProfilesStorage.Path(ident);
boost::property_tree::ptree pt;
if (!i2p::fs::Exists(path))
if (!i2p::fs::Exists(path))
{
LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
return;
}
try
try
{
boost::property_tree::read_ini (path, pt);
} catch (std::exception& ex)
} catch (std::exception& ex)
{
/* boost exception verbose enough */
LogPrint (eLogError, "Profiling: ", ex.what ());
return;
}
try
try
{
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length () > 0)
m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
{
try
{
try
{
// read participations
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident);
}
try
}
try
{
// read usage
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
}
catch (boost::property_tree::ptree_bad_path& ex)
}
catch (boost::property_tree::ptree_bad_path& ex)
{
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
}
}
else
}
else
*this = RouterProfile ();
}
catch (std::exception& ex)
}
catch (std::exception& ex)
{
LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
}
@ -126,46 +126,46 @@ namespace data
m_NumTunnelsDeclined++;
else
m_NumTunnelsAgreed++;
}
}
void RouterProfile::TunnelNonReplied ()
{
m_NumTunnelsNonReplied++;
UpdateTime ();
}
}
bool RouterProfile::IsLowPartcipationRate () const
{
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
}
}
bool RouterProfile::IsLowReplyRate () const
{
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
return m_NumTunnelsNonReplied > 10*(total + 1);
}
}
bool RouterProfile::IsBad ()
{
{
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
{
// reset profile
m_NumTunnelsAgreed = 0;
m_NumTunnelsDeclined = 0;
m_NumTunnelsNonReplied = 0;
isBad = false;
}
}
if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
return isBad;
return isBad;
}
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
{
auto profile = std::make_shared<RouterProfile> ();
profile->Load (identHash); // if possible
return profile;
}
}
void InitProfilesStorage ()
{
@ -191,5 +191,5 @@ namespace data
}
}
}
}
}
}
}

View file

@ -8,32 +8,32 @@
namespace i2p
{
namespace data
{
{
// sections
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
// params
// params
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
class RouterProfile
{
public:
RouterProfile ();
RouterProfile& operator= (const RouterProfile& ) = default;
void Save (const IdentHash& identHash);
void Load (const IdentHash& identHash);
bool IsBad ();
void TunnelBuildResponse (uint8_t ret);
void TunnelNonReplied ();
@ -45,23 +45,23 @@ namespace data
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
bool IsLowPartcipationRate () const;
bool IsLowReplyRate () const;
private:
private:
boost::posix_time::ptime m_LastUpdateTime;
// participation
uint32_t m_NumTunnelsAgreed;
uint32_t m_NumTunnelsDeclined;
uint32_t m_NumTunnelsDeclined;
uint32_t m_NumTunnelsNonReplied;
// usage
uint32_t m_NumTimesTaken;
uint32_t m_NumTimesRejected;
};
uint32_t m_NumTimesRejected;
};
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void InitProfilesStorage ();
void DeleteObsoleteProfiles ();
}
}
}
}
#endif

View file

@ -15,7 +15,7 @@ namespace util
{
template<typename Element>
class Queue
{
{
public:
void Put (Element e)
@ -29,14 +29,14 @@ namespace util
void Put (const Container<Element, R...>& vec)
{
if (!vec.empty ())
{
{
std::unique_lock<std::mutex> l(m_QueueMutex);
for (const auto& it: vec)
m_Queue.push (it);
m_Queue.push (it);
m_NonEmpty.notify_one ();
}
}
}
Element GetNext ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
@ -45,7 +45,7 @@ namespace util
{
m_NonEmpty.wait (l);
el = GetNonThreadSafe ();
}
}
return el;
}
@ -57,7 +57,7 @@ namespace util
{
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
el = GetNonThreadSafe ();
}
}
return el;
}
@ -73,17 +73,17 @@ namespace util
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout;
}
bool IsEmpty ()
{
bool IsEmpty ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.empty ();
}
int GetSize ()
int GetSize ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.size ();
}
}
void WakeUp () { m_NonEmpty.notify_all (); };
@ -91,14 +91,14 @@ namespace util
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe ();
}
}
Element Peek ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (true);
}
}
private:
Element GetNonThreadSafe (bool peek = false)
@ -109,17 +109,17 @@ namespace util
if (!peek)
m_Queue.pop ();
return el;
}
}
return nullptr;
}
}
private:
std::queue<Element> m_Queue;
std::mutex m_QueueMutex;
std::condition_variable m_NonEmpty;
};
}
}
};
}
}
#endif

View file

@ -2,7 +2,7 @@
#include <fstream>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/algorithm/string.hpp>
#include <openssl/ssl.h>
#include <openssl/err.h>
@ -23,7 +23,7 @@ namespace i2p
{
namespace data
{
Reseeder::Reseeder()
{
}
@ -114,11 +114,11 @@ namespace data
return 0;
}
}
int Reseeder::ProcessSU3File (const char * filename)
{
std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ())
if (s.is_open ())
return ProcessSU3Stream (s);
else
{
@ -130,21 +130,21 @@ namespace data
int Reseeder::ProcessZIPFile (const char * filename)
{
std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ())
{
if (s.is_open ())
{
s.seekg (0, std::ios::end);
auto len = s.tellg ();
s.seekg (0, std::ios::beg);
return ProcessZIPStream (s, len);
}
}
else
{
LogPrint (eLogError, "Reseed: Can't open file ", filename);
return 0;
}
}
const char SU3_MAGIC_NUMBER[]="I2Psu3";
}
const char SU3_MAGIC_NUMBER[]="I2Psu3";
int Reseeder::ProcessSU3Stream (std::istream& s)
{
char magicNumber[7];
@ -153,7 +153,7 @@ namespace data
{
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
return 0;
}
}
s.seekg (1, std::ios::cur); // su3 file format version
SigningKeyType signatureType;
s.read ((char *)&signatureType, 2); // signature type
@ -163,16 +163,16 @@ namespace data
signatureLength = be16toh (signatureLength);
s.seekg (1, std::ios::cur); // unused
uint8_t versionLength;
s.read ((char *)&versionLength, 1); // version length
s.read ((char *)&versionLength, 1); // version length
s.seekg (1, std::ios::cur); // unused
uint8_t signerIDLength;
s.read ((char *)&signerIDLength, 1); // signer ID length
s.read ((char *)&signerIDLength, 1); // signer ID length
uint64_t contentLength;
s.read ((char *)&contentLength, 8); // content length
s.read ((char *)&contentLength, 8); // content length
contentLength = be64toh (contentLength);
s.seekg (1, std::ios::cur); // unused
uint8_t fileType;
s.read ((char *)&fileType, 1); // file type
s.read ((char *)&fileType, 1); // file type
if (fileType != 0x00) // zip file
{
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
@ -180,7 +180,7 @@ namespace data
}
s.seekg (1, std::ios::cur); // unused
uint8_t contentType;
s.read ((char *)&contentType, 1); // content type
s.read ((char *)&contentType, 1); // content type
if (contentType != 0x03) // reseed data
{
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
@ -192,10 +192,10 @@ namespace data
char signerID[256];
s.read (signerID, signerIDLength); // signerID
signerID[signerIDLength] = 0;
bool verify; i2p::config::GetOption("reseed.verify", verify);
if (verify)
{
{
//try to verify signature
auto it = m_SigningKeys.find (signerID);
if (it != m_SigningKeys.end ())
@ -220,7 +220,7 @@ namespace data
BIGNUM * s = BN_new (), * n = BN_new ();
BN_bin2bn (signature, signatureLength, s);
BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n);
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
uint8_t * enSigBuf = new uint8_t[signatureLength];
i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
// digest is right aligned
@ -232,8 +232,8 @@ namespace data
delete[] enSigBuf;
BN_free (s); BN_free (n);
BN_CTX_free (bnctx);
}
}
delete[] signature;
delete[] tbs;
s.seekg (pos, std::ios::beg);
@ -249,21 +249,21 @@ namespace data
{
LogPrint (eLogError, "Reseed: SU3 verification failed");
return 0;
}
}
// handle content
return ProcessZIPStream (s, contentLength);
}
const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50;
const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008;
int Reseeder::ProcessZIPStream (std::istream& s, uint64_t contentLength)
{
{
int numFiles = 0;
size_t contentPos = s.tellg ();
while (!s.eof ())
{
{
uint32_t signature;
s.read ((char *)&signature, 4);
signature = le32toh (signature);
@ -272,22 +272,22 @@ namespace data
// next local file
s.seekg (2, std::ios::cur); // version
uint16_t bitFlag;
s.read ((char *)&bitFlag, 2);
s.read ((char *)&bitFlag, 2);
bitFlag = le16toh (bitFlag);
uint16_t compressionMethod;
s.read ((char *)&compressionMethod, 2);
s.read ((char *)&compressionMethod, 2);
compressionMethod = le16toh (compressionMethod);
s.seekg (4, std::ios::cur); // skip fields we don't care about
uint32_t compressedSize, uncompressedSize;
uint32_t compressedSize, uncompressedSize;
uint32_t crc_32;
s.read ((char *)&crc_32, 4);
crc_32 = le32toh (crc_32);
s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize);
s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize);
s.read ((char *)&uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize);
uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2);
uncompressedSize = le32toh (uncompressedSize);
uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2);
fileNameLength = le16toh (fileNameLength);
if ( fileNameLength > 255 ) {
// too big
@ -308,13 +308,13 @@ namespace data
{
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
return numFiles;
}
s.read ((char *)&crc_32, 4);
}
s.read ((char *)&crc_32, 4);
crc_32 = le32toh (crc_32);
s.read ((char *)&compressedSize, 4);
s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data
s.read ((char *)&uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize);
uncompressedSize = le32toh (uncompressedSize);
// now we know compressed and uncompressed size
s.seekg (pos, std::ios::beg); // back to compressed data
@ -325,8 +325,8 @@ namespace data
{
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
continue;
}
}
uint8_t * compressed = new uint8_t[compressedSize];
s.read ((char *)compressed, compressedSize);
if (compressionMethod) // we assume Deflate
@ -338,29 +338,29 @@ namespace data
inflator.next_in = compressed;
inflator.avail_in = compressedSize;
inflator.next_out = uncompressed;
inflator.avail_out = uncompressedSize;
inflator.avail_out = uncompressedSize;
int err;
if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0)
{
{
uncompressedSize -= inflator.avail_out;
if (crc32 (0, uncompressed, uncompressedSize) == crc_32)
{
i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
numFiles++;
}
}
else
LogPrint (eLogError, "Reseed: CRC32 verification failed");
}
}
else
LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
delete[] uncompressed;
delete[] uncompressed;
inflateEnd (&inflator);
}
else // no compression
{
i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
numFiles++;
}
}
delete[] compressed;
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
@ -406,15 +406,15 @@ namespace data
return numFiles;
}
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
bool Reseeder::FindZipDataDescriptor (std::istream& s)
{
size_t nextInd = 0;
size_t nextInd = 0;
while (!s.eof ())
{
uint8_t nextByte;
s.read ((char *)&nextByte, 1);
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
{
nextInd++;
if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
@ -429,24 +429,24 @@ namespace data
void Reseeder::LoadCertificate (const std::string& filename)
{
SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret)
{
{
SSL * ssl = SSL_new (ctx);
X509 * cert = SSL_get_certificate (ssl);
// verify
if (cert)
{
{
// extract issuer name
char name[100];
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
char * cn = strstr (name, "CN=");
if (cn)
{
{
cn += 3;
char * terminator = strchr (cn, '/');
if (terminator) terminator[0] = 0;
}
}
// extract RSA key (we need n only, e = 65537)
RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
const BIGNUM * n, * e, * d;
@ -457,12 +457,12 @@ namespace data
m_SigningKeys[cn] = value;
else
LogPrint (eLogError, "Reseed: Can't find CN field in ", filename);
}
SSL_free (ssl);
}
}
SSL_free (ssl);
}
else
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
SSL_CTX_free (ctx);
SSL_CTX_free (ctx);
}
void Reseeder::LoadCertificates ()
@ -483,9 +483,9 @@ namespace data
}
LoadCertificate (file);
numCertificates++;
}
}
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
}
}
std::string Reseeder::HttpsRequest (const std::string& address)
{

View file

@ -15,10 +15,10 @@ namespace data
class Reseeder
{
typedef Tag<512> PublicKey;
typedef Tag<512> PublicKey;
public:
Reseeder();
~Reseeder();
void Bootstrap ();
@ -28,19 +28,19 @@ namespace data
int ProcessZIPFile (const char * filename);
void LoadCertificates ();
private:
void LoadCertificate (const std::string& filename);
int ProcessSU3Stream (std::istream& s);
int ProcessZIPStream (std::istream& s, uint64_t contentLength);
int ProcessSU3Stream (std::istream& s);
int ProcessZIPStream (std::istream& s, uint64_t contentLength);
bool FindZipDataDescriptor (std::istream& s);
std::string HttpsRequest (const std::string& address);
private:
private:
std::map<std::string, PublicKey> m_SigningKeys;
};

View file

@ -28,7 +28,7 @@ namespace i2p
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
if (!Load ())
CreateNewRouter ();
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
UpdateRouterInfo ();
}
@ -204,7 +204,7 @@ namespace i2p
}
}
void RouterContext::SetBandwidth (char L)
void RouterContext::SetBandwidth (char L)
{
uint32_t limit = 0;
enum { low, high, extra, unlim } type = high;

View file

@ -13,7 +13,7 @@
namespace i2p
{
const char ROUTER_INFO[] = "router.info";
const char ROUTER_KEYS[] = "router.keys";
const char ROUTER_KEYS[] = "router.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
enum RouterStatus
@ -21,16 +21,16 @@ namespace i2p
eRouterStatusOK = 0,
eRouterStatusTesting = 1,
eRouterStatusFirewalled = 2,
eRouterStatusError = 3
};
eRouterStatusError = 3
};
enum RouterError
{
eRouterErrorNone = 0,
eRouterErrorClockSkew = 1
};
class RouterContext: public i2p::garlic::GarlicDestination
};
class RouterContext: public i2p::garlic::GarlicDestination
{
public:
@ -39,17 +39,17 @@ namespace i2p
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
{
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
{
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
[](const i2p::data::RouterInfo *) {});
}
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
{
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
[](i2p::garlic::GarlicDestination *) {});
}
}
uint32_t GetUptime () const;
uint32_t GetStartupTime () const { return m_StartupTime; };
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
@ -60,17 +60,17 @@ namespace i2p
RouterError GetError () const { return m_Error; };
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
int GetNetID () const { return m_NetID; };
void SetNetID (int netID) { m_NetID = netID; };
void SetNetID (int netID) { m_NetID = netID; };
void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
bool IsUnreachable () const;
void SetUnreachable ();
void SetUnreachable ();
void SetReachable ();
bool IsFloodfill () const { return m_IsFloodfill; };
void SetFloodfill (bool floodfill);
bool IsFloodfill () const { return m_IsFloodfill; };
void SetFloodfill (bool floodfill);
void SetFamily (const std::string& family);
std::string GetFamily () const;
void SetBandwidth (int limit); /* in kilobytes */
@ -83,14 +83,14 @@ namespace i2p
void SetSupportsV6 (bool supportsV6);
void SetSupportsV4 (bool supportsV4);
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
void UpdateStats ();
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
void UpdateStats ();
void CleanupDestination (); // garlic destination
// implements LocalDestination
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
void SetLeaseSetUpdated () {};
// implements GarlicDestination
@ -100,8 +100,8 @@ namespace i2p
// override GarlicDestination
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
private:
void CreateNewRouter ();
@ -109,11 +109,11 @@ namespace i2p
void UpdateRouterInfo ();
bool Load ();
void SaveKeys ();
private:
i2p::data::RouterInfo m_RouterInfo;
i2p::data::PrivateKeys m_Keys;
i2p::data::PrivateKeys m_Keys;
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
uint64_t m_LastUpdateTime;
bool m_AcceptsTunnels, m_IsFloodfill;
@ -127,6 +127,6 @@ namespace i2p
};
extern RouterContext context;
}
}
#endif

View file

@ -19,20 +19,20 @@
namespace i2p
{
namespace data
{
RouterInfo::RouterInfo (): m_Buffer (nullptr)
{
{
RouterInfo::RouterInfo (): m_Buffer (nullptr)
{
m_Addresses = boost::make_shared<Addresses>(); // create empty list
}
RouterInfo::RouterInfo (const std::string& fullPath):
m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false),
m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0), m_Caps (0)
{
m_Addresses = boost::make_shared<Addresses>(); // create empty list
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
ReadFromFile ();
}
}
RouterInfo::RouterInfo (const uint8_t * buf, int len):
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
@ -42,13 +42,13 @@ namespace data
memcpy (m_Buffer, buf, len);
m_BufferLen = len;
ReadFromBuffer (true);
}
}
RouterInfo::~RouterInfo ()
{
delete[] m_Buffer;
}
}
void RouterInfo::Update (const uint8_t * buf, int len)
{
// verify signature since we have indentity already
@ -63,35 +63,35 @@ namespace data
// don't clean up m_Addresses, it will be replaced in ReadFromStream
m_Properties.clear ();
// copy buffer
if (!m_Buffer)
if (!m_Buffer)
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
memcpy (m_Buffer, buf, len);
m_BufferLen = len;
// skip identity
size_t identityLen = m_RouterIdentity->GetFullLen ();
// read new RI
// read new RI
std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
ReadFromStream (str);
// don't delete buffer until saved to the file
}
else
{
{
LogPrint (eLogError, "RouterInfo: signature verification failed");
m_IsUnreachable = true;
}
}
}
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
{
{
m_RouterIdentity = identity;
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
}
bool RouterInfo::LoadFile ()
{
std::ifstream s(m_FullPath, std::ifstream::binary);
if (s.is_open ())
{
if (s.is_open ())
{
s.seekg (0,std::ios::end);
m_BufferLen = s.tellg ();
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
@ -103,22 +103,22 @@ namespace data
if (!m_Buffer)
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
s.read((char *)m_Buffer, m_BufferLen);
}
}
else
{
LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath);
return false;
return false;
}
return true;
}
}
void RouterInfo::ReadFromFile ()
{
if (LoadFile ())
ReadFromBuffer (false);
ReadFromBuffer (false);
else
m_IsUnreachable = true;
}
m_IsUnreachable = true;
}
void RouterInfo::ReadFromBuffer (bool verifySignature)
{
@ -131,7 +131,7 @@ namespace data
return;
}
if (verifySignature)
{
{
// reject RSA signatures
if (m_RouterIdentity->IsRSA ())
{
@ -140,15 +140,15 @@ namespace data
return;
}
// verify signature
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
{
{
LogPrint (eLogError, "RouterInfo: signature verification failed");
m_IsUnreachable = true;
return;
}
m_RouterIdentity->DropVerifier ();
}
}
// parse RI
std::stringstream str;
str.write ((const char *)m_Buffer + identityLen, m_BufferLen - identityLen);
@ -158,17 +158,17 @@ namespace data
LogPrint (eLogError, "RouterInfo: malformed message");
m_IsUnreachable = true;
}
}
}
void RouterInfo::ReadFromStream (std::istream& s)
{
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
m_Timestamp = be64toh (m_Timestamp);
// read addresses
auto addresses = boost::make_shared<Addresses>();
auto addresses = boost::make_shared<Addresses>();
uint8_t numAddresses;
s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return;
s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return;
bool introducers = false;
for (int i = 0; i < numAddresses; i++)
{
@ -181,11 +181,11 @@ namespace data
if (!strcmp (transportStyle, "NTCP"))
address->transportStyle = eTransportNTCP;
else if (!strcmp (transportStyle, "SSU"))
{
{
address->transportStyle = eTransportSSU;
address->ssu.reset (new SSUExt ());
address->ssu->mtu = 0;
}
}
else
address->transportStyle = eTransportUnknown;
address->port = 0;
@ -197,35 +197,35 @@ namespace data
char key[255], value[255];
r += ReadString (key, 255, s);
s.seekg (1, std::ios_base::cur); r++; // =
r += ReadString (value, 255, s);
r += ReadString (value, 255, s);
s.seekg (1, std::ios_base::cur); r++; // ;
if (!s) return;
if (!strcmp (key, "host"))
{
{
boost::system::error_code ecode;
address->host = boost::asio::ip::address::from_string (value, ecode);
if (ecode)
{
{
if (address->transportStyle == eTransportNTCP)
{
supportedTransports |= eNTCPV4; // TODO:
address->addressString = value;
}
else
{
{
supportedTransports |= eSSUV4; // TODO:
address->addressString = value;
}
}
}
}
else
{
// add supported protocol
if (address->host.is_v4 ())
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
else
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
}
}
}
}
else if (!strcmp (key, "port"))
address->port = boost::lexical_cast<int>(value);
else if (!strcmp (key, "mtu"))
@ -234,21 +234,21 @@ namespace data
address->ssu->mtu = boost::lexical_cast<int>(value);
else
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
}
}
else if (!strcmp (key, "key"))
{
{
if (address->ssu)
Base64ToByteStream (value, strlen (value), address->ssu->key, 32);
else
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
}
}
else if (!strcmp (key, "caps"))
ExtractCaps (value);
else if (key[0] == 'i')
{
{
// introducers
introducers = true;
size_t l = strlen(key);
size_t l = strlen(key);
unsigned char index = key[l-1] - '0'; // TODO:
key[l-1] = 0;
if (index > 9)
@ -257,13 +257,13 @@ namespace data
if (s) continue; else return;
}
if (index >= address->ssu->introducers.size ())
address->ssu->introducers.resize (index + 1);
address->ssu->introducers.resize (index + 1);
Introducer& introducer = address->ssu->introducers.at (index);
if (!strcmp (key, "ihost"))
{
boost::system::error_code ecode;
introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
}
}
else if (!strcmp (key, "iport"))
introducer.iPort = boost::lexical_cast<int>(value);
else if (!strcmp (key, "itag"))
@ -274,19 +274,19 @@ namespace data
introducer.iExp = boost::lexical_cast<uint32_t>(value);
}
if (!s) return;
}
}
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
if (supportedTransports)
{
addresses->push_back(address);
m_SupportedTransports |= supportedTransports;
}
}
#if (BOOST_VERSION >= 105300)
}
#if (BOOST_VERSION >= 105300)
boost::atomic_store (&m_Addresses, addresses);
#else
m_Addresses = addresses; // race condition
#endif
#endif
// read peers
uint8_t numPeers;
s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return;
@ -297,23 +297,23 @@ namespace data
size = be16toh (size);
while (r < size)
{
char key[255], value[255];
char key[255], value[255];
r += ReadString (key, 255, s);
s.seekg (1, std::ios_base::cur); r++; // =
r += ReadString (value, 255, s);
r += ReadString (value, 255, s);
s.seekg (1, std::ios_base::cur); r++; // ;
if (!s) return;
m_Properties[key] = value;
// extract caps
// extract caps
if (!strcmp (key, "caps"))
ExtractCaps (value);
// check netId
else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ())
{
LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
m_IsUnreachable = true;
}
m_IsUnreachable = true;
}
// family
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY))
{
@ -327,10 +327,10 @@ namespace data
LogPrint (eLogWarning, "RouterInfo: family signature verification failed");
m_Family.clear ();
}
}
}
if (!s) return;
}
}
if (!m_SupportedTransports || !m_Addresses->size() || (UsesIntroducer () && !introducers))
SetUnreachable (true);
@ -358,56 +358,56 @@ namespace data
case CAPS_FLAG_EXTRA_BANDWIDTH1:
case CAPS_FLAG_EXTRA_BANDWIDTH2:
m_Caps |= Caps::eExtraBandwidth;
break;
break;
case CAPS_FLAG_HIDDEN:
m_Caps |= Caps::eHidden;
break;
break;
case CAPS_FLAG_REACHABLE:
m_Caps |= Caps::eReachable;
break;
case CAPS_FLAG_UNREACHABLE:
m_Caps |= Caps::eUnreachable;
break;
break;
case CAPS_FLAG_SSU_TESTING:
m_Caps |= Caps::eSSUTesting;
break;
break;
case CAPS_FLAG_SSU_INTRODUCER:
m_Caps |= Caps::eSSUIntroducer;
break;
break;
default: ;
}
}
cap++;
}
}
void RouterInfo::UpdateCapsProperty ()
{
{
std::string caps;
if (m_Caps & eFloodfill)
if (m_Caps & eFloodfill)
{
if (m_Caps & eExtraBandwidth) caps += (m_Caps & eHighBandwidth) ?
CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
caps += CAPS_FLAG_FLOODFILL; // floodfill
}
else
caps += CAPS_FLAG_FLOODFILL; // floodfill
}
else
{
if (m_Caps & eExtraBandwidth)
{
if (m_Caps & eExtraBandwidth)
{
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
}
else
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
}
else
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
}
if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
SetProperty ("caps", caps);
}
void RouterInfo::WriteToStream (std::ostream& s) const
{
uint64_t ts = htobe64 (m_Timestamp);
@ -425,7 +425,7 @@ namespace data
if (address.transportStyle == eTransportNTCP)
WriteString ("NTCP", s);
else if (address.transportStyle == eTransportSSU)
{
{
WriteString ("SSU", s);
// caps
WriteString ("caps", properties);
@ -435,7 +435,7 @@ namespace data
if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
WriteString (caps, properties);
properties << ';';
}
}
else
WriteString ("", s);
@ -447,7 +447,7 @@ namespace data
{
// write introducers if any
if (address.ssu->introducers.size () > 0)
{
{
int i = 0;
for (const auto& introducer: address.ssu->introducers)
{
@ -456,7 +456,7 @@ namespace data
WriteString (introducer.iHost.to_string (), properties);
properties << ';';
i++;
}
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
@ -468,7 +468,7 @@ namespace data
WriteString (value, properties);
properties << ';';
i++;
}
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
@ -477,7 +477,7 @@ namespace data
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
properties << ';';
i++;
}
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
@ -486,7 +486,7 @@ namespace data
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
properties << ';';
i++;
}
}
i = 0;
for (const auto& introducer: address.ssu->introducers)
{
@ -498,8 +498,8 @@ namespace data
properties << ';';
}
i++;
}
}
}
}
// write intro key
WriteString ("key", properties);
properties << '=';
@ -515,17 +515,17 @@ namespace data
properties << '=';
WriteString (boost::lexical_cast<std::string>(address.ssu->mtu), properties);
properties << ';';
}
}
}
}
WriteString ("port", properties);
properties << '=';
WriteString (boost::lexical_cast<std::string>(address.port), properties);
properties << ';';
uint16_t size = htobe16 (properties.str ().size ());
s.write ((char *)&size, sizeof (size));
s.write (properties.str ().c_str (), properties.str ().size ());
}
}
// peers
uint8_t numPeers = 0;
@ -539,18 +539,18 @@ namespace data
properties << '=';
WriteString (p.second, properties);
properties << ';';
}
}
uint16_t size = htobe16 (properties.str ().size ());
s.write ((char *)&size, sizeof (size));
s.write (properties.str ().c_str (), properties.str ().size ());
}
}
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
{
if (!m_RouterIdentity) return false;
size_t size = m_RouterIdentity->GetFullLen ();
if (size + 8 > len) return false;
return bufbe64toh (buf + size) > m_Timestamp;
return bufbe64toh (buf + size) > m_Timestamp;
}
const uint8_t * RouterInfo::LoadBuffer ()
@ -559,8 +559,8 @@ namespace data
{
if (LoadFile ())
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
}
return m_Buffer;
}
return m_Buffer;
}
void RouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
@ -569,7 +569,7 @@ namespace data
std::stringstream s;
uint8_t ident[1024];
auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024);
s.write ((char *)ident, identLen);
s.write ((char *)ident, identLen);
WriteToStream (s);
m_BufferLen = s.str ().size ();
if (!m_Buffer)
@ -578,7 +578,7 @@ namespace data
// signature
privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen ();
}
}
bool RouterInfo::SaveToFile (const std::string& fullPath)
{
@ -595,13 +595,13 @@ namespace data
f.write ((char *)m_Buffer, m_BufferLen);
return true;
}
size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
{
uint8_t l;
s.read ((char *)&l, 1);
if (l < len)
{
{
s.read (str, l);
if (!s) l = 0; // failed, return empty string
str[l] = 0;
@ -611,16 +611,16 @@ namespace data
LogPrint (eLogWarning, "RouterInfo: string length ", (int)l, " exceeds buffer size ", len);
s.seekg (l, std::ios::cur); // skip
str[0] = 0;
}
}
return l+1;
}
}
void RouterInfo::WriteString (const std::string& str, std::ostream& s) const
{
uint8_t len = str.size ();
s.write ((char *)&len, 1);
s.write (str.c_str (), len);
}
}
void RouterInfo::AddNTCPAddress (const char * host, int port)
{
@ -634,7 +634,7 @@ namespace data
if (*it == *addr) return;
m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4;
m_Addresses->push_back(std::move(addr));
}
}
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
{
@ -645,7 +645,7 @@ namespace data
addr->cost = 10; // NTCP should have priority over SSU
addr->date = 0;
addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = mtu;
addr->ssu->mtu = mtu;
memcpy (addr->ssu->key, key, 32);
for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return;
@ -654,37 +654,37 @@ namespace data
m_Caps |= eSSUTesting;
m_Caps |= eSSUIntroducer;
}
}
bool RouterInfo::AddIntroducer (const Introducer& introducer)
{
for (auto& addr : *m_Addresses)
{
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{
{
for (auto& intro: addr->ssu->introducers)
if (intro.iTag == introducer.iTag) return false; // already presented
addr->ssu->introducers.push_back (introducer);
return true;
}
}
}
}
return false;
}
}
bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
{
{
for (auto& addr: *m_Addresses)
{
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{
{
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
{
addr->ssu->introducers.erase (it);
return true;
}
}
}
}
}
return false;
}
@ -693,39 +693,39 @@ namespace data
m_Caps = caps;
UpdateCapsProperty ();
}
void RouterInfo::SetCaps (const char * caps)
{
SetProperty ("caps", caps);
m_Caps = 0;
ExtractCaps (caps);
}
}
void RouterInfo::SetProperty (const std::string& key, const std::string& value)
{
m_Properties[key] = value;
}
}
void RouterInfo::DeleteProperty (const std::string& key)
{
m_Properties.erase (key);
}
std::string RouterInfo::GetProperty (const std::string& key) const
std::string RouterInfo::GetProperty (const std::string& key) const
{
auto it = m_Properties.find (key);
if (it != m_Properties.end ())
return it->second;
return "";
}
}
bool RouterInfo::IsNTCP (bool v4only) const
{
if (v4only)
return m_SupportedTransports & eNTCPV4;
else
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
}
}
bool RouterInfo::IsSSU (bool v4only) const
{
@ -744,7 +744,7 @@ namespace data
{
return m_SupportedTransports & (eNTCPV4 | eSSUV4);
}
void RouterInfo::EnableV6 ()
{
if (!IsV6 ())
@ -756,13 +756,13 @@ namespace data
if (!IsV4 ())
m_SupportedTransports |= eNTCPV4 | eSSUV4;
}
void RouterInfo::DisableV6 ()
{
{
if (IsV6 ())
{
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6);
{
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6);
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
{
auto addr = *it;
@ -770,15 +770,15 @@ namespace data
it = m_Addresses->erase (it);
else
++it;
}
}
}
}
}
void RouterInfo::DisableV4 ()
{
{
if (IsV4 ())
{
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4);
{
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4);
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
{
auto addr = *it;
@ -786,55 +786,55 @@ namespace data
it = m_Addresses->erase (it);
else
++it;
}
}
}
}
}
bool RouterInfo::UsesIntroducer () const
{
return m_Caps & Caps::eUnreachable; // non-reachable
}
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCPAddress (bool v4only) const
{
return GetAddress (eTransportNTCP, v4only);
}
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
{
return GetAddress (eTransportSSU, v4only);
}
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
{
return GetAddress (eTransportSSU, false, true);
}
}
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
{
#if (BOOST_VERSION >= 105300)
auto addresses = boost::atomic_load (&m_Addresses);
#else
#else
auto addresses = m_Addresses;
#endif
#endif
for (const auto& address : *addresses)
{
if (address->transportStyle == s)
{
{
if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ()))
return address;
}
}
}
}
return nullptr;
}
}
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
{
if (!m_Profile)
m_Profile = GetRouterProfile (GetIdentHash ());
return m_Profile;
}
}
void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
{

View file

@ -8,7 +8,7 @@
#include <list>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include "Identity.h"
#include "Profiling.h"
@ -17,15 +17,15 @@ namespace i2p
namespace data
{
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
const char ROUTER_INFO_PROPERTY_NETID[] = "netId";
const char ROUTER_INFO_PROPERTY_FAMILY[] = "family";
const char ROUTER_INFO_PROPERTY_FAMILY[] = "family";
const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig";
const char CAPS_FLAG_FLOODFILL = 'f';
const char CAPS_FLAG_HIDDEN = 'H';
const char CAPS_FLAG_REACHABLE = 'R';
const char CAPS_FLAG_UNREACHABLE = 'U';
const char CAPS_FLAG_UNREACHABLE = 'U';
/* bandwidth flags */
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */
@ -34,7 +34,7 @@ namespace data
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
const char CAPS_FLAG_SSU_TESTING = 'B';
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
@ -44,13 +44,13 @@ namespace data
public:
enum SupportedTranports
{
{
eNTCPV4 = 0x01,
eNTCPV6 = 0x02,
eSSUV4 = 0x04,
eSSUV6 = 0x08
};
enum Caps
{
eFloodfill = 0x01,
@ -71,7 +71,7 @@ namespace data
};
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
struct Introducer
struct Introducer
{
Introducer (): iExp (0) {};
boost::asio::ip::address iHost;
@ -85,9 +85,9 @@ namespace data
{
int mtu;
IntroKey key; // intro key for SSU
std::vector<Introducer> introducers;
std::vector<Introducer> introducers;
};
struct Address
{
TransportStyle transportStyle;
@ -98,23 +98,23 @@ namespace data
uint8_t cost;
std::unique_ptr<SSUExt> ssu; // not null for SSU
bool IsCompatible (const boost::asio::ip::address& other) const
bool IsCompatible (const boost::asio::ip::address& other) const
{
return (host.is_v4 () && other.is_v4 ()) ||
(host.is_v6 () && other.is_v6 ());
}
}
bool operator==(const Address& other) const
{
return transportStyle == other.transportStyle && host == other.host && port == other.port;
}
}
bool operator!=(const Address& other) const
{
return !(*this == other);
}
}
};
typedef std::list<std::shared_ptr<Address> > Addresses;
typedef std::list<std::shared_ptr<Address> > Addresses;
RouterInfo ();
RouterInfo (const std::string& fullPath);
@ -122,7 +122,7 @@ namespace data
RouterInfo& operator=(const RouterInfo& ) = default;
RouterInfo (const uint8_t * buf, int len);
~RouterInfo ();
std::shared_ptr<const IdentityEx> GetRouterIdentity () const { return m_RouterIdentity; };
void SetRouterIdentity (std::shared_ptr<const IdentityEx> identity);
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
@ -131,7 +131,7 @@ namespace data
std::shared_ptr<const Address> GetNTCPAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const;
void AddNTCPAddress (const char * host, int port);
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
bool AddIntroducer (const Introducer& introducer);
@ -156,37 +156,37 @@ namespace data
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
bool IsHidden () const { return m_Caps & eHidden; };
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
uint8_t GetCaps () const { return m_Caps; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps);
void SetCaps (const char * caps);
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; };
const uint8_t * GetBuffer () const { return m_Buffer; };
const uint8_t * LoadBuffer (); // load if necessary
int GetBufferLen () const { return m_BufferLen; };
int GetBufferLen () const { return m_BufferLen; };
void CreateBuffer (const PrivateKeys& privateKeys);
bool IsUpdated () const { return m_IsUpdated; };
void SetUpdated (bool updated) { m_IsUpdated = updated; };
void SetUpdated (bool updated) { m_IsUpdated = updated; };
bool SaveToFile (const std::string& fullPath);
std::shared_ptr<RouterProfile> GetProfile () const;
void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
void Update (const uint8_t * buf, int len);
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const;
bool IsNewer (const uint8_t * buf, size_t len) const;
/** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const;
/** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const;
// implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; };
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
bool IsDestination () const { return false; };
@ -201,7 +201,7 @@ namespace data
void WriteString (const std::string& str, std::ostream& s) const;
void ExtractCaps (const char * value);
std::shared_ptr<const Address> GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
void UpdateCapsProperty ();
void UpdateCapsProperty ();
private:
@ -210,13 +210,13 @@ namespace data
uint8_t * m_Buffer;
size_t m_BufferLen;
uint64_t m_Timestamp;
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
std::map<std::string, std::string> m_Properties;
bool m_IsUpdated, m_IsUnreachable;
uint8_t m_SupportedTransports, m_Caps;
mutable std::shared_ptr<RouterProfile> m_Profile;
};
}
};
}
}
#endif

View file

@ -13,32 +13,32 @@ namespace transport
SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
m_OnlyV6(true), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
m_TerminationTimerV6 (m_ServiceV6)
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
m_TerminationTimerV6 (m_ServiceV6)
{
OpenSocketV6 ();
}
SSUServer::SSUServer (int port):
m_OnlyV6(false), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
{
OpenSocket ();
if (context.SupportsV6 ())
OpenSocketV6 ();
}
SSUServer::~SSUServer ()
{
}
@ -46,11 +46,11 @@ namespace transport
void SSUServer::OpenSocket ()
{
m_Socket.open (boost::asio::ip::udp::v4());
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
m_Socket.bind (m_Endpoint);
}
void SSUServer::OpenSocketV6 ()
{
m_SocketV6.open (boost::asio::ip::udp::v6());
@ -58,8 +58,8 @@ namespace transport
m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
m_SocketV6.bind (m_EndpointV6);
}
}
void SSUServer::Start ()
{
m_IsRunning = true;
@ -68,16 +68,16 @@ namespace transport
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
ScheduleTermination ();
ScheduleTermination ();
}
if (context.SupportsV6 ())
{
{
m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this));
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
ScheduleTerminationV6 ();
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
ScheduleTerminationV6 ();
}
SchedulePeerTestsCleanupTimer ();
SchedulePeerTestsCleanupTimer ();
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers
}
@ -86,7 +86,7 @@ namespace transport
DeleteAllSessions ();
m_IsRunning = false;
m_TerminationTimer.cancel ();
m_TerminationTimerV6.cancel ();
m_TerminationTimerV6.cancel ();
m_Service.stop ();
m_Socket.close ();
m_ServiceV6.stop ();
@ -94,135 +94,135 @@ namespace transport
m_ReceiversService.stop ();
m_ReceiversServiceV6.stop ();
if (m_ReceiversThread)
{
m_ReceiversThread->join ();
{
m_ReceiversThread->join ();
delete m_ReceiversThread;
m_ReceiversThread = nullptr;
}
if (m_Thread)
{
m_Thread->join ();
{
m_Thread->join ();
delete m_Thread;
m_Thread = nullptr;
}
if (m_ReceiversThreadV6)
{
m_ReceiversThreadV6->join ();
{
m_ReceiversThreadV6->join ();
delete m_ReceiversThreadV6;
m_ReceiversThreadV6 = nullptr;
}
if (m_ThreadV6)
{
m_ThreadV6->join ();
{
m_ThreadV6->join ();
delete m_ThreadV6;
m_ThreadV6 = nullptr;
}
}
void SSUServer::Run ()
{
void SSUServer::Run ()
{
while (m_IsRunning)
{
try
{
{
m_Service.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ());
}
}
}
}
}
void SSUServer::RunV6 ()
{
void SSUServer::RunV6 ()
{
while (m_IsRunning)
{
try
{
{
m_ServiceV6.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ());
}
}
}
}
}
}
void SSUServer::RunReceivers ()
{
void SSUServer::RunReceivers ()
{
while (m_IsRunning)
{
try
{
{
m_ReceiversService.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
}
}
}
void SSUServer::RunReceiversV6 ()
{
}
}
}
void SSUServer::RunReceiversV6 ()
{
while (m_IsRunning)
{
try
{
{
m_ReceiversServiceV6.run ();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
}
}
}
}
}
}
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
{
m_Relays[tag] = relay;
}
}
void SSUServer::RemoveRelay (uint32_t tag)
{
m_Relays.erase (tag);
}
}
std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
{
auto it = m_Relays.find (tag);
if (it != m_Relays.end ())
{
{
if (it->second->GetState () == eSessionStateEstablished)
return it->second;
else
m_Relays.erase (it);
}
m_Relays.erase (it);
}
return nullptr;
}
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
{
if (to.protocol () == boost::asio::ip::udp::v4())
if (to.protocol () == boost::asio::ip::udp::v4())
m_Socket.send_to (boost::asio::buffer (buf, len), to);
else
m_SocketV6.send_to (boost::asio::buffer (buf, len), to);
}
}
void SSUServer::Receive ()
{
SSUPacket * packet = new SSUPacket ();
m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from,
std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet));
std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet));
}
void SSUServer::ReceiveV6 ()
{
SSUPacket * packet = new SSUPacket ();
m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from,
std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet));
}
std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet));
}
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
{
@ -235,13 +235,13 @@ namespace transport
boost::system::error_code ec;
size_t moreBytes = m_Socket.available(ec);
if (!ec)
{
{
while (moreBytes && packets.size () < 25)
{
packet = new SSUPacket ();
packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec);
if (!ec)
{
{
packets.push_back (packet);
moreBytes = m_Socket.available(ec);
if (ec) break;
@ -251,15 +251,15 @@ namespace transport
LogPrint (eLogError, "SSU: receive_from error: ", ec.message ());
delete packet;
break;
}
}
}
}
}
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
Receive ();
}
else
{
{
delete packet;
if (ecode != boost::asio::error::operation_aborted)
{
@ -268,7 +268,7 @@ namespace transport
OpenSocket ();
Receive ();
}
}
}
}
void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
@ -298,15 +298,15 @@ namespace transport
LogPrint (eLogError, "SSU: v6 receive_from error: ", ec.message ());
delete packet;
break;
}
}
}
}
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
ReceiveV6 ();
}
else
{
{
delete packet;
if (ecode != boost::asio::error::operation_aborted)
{
@ -315,17 +315,17 @@ namespace transport
OpenSocketV6 ();
ReceiveV6 ();
}
}
}
}
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
{
std::shared_ptr<SSUSession> session;
std::shared_ptr<SSUSession> session;
for (auto& packet: packets)
{
try
{
{
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
{
if (session) session->FlushData ();
@ -341,13 +341,13 @@ namespace transport
}
}
session->ProcessNextMessage (packet->buf, packet->len, packet->from);
}
}
catch (std::exception& ex)
{
LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ());
if (session) session->FlushData ();
session = nullptr;
}
}
delete packet;
}
if (session) session->FlushData ();
@ -357,26 +357,26 @@ namespace transport
{
if (!router) return nullptr;
auto address = router->GetSSUAddress (true); // v4 only
if (!address) return nullptr;
if (!address) return nullptr;
auto session = FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
if (session || !context.SupportsV6 ())
return session;
// try v6
address = router->GetSSUV6Address ();
address = router->GetSSUV6Address ();
if (!address) return nullptr;
return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
}
}
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (e);
if (it != sessions.end ())
return it->second;
else
return nullptr;
}
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest, bool v4only)
{
auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
@ -385,7 +385,7 @@ namespace transport
else
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
}
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
const boost::asio::ip::address& addr, int port, bool peerTest)
{
@ -403,27 +403,27 @@ namespace transport
}
void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest)
{
auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
{
auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (remoteEndpoint);
if (it != sessions.end ())
{
{
auto session = it->second;
if (peerTest && session->GetState () == eSessionStateEstablished)
session->SendPeerTest ();
}
}
else
{
// otherwise create new session
// otherwise create new session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
sessions[remoteEndpoint] = session;
// connect
// connect
LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
session->Connect ();
}
}
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{
if (router && router->UsesIntroducer ())
@ -435,13 +435,13 @@ namespace transport
auto it = m_Sessions.find (remoteEndpoint);
// check if session is presented already
if (it != m_Sessions.end ())
{
{
auto session = it->second;
if (peerTest && session->GetState () == eSessionStateEstablished)
session->SendPeerTest ();
return;
}
// create new session
return;
}
// create new session
int numIntroducers = address->ssu->introducers.size ();
if (numIntroducers > 0)
{
@ -455,52 +455,52 @@ namespace transport
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
if (ep.address ().is_v4 ()) // ipv4 only
{
{
if (!introducer) introducer = intr; // we pick first one for now
it = m_Sessions.find (ep);
it = m_Sessions.find (ep);
if (it != m_Sessions.end ())
{
introducerSession = it->second;
break;
}
break;
}
}
}
if (!introducer)
{
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented");
return;
}
}
if (introducerSession) // session found
if (introducerSession) // session found
LogPrint (eLogWarning, "SSU: Session to introducer already exists");
else // create new
{
LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession;
m_Sessions[introducerEndpoint] = introducerSession;
}
#if BOOST_VERSION >= 104900
#if BOOST_VERSION >= 104900
if (!address->host.is_unspecified () && address->port)
#endif
{
// create session
// create session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
m_Sessions[remoteEndpoint] = session;
// introduce
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
"] through introducer ", introducer->iHost, ":", introducer->iPort);
session->WaitForIntroduction ();
session->WaitForIntroduction ();
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
{
uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch
}
}
}
introducerSession->Introduce (*introducer, router);
}
else
else
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
}
else
@ -518,8 +518,8 @@ namespace transport
m_SessionsV6.erase (ep);
else
m_Sessions.erase (ep);
}
}
}
}
void SSUServer::DeleteAllSessions ()
{
@ -543,15 +543,15 @@ namespace transport
auto ind = rand () % filteredSessions.size ();
return filteredSessions[ind];
}
return nullptr;
return nullptr;
}
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
{
return GetRandomV4Session (
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished && session != excluded;
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished && session != excluded;
}
);
}
@ -567,15 +567,15 @@ namespace transport
auto ind = rand () % filteredSessions.size ();
return filteredSessions[ind];
}
return nullptr;
return nullptr;
}
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only
{
return GetRandomV6Session (
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished && session != excluded;
[excluded](std::shared_ptr<SSUSession> session)->bool
{
return session->GetState () == eSessionStateEstablished && session != excluded;
}
);
}
@ -587,18 +587,18 @@ namespace transport
for (int i = 0; i < maxNumIntroducers; i++)
{
auto session = GetRandomV4Session (
[&ret, ts](std::shared_ptr<SSUSession> session)->bool
{
[&ret, ts](std::shared_ptr<SSUSession> session)->bool
{
return session->GetRelayTag () && !ret.count (session.get ()) &&
session->GetState () == eSessionStateEstablished &&
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
}
);
);
if (session)
{
ret.insert (session.get ());
break;
}
}
}
return ret;
}
@ -607,7 +607,7 @@ namespace transport
{
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, std::placeholders::_1));
this, std::placeholders::_1));
}
void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode)
@ -620,7 +620,7 @@ namespace transport
// we still don't know if we need introducers
ScheduleIntroducersUpdateTimer ();
return;
}
}
if (i2p::context.GetStatus () == eRouterStatusOK) return; // we don't need introducers anymore
// we are firewalled
if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable ();
@ -628,7 +628,7 @@ namespace transport
size_t numIntroducers = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (const auto& it : m_Introducers)
{
{
auto session = FindSession (it);
if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION)
{
@ -636,7 +636,7 @@ namespace transport
newList.push_back (it);
numIntroducers++;
}
else
else
i2p::context.RemoveIntroducer (it);
}
@ -658,16 +658,16 @@ namespace transport
if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
}
}
}
}
m_Introducers = newList;
if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS)
{
auto introducer = i2p::data::netdb.GetRandomIntroducer ();
if (introducer)
CreateSession (introducer);
}
}
ScheduleIntroducersUpdateTimer ();
}
}
}
void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session)
@ -682,7 +682,7 @@ namespace transport
return it->second.role;
else
return ePeerTestParticipantUnknown;
}
}
std::shared_ptr<SSUSession> SSUServer::GetPeerTestSession (uint32_t nonce)
{
@ -698,26 +698,26 @@ namespace transport
auto it = m_PeerTests.find (nonce);
if (it != m_PeerTests.end ())
it->second.role = role;
}
}
void SSUServer::RemovePeerTest (uint32_t nonce)
{
m_PeerTests.erase (nonce);
}
}
void SSUServer::SchedulePeerTestsCleanupTimer ()
{
m_PeerTestsCleanupTimer.expires_from_now (boost::posix_time::seconds(SSU_PEER_TEST_TIMEOUT));
m_PeerTestsCleanupTimer.async_wait (std::bind (&SSUServer::HandlePeerTestsCleanupTimer,
this, std::placeholders::_1));
this, std::placeholders::_1));
}
void SSUServer::HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
int numDeleted = 0;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
int numDeleted = 0;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();)
{
if (ts > it->second.creationTime + SSU_PEER_TEST_TIMEOUT*1000LL)
@ -744,21 +744,21 @@ namespace transport
void SSUServer::HandleTerminationTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto& it: m_Sessions)
if (it.second->IsTerminationTimeoutExpired (ts))
if (it.second->IsTerminationTimeoutExpired (ts))
{
auto session = it.second;
m_Service.post ([session]
{
m_Service.post ([session]
{
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
session->Failed ();
});
});
}
ScheduleTermination ();
}
}
ScheduleTermination ();
}
}
void SSUServer::ScheduleTerminationV6 ()
{
@ -770,21 +770,21 @@ namespace transport
void SSUServer::HandleTerminationTimerV6 (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto& it: m_SessionsV6)
if (it.second->IsTerminationTimeoutExpired (ts))
if (it.second->IsTerminationTimeoutExpired (ts))
{
auto session = it.second;
m_ServiceV6.post ([session]
{
m_ServiceV6.post ([session]
{
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
session->Failed ();
});
});
}
ScheduleTerminationV6 ();
}
}
ScheduleTerminationV6 ();
}
}
}
}

View file

@ -20,8 +20,8 @@ namespace i2p
{
namespace transport
{
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
const size_t SSU_MAX_NUM_INTRODUCERS = 3;
@ -33,8 +33,8 @@ namespace transport
i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
boost::asio::ip::udp::endpoint from;
size_t len;
};
};
class SSUServer
{
public:
@ -45,7 +45,7 @@ namespace transport
void Start ();
void Stop ();
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
const boost::asio::ip::address& addr, int port, bool peerTest = false);
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
@ -53,11 +53,11 @@ namespace transport
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
std::shared_ptr<SSUSession> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions ();
void DeleteAllSessions ();
boost::asio::io_service& GetService () { return m_Service; };
boost::asio::io_service& GetServiceV6 () { return m_ServiceV6; };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
void RemoveRelay (uint32_t tag);
@ -68,7 +68,7 @@ namespace transport
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
void RemovePeerTest (uint32_t nonce);
private:
void OpenSocket ();
@ -84,13 +84,13 @@ namespace transport
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer ();
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode);
@ -111,10 +111,10 @@ namespace transport
PeerTestParticipant role;
std::shared_ptr<SSUSession> session; // for Bob to Alice
};
bool m_OnlyV6;
bool m_OnlyV6;
bool m_IsRunning;
std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread, * m_ReceiversThreadV6;
std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread, * m_ReceiversThreadV6;
boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService, m_ReceiversServiceV6;
boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork, m_ReceiversWorkV6;
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
@ -125,7 +125,7 @@ namespace transport
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
std::map<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
public:
// for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };

View file

@ -28,9 +28,9 @@ namespace transport
}
SSUData::SSUData (SSUSession& session):
m_Session (session), m_ResendTimer (session.GetService ()),
m_IncompleteMessagesCleanupTimer (session.GetService ()),
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
m_Session (session), m_ResendTimer (session.GetService ()),
m_IncompleteMessagesCleanupTimer (session.GetService ()),
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
{
}
@ -42,8 +42,8 @@ namespace transport
void SSUData::Start ()
{
ScheduleIncompleteMessagesCleanup ();
}
}
void SSUData::Stop ()
{
m_ResendTimer.cancel ();
@ -51,8 +51,8 @@ namespace transport
m_IncompleteMessages.clear ();
m_SentMessages.clear ();
m_ReceivedMessages.clear ();
}
}
void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter)
{
if (!remoteRouter) return;
@ -72,16 +72,16 @@ namespace transport
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
}
else
{
{
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
m_PacketSize = m_MaxPacketSize;
}
}
}
}
}
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
{
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
if (routerInfo)
AdjustPacketSize (routerInfo);
}
@ -91,11 +91,11 @@ namespace transport
auto it = m_SentMessages.find (msgID);
if (it != m_SentMessages.end ())
{
m_SentMessages.erase (it);
m_SentMessages.erase (it);
if (m_SentMessages.empty ())
m_ResendTimer.cancel ();
}
}
}
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
{
@ -117,7 +117,7 @@ namespace transport
{
uint32_t msgID = bufbe32toh (buf);
buf += 4; // msgID
auto it = m_SentMessages.find (msgID);
auto it = m_SentMessages.find (msgID);
// process individual Ack bitfields
bool isNonLast = false;
int fragment = 0;
@ -127,26 +127,26 @@ namespace transport
isNonLast = bitfield & 0x80;
bitfield &= 0x7F; // clear MSB
if (bitfield && it != m_SentMessages.end ())
{
int numSentFragments = it->second->fragments.size ();
{
int numSentFragments = it->second->fragments.size ();
// process bits
uint8_t mask = 0x01;
for (int j = 0; j < 7; j++)
{
{
if (bitfield & mask)
{
if (fragment < numSentFragments)
it->second->fragments[fragment].reset (nullptr);
}
}
fragment++;
mask <<= 1;
}
}
}
buf++;
}
while (isNonLast);
}
}
while (isNonLast);
}
}
}
void SSUData::ProcessFragments (uint8_t * buf)
@ -154,7 +154,7 @@ namespace transport
uint8_t numFragments = *buf; // number of fragments
buf++;
for (int i = 0; i < numFragments; i++)
{
{
uint32_t msgID = bufbe32toh (buf); // message ID
buf += 4;
uint8_t frag[4] = {0};
@ -162,8 +162,8 @@ namespace transport
buf += 3;
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
bool isLast = fragmentInfo & 0x010000; // bit 16
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
bool isLast = fragmentInfo & 0x010000; // bit 16
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
{
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
@ -172,12 +172,12 @@ namespace transport
// find message with msgID
auto it = m_IncompleteMessages.find (msgID);
if (it == m_IncompleteMessages.end ())
if (it == m_IncompleteMessages.end ())
{
// create new message
auto msg = NewI2NPShortMessage ();
msg->len -= I2NP_SHORT_HEADER_SIZE;
it = m_IncompleteMessages.insert (std::make_pair (msgID,
it = m_IncompleteMessages.insert (std::make_pair (msgID,
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
}
std::unique_ptr<IncompleteMessage>& incompleteMessage = it->second;
@ -204,10 +204,10 @@ namespace transport
}
if (isLast)
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
}
}
}
}
else
{
{
if (fragmentNum < incompleteMessage->nextFragmentNum)
// duplicate fragment
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
@ -218,28 +218,28 @@ namespace transport
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
else
else
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
}
isLast = false;
}
}
if (isLast)
{
// delete incomplete message
auto msg = incompleteMessage->msg;
incompleteMessage->msg = nullptr;
m_IncompleteMessages.erase (msgID);
m_IncompleteMessages.erase (msgID);
// process message
SendMsgAck (msgID);
msg->FromSSU (msgID);
if (m_Session.GetState () == eSessionStateEstablished)
{
if (!m_ReceivedMessages.count (msgID))
{
{
m_ReceivedMessages.insert (msgID);
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
if (!msg->IsExpired ())
if (!msg->IsExpired ())
{
#ifdef WITH_EVENTS
QueueIntEvent("transport.recvmsg", m_Session.GetIdentHashBase64(), 1);
@ -248,10 +248,10 @@ namespace transport
}
else
LogPrint (eLogDebug, "SSU: message expired");
}
}
else
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
}
}
else
{
// we expect DeliveryStatus
@ -259,22 +259,22 @@ namespace transport
{
LogPrint (eLogDebug, "SSU: session established");
m_Session.Established ();
}
}
else
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
}
}
}
}
else
SendFragmentAck (msgID, fragmentNum);
SendFragmentAck (msgID, fragmentNum);
buf += fragmentSize;
}
}
}
void SSUData::FlushReceivedMessage ()
{
m_Handler.Flush ();
}
}
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
{
//uint8_t * start = buf;
@ -303,25 +303,25 @@ namespace transport
{
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
return;
}
}
if (m_SentMessages.empty ()) // schedule resend at first message only
ScheduleResend ();
auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage)));
auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage)));
std::unique_ptr<SentMessage>& sentMessage = ret.first->second;
if (ret.second)
if (ret.second)
{
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
sentMessage->numResends = 0;
}
}
auto& fragments = sentMessage->fragments;
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength ();
uint8_t * msgBuf = msg->GetSSUHeader ();
uint32_t fragmentNum = 0;
while (len > 0)
{
{
Fragment * fragment = new Fragment;
fragment->fragmentNum = fragmentNum;
uint8_t * buf = fragment->buf;
@ -337,39 +337,39 @@ namespace transport
uint32_t fragmentInfo = (fragmentNum << 17);
if (isLast)
fragmentInfo |= 0x010000;
fragmentInfo |= size;
fragmentInfo = htobe32 (fragmentInfo);
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
payload += 3;
memcpy (payload, msgBuf, size);
size += payload - buf;
if (size & 0x0F) // make sure 16 bytes boundary
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
fragment->len = size;
fragment->len = size;
fragments.push_back (std::unique_ptr<Fragment> (fragment));
// encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
try
{
{
m_Session.Send (buf, size);
}
catch (boost::system::system_error& ec)
{
LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ());
}
}
if (!isLast)
{
{
len -= payloadSize;
msgBuf += payloadSize;
}
}
else
len = 0;
fragmentNum++;
}
}
}
}
void SSUData::SendMsgAck (uint32_t msgID)
{
@ -398,27 +398,27 @@ namespace transport
uint8_t buf[64 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
payload++;
payload++;
*payload = 1; // number of ACK bitfields
payload++;
// one ack
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
payload += 4;
div_t d = div (fragmentNum, 7);
memset (payload, 0x80, d.quot); // 0x80 means non-last
payload += d.quot;
payload += d.quot;
*payload = 0x01 << d.rem; // set corresponding bit
payload++;
*payload = 0; // number of fragments
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
// encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
m_Session.Send (buf, len);
}
}
void SSUData::ScheduleResend()
{
{
m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
auto s = m_Session.shared_from_this();
@ -435,7 +435,7 @@ namespace transport
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
{
if (ts >= it->second->nextResendTime)
{
{
if (it->second->numResends < MAX_NUM_RESENDS)
{
for (auto& f: it->second->fragments)
@ -455,13 +455,13 @@ namespace transport
it->second->numResends++;
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
++it;
}
}
else
{
LogPrint (eLogInfo, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
it = m_SentMessages.erase (it);
}
}
}
}
else
++it;
}
@ -472,9 +472,9 @@ namespace transport
{
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
m_Session.Close ();
}
}
}
}
}
}
void SSUData::ScheduleIncompleteMessagesCleanup ()
{
@ -484,7 +484,7 @@ namespace transport
m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode)
{ s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); });
}
void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
@ -496,18 +496,18 @@ namespace transport
{
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
it = m_IncompleteMessages.erase (it);
}
}
else
++it;
}
}
// decay
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES ||
i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL)
m_ReceivedMessages.clear ();
ScheduleIncompleteMessagesCleanup ();
}
}
}
}
}
}

View file

@ -24,7 +24,7 @@ namespace transport
const size_t SSU_MTU_V6 = 1488;
#endif
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440
@ -40,7 +40,7 @@ namespace transport
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
struct Fragment
{
@ -50,27 +50,27 @@ namespace transport
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
Fragment () = default;
Fragment (int n, const uint8_t * b, int l, bool last):
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
};
Fragment (int n, const uint8_t * b, int l, bool last):
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
};
struct FragmentCmp
{
bool operator() (const std::unique_ptr<Fragment>& f1, const std::unique_ptr<Fragment>& f2) const
{
return f1->fragmentNum < f2->fragmentNum;
{
return f1->fragmentNum < f2->fragmentNum;
};
};
};
struct IncompleteMessage
{
std::shared_ptr<I2NPMessage> msg;
int nextFragmentNum;
int nextFragmentNum;
uint32_t lastFragmentInsertTime; // in seconds
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {};
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
};
struct SentMessage
@ -78,24 +78,24 @@ namespace transport
std::vector<std::unique_ptr<Fragment> > fragments;
uint32_t nextResendTime; // in seconds
int numResends;
};
};
class SSUSession;
class SSUData
{
public:
SSUData (SSUSession& session);
SSUData (SSUSession& session);
~SSUData ();
void Start ();
void Stop ();
void Stop ();
void ProcessMessage (uint8_t * buf, size_t len);
void FlushReceivedMessage ();
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
private:
@ -104,16 +104,16 @@ namespace transport
void SendFragmentAck (uint32_t msgID, int fragmentNum);
void ProcessAcks (uint8_t *& buf, uint8_t flag);
void ProcessFragments (uint8_t * buf);
void ProcessSentMessageAck (uint32_t msgID);
void ProcessSentMessageAck (uint32_t msgID);
void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode);
void HandleResendTimer (const boost::system::error_code& ecode);
void ScheduleIncompleteMessagesCleanup ();
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
private:
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
private:
SSUSession& m_Session;
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
@ -123,7 +123,7 @@ namespace transport
int m_MaxPacketSize, m_PacketSize;
i2p::I2NPMessagesHandler m_Handler;
uint32_t m_LastMessageReceivedTime; // in second
};
};
}
}

View file

@ -13,12 +13,12 @@ namespace i2p
namespace transport
{
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
TransportSession (router, SSU_TERMINATION_TIMEOUT),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()),
m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
TransportSession (router, SSU_TERMINATION_TIMEOUT),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()),
m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
m_RelayTag (0), m_SentRelayTag (0), m_Data (*this), m_IsDataReceived (false)
{
{
if (router)
{
// we are client
@ -36,14 +36,14 @@ namespace transport
}
SSUSession::~SSUSession ()
{
}
boost::asio::io_service& SSUSession::GetService ()
{
return IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService ();
{
}
boost::asio::io_service& SSUSession::GetService ()
{
return IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService ();
}
void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
{
uint8_t sharedKey[256];
@ -55,14 +55,14 @@ namespace transport
sessionKey[0] = 0;
memcpy (sessionKey + 1, sharedKey, 31);
memcpy (macKey, sharedKey + 31, 32);
}
}
else if (sharedKey[0])
{
memcpy (sessionKey, sharedKey, 32);
memcpy (macKey, sharedKey + 32, 32);
}
}
else
{
{
// find first non-zero byte
uint8_t * nonZero = sharedKey + 1;
while (!*nonZero)
@ -72,16 +72,16 @@ namespace transport
{
LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored");
return;
}
}
}
memcpy (sessionKey, nonZero, 32);
SHA256(nonZero, 64 - (nonZero - sharedKey), macKey);
}
m_IsSessionKey = true;
m_SessionKeyEncryption.SetKey (m_SessionKey);
m_SessionKeyDecryption.SetKey (m_SessionKey);
}
}
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
@ -96,40 +96,40 @@ namespace transport
}
else
{
if (!len) return; // ignore zero-length packets
if (!len) return; // ignore zero-length packets
if (m_State == eSessionStateEstablished)
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
DecryptSessionKey (buf, len);
else
DecryptSessionKey (buf, len);
else
{
if (m_State == eSessionStateEstablished) Reset (); // new session key required
if (m_State == eSessionStateEstablished) Reset (); // new session key required
// try intro key depending on side
if (Validate (buf, len, m_IntroKey))
Decrypt (buf, len, m_IntroKey);
else
{
{
// try own intro key
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
if (!address)
{
LogPrint (eLogInfo, "SSU is not supported");
return;
}
}
if (Validate (buf, len, address->ssu->key))
Decrypt (buf, len, address->ssu->key);
else
{
LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
m_Server.DeleteSession (shared_from_this ());
m_Server.DeleteSession (shared_from_this ());
return;
}
}
}
}
}
}
// successfully decrypted
ProcessMessage (buf, len, senderEndpoint);
}
}
}
size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const
@ -158,14 +158,14 @@ namespace transport
ProcessData (buf + headerSize, len - headerSize);
break;
case PAYLOAD_TYPE_SESSION_REQUEST:
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
break;
case PAYLOAD_TYPE_SESSION_CREATED:
ProcessSessionCreated (buf, len); // buf with header
break;
case PAYLOAD_TYPE_SESSION_CONFIRMED:
ProcessSessionConfirmed (buf, len); // buf with header
break;
break;
case PAYLOAD_TYPE_PEER_TEST:
LogPrint (eLogDebug, "SSU: peer test received");
ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
@ -173,9 +173,9 @@ namespace transport
case PAYLOAD_TYPE_SESSION_DESTROYED:
{
LogPrint (eLogDebug, "SSU: session destroy received");
m_Server.DeleteSession (shared_from_this ());
m_Server.DeleteSession (shared_from_this ());
break;
}
}
case PAYLOAD_TYPE_RELAY_RESPONSE:
ProcessRelayResponse (buf + headerSize, len - headerSize);
if (m_State != eSessionStateEstablished)
@ -197,7 +197,7 @@ namespace transport
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
LogPrint (eLogDebug, "SSU message: session request");
bool sendRelayTag = true;
bool sendRelayTag = true;
auto headerSize = sizeof (SSUHeader);
if (((SSUHeader *)buf)->IsExtendedOptions ())
{
@ -206,14 +206,14 @@ namespace transport
if (extendedOptionsLen >= 3) // options are presented
{
uint16_t flags = bufbe16toh (buf + headerSize);
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
}
headerSize += extendedOptionsLen;
}
}
if (headerSize >= len)
{
LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len);
return;
return;
}
m_RemoteEndpoint = senderEndpoint;
if (!m_DHKeysPair)
@ -232,14 +232,14 @@ namespace transport
LogPrint (eLogDebug, "SSU message: session created");
m_ConnectTimer.cancel (); // connect timer
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
auto headerSize = GetSSUHeaderSize (buf);
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len)
{
LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len);
return;
}
uint8_t * payload = buf + headerSize;
return;
}
uint8_t * payload = buf + headerSize;
uint8_t * y = payload;
CreateAESandMacKey (y);
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
@ -250,18 +250,18 @@ namespace transport
uint8_t * ourAddress = payload;
boost::asio::ip::address ourIP;
if (addressSize == 4) // v4
{
{
boost::asio::ip::address_v4::bytes_type bytes;
memcpy (bytes.data (), ourAddress, 4);
ourIP = boost::asio::ip::address_v4 (bytes);
}
}
else // v6
{
boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), ourAddress, 16);
ourIP = boost::asio::ip::address_v6 (bytes);
}
s.Insert (ourAddress, addressSize); // our IP
}
s.Insert (ourAddress, addressSize); // our IP
payload += addressSize; // address
uint16_t ourPort = bufbe16toh (payload);
s.Insert (payload, 2); // our port
@ -271,19 +271,19 @@ namespace transport
else
s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP v6
s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port
s.Insert (payload, 8); // relayTag and signed on time
s.Insert (payload, 8); // relayTag and signed on time
m_RelayTag = bufbe32toh (payload);
payload += 4; // relayTag
if (i2p::context.GetStatus () == eRouterStatusTesting)
{
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t signedOnTime = bufbe32toh(payload);
if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
{
LogPrint (eLogError, "SSU: clock skew detected ", (int)ts - signedOnTime, ". Check your clock");
LogPrint (eLogError, "SSU: clock skew detected ", (int)ts - signedOnTime, ". Check your clock");
i2p::context.SetError (eRouterErrorClockSkew);
}
}
}
payload += 4; // signed on time
// decrypt signature
size_t signatureLen = m_RemoteIdentity->GetSignatureLen ();
@ -304,34 +304,34 @@ namespace transport
LogPrint (eLogError, "SSU: message 'created' signature verification failed");
Failed ();
}
}
}
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
{
LogPrint (eLogDebug, "SSU: Session confirmed received");
auto headerSize = GetSSUHeaderSize (buf);
LogPrint (eLogDebug, "SSU: Session confirmed received");
auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len)
{
LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len);
return;
}
return;
}
const uint8_t * payload = buf + headerSize;
payload++; // identity fragment info
uint16_t identitySize = bufbe16toh (payload);
uint16_t identitySize = bufbe16toh (payload);
payload += 2; // size of identity fragment
auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize);
auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : identity);
m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ());
payload += identitySize; // identity
payload += identitySize; // identity
auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t signedOnTime = bufbe32toh(payload);
uint32_t signedOnTime = bufbe32toh(payload);
if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
{
LogPrint (eLogError, "SSU message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew");
LogPrint (eLogError, "SSU message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew");
Failed ();
return;
}
}
if (m_SignedData)
m_SignedData->Insert (payload, 4); // insert Alice's signed on time
payload += 4; // signed-on time
@ -345,7 +345,7 @@ namespace transport
m_Data.Send (CreateDeliveryStatusMsg (0));
Established ();
}
else
else
{
LogPrint (eLogError, "SSU message 'confirmed' signature verification failed");
Failed ();
@ -353,33 +353,33 @@ namespace transport
}
void SSUSession::SendSessionRequest ()
{
{
uint8_t buf[320 + 18] = {0}; // 304 bytes for ipv4, 320 for ipv6
uint8_t * payload = buf + sizeof (SSUHeader);
uint8_t flag = 0;
// fill extended options, 3 bytes extended options don't change message size
if (i2p::context.GetStatus () == eRouterStatusOK) // we don't need relays
{
{
// tell out peer to now assign relay tag
flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED;
*payload = 2; payload++; // 1 byte length
uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
htobe16buf (payload, flags);
htobe16buf (payload, flags);
payload += 2;
}
}
// fill payload
memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x
bool isV4 = m_RemoteEndpoint.address ().is_v4 ();
if (isV4)
{
payload[256] = 4;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
payload[256] = 4;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
}
else
{
payload[256] = 16;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
}
payload[256] = 16;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
}
// encrypt and send
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
@ -395,7 +395,7 @@ namespace transport
LogPrint (eLogInfo, "SSU is not supported");
return;
}
uint8_t buf[96 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader);
htobe32buf (payload, introducer.iTag);
@ -405,17 +405,17 @@ namespace transport
htobuf16(payload, 0); // port = 0
payload += 2;
*payload = 0; // challenge
payload++;
payload++;
memcpy (payload, (const uint8_t *)address->ssu->key, 32);
payload += 32;
htobe32buf (payload, nonce); // nonce
htobe32buf (payload, nonce); // nonce
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
if (m_State == eSessionStateEstablished)
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, m_SessionKey, iv, m_MacKey);
else
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
m_Server.Send (buf, 96, m_RemoteEndpoint);
}
@ -428,7 +428,7 @@ namespace transport
LogPrint (eLogInfo, "SSU is not supported");
return;
}
SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
s.Insert (x, 256); // x
uint8_t buf[384 + 18] = {0};
@ -441,7 +441,7 @@ namespace transport
// ipv4
*payload = 4;
payload++;
memcpy (payload, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
memcpy (payload, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
s.Insert (payload, 4); // remote endpoint IP V4
payload += 4;
}
@ -450,7 +450,7 @@ namespace transport
// ipv6
*payload = 16;
payload++;
memcpy (payload, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
memcpy (payload, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
s.Insert (payload, 16); // remote endpoint IP V6
payload += 16;
}
@ -467,20 +467,20 @@ namespace transport
RAND_bytes((uint8_t *)&m_SentRelayTag, 4);
if (!m_SentRelayTag) m_SentRelayTag = 1;
}
htobe32buf (payload, m_SentRelayTag);
payload += 4; // relay tag
htobe32buf (payload, m_SentRelayTag);
payload += 4; // relay tag
htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time
payload += 4;
s.Insert (payload - 8, 4); // relayTag
s.Insert (payload - 8, 4); // relayTag
// we have to store this signed data for session confirmed
// same data but signed on time, it will Alice's there
m_SignedData = std::unique_ptr<SignedData>(new SignedData (s));
s.Insert (payload - 4, 4); // BOB's signed on time
// same data but signed on time, it will Alice's there
m_SignedData = std::unique_ptr<SignedData>(new SignedData (s));
s.Insert (payload - 4, 4); // BOB's signed on time
s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
// encrypt signature and padding with newly created session key
// encrypt signature and padding with newly created session key
size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen ();
size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0)
@ -493,9 +493,9 @@ namespace transport
m_SessionKeyEncryption.Encrypt (payload, signatureLen, payload);
payload += signatureLen;
size_t msgLen = payload - buf;
// encrypt message with intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, m_IntroKey, iv, m_IntroKey);
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, m_IntroKey, iv, m_IntroKey);
Send (buf, msgLen);
}
@ -518,21 +518,21 @@ namespace transport
if (paddingSize > 0) paddingSize = 16 - paddingSize;
RAND_bytes(payload, paddingSize); // fill padding with random
payload += paddingSize; // padding size
// signature
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
// signature
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
s.Insert (y, 256); // y
s.Insert (ourAddress, ourAddressLen); // our address/port as seem by party
if (m_RemoteEndpoint.address ().is_v4 ())
s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP V4
else
s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP V6
s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP V6
s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port
s.Insert (htobe32 (m_RelayTag)); // relay tag
s.Insert (htobe32 (signedOnTime)); // signed on time
s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
payload += signatureLen;
size_t msgLen = payload - buf;
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
@ -547,7 +547,7 @@ namespace transport
auto session = m_Server.FindRelaySession (relayTag);
if (session)
{
buf += 4; // relay tag
buf += 4; // relay tag
uint8_t size = *buf;
buf++; // size
buf += size; // address
@ -560,7 +560,7 @@ namespace transport
uint32_t nonce = bufbe32toh (buf);
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
SendRelayIntro (session, from);
}
}
}
void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
@ -577,7 +577,7 @@ namespace transport
*payload = 4;
payload++; // size
htobe32buf (payload, to.address ().to_v4 ().to_ulong ()); // Charlie's IP
payload += 4; // address
payload += 4; // address
htobe16buf (payload, to.port ()); // Charlie's port
payload += 2; // port
// Alice
@ -587,25 +587,25 @@ namespace transport
*payload = 4;
payload++; // size
memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4
payload += 4; // address
payload += 4; // address
}
else
{
*payload = 16;
payload++; // size
memcpy (payload, from.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6
payload += 16; // address
payload += 16; // address
}
htobe16buf (payload, from.port ()); // Alice's port
payload += 2; // port
htobe32buf (payload, nonce);
htobe32buf (payload, nonce);
if (m_State == eSessionStateEstablished)
{
{
// encrypt with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80);
Send (buf, isV4 ? 64 : 80);
}
}
else
{
// ecrypt with Alice's intro key
@ -613,45 +613,45 @@ namespace transport
RAND_bytes (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
m_Server.Send (buf, isV4 ? 64 : 80, from);
}
}
LogPrint (eLogDebug, "SSU: relay response sent");
}
}
void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from)
{
if (!session) return;
if (!session) return;
// Alice's address always v4
if (!from.address ().is_v4 ())
{
LogPrint (eLogWarning, "SSU: Alice's IP must be v4");
return;
}
}
uint8_t buf[48 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = 4;
payload++; // size
htobe32buf (payload, from.address ().to_v4 ().to_ulong ()); // Alice's IP
payload += 4; // address
payload += 4; // address
htobe16buf (payload, from.port ()); // Alice's port
payload += 2; // port
*payload = 0; // challenge size
*payload = 0; // challenge size
uint8_t iv[16];
RAND_bytes (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey);
m_Server.Send (buf, 48, session->m_RemoteEndpoint);
LogPrint (eLogDebug, "SSU: relay intro sent");
}
void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
{
LogPrint (eLogDebug, "SSU message: Relay response received");
uint8_t remoteSize = *buf;
LogPrint (eLogDebug, "SSU message: Relay response received");
uint8_t remoteSize = *buf;
buf++; // remote size
boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf));
buf += remoteSize; // remote address
uint16_t remotePort = bufbe16toh (buf);
buf += 2; // remote port
uint8_t ourSize = *buf;
uint8_t ourSize = *buf;
buf++; // our size
boost::asio::ip::address ourIP;
if (ourSize == 4)
@ -675,7 +675,7 @@ namespace transport
buf += 4; // nonce
auto it = m_RelayRequests.find (nonce);
if (it != m_RelayRequests.end ())
{
{
// check if we are waiting for introduction
boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort);
if (!m_Server.FindSession (remoteEndpoint))
@ -686,10 +686,10 @@ namespace transport
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
m_Server.CreateDirectSession (it->second, remoteEndpoint, false);
}
}
// delete request
m_RelayRequests.erase (it);
}
}
else
LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce);
}
@ -708,11 +708,11 @@ namespace transport
}
else
LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported");
}
}
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag)
{
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
@ -753,18 +753,18 @@ namespace transport
memcpy (buf + len, header->iv, 16);
htobe16buf (buf + len + 16, encryptedLen);
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
}
}
void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
uint16_t encryptedLen = len - (encrypted - buf);
i2p::crypto::CBCDecryption decryption;
decryption.SetKey (aesKey);
decryption.SetIV (header->iv);
@ -777,24 +777,24 @@ namespace transport
{
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return;
}
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
uint16_t encryptedLen = len - (encrypted - buf);
if (encryptedLen > 0)
{
{
m_SessionKeyDecryption.SetIV (header->iv);
m_SessionKeyDecryption.Decrypt (encrypted, encryptedLen, encrypted);
}
}
}
}
bool SSUSession::Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey)
{
if (len < sizeof (SSUHeader))
{
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return false;
}
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
@ -809,12 +809,12 @@ namespace transport
void SSUSession::Connect ()
{
if (m_State == eSessionStateUnknown)
{
{
// set connect timer
ScheduleConnectTimer ();
m_DHKeysPair = transports.GetNextDHKeysPair ();
SendSessionRequest ();
}
}
}
void SSUSession::WaitForConnect ()
@ -830,7 +830,7 @@ namespace transport
m_ConnectTimer.cancel ();
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1));
shared_from_this (), std::placeholders::_1));
}
void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode)
@ -840,14 +840,14 @@ namespace transport
// timeout expired
LogPrint (eLogWarning, "SSU: session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
Failed ();
}
}
}
}
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer,
std::shared_ptr<const i2p::data::RouterInfo> to)
{
if (m_State == eSessionStateUnknown)
{
{
// set connect timer
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
@ -865,7 +865,7 @@ namespace transport
// set connect timer
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1));
shared_from_this (), std::placeholders::_1));
}
void SSUSession::Close ()
@ -873,7 +873,7 @@ namespace transport
SendSessionDestroyed ();
Reset ();
m_State = eSessionStateClosed;
}
}
void SSUSession::Reset ()
{
@ -882,10 +882,10 @@ namespace transport
m_Data.Stop ();
m_ConnectTimer.cancel ();
if (m_SentRelayTag)
{
{
m_Server.RemoveRelay (m_SentRelayTag); // relay tag is not valid anymore
m_SentRelayTag = 0;
}
}
m_DHKeysPair = nullptr;
m_SignedData = nullptr;
m_IsSessionKey = false;
@ -908,20 +908,20 @@ namespace transport
if (m_SentRelayTag)
m_Server.AddRelay (m_SentRelayTag, shared_from_this ());
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
}
}
void SSUSession::Failed ()
{
if (m_State != eSessionStateFailed)
{
{
m_State = eSessionStateFailed;
m_Server.DeleteSession (shared_from_this ());
}
}
m_Server.DeleteSession (shared_from_this ());
}
}
void SSUSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{
GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs));
GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs));
}
void SSUSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
@ -931,7 +931,7 @@ namespace transport
for (const auto& it: msgs)
if (it) m_Data.Send (it);
}
}
}
void SSUSession::ProcessData (uint8_t * buf, size_t len)
{
@ -942,29 +942,29 @@ namespace transport
void SSUSession::FlushData ()
{
if (m_IsDataReceived)
{
{
m_Data.FlushReceivedMessage ();
m_IsDataReceived = false;
}
}
}
void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
uint32_t nonce = bufbe32toh (buf); // 4 bytes
uint8_t size = buf[4]; // 1 byte
uint8_t size = buf[4]; // 1 byte
const uint8_t * address = buf + 5; // big endian, size bytes
uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes
const uint8_t * introKey = buf + size + 7;
if (port && (size != 4) && (size != 16))
if (port && (size != 4) && (size != 16))
{
LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported");
return;
}
}
switch (m_Server.GetPeerTestParticipant (nonce))
{
// existing test
{
// existing test
case ePeerTestParticipantAlice1:
{
{
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
{
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
@ -981,7 +981,7 @@ namespace transport
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
}
break;
}
}
case ePeerTestParticipantAlice2:
{
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
@ -994,8 +994,8 @@ namespace transport
m_Server.RemovePeerTest (nonce);
}
break;
}
case ePeerTestParticipantBob:
}
case ePeerTestParticipantBob:
{
LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob");
auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
@ -1005,13 +1005,13 @@ namespace transport
break;
}
case ePeerTestParticipantCharlie:
{
{
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address
m_Server.RemovePeerTest (nonce); // nonce has been used
break;
}
// test not found
// test not found
case ePeerTestParticipantUnknown:
{
if (m_State == eSessionStateEstablished)
@ -1034,7 +1034,7 @@ namespace transport
boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), address, 16);
addr = boost::asio::ip::address_v6 (bytes);
}
}
SendPeerTest (nonce, addr, be16toh (port), introKey); // to Alice with her address received from Bob
}
else
@ -1044,26 +1044,26 @@ namespace transport
if (session)
{
m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ());
session->SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address
}
session->SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address
}
}
}
else
LogPrint (eLogError, "SSU: unexpected peer test");
}
}
}
}
void SSUSession::SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port,
void SSUSession::SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port,
const uint8_t * introKey, bool toAddress, bool sendAddress)
// toAddress is true for Alice<->Chalie communications only
// sendAddress is false if message comes from Alice
// sendAddress is false if message comes from Alice
{
uint8_t buf[80 + 18] = {0};
uint8_t iv[16];
uint8_t * payload = buf + sizeof (SSUHeader);
htobe32buf (payload, nonce);
payload += 4; // nonce
payload += 4; // nonce
// address and port
if (sendAddress)
{
@ -1075,11 +1075,11 @@ namespace transport
else if (address.is_v6 ())
{
*payload = 16;
memcpy (payload + 1, address.to_v6 ().to_bytes ().data (), 16); // our IP V6
memcpy (payload + 1, address.to_v6 ().to_bytes ().data (), 16); // our IP V6
}
else
*payload = 0;
payload += (payload[0] + 1);
payload += (payload[0] + 1);
}
else
{
@ -1096,27 +1096,27 @@ namespace transport
if (addr)
memcpy (payload, addr->ssu->key, 32); // intro key
else
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
}
else
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
}
else
memcpy (payload, introKey, 32); // intro key
// send
// send
RAND_bytes (iv, 16); // random iv
if (toAddress)
{
{
// encrypt message with specified intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey);
boost::asio::ip::udp::endpoint e (address, port);
m_Server.Send (buf, 80, e);
}
}
else
{
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80);
Send (buf, 80);
}
}
}
void SSUSession::SendPeerTest ()
{
@ -1134,23 +1134,23 @@ namespace transport
m_IsPeerTest = false;
m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ());
SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice
}
}
void SSUSession::SendKeepAlive ()
{
if (m_State == eSessionStateEstablished)
{
{
uint8_t buf[48 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = 0; // flags
payload++;
*payload = 0; // num fragments
*payload = 0; // num fragments
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
Send (buf, 48);
LogPrint (eLogDebug, "SSU: keep-alive sent");
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
}
}
}
void SSUSession::SendSessionDestroyed ()
@ -1170,31 +1170,31 @@ namespace transport
}
LogPrint (eLogDebug, "SSU: session destroyed sent");
}
}
}
void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len)
{
uint8_t buf[SSU_MTU_V4 + 18] = {0};
size_t msgSize = len + sizeof (SSUHeader);
size_t msgSize = len + sizeof (SSUHeader);
size_t paddingSize = msgSize & 0x0F; // %16
if (paddingSize > 0) msgSize += (16 - paddingSize);
if (msgSize > SSU_MTU_V4)
{
LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU");
return;
}
}
memcpy (buf + sizeof (SSUHeader), payload, len);
// encrypt message with session key
FillHeaderAndEncrypt (type, buf, msgSize);
Send (buf, msgSize);
}
}
void SSUSession::Send (const uint8_t * buf, size_t size)
{
m_NumSentBytes += size;
i2p::transport::transports.UpdateSentBytes (size);
m_Server.Send (buf, size, m_RemoteEndpoint);
}
}
}
}

View file

@ -19,15 +19,15 @@ namespace transport
uint8_t mac[16];
uint8_t iv[16];
uint8_t flag;
uint8_t time[4];
uint8_t time[4];
uint8_t GetPayloadType () const { return flag >> 4; };
bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
};
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
const int SSU_CLOCK_SKEW = 60; // in seconds
const int SSU_CLOCK_SKEW = 60; // in seconds
// payload types (4 bits)
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
@ -45,12 +45,12 @@ namespace transport
enum SessionState
{
eSessionStateUnknown,
eSessionStateUnknown,
eSessionStateIntroduced,
eSessionStateEstablished,
eSessionStateClosed,
eSessionStateFailed
};
};
enum PeerTestParticipant
{
@ -60,7 +60,7 @@ namespace transport
ePeerTestParticipantBob,
ePeerTestParticipantCharlie
};
class SSUServer;
class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
{
@ -68,12 +68,12 @@ namespace transport
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession ();
void Connect ();
void WaitForConnect ();
void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
void WaitForIntroduction ();
void Close ();
@ -82,23 +82,23 @@ namespace transport
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void SendPeerTest (); // Alice
void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; };
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void SendKeepAlive ();
uint32_t GetRelayTag () const { return m_RelayTag; };
void SendKeepAlive ();
uint32_t GetRelayTag () const { return m_RelayTag; };
const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
uint32_t GetCreationTime () const { return m_CreationTime; };
void FlushData ();
private:
boost::asio::io_service& GetService ();
void CreateAESandMacKey (const uint8_t * pubKey);
void CreateAESandMacKey (const uint8_t * pubKey);
size_t GetSSUHeaderSize (const uint8_t * buf) const;
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
@ -119,23 +119,23 @@ namespace transport
void ScheduleConnectTimer ();
void HandleConnectTimer (const boost::system::error_code& ecode);
void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
void ProcessData (uint8_t * buf, size_t len);
void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
void ProcessData (uint8_t * buf, size_t len);
void SendSessionDestroyed ();
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
void Send (const uint8_t * buf, size_t size);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
void Send (const uint8_t * buf, size_t size);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
void DecryptSessionKey (uint8_t * buf, size_t len);
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
void Reset ();
private:
friend class SSUData; // TODO: change in later
SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;

View file

@ -16,24 +16,24 @@ namespace crypto
BIGNUM * tmp = BN_new ();
q = BN_new ();
// 2^255-19
BN_set_bit (q, 255); // 2^255
// 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
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_mod_inverse (tmp, tmp, q, ctx);
BN_set_word (d, 121665);
BN_set_negative (d, 1);
BN_set_negative (d, 1);
BN_mul (d, d, tmp, ctx);
// 2^((q-1)/4)
@ -41,20 +41,20 @@ namespace crypto
BN_free (tmp);
tmp = BN_dup (q);
BN_sub_word (tmp, 1);
BN_div_word (tmp, 4);
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_free (tmp);
// 4*inv(5)
BIGNUM * By = BN_new ();
BN_set_word (By, 5);
BN_mod_inverse (By, By, q, ctx);
BN_mod_inverse (By, By, q, ctx);
BN_mul_word (By, 4);
BIGNUM * Bx = RecoverX (By, ctx);
BIGNUM * Bx = RecoverX (By, ctx);
BN_mod (Bx, Bx, q, ctx); // % q
BN_mod (By, By, q, ctx); // % q
BN_mod (By, By, q, ctx); // % q
// precalculate Bi256 table
Bi256Carry = { Bx, By }; // B
for (int i = 0; i < 32; i++)
@ -70,7 +70,7 @@ namespace crypto
BN_CTX_free (ctx);
}
Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)),
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)
{
@ -106,9 +106,9 @@ namespace crypto
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const
{
BN_CTX * ctx = BN_CTX_new ();
BN_CTX * ctx = BN_CTX_new ();
BIGNUM * h = DecodeBN<64> (digest);
// signature 0..31 - R, 32..63 - S
// 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;
@ -117,14 +117,14 @@ namespace crypto
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_free (h);
BN_CTX_free (ctx);
if (!passed)
LogPrint (eLogError, "25519 signature verification failed");
return passed;
return passed;
}
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len,
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 ();
@ -138,14 +138,14 @@ namespace crypto
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
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);
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
@ -156,7 +156,7 @@ namespace crypto
BN_CTX_free (bnCtx);
}
private:
private:
EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
{
@ -165,9 +165,9 @@ namespace crypto
// 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_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;
@ -189,10 +189,10 @@ namespace crypto
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 (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);
@ -202,9 +202,9 @@ namespace crypto
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_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);
@ -215,40 +215,40 @@ namespace crypto
{
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
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
}
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
if (p.z)
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
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_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 (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
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
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_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 ();
@ -262,10 +262,10 @@ namespace crypto
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 ();
@ -275,15 +275,15 @@ namespace crypto
for (int i = 0; i < 32; i++)
{
uint8_t x = e[i];
if (carry)
{
if (x < 255)
{
x++;
if (carry)
{
if (x < 255)
{
x++;
carry = false;
}
else
x = 0;
}
else
x = 0;
}
if (x > 0)
{
@ -293,7 +293,7 @@ namespace crypto
{
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
carry = true;
}
}
}
}
if (carry) res = Sum (res, Bi256Carry, ctx);
@ -320,9 +320,9 @@ namespace crypto
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
// y^2 - x^2 - 1 - d*x^2*y^2
BN_mul (tmp, d, x2, ctx);
BN_mul (tmp, tmp, y2, ctx);
BN_mul (tmp, tmp, y2, ctx);
BN_sub (tmp, y2, tmp);
BN_sub (tmp, tmp, x2);
BN_sub_word (tmp, 1);
@ -330,25 +330,25 @@ namespace crypto
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)
// 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)
// 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
// check (x^2 -xx) % q
BN_sqr (y2, x, ctx);
BN_mod_sub (y2, y2, xx, q, 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))
@ -373,18 +373,18 @@ namespace crypto
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_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))
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);
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
}
@ -413,12 +413,12 @@ namespace crypto
uint8_t tmp = buf[i];
buf[i] = buf[len -1 - i];
buf[len -1 - i] = tmp;
}
}
}
private:
BIGNUM * q, * l, * d, * I;
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
@ -437,14 +437,14 @@ namespace crypto
g_Ed25519.reset (c);
else
delete c;
}
return g_Ed25519;
}
}
return g_Ed25519;
}
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
{
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
BN_CTX * ctx = BN_CTX_new ();
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
BN_CTX_free (ctx);
@ -457,40 +457,40 @@ namespace crypto
SHA512_Init (&ctx);
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
SHA512_Update (&ctx, buf, len); // data
SHA512_Update (&ctx, buf, len); // data
SHA512_Final (digest, &ctx);
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
}
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
{
{
// expand key
SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey);
m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits
m_ExpandedPrivateKey[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
BN_CTX * ctx = BN_CTX_new ();
BN_CTX * ctx = BN_CTX_new ();
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
if (signingPublicKey && memcmp (m_PublicKeyEncoded, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
{
// keys don't match, it means older key with 0x1F
LogPrint (eLogWarning, "Older EdDSA key detected");
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit
publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
}
BN_CTX_free (ctx);
}
}
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
}
}
}
}

View file

@ -18,7 +18,7 @@ namespace crypto
class Verifier
{
public:
virtual ~Verifier () {};
virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0;
virtual size_t GetPublicKeyLen () const = 0;
@ -30,12 +30,12 @@ namespace crypto
{
public:
virtual ~Signer () {};
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
virtual ~Signer () {};
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
};
const size_t DSA_PUBLIC_KEY_LENGTH = 128;
const size_t DSA_SIGNATURE_LENGTH = 40;
const size_t DSA_SIGNATURE_LENGTH = 40;
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
class DSAVerifier: public Verifier
{
@ -51,7 +51,7 @@ namespace crypto
{
DSA_free (m_PublicKey);
}
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
// calculate SHA1 digest
@ -64,11 +64,11 @@ namespace crypto
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
DSA_SIG_free(sig);
return ret;
}
}
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
private:
DSA * m_PublicKey;
@ -89,7 +89,7 @@ namespace crypto
{
DSA_free (m_PrivateKey);
}
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
uint8_t digest[20];
@ -115,21 +115,21 @@ namespace crypto
DSA_get0_key(dsa, &pub_key, &priv_key);
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
DSA_free (dsa);
}
DSA_free (dsa);
}
struct SHA256Hash
{
{
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA256 (buf, len, digest);
}
enum { hashLen = 32 };
};
};
struct SHA384Hash
{
{
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA384 (buf, len, digest);
@ -139,7 +139,7 @@ namespace crypto
};
struct SHA512Hash
{
{
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA512 (buf, len, digest);
@ -147,10 +147,10 @@ namespace crypto
enum { hashLen = 64 };
};
template<typename Hash, int curve, size_t keyLen>
class ECDSAVerifier: public Verifier
{
{
public:
ECDSAVerifier (const uint8_t * signingKey)
@ -166,7 +166,7 @@ namespace crypto
{
EC_KEY_free (m_PublicKey);
}
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
uint8_t digest[Hash::hashLen];
@ -179,12 +179,12 @@ namespace crypto
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey);
ECDSA_SIG_free(sig);
return ret;
}
}
size_t GetPublicKeyLen () const { return keyLen; };
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
private:
EC_KEY * m_PublicKey;
@ -198,14 +198,14 @@ namespace crypto
ECDSASigner (const uint8_t * signingPrivateKey)
{
m_PrivateKey = EC_KEY_new_by_curve_name (curve);
EC_KEY_set_private_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen/2, NULL));
EC_KEY_set_private_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen/2, NULL));
}
~ECDSASigner ()
{
EC_KEY_free (m_PrivateKey);
}
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
uint8_t digest[Hash::hashLen];
@ -235,18 +235,18 @@ namespace crypto
bn2buf (x, signingPublicKey, keyLen/2);
bn2buf (y, signingPublicKey + keyLen/2, keyLen/2);
BN_free (x); BN_free (y);
EC_KEY_free (signingKey);
EC_KEY_free (signingKey);
}
// ECDSA_SHA256_P256
const size_t ECDSAP256_KEY_LENGTH = 64;
const size_t ECDSAP256_KEY_LENGTH = 64;
typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier;
typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer;
inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
}
// ECDSA_SHA384_P384
const size_t ECDSAP384_KEY_LENGTH = 96;
@ -256,7 +256,7 @@ namespace crypto
inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
}
}
// ECDSA_SHA512_P521
const size_t ECDSAP521_KEY_LENGTH = 132;
@ -269,7 +269,7 @@ namespace crypto
}
// RSA
template<typename Hash, int type, size_t keyLen>
template<typename Hash, int type, size_t keyLen>
class RSAVerifier: public Verifier
{
public:
@ -284,23 +284,23 @@ namespace crypto
{
RSA_free (m_PublicKey);
}
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
uint8_t digest[Hash::hashLen];
Hash::CalculateHash (buf, len, digest);
return RSA_verify (type, digest, Hash::hashLen, signature, GetSignatureLen (), m_PublicKey);
}
size_t GetPublicKeyLen () const { return keyLen; }
size_t GetSignatureLen () const { return keyLen; }
size_t GetSignatureLen () const { return keyLen; }
size_t GetPrivateKeyLen () const { return GetSignatureLen ()*2; };
private:
RSA * m_PublicKey;
};
RSA * m_PublicKey;
};
template<typename Hash, int type, size_t keyLen>
class RSASigner: public Signer
{
@ -317,7 +317,7 @@ namespace crypto
{
RSA_free (m_PrivateKey);
}
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{
uint8_t digest[Hash::hashLen];
@ -325,11 +325,11 @@ namespace crypto
unsigned int signatureLen = keyLen;
RSA_sign (type, digest, Hash::hashLen, signature, &signatureLen, m_PrivateKey);
}
private:
RSA * m_PrivateKey;
};
};
inline void CreateRSARandomKeys (size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
@ -337,14 +337,14 @@ namespace crypto
BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const
RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL);
const BIGNUM * n, * d, * e1;
RSA_get0_key (rsa, &n, &e1, &d);
RSA_get0_key (rsa, &n, &e1, &d);
bn2buf (n, signingPrivateKey, publicKeyLen);
bn2buf (d, signingPrivateKey + publicKeyLen, publicKeyLen);
bn2buf (n, signingPublicKey, publicKeyLen);
BN_free (e); // this e is not assigned to rsa->e
RSA_free (rsa);
}
}
// RSA_SHA256_2048
const size_t RSASHA2562048_KEY_LENGTH = 256;
typedef RSAVerifier<SHA256Hash, NID_sha256, RSASHA2562048_KEY_LENGTH> RSASHA2562048Verifier;
@ -353,7 +353,7 @@ namespace crypto
// RSA_SHA384_3072
const size_t RSASHA3843072_KEY_LENGTH = 384;
typedef RSAVerifier<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Verifier;
typedef RSASigner<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Signer;
typedef RSASigner<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Signer;
// RSA_SHA512_4096
const size_t RSASHA5124096_KEY_LENGTH = 512;
@ -379,7 +379,7 @@ namespace crypto
{}
~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); }
EDDSAPoint& operator=(EDDSAPoint&& other)
EDDSAPoint& operator=(EDDSAPoint&& other)
{
if (this != &other)
{
@ -389,9 +389,9 @@ namespace crypto
BN_free (t); t = other.t; other.t = nullptr;
}
return *this;
}
}
EDDSAPoint& operator=(const EDDSAPoint& other)
EDDSAPoint& operator=(const EDDSAPoint& other)
{
if (this != &other)
{
@ -412,11 +412,11 @@ namespace crypto
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;
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
class EDDSA25519Verifier: public Verifier
{
public:
@ -429,7 +429,7 @@ namespace crypto
private:
EDDSAPoint m_PublicKey;
EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
};
@ -437,14 +437,14 @@ namespace crypto
{
public:
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
// we pass signingPublicKey to check if it matches private key
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
// we pass signingPublicKey to check if it matches private key
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; };
private:
uint8_t m_ExpandedPrivateKey[64];
uint8_t m_ExpandedPrivateKey[64];
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
};
@ -456,22 +456,22 @@ namespace crypto
}
// ГОСТ Р 34.11
// ГОСТ Р 34.11
struct GOSTR3411_256_Hash
{
{
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
GOSTR3411_2012_256 (buf, len, digest);
GOSTR3411_2012_256 (buf, len, digest);
}
enum { hashLen = 32 };
};
struct GOSTR3411_512_Hash
{
{
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
GOSTR3411_2012_512 (buf, len, digest);
GOSTR3411_2012_512 (buf, len, digest);
}
enum { hashLen = 64 };
@ -487,7 +487,7 @@ namespace crypto
public:
enum { keyLen = Hash::hashLen };
GOSTR3410Verifier (GOSTR3410ParamSet paramSet, const uint8_t * signingKey):
m_ParamSet (paramSet)
{
@ -497,7 +497,7 @@ namespace crypto
BN_free (x); BN_free (y);
}
~GOSTR3410Verifier () { EC_POINT_free (m_PublicKey); }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{
uint8_t digest[Hash::hashLen];
@ -506,7 +506,7 @@ namespace crypto
BIGNUM * r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL);
BIGNUM * s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
bool ret = GetGOSTR3410Curve (m_ParamSet)->Verify (m_PublicKey, d, r, s);
BN_free (d); BN_free (r); BN_free (s);
BN_free (d); BN_free (r); BN_free (s);
return ret;
}
@ -517,7 +517,7 @@ namespace crypto
GOSTR3410ParamSet m_ParamSet;
EC_POINT * m_PublicKey;
};
};
template<typename Hash>
class GOSTR3410Signer: public Signer
@ -525,11 +525,11 @@ namespace crypto
public:
enum { keyLen = Hash::hashLen };
GOSTR3410Signer (GOSTR3410ParamSet paramSet, const uint8_t * signingPrivateKey):
m_ParamSet (paramSet)
{
m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
{
m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
}
~GOSTR3410Signer () { BN_free (m_PrivateKey); }
@ -537,19 +537,19 @@ namespace crypto
{
uint8_t digest[Hash::hashLen];
Hash::CalculateHash (buf, len, digest);
BIGNUM * d = BN_bin2bn (digest, Hash::hashLen, nullptr);
BIGNUM * d = BN_bin2bn (digest, Hash::hashLen, nullptr);
BIGNUM * r = BN_new (), * s = BN_new ();
GetGOSTR3410Curve (m_ParamSet)->Sign (m_PrivateKey, d, r, s);
bn2buf (r, signature, keyLen);
bn2buf (s, signature + keyLen, keyLen);
BN_free (d); BN_free (r); BN_free (s);
}
private:
GOSTR3410ParamSet m_ParamSet;
BIGNUM * m_PrivateKey;
};
};
inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{
@ -557,7 +557,7 @@ namespace crypto
auto keyLen = curve->GetKeyLen ();
RAND_bytes (signingPrivateKey, keyLen);
BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
auto pub = curve->MulP (priv);
BN_free (priv);
BIGNUM * x = BN_new (), * y = BN_new ();
@ -565,7 +565,7 @@ namespace crypto
EC_POINT_free (pub);
bn2buf (x, signingPublicKey, keyLen);
bn2buf (y, signingPublicKey + keyLen, keyLen);
BN_free (x); BN_free (y);
BN_free (x); BN_free (y);
}
typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier;

View file

@ -12,11 +12,11 @@ namespace i2p
namespace stream
{
void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
{
{
m_Buffers.push_back (std::make_shared<SendBuffer>(buf, len, handler));
m_Size += len;
}
size_t SendBufferQueue::Get (uint8_t * buf, size_t len)
{
size_t offset = 0;
@ -30,7 +30,7 @@ namespace stream
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem);
offset += rem;
m_Buffers.pop_front (); // delete it
}
}
else
{
// partially
@ -38,23 +38,23 @@ namespace stream
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
nextBuffer->offset += (len - offset);
offset = len; // break
}
}
}
}
m_Size -= offset;
return offset;
}
}
void SendBufferQueue::CleanUp ()
{
void SendBufferQueue::CleanUp ()
{
if (!m_Buffers.empty ())
{
{
for (auto it: m_Buffers)
it->Cancel ();
m_Buffers.clear ();
m_Buffers.clear ();
m_Size = 0;
}
}
}
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
std::shared_ptr<const i2p::data::LeaseSet> remote, int port): m_Service (service),
m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1),
@ -100,7 +100,7 @@ namespace stream
{
std::unique_lock<std::mutex> l(m_SendBufferMutex);
m_SendBuffer.CleanUp ();
}
}
while (!m_ReceiveQueue.empty ())
{
auto packet = m_ReceiveQueue.front ();
@ -1108,7 +1108,7 @@ namespace stream
}
else // we must save old acceptor and set it back
{
m_Acceptor = std::bind (&StreamingDestination::AcceptOnceAcceptor, this,
m_Acceptor = std::bind (&StreamingDestination::AcceptOnceAcceptor, this,
std::placeholders::_1, acceptor, m_Acceptor);
}
});
@ -1118,8 +1118,8 @@ namespace stream
{
m_Acceptor = prev;
acceptor (stream);
}
}
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)

View file

@ -41,40 +41,40 @@ namespace stream
const size_t STREAMING_MTU = 1730;
const size_t MAX_PACKET_SIZE = 4096;
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
const int MAX_NUM_RESEND_ATTEMPTS = 6;
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
const int MAX_NUM_RESEND_ATTEMPTS = 6;
const int WINDOW_SIZE = 6; // in messages
const int MIN_WINDOW_SIZE = 1;
const int MAX_WINDOW_SIZE = 128;
const int MAX_WINDOW_SIZE = 128;
const int INITIAL_RTT = 8000; // in milliseconds
const int INITIAL_RTO = 9000; // in milliseconds
const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds
const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
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
* TODO: make configurable
*/
const uint64_t DEFAULT_BAN_INTERVAL = 60 * 60 * 1000;
struct Packet
{
size_t len, offset;
uint8_t buf[MAX_PACKET_SIZE];
uint8_t buf[MAX_PACKET_SIZE];
uint64_t sendTime;
Packet (): len (0), offset (0), sendTime (0) {};
uint8_t * GetBuffer () { return buf + offset; };
size_t GetLength () const { return len - offset; };
@ -93,15 +93,15 @@ namespace stream
bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; };
bool IsNoAck () const { return GetFlags () & PACKET_FLAG_NO_ACK; };
};
};
struct PacketCmp
{
bool operator() (const Packet * p1, const Packet * p2) const
{
return p1->GetSeqn () < p2->GetSeqn ();
{
return p1->GetSeqn () < p2->GetSeqn ();
};
};
};
typedef std::function<void (const boost::system::error_code& ecode)> SendHandler;
struct SendBuffer
@ -115,16 +115,16 @@ namespace stream
{
buf = new uint8_t[len];
memcpy (buf, b, len);
}
}
~SendBuffer ()
{
delete[] buf;
if (handler) handler(boost::system::error_code ());
}
}
size_t GetRemainingSize () const { return len - offset; };
const uint8_t * GetRemaningBuffer () const { return buf + offset; };
const uint8_t * GetRemaningBuffer () const { return buf + offset; };
void Cancel () { if (handler) handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted)); handler = nullptr; };
};
};
class SendBufferQueue
{
@ -133,18 +133,18 @@ namespace stream
SendBufferQueue (): m_Size (0) {};
~SendBufferQueue () { CleanUp (); };
void Add (const uint8_t * buf, size_t len, SendHandler handler);
size_t Get (uint8_t * buf, size_t len);
void Add (const uint8_t * buf, size_t len, SendHandler handler);
size_t Get (uint8_t * buf, size_t len);
size_t GetSize () const { return m_Size; };
bool IsEmpty () const { return m_Buffers.empty (); };
void CleanUp ();
private:
private:
std::list<std::shared_ptr<SendBuffer> > m_Buffers;
size_t m_Size;
};
};
enum StreamStatus
{
eStreamStatusNew = 0,
@ -152,16 +152,16 @@ namespace stream
eStreamStatusReset,
eStreamStatusClosing,
eStreamStatusClosed
};
};
class StreamingDestination;
class Stream: public std::enable_shared_from_this<Stream>
{
{
public:
Stream (boost::asio::io_service& service, StreamingDestination& local,
Stream (boost::asio::io_service& service, StreamingDestination& local,
std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
~Stream ();
uint32_t GetSendStreamID () const { return m_SendStreamID; };
@ -172,15 +172,15 @@ namespace stream
bool IsEstablished () const { return m_SendStreamID; };
StreamStatus GetStatus () const { return m_Status; };
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
void HandleNextPacket (Packet * packet);
size_t Send (const uint8_t * buf, size_t len);
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
template<typename Buffer, typename ReceiveHandler>
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
void Close ();
void Cancel () { m_ReceiveTimer.cancel (); };
@ -194,11 +194,11 @@ namespace stream
/** don't call me */
void Terminate ();
private:
void CleanUp ();
void SendBuffer ();
void SendQuickAck ();
void SendClose ();
@ -212,14 +212,14 @@ namespace stream
size_t ConcatenatePackets (uint8_t * buf, size_t len);
void UpdateCurrentRemoteLease (bool expired = false);
template<typename Buffer, typename ReceiveHandler>
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout);
void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode);
void HandleAckSendTimer (const boost::system::error_code& ecode);
private:
boost::asio::io_service& m_Service;
@ -254,16 +254,16 @@ namespace stream
typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0, bool gzip = true);
~StreamingDestination ();
~StreamingDestination ();
void Start ();
void Stop ();
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void DeleteStream (std::shared_ptr<Stream> stream);
void DeleteStream (std::shared_ptr<Stream> stream);
void SetAcceptor (const Acceptor& acceptor);
void ResetAcceptor ();
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
void AcceptOnce (const Acceptor& acceptor);
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
@ -278,11 +278,11 @@ namespace stream
Packet * NewPacket () { return m_PacketsPool.Acquire (); }
void DeletePacket (Packet * p) { m_PacketsPool.Release (p); }
private:
private:
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
void HandleNextPacket (Packet * packet);
std::shared_ptr<Stream> CreateNewIncomingStream ();
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
@ -293,7 +293,7 @@ namespace stream
bool DropNewStream(const i2p::data::IdentHash & ident);
void ScheduleConnTrack();
private:
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
@ -306,7 +306,7 @@ namespace stream
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
boost::asio::deadline_timer m_PendingIncomingTimer;
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;
@ -318,15 +318,15 @@ namespace stream
i2p::util::MemoryPool<Packet> m_PacketsPool;
bool m_EnableDrop;
public:
i2p::data::GzipInflator m_Inflator;
i2p::data::GzipDeflator m_Deflator;
// for HTTP only
const decltype(m_Streams)& GetStreams () const { return m_Streams; };
};
};
//-------------------------------------------------
@ -336,7 +336,7 @@ namespace stream
auto s = shared_from_this();
m_Service.post ([=](void)
{
if (!m_ReceiveQueue.empty () || m_Status == eStreamStatusReset)
if (!s->m_ReceiveQueue.empty () || s->m_Status == eStreamStatusReset)
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler, 0);
else
{
@ -345,7 +345,7 @@ namespace stream
s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ s->HandleReceiveTimer (ecode, buffer, handler, timeout - t); });
}
});
});
}
template<typename Buffer, typename ReceiveHandler>
@ -355,27 +355,27 @@ namespace stream
if (received > 0)
handler (boost::system::error_code (), received);
else if (ecode == boost::asio::error::operation_aborted)
{
// timeout not expired
{
// timeout not expired
if (m_Status == eStreamStatusReset)
handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0);
else
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0);
}
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0);
}
else
{
{
// timeout expired
if (remainingTimeout <= 0)
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
else
{
{
// itermediate iterrupt
SendUpdatedLeaseSet (); // send our leaseset if applicable
AsyncReceive (buffer, handler, remainingTimeout);
}
}
AsyncReceive (buffer, handler, remainingTimeout);
}
}
}
}
}
}
}
#endif

View file

@ -56,7 +56,7 @@ public:
{
RAND_bytes(m_Buf, sz);
}
std::string ToBase64 () const
{
char str[sz*2];

View file

@ -40,7 +40,7 @@ namespace util
int i = 0;
while (!socket.available() && i < 10) // 10 seconds max
{
std::this_thread::sleep_for (std::chrono::seconds(1));
std::this_thread::sleep_for (std::chrono::seconds(1));
i++;
}
if (socket.available ())

View file

@ -11,19 +11,19 @@ namespace util
inline uint64_t GetMillisecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
std::chrono::system_clock::now().time_since_epoch()).count ();
}
inline uint32_t GetHoursSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::system_clock::now().time_since_epoch()).count ();
std::chrono::system_clock::now().time_since_epoch()).count ();
}
inline uint64_t GetSecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
std::chrono::system_clock::now().time_since_epoch()).count ();
}
}
}

View file

@ -10,58 +10,58 @@
namespace i2p
{
namespace tunnel
{
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
{
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
TunnelBase (receiveTunnelID, nextTunnelID, nextIdent)
{
{
m_Encryption.SetKeys (layerKey, ivKey);
}
}
void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{
m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
{
m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE);
}
}
TransitTunnelParticipant::~TransitTunnelParticipant ()
{
}
}
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{
auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg);
m_NumTransmittedBytes += tunnelMsg->GetLength ();
htobe32buf (newMsg->GetPayload (), GetNextTunnelID ());
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
m_TunnelDataMsgs.push_back (newMsg);
}
void TransitTunnelParticipant::FlushTunnelDataMsgs ()
{
if (!m_TunnelDataMsgs.empty ())
{
{
auto num = m_TunnelDataMsgs.size ();
if (num > 1)
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
m_TunnelDataMsgs.clear ();
}
}
}
}
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
{
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
}
}
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
}
}
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{
TunnelMessageBlock block;
@ -69,43 +69,43 @@ namespace tunnel
block.data = msg;
std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.PutTunnelDataMsg (block);
}
}
void TransitTunnelGateway::FlushTunnelDataMsgs ()
{
std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.SendBuffer ();
}
}
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{
auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg);
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
}
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint)
{
if (isEndpoint)
{
{
LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
}
else if (isGateway)
{
{
LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
else
{
}
else
{
LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
}
}
}
}
}
}

View file

@ -14,34 +14,34 @@
namespace i2p
{
namespace tunnel
{
class TransitTunnel: public TunnelBase
{
class TransitTunnel: public TunnelBase
{
public:
TransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey);
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey);
virtual size_t GetNumTransmittedBytes () const { return 0; };
// implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
private:
i2p::crypto::TunnelEncryption m_Encryption;
};
};
class TransitTunnelParticipant: public TransitTunnel
{
public:
TransitTunnelParticipant (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_NumTransmittedBytes (0) {};
~TransitTunnelParticipant ();
@ -53,51 +53,51 @@ namespace tunnel
size_t m_NumTransmittedBytes;
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
};
};
class TransitTunnelGateway: public TransitTunnel
{
public:
TransitTunnelGateway (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {};
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void FlushTunnelDataMsgs ();
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
private:
std::mutex m_SendMutex;
TunnelGateway m_Gateway;
};
};
class TransitTunnelEndpoint: public TransitTunnel
{
public:
TransitTunnelEndpoint (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
m_Endpoint (false) {}; // transit endpoint is always outbound
void Cleanup () { m_Endpoint.Cleanup (); }
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
private:
TunnelEndpoint m_Endpoint;
};
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey,
const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint);
}
}

View file

@ -20,42 +20,42 @@ namespace transport
public:
SignedData () {}
SignedData (const SignedData& other)
SignedData (const SignedData& other)
{
m_Stream << other.m_Stream.rdbuf ();
}
void Insert (const uint8_t * buf, size_t len)
{
m_Stream.write ((char *)buf, len);
}
}
void Insert (const uint8_t * buf, size_t len)
{
m_Stream.write ((char *)buf, len);
}
template<typename T>
void Insert (T t)
{
m_Stream.write ((char *)&t, sizeof (T));
m_Stream.write ((char *)&t, sizeof (T));
}
bool Verify (std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t * signature) const
{
return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
}
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const
{
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
}
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
}
private:
std::stringstream m_Stream;
};
};
class TransportSession
{
public:
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ())
{
if (router)
@ -66,30 +66,30 @@ namespace transport
virtual void Done () = 0;
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; };
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; };
size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
bool IsOutgoing () const { return m_IsOutgoing; };
int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
protected:
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
size_t m_NumSentBytes, m_NumReceivedBytes;
bool m_IsOutgoing;
int m_TerminationTimeout;
uint64_t m_LastActivityTimestamp;
};
};
}
}

View file

@ -119,7 +119,7 @@ namespace transport
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
{
@ -144,7 +144,7 @@ namespace transport
m_Service = new boost::asio::io_service ();
m_Work = new boost::asio::io_service::work (*m_Service);
m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
}
i2p::config::GetOption("nat", m_IsNAT);
@ -623,7 +623,7 @@ namespace transport
void Transports::DetectExternalIP ()
{
if (RoutesRestricted())
{
{
LogPrint(eLogInfo, "Transports: restricted routes enabled, not detecting ip");
i2p::context.SetStatus (eRouterStatusOK);
return;

View file

@ -136,10 +136,10 @@ namespace transport
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void UpdateBandwidth ();
void DetectExternalIP ();

Some files were not shown because too many files have changed in this diff Show more