Merge remote-tracking branch 'purple/openssl' into i2cp-session-reconfig

This commit is contained in:
Jeff Becker 2018-02-26 07:58:03 -05:00
commit 2f7cfddfc4
No known key found for this signature in database
GPG key ID: F357B3B42F6F9B05
166 changed files with 5382 additions and 4393 deletions

View file

@ -1,6 +1,23 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.18.0] - 2018-01-30
### Added
- Show tunnel nicknames for I2CP destination in WebUI
- Re-create HTTP and SOCKS proxy by tunnel reload
- Graceful shutdown as soon as no more transit tunnels
### Changed
- Regenerate shared local destination by tunnel reload
- Use transient local destination by default if not specified
- Return correct code if pid file can't be created
- Timing and number of attempts for adressbook requests
- Certificates list
### Fixed
- Malformed addressbook subsctiption request
- Build with boost 1.66
- Few race conditions for SAM
- Check LeaseSet's signature before update
## [2.17.0] - 2017-12-04 ## [2.17.0] - 2017-12-04
### Added ### Added
- Reseed through HTTP and SOCKS proxy - Reseed through HTTP and SOCKS proxy
@ -37,7 +54,7 @@
## [2.15.0] - 2017-08-17 ## [2.15.0] - 2017-08-17
### Added ### Added
- QT GUI - QT GUI
- Ability to add and remove I2P tunnels without restart - Ability to add and remove I2P tunnels without restart
- Ability to disable SOCKS outproxy option - Ability to disable SOCKS outproxy option
### Changed ### Changed
@ -81,7 +98,7 @@
- Some stats in a main window for Windows version - Some stats in a main window for Windows version
### Changed ### Changed
- Reseed servers list - Reseed servers list
- MTU of 1488 for ipv6 - MTU of 1488 for ipv6
- Android and Mac OS X versions use OpenSSL 1.1 - Android and Mac OS X versions use OpenSSL 1.1
- New logo for Android - New logo for Android
### Fixed ### Fixed
@ -111,7 +128,7 @@
## [2.10.2] - 2016-12-04 ## [2.10.2] - 2016-12-04
### Fixed ### Fixed
- Fixes UPnP discovery bug, producing excessive CPU usage - 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 ## [2.10.1] - 2016-11-07
### Fixed ### Fixed

View file

@ -1,54 +0,0 @@
FROM alpine:latest
MAINTAINER Mikal Villa <mikal@sigterm.no>
ENV GIT_BRANCH="master"
ENV I2PD_PREFIX="/opt/i2pd-${GIT_BRANCH}"
ENV PATH=${I2PD_PREFIX}/bin:$PATH
ENV GOSU_VERSION=1.7
ENV GOSU_SHASUM="34049cfc713e8b74b90d6de49690fa601dc040021980812b2f1f691534be8a50 /usr/local/bin/gosu"
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
# 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.
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 \
&& cd i2pd \
&& make -j4 \
&& mkdir -p ${I2PD_PREFIX}/bin \
&& mv i2pd ${I2PD_PREFIX}/bin/ \
&& cd ${I2PD_PREFIX}/bin \
&& strip i2pd \
&& rm -fr /tmp/build && apk --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \
boost-python3 python3 gdbm boost-unit_test_framework boost-python linux-headers boost-prg_exec_monitor \
boost-serialization boost-signals boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \
libtool g++ gcc pkgconfig
# 2. Adding required libraries to run i2pd to ensure it will run.
RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl musl-utils libstdc++
# Gosu is a replacement for su/sudo in docker and not a backdoor :) See https://github.com/tianon/gosu
RUN wget -O /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64 \
&& echo "${GOSU_SHASUM}" | sha256sum -c && chmod +x /usr/local/bin/gosu
COPY entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh
RUN echo "export PATH=${PATH}" >> /etc/profile
VOLUME [ "/var/lib/i2pd" ]
EXPOSE 7070 4444 4447 7656 2827 7654 7650
ENTRYPOINT [ "/entrypoint.sh" ]

View file

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

View file

@ -1,5 +1,5 @@
CXX = clang++ 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 ## 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. ## **without** overwriting the CXXFLAGS which we need in order to build.
## For example, when adding 'hardening flags' to the build ## For example, when adding 'hardening flags' to the build

View file

@ -4,7 +4,7 @@ BOOSTROOT = ${BREWROOT}/opt/boost
SSLROOT = ${BREWROOT}/opt/libressl SSLROOT = ${BREWROOT}/opt/libressl
UPNPROOT = ${BREWROOT}/opt/miniupnpc UPNPROOT = ${BREWROOT}/opt/miniupnpc
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual 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 ifndef TRAVIS
CXX = clang++ CXX = clang++
@ -33,10 +33,13 @@ endif
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html # http://www.hutsby.net/2011/08/macs-with-aes-ni.html
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
# note from psi: 2009 macbook does not have aesni ifeq ($(USE_AESNI),yes)
#ifeq ($(USE_AESNI),yes) CXXFLAGS += -maes -DAESNI
# CXXFLAGS += -maes -DAESNI endif
#endif ifeq ($(USE_AVX),1)
CXXFLAGS += -mavx
endif
# Disabled, since it will be the default make rule. I think its better # Disabled, since it will be the default make rule. I think its better
# to define the default rule in Makefile and not Makefile.<ostype> - torkel # to define the default rule in Makefile and not Makefile.<ostype> - torkel

View file

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

View file

@ -1,7 +1,7 @@
CXX = clang++ CXX = clang++
CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11 #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 LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)

View file

@ -3,27 +3,27 @@ i2pd
[Русская версия](https://github.com/PurpleI2P/i2pd_docs_ru/blob/master/README.md) [Русская версия](https://github.com/PurpleI2P/i2pd_docs_ru/blob/master/README.md)
i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client. 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 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 I2P client is a software used for building and using anonymous I2P
networks. Such networks are commonly used for anonymous peer-to-peer networks. Such networks are commonly used for anonymous peer-to-peer
applications (filesharing, cryptocurrencies) and anonymous client-server applications (filesharing, cryptocurrencies) and anonymous client-server
applications (websites, instant messengers, chat-servers). applications (websites, instant messengers, chat-servers).
I2P allows people from all around the world to communicate and share information I2P allows people from all around the world to communicate and share information
without restrictions. without restrictions.
Features Features
-------- --------
* Distributed anonymous networking framework * Distributed anonymous networking framework
* End-to-end encrypted communications * End-to-end encrypted communications
* Small footprint, simple dependencies, fast performance * Small footprint, simple dependencies, fast performance
* Rich set of APIs for developers of secure applications * Rich set of APIs for developers of secure applications
Resources Resources
--------- ---------
@ -38,10 +38,10 @@ Resources
Installing Installing
---------- ----------
The easiest way to install i2pd is by using The easiest way to install i2pd is by using
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest). [precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
i2pd from source on your OS. i2pd from source on your OS.
Build instructions: Build instructions:
@ -57,29 +57,30 @@ Build instructions:
* GNU/Linux x86/x64 - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) * GNU/Linux x86/x64 - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
* Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd) * 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) * Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
* CentOS / Fedora - [![Build Status](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/status_image/last_build.png)](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
* Docker image - [![Build Status](https://dockerbuildbadges.quelltext.eu/status.svg?organization=meeh&repository=i2pd)](https://hub.docker.com/r/meeh/i2pd/builds/)
* FreeBSD * FreeBSD
* Android * Android
* iOS * iOS
Using i2pd 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). [example config file](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/i2pd.conf).
Donations Donations
--------- ---------
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY BTC: 3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59 LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y ETH: 0x9e5bac70d20d1079ceaa111127f4fb3bccce379d
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
License License
------- -------
This project is licensed under the BSD 3-clause license, which can be found in the file This project is licensed under the BSD 3-clause license, which can be found in the file
LICENSE in the root of the project source code. LICENSE in the root of the project source code.

View file

@ -21,6 +21,7 @@ namespace util
SetConsoleCP(1251); SetConsoleCP(1251);
SetConsoleOutputCP(1251); SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian"); setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C");
if (!Daemon_Singleton::init(argc, argv)) if (!Daemon_Singleton::init(argc, argv))
return false; return false;
@ -68,6 +69,7 @@ namespace util
SetConsoleCP(1251); SetConsoleCP(1251);
SetConsoleOutputCP(1251); SetConsoleOutputCP(1251);
setlocale(LC_ALL, "Russian"); setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C");
#ifdef WIN32_APP #ifdef WIN32_APP
if (!i2p::win32::StartWin32App ()) return false; if (!i2p::win32::StartWin32App ()) return false;

View file

@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.17.0" #define I2Pd_ver "2.18.0"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
[Setup] [Setup]

9
android/.gitignore vendored
View file

@ -5,4 +5,11 @@ ant.properties
local.properties local.properties
build.sh build.sh
bin bin
log* log*
.gradle
android.iml
build
gradle
gradlew
gradlew.bat

View file

@ -1,26 +1,56 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.purplei2p.i2pd" package="org.purplei2p.i2pd"
android:versionCode="1" android:installLocation="auto"
android:versionName="2.17.0" android:versionCode="1"
android:installLocation="auto"> android:versionName="2.18.0">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="25"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-sdk
<uses-permission android:name="android.permission.INTERNET"/> android:minSdkVersion="14"
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> android:targetSdkVersion="25" />
<application android:label="@string/app_name" android:allowBackup="true" android:icon="@drawable/icon">
<receiver android:name=".NetworkStateChangeReceiver"> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<intent-filter> <uses-permission android:name="android.permission.INTERNET" /> <!-- normal perm, per https://developer.android.com/guide/topics/permissions/normal-permissions.html -->
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</intent-filter> <uses-permission android:name="android.permission.READ_PHONE_STATE" />
</receiver> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- normal perm -->
<activity android:name=".I2PD" <application
android:label="@string/app_name"> android:allowBackup="true"
android:icon="@drawable/icon"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
>
<receiver android:name=".NetworkStateChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<activity
android:name=".I2PDPermsAskerActivity"
android:label="@string/app_name">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<service android:enabled="true" android:name=".ForegroundService"/> <activity
android:name=".I2PDActivity"
android:label="@string/app_name" />
<service
android:name=".ForegroundService"
android:enabled="true" />
<activity
android:name=".I2PDPermsExplanationActivity"
android:label="@string/title_activity_i2_pdperms_asker_prompt"
android:parentActivityName=".I2PDPermsAskerActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" />
</activity>
</application> </application>
</manifest>
</manifest>

View file

@ -1,33 +1,44 @@
buildscript { buildscript {
repositories { repositories {
mavenCentral() mavenCentral()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.1.2' classpath 'com.android.tools.build:gradle:2.3.3'
} }
} }
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
repositories {
jcenter()
maven {
url 'https://maven.google.com'
}
}
android { android {
compileSdkVersion 25 compileSdkVersion 25
buildToolsVersion "25.0.2" buildToolsVersion "25.0.2"
defaultConfig { defaultConfig {
applicationId "org.purplei2p.i2pd" applicationId "org.purplei2p.i2pd"
targetSdkVersion 25 targetSdkVersion 25
minSdkVersion 14 minSdkVersion 14
versionCode 1 versionCode 1
versionName "2.17.1" versionName "2.18.0"
ndk {
abiFilters 'armeabi-v7a'
//abiFilters 'x86'
} }
}
sourceSets { sourceSets {
main { main {
manifest.srcFile 'AndroidManifest.xml' manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src'] java.srcDirs = ['src']
res.srcDirs = ['res'] res.srcDirs = ['res']
jniLibs.srcDirs = ['libs'] jniLibs.srcDirs = ['libs']
}
} }
}
signingConfigs { signingConfigs {
orignal { orignal {
storeFile file("i2pdapk.jks") storeFile file("i2pdapk.jks")
@ -37,11 +48,17 @@ android {
} }
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
signingConfig signingConfigs.orignal signingConfig signingConfigs.orignal
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
} }
}
externalNativeBuild {
ndkBuild {
path './jni/Android.mk'
}
} }
} }

View file

@ -0,0 +1,27 @@
<LinearLayout android:id="@+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/vertical_page_margin"
android:paddingLeft="@dimen/horizontal_page_margin"
android:paddingRight="@dimen/horizontal_page_margin"
android:paddingTop="@dimen/vertical_page_margin"
tools:context=".I2PDPermsAskerActivity">
<TextView
android:id="@+id/textview_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/horizontal_page_margin"
android:visibility="gone"
/>
<Button
android:id="@+id/button_request_write_ext_storage_perms"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Retry requesting the SD card write permissions"
android:visibility="gone"/>
</LinearLayout>

View file

@ -0,0 +1,27 @@
<LinearLayout android:id="@+id/layout_prompt"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/vertical_page_margin"
android:paddingLeft="@dimen/horizontal_page_margin"
android:paddingRight="@dimen/horizontal_page_margin"
android:paddingTop="@dimen/vertical_page_margin"
tools:context=".I2PDPermsAskerActivity">
<TextView
android:id="@+id/textview_explanation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/horizontal_page_margin"
android:text="SD card write access is required to write the keys and other files to the I2PD folder on SD card."
/>
<Button
android:id="@+id/button_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"
/>
</LinearLayout>

View file

@ -1,16 +1,16 @@
<menu <menu
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" 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"> tools:context=".I2PDActivity">
<item <item
android:id="@+id/action_graceful_quit" android:id="@+id/action_graceful_stop"
android:title="@string/action_graceful_quit" android:title="@string/action_graceful_stop"
android:orderInCategory="98" android:orderInCategory="98"
/> />
<item <item
android:id="@+id/action_quit" android:id="@+id/action_stop"
android:title="@string/action_quit" android:title="@string/action_stop"
android:orderInCategory="99" android:orderInCategory="99"
/> />
</menu> </menu>

View file

@ -1,11 +1,18 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">i2pd</string> <string name="app_name">i2pd</string>
<string name="i2pd_started">i2pd started</string> <string name="action_stop">Stop</string>
<string name="i2pd_service_started">i2pd service started</string> <string name="action_graceful_stop">Graceful Stop</string>
<string name="i2pd_service_stopped">i2pd service stopped</string> <string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string>
<string name="action_quit">Quit</string> <string name="graceful_stop_is_in_progress">Graceful stop is in progress</string>
<string name="action_graceful_quit">Graceful Quit</string> <string name="already_stopped">Already stopped</string>
<string name="graceful_quit_is_already_in_progress">Graceful quit is already in progress</string> <string name="uninitialized">i2pd initializing</string>
<string name="graceful_quit_is_in_progress">Graceful quit is in progress</string> <string name="starting">i2pd is starting</string>
<string name="jniLibraryLoaded">i2pd: loaded JNI libraries</string>
<string name="startedOkay">i2pd started</string>
<string name="startFailed">i2pd start failed</string>
<string name="gracefulShutdownInProgress">i2pd: graceful shutdown in progress</string>
<string name="stopped">i2pd has stopped</string>
<string name="remaining">remaining</string>
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
</resources> </resources>

View file

@ -0,0 +1,16 @@
<resources>
<!-- Define standard dimensions to comply with Holo-style grids and rhythm. -->
<dimen name="margin_tiny">4dp</dimen>
<dimen name="margin_small">8dp</dimen>
<dimen name="margin_medium">16dp</dimen>
<dimen name="margin_large">32dp</dimen>
<dimen name="margin_huge">64dp</dimen>
<!-- Semantic definitions -->
<dimen name="horizontal_page_margin">@dimen/margin_medium</dimen>
<dimen name="vertical_page_margin">@dimen/margin_medium</dimen>
</resources>

View file

@ -8,89 +8,98 @@ import android.util.Log;
public class DaemonSingleton { public class DaemonSingleton {
private static final String TAG="i2pd"; private static final String TAG="i2pd";
private static final DaemonSingleton instance = new DaemonSingleton(); private static final DaemonSingleton instance = new DaemonSingleton();
public static interface StateUpdateListener { void daemonStateUpdate(); } public interface StateUpdateListener { void daemonStateUpdate(); }
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<StateUpdateListener>(); private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
public static DaemonSingleton getInstance() { public static DaemonSingleton getInstance() {
return instance; return instance;
} }
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
private synchronized void setState(State newState) {
if(newState==null)throw new NullPointerException();
State oldState = state;
if(oldState==null)throw new NullPointerException();
if(oldState.equals(newState))return;
state=newState;
fireStateUpdate1();
}
public synchronized void stopAcceptingTunnels() { public synchronized void stopAcceptingTunnels() {
if(isStartedOkay()){ if(isStartedOkay()){
state=State.gracefulShutdownInProgress; setState(State.gracefulShutdownInProgress);
fireStateUpdate();
I2PD_JNI.stopAcceptingTunnels(); 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 volatile boolean startedOkay;
private State state = State.uninitialized; public enum State {
uninitialized(R.string.uninitialized),
starting(R.string.starting),
jniLibraryLoaded(R.string.jniLibraryLoaded),
startedOkay(R.string.startedOkay),
startFailed(R.string.startFailed),
gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
stopped(R.string.stopped);
State(int statusStringResourceId) {
this.statusStringResourceId = statusStringResourceId;
}
private final int statusStringResourceId;
public int getStatusStringResourceId() {
return statusStringResourceId;
}
};
private volatile State state = State.uninitialized;
public State getState() { return state; } public State getState() { return state; }
public synchronized void start() { {
if(state != State.uninitialized)return; setState(State.starting);
state = State.starting;
fireStateUpdate();
new Thread(new Runnable(){ new Thread(new Runnable(){
@Override @Override
public void run() { public void run() {
try { try {
I2PD_JNI.loadLibraries(); I2PD_JNI.loadLibraries();
synchronized (DaemonSingleton.this) { setState(State.jniLibraryLoaded);
state = State.jniLibraryLoaded;
fireStateUpdate();
}
} catch (Throwable tr) { } catch (Throwable tr) {
lastThrowable=tr; lastThrowable=tr;
synchronized (DaemonSingleton.this) { setState(State.startFailed);
state = State.startFailed;
fireStateUpdate();
}
return; return;
} }
try { try {
synchronized (DaemonSingleton.this) { synchronized (DaemonSingleton.this) {
daemonStartResult = I2PD_JNI.startDaemon(); daemonStartResult = I2PD_JNI.startDaemon();
if("ok".equals(daemonStartResult)){ if("ok".equals(daemonStartResult)){
state=State.startedOkay; setState(State.startedOkay);
setStartedOkay(true); setStartedOkay(true);
}else state=State.startFailed; }else setState(State.startFailed);
fireStateUpdate();
} }
} catch (Throwable tr) { } catch (Throwable tr) {
lastThrowable=tr; lastThrowable=tr;
synchronized (DaemonSingleton.this) { setState(State.startFailed);
state = State.startFailed;
fireStateUpdate();
}
return; return;
} }
} }
}, "i2pdDaemonStart").start(); }, "i2pdDaemonStart").start();
} }
private Throwable lastThrowable; private Throwable lastThrowable;
private String daemonStartResult="N/A"; private String daemonStartResult="N/A";
private synchronized void fireStateUpdate() { private void fireStateUpdate1() {
Log.i(TAG, "daemon state change: "+state); Log.i(TAG, "daemon state change: "+state);
for(StateUpdateListener listener : stateUpdateListeners) { for(StateUpdateListener listener : stateUpdateListeners) {
try { try {
listener.daemonStateUpdate(); listener.daemonStateUpdate();
} catch (Throwable tr) { } catch (Throwable tr) {
Log.e(TAG, "exception in listener ignored", tr); Log.e(TAG, "exception in listener ignored", tr);
} }
} }
} }
@ -102,7 +111,7 @@ public class DaemonSingleton {
public String getDaemonStartResult() { public String getDaemonStartResult() {
return daemonStartResult; return daemonStartResult;
} }
private final Object startedOkayLock = new Object(); private final Object startedOkayLock = new Object();
public boolean isStartedOkay() { public boolean isStartedOkay() {
@ -121,6 +130,7 @@ public class DaemonSingleton {
if(isStartedOkay()){ if(isStartedOkay()){
try {I2PD_JNI.stopDaemon();}catch(Throwable tr){Log.e(TAG, "", tr);} try {I2PD_JNI.stopDaemon();}catch(Throwable tr){Log.e(TAG, "", tr);}
setStartedOkay(false); setStartedOkay(false);
setState(State.stopped);
} }
} }
} }

View file

@ -11,11 +11,32 @@ import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
public class ForegroundService extends Service { public class ForegroundService extends Service {
private static final String TAG="FgService";
private volatile boolean shown;
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() {
@Override
public void daemonStateUpdate() {
try {
synchronized (ForegroundService.this) {
if (shown) cancelNotification();
showNotification();
}
} catch (Throwable tr) {
Log.e(TAG,"error ignored",tr);
}
}
};
private NotificationManager notificationManager; private NotificationManager notificationManager;
// Unique Identification Number for the Notification. // Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it. // We use it on Notification start, and to cancel it.
private int NOTIFICATION = R.string.i2pd_started; private int NOTIFICATION = 1;
/** /**
* Class for clients to access. Because we know this service always * Class for clients to access. Because we know this service always
@ -32,29 +53,35 @@ public class ForegroundService extends Service {
public void onCreate() { public void onCreate() {
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Display a notification about us starting. We put an icon in the status bar. synchronized (this) {
showNotification(); DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
daemon.start(); if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
}
// Tell the user we started. // Tell the user we started.
Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); // Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("ForegroundService", "Received start id " + startId + ": " + intent); Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
daemon.start();
return START_STICKY; return START_STICKY;
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
cancelNotification();
}
private synchronized void cancelNotification() {
// Cancel the persistent notification. // Cancel the persistent notification.
notificationManager.cancel(NOTIFICATION); notificationManager.cancel(NOTIFICATION);
stopForeground(true); stopForeground(true);
// Tell the user we stopped. // Tell the user we stopped.
Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); // Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
shown=false;
} }
@Override @Override
@ -69,13 +96,13 @@ public class ForegroundService extends Service {
/** /**
* Show a notification while this service is running. * Show a notification while this service is running.
*/ */
private void showNotification() { private synchronized void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification // In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.i2pd_started); CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
// The PendingIntent to launch our activity if the user selects this notification // The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, I2PD.class), 0); new Intent(this, I2PDActivity.class), 0);
// Set the info for the views that show in the notification panel. // Set the info for the views that show in the notification panel.
Notification notification = new Notification.Builder(this) Notification notification = new Notification.Builder(this)
@ -90,8 +117,9 @@ public class ForegroundService extends Service {
// Send the notification. // Send the notification.
//mNM.notify(NOTIFICATION, notification); //mNM.notify(NOTIFICATION, notification);
startForeground(NOTIFICATION, notification); startForeground(NOTIFICATION, notification);
shown=true;
} }
private final DaemonSingleton daemon = DaemonSingleton.getInstance(); private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
} }

View file

@ -1,245 +0,0 @@
package org.purplei2p.i2pd;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Timer;
import java.util.TimerTask;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class I2PD extends Activity {
private static final String TAG = "i2pd";
private TextView textView;
private final DaemonSingleton daemon = DaemonSingleton.getInstance();
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() {
@Override
public void daemonStateUpdate() {
runOnUiThread(new Runnable(){
@Override
public void run() {
try {
if(textView==null)return;
Throwable tr = daemon.getLastThrowable();
if(tr!=null) {
textView.setText(throwableToString(tr));
return;
}
DaemonSingleton.State state = daemon.getState();
textView.setText(String.valueOf(state)+
(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():""));
} catch (Throwable tr) {
Log.e(TAG,"error ignored",tr);
}
}
});
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
setContentView(textView);
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
daemonStateUpdatedListener.daemonStateUpdate();
//set the app be foreground
doBindService();
}
@Override
protected void onDestroy() {
super.onDestroy();
localDestroy();
}
private void localDestroy() {
textView = null;
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null) {
gracefulQuitTimer.cancel();
setGracefulQuitTimer(null);
}
try{
doUnbindService();
}catch(Throwable tr){
Log.e(TAG, "", tr);
}
}
private CharSequence throwableToString(Throwable tr) {
StringWriter sw = new StringWriter(8192);
PrintWriter pw = new PrintWriter(sw);
tr.printStackTrace(pw);
pw.close();
return sw.toString();
}
// private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
// mBoundService = ((LocalService.LocalBinder)service).getService();
// Tell the user about this for our demo.
// Toast.makeText(Binding.this, R.string.local_service_connected,
// Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
// mBoundService = null;
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
// Toast.LENGTH_SHORT).show();
}
};
private boolean mIsBound;
private void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindService(new Intent(this,
ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.options_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch(id){
case R.id.action_quit:
quit();
return true;
case R.id.action_graceful_quit:
gracefulQuit();
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressLint("NewApi")
private void quit() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
finishAffinity();
} else {
//moveTaskToBack(true);
finish();
}
}catch (Throwable tr) {
Log.e(TAG, "", tr);
}
try{
daemon.stopDaemon();
}catch (Throwable tr) {
Log.e(TAG, "", tr);
}
System.exit(0);
}
private Timer gracefulQuitTimer;
private final Object gracefulQuitTimerLock = new Object();
private void gracefulQuit() {
if(getGracefulQuitTimer()!=null){
Toast.makeText(this, R.string.graceful_quit_is_already_in_progress,
Toast.LENGTH_SHORT).show();
return;
}
Toast.makeText(this, R.string.graceful_quit_is_in_progress,
Toast.LENGTH_SHORT).show();
new Thread(new Runnable(){
@Override
public void run() {
try{
Log.d(TAG, "grac stopping");
if(daemon.isStartedOkay()) {
daemon.stopAcceptingTunnels();
Timer gracefulQuitTimer = new Timer(true);
setGracefulQuitTimer(gracefulQuitTimer);
gracefulQuitTimer.schedule(new TimerTask(){
@Override
public void run() {
quit();
}
}, 10*60*1000/*milliseconds*/);
}else{
quit();
}
} catch(Throwable tr) {
Log.e(TAG,"",tr);
}
}
},"gracQuitInit").start();
}
private Timer getGracefulQuitTimer() {
synchronized (gracefulQuitTimerLock) {
return gracefulQuitTimer;
}
}
private void setGracefulQuitTimer(Timer gracefulQuitTimer) {
synchronized (gracefulQuitTimerLock) {
this.gracefulQuitTimer = gracefulQuitTimer;
}
}
}

View file

@ -0,0 +1,285 @@
package org.purplei2p.i2pd;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class I2PDActivity extends Activity {
private static final String TAG = "i2pdActvt";
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
private TextView textView;
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() {
@Override
public void daemonStateUpdate() {
runOnUiThread(new Runnable(){
@Override
public void run() {
try {
if(textView==null)return;
Throwable tr = daemon.getLastThrowable();
if(tr!=null) {
textView.setText(throwableToString(tr));
return;
}
DaemonSingleton.State state = daemon.getState();
textView.setText(
String.valueOf(state)+
(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+
(DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"")
);
} catch (Throwable tr) {
Log.e(TAG,"error ignored",tr);
}
}
});
}
};
private static volatile long graceStartedMillis;
private static final Object graceStartedMillis_LOCK=new Object();
private static String formatGraceTimeRemaining() {
long remainingSeconds;
synchronized (graceStartedMillis_LOCK){
remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D);
}
long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D);
long remSec=remainingSeconds-remainingMinutes*60;
return remainingMinutes+":"+(remSec/10)+remSec%10;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textView = new TextView(this);
setContentView(textView);
daemon.addStateChangeListener(daemonStateUpdatedListener);
daemonStateUpdatedListener.daemonStateUpdate();
//set the app be foreground
doBindService();
final Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null){
long gracefulStopAtMillis;
synchronized (graceStartedMillis_LOCK) {
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
}
rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
textView = null;
daemon.removeStateChangeListener(daemonStateUpdatedListener);
//cancelGracefulStop();
try{
doUnbindService();
}catch(Throwable tr){
Log.e(TAG, "", tr);
}
}
private static void cancelGracefulStop() {
Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null) {
gracefulQuitTimer.cancel();
setGracefulQuitTimer(null);
}
}
private CharSequence throwableToString(Throwable tr) {
StringWriter sw = new StringWriter(8192);
PrintWriter pw = new PrintWriter(sw);
tr.printStackTrace(pw);
pw.close();
return sw.toString();
}
// private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
// mBoundService = ((LocalService.LocalBinder)service).getService();
// Tell the user about this for our demo.
// Toast.makeText(Binding.this, R.string.local_service_connected,
// Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
// mBoundService = null;
// Toast.makeText(Binding.this, R.string.local_service_disconnected,
// Toast.LENGTH_SHORT).show();
}
};
private static volatile boolean mIsBound;
private void doBindService() {
synchronized (I2PDActivity.class) {
if (mIsBound) return;
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
}
private void doUnbindService() {
synchronized (I2PDActivity.class) {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.options_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch(id){
case R.id.action_stop:
i2pdStop();
return true;
case R.id.action_graceful_stop:
i2pdGracefulStop();
return true;
}
return super.onOptionsItemSelected(item);
}
private void i2pdStop() {
cancelGracefulStop();
new Thread(new Runnable(){
@Override
public void run() {
Log.d(TAG, "stopping");
try{
daemon.stopDaemon();
}catch (Throwable tr) {
Log.e(TAG, "", tr);
}
}
},"stop").start();
}
private static volatile Timer gracefulQuitTimer;
private void i2pdGracefulStop() {
if(daemon.getState()==DaemonSingleton.State.stopped){
Toast.makeText(this, R.string.already_stopped,
Toast.LENGTH_SHORT).show();
return;
}
if(getGracefulQuitTimer()!=null){
Toast.makeText(this, R.string.graceful_stop_is_already_in_progress,
Toast.LENGTH_SHORT).show();
return;
}
Toast.makeText(this, R.string.graceful_stop_is_in_progress,
Toast.LENGTH_SHORT).show();
new Thread(new Runnable(){
@Override
public void run() {
try{
Log.d(TAG, "grac stopping");
if(daemon.isStartedOkay()) {
daemon.stopAcceptingTunnels();
long gracefulStopAtMillis;
synchronized (graceStartedMillis_LOCK) {
graceStartedMillis = System.currentTimeMillis();
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
}
rescheduleGraceStop(null,gracefulStopAtMillis);
}else{
i2pdStop();
}
} catch(Throwable tr) {
Log.e(TAG,"",tr);
}
}
},"gracInit").start();
}
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel();
final Timer gracefulQuitTimer = new Timer(true);
setGracefulQuitTimer(gracefulQuitTimer);
gracefulQuitTimer.schedule(new TimerTask(){
@Override
public void run() {
i2pdStop();
}
}, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis()));
final TimerTask tickerTask = new TimerTask() {
@Override
public void run() {
daemonStateUpdatedListener.daemonStateUpdate();
}
};
gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/);
}
private static Timer getGracefulQuitTimer() {
return gracefulQuitTimer;
}
private static void setGracefulQuitTimer(Timer gracefulQuitTimer) {
I2PDActivity.gracefulQuitTimer = gracefulQuitTimer;
}
}

View file

@ -0,0 +1,171 @@
package org.purplei2p.i2pd;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.lang.reflect.Method;
//dangerous perms, per https://developer.android.com/guide/topics/permissions/normal-permissions.html :
//android.permission.WRITE_EXTERNAL_STORAGE
public class I2PDPermsAskerActivity extends Activity {
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 0;
private Button button_request_write_ext_storage_perms;
private TextView textview_retry;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//if less than Android 6, no runtime perms req system present
if (android.os.Build.VERSION.SDK_INT < 23) {
startMainActivity();
return;
}
setContentView(R.layout.activity_perms_asker);
button_request_write_ext_storage_perms = (Button) findViewById(R.id.button_request_write_ext_storage_perms);
textview_retry = (TextView) findViewById(R.id.textview_retry);
button_request_write_ext_storage_perms.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
request_write_ext_storage_perms();
}
});
request_write_ext_storage_perms();
}
private void request_write_ext_storage_perms() {
textview_retry.setVisibility(TextView.GONE);
button_request_write_ext_storage_perms.setVisibility(Button.GONE);
Method methodCheckPermission;
Method method_shouldShowRequestPermissionRationale;
Method method_requestPermissions;
try {
methodCheckPermission = getClass().getMethod("checkSelfPermission", String.class);
method_shouldShowRequestPermissionRationale =
getClass().getMethod("shouldShowRequestPermissionRationale", String.class);
method_requestPermissions =
getClass().getMethod("requestPermissions", String[].class, int.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
Integer resultObj;
try {
resultObj = (Integer) methodCheckPermission.invoke(
this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
} catch (Throwable e) {
throw new RuntimeException(e);
}
if (resultObj != PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
Boolean aBoolean;
try {
aBoolean = (Boolean) method_shouldShowRequestPermissionRationale.invoke(this,
Manifest.permission.WRITE_EXTERNAL_STORAGE);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (aBoolean) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
showExplanation();
} else {
// No explanation needed, we can request the permission.
try {
method_requestPermissions.invoke(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_WRITE_EXTERNAL_STORAGE);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} else startMainActivity();
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_WRITE_EXTERNAL_STORAGE: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
startMainActivity();
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
textview_retry.setText("SD card write permission denied, you need to allow this to continue");
textview_retry.setVisibility(TextView.VISIBLE);
button_request_write_ext_storage_perms.setVisibility(Button.VISIBLE);
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
private void startMainActivity() {
startActivity(new Intent(this, I2PDActivity.class));
finish();
}
private static final int SHOW_EXPLANATION_REQUEST = 1; // The request code
private void showExplanation() {
Intent intent = new Intent(this, I2PDPermsExplanationActivity.class);
startActivityForResult(intent, SHOW_EXPLANATION_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == SHOW_EXPLANATION_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// Request the permission
Method method_requestPermissions;
try {
method_requestPermissions =
getClass().getMethod("requestPermissions", String[].class, int.class);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
try {
method_requestPermissions.invoke(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_WRITE_EXTERNAL_STORAGE);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
finish(); //close the app
}
}
}
}

View file

@ -0,0 +1,38 @@
package org.purplei2p.i2pd;
import android.app.ActionBar;
import android.content.Intent;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.Button;
public class I2PDPermsExplanationActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_perms_explanation);
ActionBar actionBar = getActionBar();
if(actionBar!=null)actionBar.setHomeButtonEnabled(false);
Button button_ok = (Button) findViewById(R.id.button_ok);
button_ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
returnFromActivity();
}
});
}
private void returnFromActivity() {
Intent data = new Intent();
Activity parent = getParent();
if (parent == null) {
setResult(Activity.RESULT_OK, data);
} else {
parent.setResult(Activity.RESULT_OK, data);
}
finish();
}
}

View file

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

View file

@ -1,4 +1,4 @@
version: 2.17.{build} version: 2.18.{build}
pull_requests: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
branches: branches:
@ -17,8 +17,8 @@ environment:
- MSYSTEM: MINGW32 - MSYSTEM: MINGW32
install: install:
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc catgets"
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu "
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"

View file

@ -39,6 +39,7 @@ include_directories(${LIBI2PD_CLIENT_SRC_DIR})
set (LIBI2PD_SRC set (LIBI2PD_SRC
"${LIBI2PD_SRC_DIR}/BloomFilter.cpp" "${LIBI2PD_SRC_DIR}/BloomFilter.cpp"
"${LIBI2PD_SRC_DIR}/Config.cpp" "${LIBI2PD_SRC_DIR}/Config.cpp"
"${LIBI2PD_SRC_DIR}/CPU.cpp"
"${LIBI2PD_SRC_DIR}/Crypto.cpp" "${LIBI2PD_SRC_DIR}/Crypto.cpp"
"${LIBI2PD_SRC_DIR}/CryptoKey.cpp" "${LIBI2PD_SRC_DIR}/CryptoKey.cpp"
"${LIBI2PD_SRC_DIR}/Garlic.cpp" "${LIBI2PD_SRC_DIR}/Garlic.cpp"
@ -83,7 +84,7 @@ if (WITH_WEBSOCKETS)
find_package(websocketpp REQUIRED) find_package(websocketpp REQUIRED)
endif () endif ()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR MSYS) if (WIN32 OR MSYS)
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp") list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
endif () endif ()
@ -184,6 +185,8 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# more tweaks # more tweaks
if (NOT (MSVC OR MSYS OR APPLE)) if (NOT (MSVC OR MSYS OR APPLE))
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libstdc++" ) # required for <atomic>
list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++") # required to link with -stdlib=libstdc++
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions" ) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions" )
endif() endif()
endif () endif ()
@ -194,20 +197,14 @@ if (WITH_HARDENING AND MSVC)
endif () endif ()
# compiler flags customization (by system) # compiler flags customization (by system)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux") if (UNIX)
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp") 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 if (NOT (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR APPLE))
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" ) # "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" )
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp") endif ()
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8 elseif (WIN32 OR MSYS)
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" ) list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp")
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 (WITH_GUI) if (WITH_GUI)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32App.cpp") list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32App.cpp")
set_source_files_properties("${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp" set_source_files_properties("${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp"
@ -330,10 +327,6 @@ endif()
find_package ( OpenSSL REQUIRED ) find_package ( OpenSSL REQUIRED )
if(NOT DEFINED OPENSSL_INCLUDE_DIR) if(NOT DEFINED OPENSSL_INCLUDE_DIR)
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
else()
if(NOT (OPENSSL_VERSION VERSION_LESS 1.1))
message(WARNING "Your OpenSSL version ${OPENSSL_VERSION} >=1.1 is experimental: build with v1.0 when possible.")
endif()
endif() endif()
if (WITH_UPNP) if (WITH_UPNP)
@ -370,11 +363,13 @@ if (NOT ZLIB_FOUND )
if (NOT WITH_STATIC) if (NOT WITH_STATIC)
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE) set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
endif () endif ()
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib)
else()
link_directories(${ZLIB_ROOT}/lib)
endif () endif ()
if (WITH_STATIC AND (MSVC OR MSYS)) if (WITH_STATIC AND (MSVC OR MSYS))
set ( ZLIB_LIBRARY debug zlibstaticd optimized zlibstatic CACHE STRING "zlib libraries" FORCE) set ( ZLIB_LIBRARY debug zlibstaticd optimized zlibstatic CACHE STRING "zlib libraries" FORCE)
endif () endif ()
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib ${ZLIB_ROOT}/lib)
# load includes # load includes
include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} )
@ -386,11 +381,7 @@ if (WITH_MESHNET)
message(WARNING "This build will NOT work on mainline i2p") message(WARNING "This build will NOT work on mainline i2p")
endif() endif()
if (ARCHITECTURE MATCHES "arm") include(CheckAtomic)
set(ATOMIC_LIB -latomic)
else()
set(ATMOIC_LIB "")
endif()
# show summary # show summary
@ -459,7 +450,7 @@ if (WITH_BINARY)
if (WITH_STATIC) if (WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS}) set(DL_LIB ${CMAKE_DL_LIBS})
endif() endif()
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}) target_link_libraries( "${PROJECT_NAME}" libi2pd i2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}") set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

View file

@ -58,6 +58,7 @@ pause
exit /b 0 exit /b 0
:BUILDING :BUILDING
%xSH% "make clean" >> nul
echo Building i2pd %tag% for win%bitness%: echo Building i2pd %tag% for win%bitness%:
echo Build AVX+AESNI... echo Build AVX+AESNI...
%xSH% "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 %xSH% "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1

View file

@ -0,0 +1,106 @@
# atomic builtins are required for threading support.
INCLUDE(CheckCXXSourceCompiles)
# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.
function(check_working_cxx_atomics varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(CMAKE_REQUIRED_FLAGS "-std=c++11")
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
std::atomic<int> x;
int main() {
return x;
}
" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction(check_working_cxx_atomics)
function(check_working_cxx_atomics64 varname)
set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}")
CHECK_CXX_SOURCE_COMPILES("
#include <atomic>
#include <cstdint>
std::atomic<uint64_t> x (0);
int main() {
uint64_t i = x.load(std::memory_order_relaxed);
return 0;
}
" ${varname})
set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction(check_working_cxx_atomics64)
# This isn't necessary on MSVC, so avoid command-line switch annoyance
# by only running on GCC-like hosts.
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
# First check if atomics work without the library.
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
if( HAVE_LIBATOMIC )
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
else()
message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
endif()
# Check for 64 bit atomic operations.
if(MSVC)
set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True)
else()
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
endif()
# If not, check if the library exists, and atomics work with it.
if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
if(HAVE_CXX_LIBATOMICS64)
list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
message(FATAL_ERROR "Host compiler must support std::atomic!")
endif()
else()
message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
endif()
endif()
## TODO: This define is only used for the legacy atomic operations in
## llvm's Atomic.h, which should be replaced. Other code simply
## assumes C++11 <atomic> works.
CHECK_CXX_SOURCE_COMPILES("
#ifdef _MSC_VER
#include <Intrin.h> /* Workaround for PR19898. */
#include <windows.h>
#endif
int main() {
#ifdef _MSC_VER
volatile LONG val = 1;
MemoryBarrier();
InterlockedCompareExchange(&val, 0, 1);
InterlockedIncrement(&val);
InterlockedDecrement(&val);
#else
volatile unsigned long val = 1;
__sync_synchronize();
__sync_val_compare_and_swap(&val, 1, 0);
__sync_add_and_fetch(&val, 1);
__sync_sub_and_fetch(&val, 1);
#endif
return 0;
}
" LLVM_HAS_ATOMICS)
if( NOT LLVM_HAS_ATOMICS )
message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing")
endif()

View file

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

View file

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

View file

@ -1,4 +1,4 @@
# Basic profile for i2pd # Basic profile for i2pd
# Should work without modifications with Ubuntu/Debian packages # Should work without modifications with Ubuntu/Debian packages
# Author: Darknet Villain <supervillain@riseup.net> # Author: Darknet Villain <supervillain@riseup.net>
# #
@ -21,10 +21,14 @@
# path specific (feel free to modify if you have another paths) # path specific (feel free to modify if you have another paths)
/etc/i2pd/** r, /etc/i2pd/** r,
/run/i2pd/i2pd.pid rw,
/var/lib/i2pd/** rw, /var/lib/i2pd/** rw,
/var/log/i2pd.log w, /var/log/i2pd/i2pd.log w,
/var/run/i2pd/i2pd.pid rw, /var/run/i2pd/i2pd.pid rw,
/usr/sbin/i2pd mr, /usr/sbin/i2pd mr,
/usr/share/i2pd/** r,
# user homedir (if started not by init.d or systemd)
owner @{HOME}/.i2pd/ rw,
owner @{HOME}/.i2pd/** rwk,
} }

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

@ -1,27 +0,0 @@
[Unit]
Description=I2P Router written in C++
After=network.target
[Service]
User=i2pd
Group=i2pd
RuntimeDirectory=i2pd
RuntimeDirectoryMode=0700
Type=simple
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/i2pd/i2pd.pid
### Uncomment, if auto restart needed
#Restart=on-failure
### Use SIGINT for graceful stop daemon.
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die.
KillSignal=SIGINT
TimeoutStopSec=10m
# If you have problems with hunging i2pd, you can try enable this
#LimitNOFILE=4096
PrivateDevices=yes
[Install]
WantedBy=multi-user.target

1
contrib/debian/i2pd.service Symbolic link
View file

@ -0,0 +1 @@
../i2pd.service

View file

@ -17,13 +17,13 @@ RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
&& chown -R i2pd:nobody "$I2PD_HOME" && 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. # image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
# #
# 1. install deps, clone and build. # 1. install deps, clone and build.
# 2. strip binaries. # 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory. # 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 \ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \
&& mkdir -p /tmp/build \ && mkdir -p /tmp/build \
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \ && cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
@ -35,7 +35,7 @@ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boos
&& mv i2pd /usr/local/bin \ && mv i2pd /usr/local/bin \
&& cd /usr/local/bin \ && cd /usr/local/bin \
&& strip i2pd \ && strip i2pd \
&& rm -fr /tmp/build && apk --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \ && rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \
boost-python3 python3 gdbm boost-unit_test_framework boost-python linux-headers boost-prg_exec_monitor \ boost-python3 python3 gdbm boost-unit_test_framework boost-python linux-headers boost-prg_exec_monitor \
boost-serialization boost-signals boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \ boost-serialization boost-signals boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \
libtool g++ gcc pkgconfig libtool g++ gcc pkgconfig

View file

@ -54,7 +54,7 @@ ipv4 = true
ipv6 = false ipv6 = false
## Network interface to bind to ## Network interface to bind to
# ifname = # ifname =
## Enable NTCP transport (default = true) ## Enable NTCP transport (default = true)
# ntcp = true # ntcp = true
@ -88,18 +88,18 @@ ipv6 = false
[upnp] [upnp]
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) ## 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 appears in UPnP forwardings list (default = I2Pd)
# name = I2Pd # name = I2Pd
[reseed] [reseed]
## Enable or disable reseed data verification. ## Enable or disable reseed data verification.
verify = true verify = true
## URLs to request reseed data from, separated by comma ## URLs to request reseed data from, separated by comma
## Default: "mainline" I2P Network reseeds ## Default: "mainline" I2P Network reseeds
# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ # 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 # file = /path/to/i2pseeds.su3
## or HTTPS URL to reseed from ## or HTTPS URL to reseed from
# file = https://legit-website.com/i2pseeds.su3 # file = https://legit-website.com/i2pseeds.su3

29
contrib/i2pd.service Normal file
View file

@ -0,0 +1,29 @@
[Unit]
Description=I2P Router written in C++
Documentation=man:i2pd(1) https://i2pd.readthedocs.io/en/latest/
After=network.target
[Service]
User=i2pd
Group=i2pd
RuntimeDirectory=i2pd
RuntimeDirectoryMode=0700
Type=simple
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/i2pd/i2pd.pid
### Uncomment, if auto restart needed
#Restart=on-failure
KillSignal=SIGQUIT
# If you have the patience waiting 10 min on restarting/stopping it, uncomment this.
# i2pd stops accepting new tunnels and waits ~10 min while old ones do not die.
#KillSignal=SIGINT
#TimeoutStopSec=10m
# If you have problems with hanging i2pd, you can try enable this
#LimitNOFILE=4096
PrivateDevices=yes
[Install]
WantedBy=multi-user.target

102
contrib/rpm/i2pd-git.spec Normal file
View file

@ -0,0 +1,102 @@
%define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git
Version: 2.18.0
Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++
Conflicts: i2pd
License: BSD
URL: https://github.com/PurpleI2P/i2pd
Source0: https://github.com/PurpleI2P/i2pd/archive/openssl/i2pd-openssl.tar.gz
%if 0%{?rhel} == 7
BuildRequires: cmake3
%else
BuildRequires: cmake
%endif
BuildRequires: chrpath
BuildRequires: gcc-c++
BuildRequires: zlib-devel
BuildRequires: boost-devel
BuildRequires: openssl-devel
BuildRequires: miniupnpc-devel
BuildRequires: systemd-units
Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
%description
C++ implementation of I2P.
%prep
%setup -q
%build
cd build
%if 0%{?rhel} == 7
%cmake3 \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
-DWITH_HARDENING=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF
%else
%cmake \
-DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \
-DWITH_HARDENING=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF
%endif
make %{?_smp_mflags}
%install
cd build
chrpath -d i2pd
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
install -d -m 755 %{buildroot}%{_datadir}/i2pd
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
%pre
getent group i2pd >/dev/null || %{_sbindir}/groupadd -r i2pd
getent passwd i2pd >/dev/null || \
%{_sbindir}/useradd -r -g i2pd -s %{_sbindir}/nologin \
-d %{_sharedstatedir}/i2pd -c 'I2P Service' i2pd
%post
%systemd_post i2pd.service
%preun
%systemd_preun i2pd.service
%postun
%systemd_postun_with_restart i2pd.service
%files
%doc LICENSE README.md
%{_sbindir}/i2pd
%{_datadir}/i2pd/certificates
%config(noreplace) %{_sysconfdir}/i2pd/*
/%{_unitdir}/i2pd.service
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd
%dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd
%{_sharedstatedir}/i2pd/certificates
%changelog
* Thu Feb 01 2018 r4sas <r4sas@i2pmail.org> - 2.18.0
- Initial i2pd-git based on i2pd 2.18.0-1 spec

View file

@ -1,16 +0,0 @@
[Unit]
Description=I2P router
After=network.target
[Service]
User=i2pd
Group=i2pd
Type=simple
ExecStart=/usr/bin/i2pd --service
PIDFile=/var/lib/i2pd/i2pd.pid
Restart=always
PrivateTmp=true
[Install]
WantedBy=multi-user.target

1
contrib/rpm/i2pd.service Symbolic link
View file

@ -0,0 +1 @@
../i2pd.service

View file

@ -1,9 +1,8 @@
%define build_timestamp %(date +"%Y%m%d")
Name: i2pd Name: i2pd
Version: 2.17.0 Version: 2.18.0
Release: %{build_timestamp}git%{?dist} Release: 2%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git
License: BSD License: BSD
URL: https://github.com/PurpleI2P/i2pd URL: https://github.com/PurpleI2P/i2pd
@ -23,32 +22,19 @@ BuildRequires: openssl-devel
BuildRequires: miniupnpc-devel BuildRequires: miniupnpc-devel
BuildRequires: systemd-units BuildRequires: systemd-units
%description
C++ implementation of I2P.
%package systemd
Summary: Files to run I2P router under systemd
Requires: i2pd
Requires: systemd Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
Obsoletes: %{name}-daemon
%description
%description systemd
C++ implementation of I2P. C++ implementation of I2P.
This package contains systemd unit file to run i2pd as a system service
using dedicated user's permissions.
%prep %prep
%setup -q %setup -q
%build %build
cd build cd build
%if 0%{?rhel} == 7 %if 0%{?rhel} == 7
%cmake3 \ %cmake3 \
-DWITH_LIBRARY=OFF \ -DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \ -DWITH_UPNP=ON \
@ -68,114 +54,84 @@ make %{?_smp_mflags}
%install %install
cd build cd build
chrpath -d i2pd chrpath -d i2pd
install -D -m 755 i2pd %{buildroot}%{_bindir}/i2pd install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}/%{_unitdir}/i2pd.service install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
install -d -m 700 %{buildroot}/%{_sharedstatedir}/i2pd install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
install -d -m 755 %{buildroot}%{_datadir}/i2pd
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
%pre systemd %pre
getent group i2pd >/dev/null || %{_sbindir}/groupadd -r i2pd getent group i2pd >/dev/null || %{_sbindir}/groupadd -r i2pd
getent passwd i2pd >/dev/null || \ getent passwd i2pd >/dev/null || \
%{_sbindir}/useradd -r -g i2pd -s %{_sbindir}/nologin \ %{_sbindir}/useradd -r -g i2pd -s %{_sbindir}/nologin \
-d %{_sharedstatedir}/i2pd -c 'I2P Service' i2pd -d %{_sharedstatedir}/i2pd -c 'I2P Service' i2pd
%post systemd %post
%systemd_post i2pd.service %systemd_post i2pd.service
%preun systemd %preun
%systemd_preun i2pd.service %systemd_preun i2pd.service
%postun systemd %postun
%systemd_postun_with_restart i2pd.service %systemd_postun_with_restart i2pd.service
%files %files
%doc LICENSE README.md %doc LICENSE README.md
%_bindir/i2pd %{_sbindir}/i2pd
%{_datadir}/i2pd/certificates
%config(noreplace) %{_sysconfdir}/i2pd/*
%files systemd /%{_unitdir}/i2pd.service
/%_unitdir/i2pd.service %dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd
%dir %attr(0700,i2pd,i2pd) %_sharedstatedir/i2pd %dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd
%{_sharedstatedir}/i2pd/certificates
%changelog %changelog
* Mon Feb 05 2018 r4sas <r4sas@i2pmail.org> - 2.18.0-2
- Fixed blocking system shutdown for 10 minutes (#1089)
* Thu Feb 01 2018 r4sas <r4sas@i2pmail.org> - 2.18.0-1
- Added to conflicts i2pd-git package
- Fixed release versioning
- Fixed paths with double slashes
* Tue Jan 30 2018 orignal <i2porignal@yandex.ru> - 2.18.0
- update to 2.18.0
* Sat Jan 27 2018 l-n-s <supervillain@riseup.net> - 2.17.0-1
- Added certificates and default configuration files
- Merge i2pd with i2pd-systemd package
- Fixed package changelogs to comply with guidelines
* Mon Dec 04 2017 orignal <i2porignal@yandex.ru> - 2.17.0 * Mon Dec 04 2017 orignal <i2porignal@yandex.ru> - 2.17.0
- Added reseed through HTTP and SOCKS proxy - update to 2.17.0
- Added show status of client services through web console
- Added change log level through web connsole
- Added transient keys for tunnels
- Added i2p.streaming.initialAckDelay parameter
- Added CRYPTO_TYPE for SAM destination
- Added signature and crypto type for newkeys BOB command
- Changed - correct publication of ECIES destinations
- Changed - disable RSA signatures completely
- Fixed CVE-2017-17066
- Fixed possible buffer overflow for RSA-4096
- Fixed shutdown from web console for Windows
- Fixed web console page layout
* Mon Nov 13 2017 orignal <i2porignal@yandex.ru> - 2.16.0 * Mon Nov 13 2017 orignal <i2porignal@yandex.ru> - 2.16.0
- Added https and "Connect" method for HTTP proxy - update to 2.16.0
- Added outproxy for HTTP proxy
- Added initial support of ECIES crypto
- Added NTCP soft and hard descriptors limits
- Added support full timestamps in logs
- Changed faster implmentation of GOST R 34.11 hash
- Changed reject routers with RSA signtures
- Changed reload config and shudown from Windows GUI
- Changed update tunnels address(destination) without restart
- Fixed BOB crashes if destination is not set
- Fixed correct SAM tunnel name
- Fixed QT GUI issues
* Thu Aug 17 2017 orignal <i2porignal@yandex.ru> - 2.15.0 * Thu Aug 17 2017 orignal <i2porignal@yandex.ru> - 2.15.0
- Added QT GUI - update to 2.15.0
- Added ability add and remove I2P tunnels without restart
- Added ability to disable SOCKS outproxy option
- Changed strip-out Accept-* hedaers in HTTP proxy
- Changed peer test if nat=false
- Changed separate output of NTCP and SSU sessions in Transports tab
- Fixed handle lines with comments in hosts.txt file for address book
- Fixed run router with empty netdb for testnet
- Fixed skip expired introducers by iexp
* Thu Jun 01 2017 orignal <i2porignal@yandex.ru> - 2.14.0 * Thu Jun 01 2017 orignal <i2porignal@yandex.ru> - 2.14.0
- Added transit traffic bandwidth limitation - update to 2.14.0
- Added NTCP connections through HTTP and SOCKS proxies
- Added ability to disable address helper for HTTP proxy
- Changed reseed servers list
* Thu Apr 06 2017 orignal <i2porignal@yandex.ru> - 2.13.0 * Thu Apr 06 2017 orignal <i2porignal@yandex.ru> - 2.13.0
- Added persist local destination's tags - update to 2.13.0
- Added GOST signature types 9 and 10
- Added exploratory tunnels configuration
- Changed reseed servers list
- Changed inactive NTCP sockets get closed faster
- Changed some EdDSA speed up
- Fixed multiple acceptors for SAM
- Fixed follow on data after STREAM CREATE for SAM
- Fixed memory leaks
* Tue Feb 14 2017 orignal <i2porignal@yandex.ru> - 2.12.0 * Tue Feb 14 2017 orignal <i2porignal@yandex.ru> - 2.12.0
- Additional HTTP and SOCKS proxy tunnels - update to 2.12.0
- Reseed from ZIP archive
- 'X' bandwidth code
- Reduced memory and file descriptors usage
* Mon Dec 19 2016 orignal <i2porignal@yandex.ru> - 2.11.0 * Mon Dec 19 2016 orignal <i2porignal@yandex.ru> - 2.11.0
- Full support of zero-hops tunnels - update to 2.11.0
- Tunnel configuration for HTTP and SOCKS proxy
- Websockets support
- Multiple acceptors for SAM destination
- Routing path for UDP tunnels
- Reseed through a floodfill
- Use AVX instructions for DHT and HMAC if applicable
- Fixed UPnP discovery bug, producing excessive CPU usage
- Handle multiple lookups of the same LeaseSet correctly
* Thu Oct 20 2016 Anatolii Vorona <vorona.tolik@gmail.com> - 2.10.0-3 * Thu Oct 20 2016 Anatolii Vorona <vorona.tolik@gmail.com> - 2.10.0-3
- add support C7 - add support C7

View file

@ -119,12 +119,6 @@ namespace i2p
} }
LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
#ifdef AESNI
LogPrint(eLogInfo, "AESNI enabled");
#endif
#if defined(__AVX__)
LogPrint(eLogInfo, "AVX enabled");
#endif
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir); 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"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif #endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n"; 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 << "<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=none&token=" << token << "\">[none]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> "; s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> ";
@ -733,8 +733,9 @@ namespace http {
} }
} }
HTTPConnection::HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket): HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0) m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0),
expected_host(hostname)
{ {
/* cache options */ /* cache options */
i2p::config::GetOption("http.auth", needAuth); i2p::config::GetOption("http.auth", needAuth);
@ -833,7 +834,28 @@ namespace http {
SendReply(res, content); SendReply(res, content);
return; return;
} }
bool strictheaders;
i2p::config::GetOption("http.strictheaders", strictheaders);
if (strictheaders)
{
std::string http_hostname;
i2p::config::GetOption("http.hostname", http_hostname);
std::string host = req.GetHeader("Host");
auto idx = host.find(':');
/* strip out port so it's just host */
if (idx != std::string::npos && idx > 0)
{
host = host.substr(0, idx);
}
if (!(host == expected_host || host == http_hostname))
{
/* deny request as it's from a non whitelisted hostname */
res.code = 403;
content = "host missmatch";
SendReply(res, content);
return;
}
}
// Html5 head start // Html5 head start
ShowPageHead (s); ShowPageHead (s);
if (req.uri.find("page=") != std::string::npos) { if (req.uri.find("page=") != std::string::npos) {
@ -976,7 +998,8 @@ namespace http {
HTTPServer::HTTPServer (const std::string& address, int port): HTTPServer::HTTPServer (const std::string& address, int port):
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)) m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string(address), port)),
m_Hostname(address)
{ {
} }
@ -1061,7 +1084,7 @@ namespace http {
void HTTPServer::CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket) void HTTPServer::CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
{ {
auto conn = std::make_shared<HTTPConnection> (newSocket); auto conn = std::make_shared<HTTPConnection> (m_Hostname, newSocket);
conn->Receive (); conn->Receive ();
} }
} // http } // http

View file

@ -10,20 +10,20 @@
#include <sstream> #include <sstream>
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p
{ {
namespace http namespace http
{ {
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection> class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{ {
public: public:
HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket); HTTPConnection (std::string serverhost, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void Receive (); void Receive ();
private: private:
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -46,6 +46,7 @@ namespace http
bool needAuth; bool needAuth;
std::string user; std::string user;
std::string pass; std::string pass;
std::string expected_host;
static std::map<uint32_t, uint32_t> m_Tokens; // token->timestamp in seconds static std::map<uint32_t, uint32_t> m_Tokens; // token->timestamp in seconds
}; };
@ -63,11 +64,11 @@ namespace http
private: private:
void Run (); void Run ();
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode, void HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket); std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket); void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
private: private:
bool m_IsRunning; bool m_IsRunning;
@ -75,6 +76,7 @@ namespace http
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work;
boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::tcp::acceptor m_Acceptor;
std::string m_Hostname;
}; };
//all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml //all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml

View file

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

View file

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

View file

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

View file

@ -13,6 +13,7 @@
#include "Config.h" #include "Config.h"
#include "FS.h" #include "FS.h"
#include "Log.h" #include "Log.h"
#include "Tunnel.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "ClientContext.h" #include "ClientContext.h"
@ -183,7 +184,7 @@ namespace i2p
if (gracefulShutdownInterval) if (gracefulShutdownInterval)
{ {
gracefulShutdownInterval--; // - 1 second gracefulShutdownInterval--; // - 1 second
if (gracefulShutdownInterval <= 0) if (gracefulShutdownInterval <= 0 || i2p::tunnel::tunnels.CountTransitTunnels() <= 0)
{ {
LogPrint(eLogInfo, "Graceful shutdown"); LogPrint(eLogInfo, "Graceful shutdown");
return; return;

View file

@ -22,6 +22,8 @@ int main( int argc, char* argv[] )
{ {
if (Daemon.start()) if (Daemon.start())
Daemon.run (); Daemon.run ();
else
return EXIT_FAILURE;
Daemon.stop(); Daemon.stop();
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;

10
debian/changelog vendored
View file

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

2
debian/compat vendored
View file

@ -1 +1 @@
9 9

4
debian/control vendored
View file

@ -2,11 +2,11 @@ Source: i2pd
Section: net Section: net
Priority: optional Priority: optional
Maintainer: R4SAS <r4sas@i2pmail.org> Maintainer: R4SAS <r4sas@i2pmail.org>
Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev, libboost-filesystem-dev, libboost-program-options-dev, libminiupnpc-dev, libssl-dev, zlib1g-dev, dh-apparmor Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), gcc (>= 4.7) | clang (>= 3.3), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev, dh-apparmor
Standards-Version: 3.9.6 Standards-Version: 3.9.6
Homepage: http://i2pd.website/ Homepage: http://i2pd.website/
Vcs-Git: git://github.com/PurpleI2P/i2pd.git Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd.git Vcs-Browser: https://github.com/PurpleI2P/i2pd
Package: i2pd Package: i2pd
Architecture: any Architecture: any

44
debian/copyright vendored
View file

@ -4,6 +4,22 @@ Source: https://github.com/PurpleI2P
Files: * Files: *
Copyright: 2013-2017 PurpleI2P Copyright: 2013-2017 PurpleI2P
License: BSD-3-clause
Files: qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl
qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistroCallback.aidl
qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtActivity.java
qt/i2pd_qt/android/src/org/qtproject/qt5/android/bindings/QtApplication.java
Copyright: 2011-2013 BogDan Vatra <bogdan@kde.org>
License: BSD-2-Clause
Files: debian/*
Copyright: 2013-2015 Kill Your TV <killyourtv@i2pmail.org>
2014-2016 hagen <hagen@i2pmail.org>
2016-2017 R4SAS <r4sas@i2pmail.org>
2017-2018 Yangfl <mmyangfl@gmail.com>
License: GPL-2+
License: BSD-3-clause License: BSD-3-clause
Copyright (c) 2013-2017, The PurpleI2P Project Copyright (c) 2013-2017, The PurpleI2P Project
. .
@ -33,11 +49,29 @@ License: BSD-3-clause
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Files: debian/* License: BSD-2-Clause
Copyright: 2016-2017 R4SAS <r4sas@i2pmail.org> Redistribution and use in source and binary forms, with or without
2014-2016 hagen <hagen@i2pmail.org> modification, are permitted provided that the following conditions
2013-2015 Kill Your TV <killyourtv@i2pmail.org> are met:
License: GPL-2.0+ 1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License: GPL-2+
This package is free software; you can redistribute it and/or modify This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or

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 # see possible switches in /usr/share/doc/i2pd/configuration.md.gz
DAEMON_OPTS="" 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 ulimit -n 4096

2
debian/lintian-overrides vendored Normal file
View file

@ -0,0 +1,2 @@
# GPL come from debian/
i2pd: possible-gpl-code-linked-with-openssl

View file

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

View file

@ -1,24 +0,0 @@
#!/bin/sh
ARGS=""
if [ "${ENABLE_IPV6}" != "" ]; then
ARGS="${ARGS} ipv6"
fi
if [ "${LOGLEVEL}" != "" ]; then
ARGS="${ARGS} loglevel=${LOGLEVEL}"
fi
if [ "${ENABLE_AUTH}" != "" ]; then
ARGS="${ARGS} http.auth"
fi
# To make ports exposeable
DEFAULT_ARGS=" http.address=0.0.0.0 httpproxy.address=0.0.0.0 -socksproxy.address=0.0.0.0 sam.address=0.0.0.0 bob.address=0.0.0.0 i2cp.address=0.0.0.0 i2pcontrol.port=0.0.0.0 upnp.enabled=false -service "
mkdir -p /var/lib/i2pd && chown -R i2pd:nobody /var/lib/i2pd && chmod u+rw /var/lib/i2pd
gosu i2pd i2pd $DEFAULT_ARGS $ARGS

View file

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

43
libi2pd/CPU.cpp Normal file
View file

@ -0,0 +1,43 @@
#include "CPU.h"
#if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h>
#endif
#include "Log.h"
#ifndef bit_AES
#define bit_AES (1 << 25)
#endif
#ifndef bit_AVX
#define bit_AVX (1 << 28)
#endif
namespace i2p
{
namespace cpu
{
bool aesni = false;
bool avx = false;
void Detect()
{
#if defined(__x86_64__) || defined(__i386__)
int info[4];
__cpuid(0, info[0], info[1], info[2], info[3]);
if (info[0] >= 0x00000001) {
__cpuid(0x00000001, info[0], info[1], info[2], info[3]);
aesni = info[2] & bit_AES; // AESNI
avx = info[2] & bit_AVX; // AVX
}
#endif
if(aesni)
{
LogPrint(eLogInfo, "AESNI enabled");
}
if(avx)
{
LogPrint(eLogInfo, "AVX enabled");
}
}
}
}

15
libi2pd/CPU.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef LIBI2PD_CPU_H
#define LIBI2PD_CPU_H
namespace i2p
{
namespace cpu
{
extern bool aesni;
extern bool avx;
void Detect();
}
}
#endif

View file

@ -73,6 +73,7 @@ namespace config {
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)") ("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabalistic backoff with ntcp sessions (default: use system limit)") ("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabalistic backoff with ntcp sessions (default: use system limit)")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)") ("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)")
; ;
options_description httpserver("HTTP Server options"); options_description httpserver("HTTP Server options");
@ -83,6 +84,8 @@ namespace config {
("http.auth", value<bool>()->default_value(false), "Enable Basic HTTP auth for webconsole") ("http.auth", value<bool>()->default_value(false), "Enable Basic HTTP auth for webconsole")
("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth") ("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth")
("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)") ("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)")
("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI")
("http.hostname", value<std::string>()->default_value("localhost"),"Expected hostname for WebUI")
; ;
options_description httpproxy("HTTP Proxy options"); options_description httpproxy("HTTP Proxy options");

View file

@ -79,10 +79,10 @@ namespace config {
} }
template<typename T> 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); return GetOption (name.c_str (), value);
} }
bool GetOptionAsAny(const char *name, boost::any& value); bool GetOptionAsAny(const char *name, boost::any& value);
bool GetOptionAsAny(const std::string& 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, 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, 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, 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, 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, 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, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
@ -479,10 +479,9 @@ namespace crypto
const uint64_t IPAD = 0x3636363636363636; const uint64_t IPAD = 0x3636363636363636;
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
#if defined(__AVX__)
static const uint64_t ipads[] = { IPAD, IPAD, IPAD, IPAD }; static const uint64_t ipads[] = { IPAD, IPAD, IPAD, IPAD };
static const uint64_t opads[] = { OPAD, OPAD, OPAD, OPAD }; static const uint64_t opads[] = { OPAD, OPAD, OPAD, OPAD };
#endif
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest) void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest)
// key is 32 bytes // key is 32 bytes
@ -491,47 +490,73 @@ namespace crypto
{ {
uint64_t buf[256]; uint64_t buf[256];
uint64_t hash[12]; // 96 bytes uint64_t hash[12]; // 96 bytes
#if defined(__AVX__) // for AVX if(i2p::cpu::avx)
__asm__ {
( #ifdef AVX
"vmovups %[key], %%ymm0 \n" __asm__
"vmovups %[ipad], %%ymm1 \n" (
"vmovups %%ymm1, 32(%[buf]) \n" "vmovups %[key], %%ymm0 \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n" "vmovups %[ipad], %%ymm1 \n"
"vmovups %%ymm1, (%[buf]) \n" "vmovups %%ymm1, 32(%[buf]) \n"
"vmovups %[opad], %%ymm1 \n" "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, 32(%[hash]) \n" "vmovups %%ymm1, (%[buf]) \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n" "vmovups %[opad], %%ymm1 \n"
"vmovups %%ymm1, (%[hash]) \n" "vmovups %%ymm1, 32(%[hash]) \n"
"vzeroall \n" // end of AVX "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes "vmovups %%ymm1, (%[hash]) \n"
: "vzeroall \n" // end of AVX
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads), "movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes
[buf]"r"(buf), [hash]"r"(hash) :
: "memory", "%xmm0" // TODO: change to %ymm0 later : [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
); [buf]"r"(buf), [hash]"r"(hash)
: "memory", "%xmm0" // TODO: change to %ymm0 later
);
#else #else
// ikeypad // ikeypad
buf[0] = key.GetLL ()[0] ^ IPAD; buf[0] = key.GetLL ()[0] ^ IPAD;
buf[1] = key.GetLL ()[1] ^ IPAD; buf[1] = key.GetLL ()[1] ^ IPAD;
buf[2] = key.GetLL ()[2] ^ IPAD; buf[2] = key.GetLL ()[2] ^ IPAD;
buf[3] = key.GetLL ()[3] ^ IPAD; buf[3] = key.GetLL ()[3] ^ IPAD;
buf[4] = IPAD; buf[4] = IPAD;
buf[5] = IPAD; buf[5] = IPAD;
buf[6] = IPAD; buf[6] = IPAD;
buf[7] = IPAD; buf[7] = IPAD;
// okeypad // okeypad
hash[0] = key.GetLL ()[0] ^ OPAD; hash[0] = key.GetLL ()[0] ^ OPAD;
hash[1] = key.GetLL ()[1] ^ OPAD; hash[1] = key.GetLL ()[1] ^ OPAD;
hash[2] = key.GetLL ()[2] ^ OPAD; hash[2] = key.GetLL ()[2] ^ OPAD;
hash[3] = key.GetLL ()[3] ^ OPAD; hash[3] = key.GetLL ()[3] ^ OPAD;
hash[4] = OPAD; hash[4] = OPAD;
hash[5] = OPAD; hash[5] = OPAD;
hash[6] = OPAD; hash[6] = OPAD;
hash[7] = OPAD; hash[7] = OPAD;
// fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P) // fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
memset (hash + 10, 0, 16); memset (hash + 10, 0, 16);
#endif #endif
}
else
{
// ikeypad
buf[0] = key.GetLL ()[0] ^ IPAD;
buf[1] = key.GetLL ()[1] ^ IPAD;
buf[2] = key.GetLL ()[2] ^ IPAD;
buf[3] = key.GetLL ()[3] ^ IPAD;
buf[4] = IPAD;
buf[5] = IPAD;
buf[6] = IPAD;
buf[7] = IPAD;
// okeypad
hash[0] = key.GetLL ()[0] ^ OPAD;
hash[1] = key.GetLL ()[1] ^ OPAD;
hash[2] = key.GetLL ()[2] ^ OPAD;
hash[3] = key.GetLL ()[3] ^ OPAD;
hash[4] = OPAD;
hash[5] = OPAD;
hash[6] = OPAD;
hash[7] = OPAD;
// fill last 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
memset (hash + 10, 0, 16);
}
// concatenate with msg // concatenate with msg
memcpy (buf + 8, msg, len); memcpy (buf + 8, msg, len);
@ -543,8 +568,7 @@ namespace crypto
} }
// AES // AES
#ifdef AESNI #ifdef AESNI
#define KeyExpansion256(round0,round1) \ #define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \ "pshufd $0xff, %%xmm2, %%xmm2 \n" \
"movaps %%xmm1, %%xmm4 \n" \ "movaps %%xmm1, %%xmm4 \n" \
@ -567,7 +591,9 @@ namespace crypto
"pxor %%xmm4, %%xmm3 \n" \ "pxor %%xmm4, %%xmm3 \n" \
"pxor %%xmm2, %%xmm3 \n" \ "pxor %%xmm2, %%xmm3 \n" \
"movaps %%xmm3, "#round1"(%[sched]) \n" "movaps %%xmm3, "#round1"(%[sched]) \n"
#endif
#ifdef AESNI
void ECBCryptoAESNI::ExpandKey (const AESKey& key) void ECBCryptoAESNI::ExpandKey (const AESKey& key)
{ {
__asm__ __asm__
@ -604,8 +630,11 @@ namespace crypto
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input : [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
); );
} }
#endif
#if AESNI
#define EncryptAES256(sched) \ #define EncryptAES256(sched) \
"pxor (%["#sched"]), %%xmm0 \n" \ "pxor (%["#sched"]), %%xmm0 \n" \
"aesenc 16(%["#sched"]), %%xmm0 \n" \ "aesenc 16(%["#sched"]), %%xmm0 \n" \
@ -622,18 +651,31 @@ namespace crypto
"aesenc 192(%["#sched"]), %%xmm0 \n" \ "aesenc 192(%["#sched"]), %%xmm0 \n" \
"aesenc 208(%["#sched"]), %%xmm0 \n" \ "aesenc 208(%["#sched"]), %%xmm0 \n" \
"aesenclast 224(%["#sched"]), %%xmm0 \n" "aesenclast 224(%["#sched"]), %%xmm0 \n"
#endif
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
__asm__ if(i2p::cpu::aesni)
( {
"movups (%[in]), %%xmm0 \n" #ifdef AESNI
EncryptAES256(sched) __asm__
"movups %%xmm0, (%[out]) \n" (
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" "movups (%[in]), %%xmm0 \n"
); EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
);
#else
AES_encrypt (in->buf, out->buf, &m_Key);
#endif
}
else
{
AES_encrypt (in->buf, out->buf, &m_Key);
}
} }
#ifdef AESNI
#define DecryptAES256(sched) \ #define DecryptAES256(sched) \
"pxor 224(%["#sched"]), %%xmm0 \n" \ "pxor 224(%["#sched"]), %%xmm0 \n" \
"aesdec 208(%["#sched"]), %%xmm0 \n" \ "aesdec 208(%["#sched"]), %%xmm0 \n" \
@ -650,79 +692,130 @@ namespace crypto
"aesdec 32(%["#sched"]), %%xmm0 \n" \ "aesdec 32(%["#sched"]), %%xmm0 \n" \
"aesdec 16(%["#sched"]), %%xmm0 \n" \ "aesdec 16(%["#sched"]), %%xmm0 \n" \
"aesdeclast (%["#sched"]), %%xmm0 \n" "aesdeclast (%["#sched"]), %%xmm0 \n"
#endif
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out)
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
__asm__ if(i2p::cpu::aesni)
( {
"movups (%[in]), %%xmm0 \n" #ifdef AESNI
DecryptAES256(sched) __asm__
"movups %%xmm0, (%[out]) \n" (
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" "movups (%[in]), %%xmm0 \n"
); DecryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
);
#else
AES_decrypt (in->buf, out->buf, &m_Key);
#endif
}
else
{
AES_decrypt (in->buf, out->buf, &m_Key);
}
} }
#ifdef AESNI
#define CallAESIMC(offset) \ #define CallAESIMC(offset) \
"movaps "#offset"(%[shed]), %%xmm0 \n" \ "movaps "#offset"(%[shed]), %%xmm0 \n" \
"aesimc %%xmm0, %%xmm0 \n" \ "aesimc %%xmm0, %%xmm0 \n" \
"movaps %%xmm0, "#offset"(%[shed]) \n" "movaps %%xmm0, "#offset"(%[shed]) \n"
void ECBDecryptionAESNI::SetKey (const AESKey& key)
{
ExpandKey (key); // expand encryption key first
// then invert it using aesimc
__asm__
(
CallAESIMC(16)
CallAESIMC(32)
CallAESIMC(48)
CallAESIMC(64)
CallAESIMC(80)
CallAESIMC(96)
CallAESIMC(112)
CallAESIMC(128)
CallAESIMC(144)
CallAESIMC(160)
CallAESIMC(176)
CallAESIMC(192)
CallAESIMC(208)
: : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
);
}
#endif #endif
void ECBEncryption::SetKey (const AESKey& key)
{
if(i2p::cpu::aesni)
{
#ifdef AESNI
ExpandKey (key);
#else
AES_set_encrypt_key (key, 256, &m_Key);
#endif
}
else
{
AES_set_encrypt_key (key, 256, &m_Key);
}
}
void ECBDecryption::SetKey (const AESKey& key)
{
if(i2p::cpu::aesni)
{
#ifdef AESNI
ExpandKey (key); // expand encryption key first
// then invert it using aesimc
__asm__
(
CallAESIMC(16)
CallAESIMC(32)
CallAESIMC(48)
CallAESIMC(64)
CallAESIMC(80)
CallAESIMC(96)
CallAESIMC(112)
CallAESIMC(128)
CallAESIMC(144)
CallAESIMC(160)
CallAESIMC(176)
CallAESIMC(192)
CallAESIMC(208)
: : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
);
#else
AES_set_decrypt_key (key, 256, &m_Key);
#endif
}
else
{
AES_set_decrypt_key (key, 256, &m_Key);
}
}
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{ {
#ifdef AESNI if(i2p::cpu::aesni)
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"1: \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched)
"movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz 1b \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "cc", "memory"
);
#else
for (int i = 0; i < numBlocks; i++)
{ {
*m_LastBlock.GetChipherBlock () ^= in[i]; #ifdef AESNI
m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ()); __asm__
out[i] = *m_LastBlock.GetChipherBlock (); (
} "movups (%[iv]), %%xmm1 \n"
"1: \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched)
"movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz 1b \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "cc", "memory"
);
#else
for (int i = 0; i < numBlocks; i++)
{
*m_LastBlock.GetChipherBlock () ^= in[i];
m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ());
out[i] = *m_LastBlock.GetChipherBlock ();
}
#endif #endif
}
else
{
for (int i = 0; i < numBlocks; i++)
{
*m_LastBlock.GetChipherBlock () ^= in[i];
m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ());
out[i] = *m_LastBlock.GetChipherBlock ();
}
}
} }
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out) void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out)
@ -735,57 +828,75 @@ namespace crypto
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{ {
if(i2p::cpu::aesni)
{
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"movups %%xmm0, (%[iv]) \n" "movups %%xmm0, (%[iv]) \n"
: :
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out) [in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
#else #else
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
#endif #endif
}
else
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
} }
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{ {
#ifdef AESNI if(i2p::cpu::aesni)
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"1: \n"
"movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz 1b \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
);
#else
for (int i = 0; i < numBlocks; i++)
{ {
ChipherBlock tmp = in[i]; #ifdef AESNI
m_ECBDecryption.Decrypt (in + i, out + i); __asm__
out[i] ^= *m_IV.GetChipherBlock (); (
*m_IV.GetChipherBlock () = tmp; "movups (%[iv]), %%xmm1 \n"
} "1: \n"
"movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz 1b \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
);
#else
for (int i = 0; i < numBlocks; i++)
{
ChipherBlock tmp = in[i];
m_ECBDecryption.Decrypt (in + i, out + i);
out[i] ^= *m_IV.GetChipherBlock ();
*m_IV.GetChipherBlock () = tmp;
}
#endif #endif
}
else
{
for (int i = 0; i < numBlocks; i++)
{
ChipherBlock tmp = in[i];
m_ECBDecryption.Decrypt (in + i, out + i);
out[i] ^= *m_IV.GetChipherBlock ();
*m_IV.GetChipherBlock () = tmp;
}
}
} }
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out) void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out)
@ -797,96 +908,121 @@ namespace crypto
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{ {
if(i2p::cpu::aesni)
{
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movups %%xmm0, (%[iv]) \n" "movups %%xmm0, (%[iv]) \n"
DecryptAES256(sched) DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
: :
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out) [in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
#else #else
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out); Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
#endif #endif
}
else
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
} }
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{ {
if(i2p::cpu::aesni)
{
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
// encrypt IV // encrypt IV
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
// double IV encryption // double IV encryption
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
// encrypt data, IV is xmm1 // encrypt data, IV is xmm1
"1: \n" "1: \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched_l) EncryptAES256(sched_l)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
: :
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()), : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "cc", "memory" : "%xmm0", "%xmm1", "cc", "memory"
); );
#else #else
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerEncryption.SetIV (out); m_LayerEncryption.SetIV (out);
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
#endif #endif
}
else
{
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerEncryption.SetIV (out);
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
}
} }
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{ {
if(i2p::cpu::aesni)
{
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
// decrypt IV // decrypt IV
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
// double IV encryption // double IV encryption
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
// decrypt data, IV is xmm1 // decrypt data, IV is xmm1
"1: \n" "1: \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched_l) DecryptAES256(sched_l)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n" "movaps %%xmm2, %%xmm1 \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
: :
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()), : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory" : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
); );
#else #else
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerDecryption.SetIV (out); m_LayerDecryption.SetIV (out);
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
#endif #endif
}
else
{
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerDecryption.SetIV (out);
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
}
} }
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes; /* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
@ -904,6 +1040,7 @@ namespace crypto
void InitCrypto (bool precomputation) void InitCrypto (bool precomputation)
{ {
i2p::cpu::Detect ();
SSL_library_init (); SSL_library_init ();
/* auto numLocks = CRYPTO_num_locks(); /* auto numLocks = CRYPTO_num_locks();
for (int i = 0; i < numLocks; i++) for (int i = 0; i < numLocks; i++)

View file

@ -16,6 +16,7 @@
#include "Base.h" #include "Base.h"
#include "Tag.h" #include "Tag.h"
#include "CPU.h"
namespace i2p namespace i2p
{ {
@ -24,7 +25,7 @@ namespace crypto
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len); bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
// DSA // DSA
DSA * CreateDSA (); DSA * CreateDSA ();
// RSA // RSA
const BIGNUM * GetRSAE (); const BIGNUM * GetRSAE ();
@ -33,20 +34,20 @@ namespace crypto
class DHKeys class DHKeys
{ {
public: public:
DHKeys (); DHKeys ();
~DHKeys (); ~DHKeys ();
void GenerateKeys (); void GenerateKeys ();
const uint8_t * GetPublicKey () const { return m_PublicKey; }; const uint8_t * GetPublicKey () const { return m_PublicKey; };
void Agree (const uint8_t * pub, uint8_t * shared); void Agree (const uint8_t * pub, uint8_t * shared);
private: private:
DH * m_DH; DH * m_DH;
uint8_t m_PublicKey[256]; uint8_t m_PublicKey[256];
}; };
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false); 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); bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
@ -54,57 +55,54 @@ namespace crypto
// ECIES // 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 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); void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
// HMAC // 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); void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest);
// AES // AES
struct ChipherBlock struct ChipherBlock
{ {
uint8_t buf[16]; uint8_t buf[16];
void operator^=(const ChipherBlock& other) // XOR void operator^=(const ChipherBlock& other) // XOR
{ {
#if defined(__AVX__) // AVX if (i2p::cpu::avx)
__asm__ {
( #ifdef AVX
"vmovups (%[buf]), %%xmm0 \n" __asm__
"vmovups (%[other]), %%xmm1 \n" (
"vxorps %%xmm0, %%xmm1, %%xmm0 \n" "vmovups (%[buf]), %%xmm0 \n"
"vmovups %%xmm0, (%[buf]) \n" "vmovups (%[other]), %%xmm1 \n"
: "vxorps %%xmm0, %%xmm1, %%xmm0 \n"
: [buf]"r"(buf), [other]"r"(other.buf) "vmovups %%xmm0, (%[buf]) \n"
: "%xmm0", "%xmm1", "memory" :
); : [buf]"r"(buf), [other]"r"(other.buf)
#elif defined(__SSE__) // SSE : "%xmm0", "%xmm1", "memory"
__asm__ );
(
"movups (%[buf]), %%xmm0 \n"
"movups (%[other]), %%xmm1 \n"
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory"
);
#else #else
// TODO: implement it better for (int i = 0; i < 16; i++)
for (int i = 0; i < 16; i++) buf[i] ^= other.buf[i];
buf[i] ^= other.buf[i];
#endif #endif
} }
else
{
// TODO: implement it better
for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i];
}
}
}; };
typedef i2p::data::Tag<32> AESKey; typedef i2p::data::Tag<32> AESKey;
template<size_t sz> template<size_t sz>
class AESAlignedBuffer // 16 bytes alignment class AESAlignedBuffer // 16 bytes alignment
{ {
public: public:
AESAlignedBuffer () AESAlignedBuffer ()
{ {
m_Buf = m_UnalignedBuffer; m_Buf = m_UnalignedBuffer;
@ -112,22 +110,22 @@ namespace crypto
if (rem) if (rem)
m_Buf += (16 - rem); m_Buf += (16 - rem);
} }
operator uint8_t * () { return m_Buf; }; operator uint8_t * () { return m_Buf; };
operator const uint8_t * () const { return m_Buf; }; operator const uint8_t * () const { return m_Buf; };
ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; }; ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; };
const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; }; const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; };
private: private:
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
uint8_t * m_Buf; uint8_t * m_Buf;
}; };
#ifdef AESNI #ifdef AESNI
class ECBCryptoAESNI class ECBCryptoAESNI
{ {
public: public:
uint8_t * GetKeySchedule () { return m_KeySchedule; }; uint8_t * GetKeySchedule () { return m_KeySchedule; };
@ -135,76 +133,47 @@ namespace crypto
protected: protected:
void ExpandKey (const AESKey& key); void ExpandKey (const AESKey& key);
private: private:
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
}; };
#endif
class ECBEncryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const AESKey& key) { ExpandKey (key); };
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
};
class ECBDecryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const AESKey& key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
};
typedef ECBEncryptionAESNI ECBEncryption;
typedef ECBDecryptionAESNI ECBDecryption;
#else // use openssl
#ifdef AESNI
class ECBEncryption: public ECBCryptoAESNI
#else
class ECBEncryption class ECBEncryption
#endif
{ {
public: public:
void SetKey (const AESKey& key);
void SetKey (const AESKey& key) void Encrypt(const ChipherBlock * in, ChipherBlock * out);
{
AES_set_encrypt_key (key, 256, &m_Key);
}
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
{
AES_encrypt (in->buf, out->buf, &m_Key);
}
private: private:
AES_KEY m_Key;
AES_KEY m_Key; };
};
#ifdef AESNI
class ECBDecryption: public ECBCryptoAESNI
#else
class ECBDecryption class ECBDecryption
#endif
{ {
public: public:
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);
}
void SetKey (const AESKey& key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
private: private:
AES_KEY m_Key; AES_KEY m_Key;
}; };
#endif
class CBCEncryption class CBCEncryption
{ {
public: public:
CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); }; CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); };
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
@ -214,17 +183,19 @@ namespace crypto
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Encrypt (const uint8_t * in, uint8_t * out); // one block void Encrypt (const uint8_t * in, uint8_t * out); // one block
ECBEncryption & ECB() { return m_ECBEncryption; }
private: private:
AESAlignedBuffer<16> m_LastBlock; AESAlignedBuffer<16> m_LastBlock;
ECBEncryption m_ECBEncryption; ECBEncryption m_ECBEncryption;
}; };
class CBCDecryption class CBCDecryption
{ {
public: public:
CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); }; CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); };
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
@ -234,11 +205,13 @@ namespace crypto
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Decrypt (const uint8_t * in, uint8_t * out); // one block void Decrypt (const uint8_t * in, uint8_t * out); // one block
ECBDecryption & ECB() { return m_ECBDecryption; }
private: private:
AESAlignedBuffer<16> m_IV; AESAlignedBuffer<16> m_IV;
ECBDecryption m_ECBDecryption; ECBDecryption m_ECBDecryption;
}; };
class TunnelEncryption // with double IV encryption class TunnelEncryption // with double IV encryption
{ {
@ -248,18 +221,14 @@ namespace crypto
{ {
m_LayerEncryption.SetKey (layerKey); m_LayerEncryption.SetKey (layerKey);
m_IVEncryption.SetKey (ivKey); 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: private:
ECBEncryption m_IVEncryption; ECBEncryption m_IVEncryption;
#ifdef AESNI
ECBEncryption m_LayerEncryption;
#else
CBCEncryption m_LayerEncryption; CBCEncryption m_LayerEncryption;
#endif
}; };
class TunnelDecryption // with double IV encryption class TunnelDecryption // with double IV encryption
@ -270,84 +239,80 @@ namespace crypto
{ {
m_LayerDecryption.SetKey (layerKey); m_LayerDecryption.SetKey (layerKey);
m_IVDecryption.SetKey (ivKey); 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: private:
ECBDecryption m_IVDecryption; ECBDecryption m_IVDecryption;
#ifdef AESNI
ECBDecryption m_LayerDecryption;
#else
CBCDecryption m_LayerDecryption; CBCDecryption m_LayerDecryption;
#endif };
};
void InitCrypto (bool precomputation); void InitCrypto (bool precomputation);
void TerminateCrypto (); void TerminateCrypto ();
} }
} }
// take care about openssl version // take care about openssl version
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL #if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL
// define getters and setters introduced in 1.1.0 // define getters and setters introduced in 1.1.0
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ {
if (d->p) BN_free (d->p); if (d->p) BN_free (d->p);
if (d->q) BN_free (d->q); if (d->q) BN_free (d->q);
if (d->g) BN_free (d->g); 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->pub_key) BN_free (d->pub_key);
if (d->priv_key) BN_free (d->priv_key); if (d->priv_key) BN_free (d->priv_key);
d->pub_key = pub_key; d->priv_key = priv_key; return 1; 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) 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; } { *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->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s); 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; } { *pr = sig->r; *ps = sig->s; }
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{ {
if (sig->r) BN_free (sig->r); if (sig->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s); 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) inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; } { *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->n) BN_free (r->n);
if (r->e) BN_free (r->e); if (r->e) BN_free (r->e);
if (r->d) BN_free (r->d); 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) 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; } { *n = r->n; *e = r->e; *d = r->d; }
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ {
if (dh->p) BN_free (dh->p); if (dh->p) BN_free (dh->p);
if (dh->q) BN_free (dh->q); if (dh->q) BN_free (dh->q);
if (dh->g) BN_free (dh->g); 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) 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); 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) 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; } { *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) void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub)
{ {
EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1); EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1);
EC_POINT * p = nullptr; EC_POINT * p = nullptr;
BIGNUM * key = nullptr; BIGNUM * key = nullptr;
GenerateECIESKeyPair (curve, key, p); GenerateECIESKeyPair (curve, key, p);
bn2buf (key, priv, 32); bn2buf (key, priv, 32);
@ -81,11 +81,11 @@ namespace crypto
BIGNUM * x = BN_new (), * y = BN_new (); BIGNUM * x = BN_new (), * y = BN_new ();
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL);
bn2buf (x, pub, 32); bn2buf (x, pub, 32);
bn2buf (y, pub + 32, 32); bn2buf (y, pub + 32, 32);
RAND_bytes (pub + 64, 192); RAND_bytes (pub + 64, 192);
EC_POINT_free (p); EC_POINT_free (p);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
EC_GROUP_free (curve); EC_GROUP_free (curve);
} }
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub) ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub)
@ -131,7 +131,7 @@ namespace crypto
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub) void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub)
{ {
auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA); auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA);
EC_POINT * p = nullptr; EC_POINT * p = nullptr;
BIGNUM * key = nullptr; BIGNUM * key = nullptr;
GenerateECIESKeyPair (curve->GetGroup (), key, p); GenerateECIESKeyPair (curve->GetGroup (), key, p);
bn2buf (key, priv, 32); bn2buf (key, priv, 32);
@ -140,9 +140,9 @@ namespace crypto
BIGNUM * x = BN_new (), * y = BN_new (); BIGNUM * x = BN_new (), * y = BN_new ();
EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL); EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL);
bn2buf (x, pub, 32); bn2buf (x, pub, 32);
bn2buf (y, pub + 32, 32); bn2buf (y, pub + 32, 32);
RAND_bytes (pub + 64, 192); RAND_bytes (pub + 64, 192);
EC_POINT_free (p); EC_POINT_free (p);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }

View file

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

81
libi2pd/CryptoWorker.h Normal file
View file

@ -0,0 +1,81 @@
#ifndef CRYPTO_WORKER_H_
#define CRYPTO_WORKER_H_
#include <condition_variable>
#include <mutex>
#include <deque>
#include <thread>
#include <vector>
#include <memory>
namespace i2p
{
namespace worker
{
template<typename Caller>
struct ThreadPool
{
typedef std::function<void(void)> ResultFunc;
typedef std::function<ResultFunc(void)> WorkFunc;
typedef std::pair<std::shared_ptr<Caller>, WorkFunc> Job;
typedef std::mutex mtx_t;
typedef std::unique_lock<mtx_t> lock_t;
typedef std::condition_variable cond_t;
ThreadPool(int workers)
{
stop = false;
if(workers > 0)
{
while(workers--)
{
threads.emplace_back([this] {
for (;;)
{
Job job;
{
lock_t lock(this->queue_mutex);
this->condition.wait(
lock, [this] { return this->stop || !this->jobs.empty(); });
if (this->stop && this->jobs.empty()) return;
job = std::move(this->jobs.front());
this->jobs.pop_front();
}
ResultFunc result = job.second();
job.first->GetService().post(result);
}
});
}
}
};
void Offer(const Job & job)
{
{
lock_t lock(queue_mutex);
if (stop) return;
jobs.emplace_back(job);
}
condition.notify_one();
}
~ThreadPool()
{
{
lock_t lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(auto &t: threads) t.join();
}
std::vector<std::thread> threads;
std::deque<Job> jobs;
mtx_t queue_mutex;
cond_t condition;
bool stop;
};
}
}
#endif

View file

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

View file

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

View file

@ -194,9 +194,9 @@ namespace client
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); };
// ref counter // ref counter
int Acquire () { return ++m_RefCounter; }; int Acquire () { return ++m_RefCounter; };
int Release () { return --m_RefCounter; }; int Release () { return --m_RefCounter; };
int GetRefCounter () const { return m_RefCounter; }; int GetRefCounter () const { return m_RefCounter; };
// streaming // streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
@ -243,7 +243,7 @@ namespace client
int m_StreamingAckDelay; int m_StreamingAckDelay;
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts; 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 int m_RefCounter; // how many clients(tunnels) use this destination
boost::asio::deadline_timer m_ReadyChecker; boost::asio::deadline_timer m_ReadyChecker;

View file

@ -30,7 +30,7 @@ namespace i2p
} }
m_collected[key].Val += val; m_collected[key].Val += val;
} }
void EventCore::PumpCollected(EventListener * listener) void EventCore::PumpCollected(EventListener * listener)
{ {
std::unique_lock<std::mutex> lock(m_collect_mutex); 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 CollectEvent(const std::string & type, const std::string & ident, uint64_t val);
void SetListener(EventListener * l); void SetListener(EventListener * l);
void PumpCollected(EventListener * l); void PumpCollected(EventListener * l);
private: private:
std::mutex m_collect_mutex; std::mutex m_collect_mutex;
struct CollectedEvent struct CollectedEvent
@ -41,7 +41,7 @@ namespace i2p
std::map<std::string, CollectedEvent> m_collected; std::map<std::string, CollectedEvent> m_collected;
EventListener * m_listener = nullptr; EventListener * m_listener = nullptr;
}; };
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
extern EventCore core; extern EventCore core;
#endif #endif
} }

View file

@ -68,7 +68,7 @@ namespace fs {
#else /* other unix */ #else /* other unix */
#if defined(ANDROID) #if defined(ANDROID)
const char * ext = getenv("EXTERNAL_STORAGE"); const char * ext = getenv("EXTERNAL_STORAGE");
if (!ext) ext = "/sdcard"; if (!ext) ext = "/sdcard";
if (boost::filesystem::exists(ext)) if (boost::filesystem::exists(ext))
{ {
dataDir = std::string (ext) + "/" + appName; dataDir = std::string (ext) + "/" + appName;
@ -96,7 +96,7 @@ namespace fs {
boost::filesystem::create_directory(destinations); boost::filesystem::create_directory(destinations);
std::string tags = DataDirPath("tags"); std::string tags = DataDirPath("tags");
if (!boost::filesystem::exists(tags)) if (!boost::filesystem::exists(tags))
boost::filesystem::create_directory(tags); boost::filesystem::create_directory(tags);
else else
i2p::garlic::CleanUpTagsFiles (); i2p::garlic::CleanUpTagsFiles ();
@ -123,12 +123,12 @@ namespace fs {
} }
uint32_t GetLastUpdateTime (const std::string & path) uint32_t GetLastUpdateTime (const std::string & path)
{ {
if (!boost::filesystem::exists(path)) return 0; if (!boost::filesystem::exists(path)) return 0;
boost::system::error_code ec; boost::system::error_code ec;
auto t = boost::filesystem::last_write_time (path, ec); auto t = boost::filesystem::last_write_time (path, ec);
return ec ? 0 : t; return ec ? 0 : t;
} }
bool Remove(const std::string & path) { bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path)) if (!boost::filesystem::exists(path))
@ -136,7 +136,7 @@ namespace fs {
return boost::filesystem::remove(path); return boost::filesystem::remove(path);
} }
bool CreateDirectory (const std::string& path) bool CreateDirectory (const std::string& path)
{ {
if (boost::filesystem::exists(path) && if (boost::filesystem::exists(path) &&
boost::filesystem::is_directory (boost::filesystem::status (path))) return true; 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 * @param files Vector to store found files
* @return true on success and false if directory not exists * @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 * @brief Remove file with given path
@ -113,9 +113,9 @@ namespace fs {
*/ */
bool Exists(const std::string & path); bool Exists(const std::string & path);
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
bool CreateDirectory (const std::string& path); bool CreateDirectory (const std::string& path);
template<typename T> template<typename T>
void _ExpandPath(std::stringstream & path, T c) { void _ExpandPath(std::stringstream & path, T c) {
@ -153,7 +153,7 @@ namespace fs {
_ExpandPath(s, filenames...); _ExpandPath(s, filenames...);
return s.str(); return s.str();
} }
} // fs } // fs
} // i2p } // i2p

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,6 +8,7 @@
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <stdio.h>
#include "util.h" #include "util.h"
#include "HTTP.h" #include "HTTP.h"
#include <ctime> #include <ctime>
@ -21,6 +22,13 @@ namespace http {
const std::vector<std::string> HTTP_VERSIONS = { const std::vector<std::string> HTTP_VERSIONS = {
"HTTP/1.0", "HTTP/1.1" "HTTP/1.0", "HTTP/1.1"
}; };
const std::vector<const char *> weekdays = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
const std::vector<const char *> months = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
inline bool is_http_version(const std::string & str) { inline bool is_http_version(const std::string & str) {
return std::find(HTTP_VERSIONS.begin(), HTTP_VERSIONS.end(), str) != std::end(HTTP_VERSIONS); return std::find(HTTP_VERSIONS.begin(), HTTP_VERSIONS.end(), str) != std::end(HTTP_VERSIONS);
@ -44,7 +52,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 pos = 0;
std::size_t len = 2; /* strlen(": ") */ std::size_t len = 2; /* strlen(": ") */
@ -56,10 +64,14 @@ namespace http {
return std::make_pair(line.substr(0, pos), line.substr(pos + len)); return std::make_pair(line.substr(0, pos), line.substr(pos + len));
} }
void gen_rfc1123_date(std::string & out) { void gen_rfc7231_date(std::string & out) {
std::time_t now = std::time(nullptr); std::time_t now = std::time(nullptr);
char buf[128]; char buf[128];
std::strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", std::gmtime(&now)); std::tm *tm = std::gmtime(&now);
snprintf(buf, sizeof(buf), "%s, %02d %s %d %02d:%02d:%02d GMT",
weekdays[tm->tm_wday], tm->tm_mday, months[tm->tm_mon],
tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec
);
out = buf; out = buf;
} }
@ -88,7 +100,7 @@ namespace http {
user = url.substr(pos_p, delim - pos_p); user = url.substr(pos_p, delim - pos_p);
delim += 1; delim += 1;
pass = url.substr(delim, pos_c - delim); pass = url.substr(delim, pos_c - delim);
} else { } else if(delim) {
user = url.substr(pos_p, pos_c - pos_p); user = url.substr(pos_p, pos_c - pos_p);
} }
pos_p = pos_c + 1; pos_p = pos_c + 1;
@ -251,14 +263,14 @@ namespace http {
uri = tokens[1]; uri = tokens[1];
version = tokens[2]; version = tokens[2];
expect = HEADER_LINE; expect = HEADER_LINE;
} }
else else
{ {
std::string line = str.substr(pos, eol - pos); std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length () > 0) if (p.first.length () > 0)
headers.push_back (p); headers.push_back (p);
else else
return -1; return -1;
} }
pos = eol + strlen(CRLF); pos = eol + strlen(CRLF);
@ -268,11 +280,11 @@ namespace http {
return eoh + strlen(HTTP_EOH); return eoh + strlen(HTTP_EOH);
} }
void HTTPReq::write(std::ostream & o) void HTTPReq::write(std::ostream & o)
{ {
o << method << " " << uri << " " << version << CRLF; o << method << " " << uri << " " << version << CRLF;
for (auto & h : headers) for (auto & h : headers)
o << h.first << ": " << h.second << CRLF; o << h.first << ": " << h.second << CRLF;
o << CRLF; o << CRLF;
} }
@ -284,7 +296,7 @@ namespace http {
} }
void HTTPReq::AddHeader (const std::string& name, const std::string& value) void HTTPReq::AddHeader (const std::string& name, const std::string& value)
{ {
headers.push_back (std::make_pair(name, value)); headers.push_back (std::make_pair(name, value));
} }
@ -295,28 +307,28 @@ namespace http {
{ {
it.second = value; it.second = value;
break; break;
} }
} }
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt) void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt)
{ {
for (auto it = headers.begin (); it != headers.end ();) 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); it = headers.erase (it);
else else
it++; it++;
} }
} }
std::string HTTPReq::GetHeader (const std::string& name) const std::string HTTPReq::GetHeader (const std::string& name) const
{ {
for (auto& it : headers) for (auto& it : headers)
if (it.first == name) if (it.first == name)
return it.second; return it.second;
return ""; return "";
} }
bool HTTPRes::is_chunked() const bool HTTPRes::is_chunked() const
{ {
auto it = headers.find("Transfer-Encoding"); auto it = headers.find("Transfer-Encoding");
@ -335,10 +347,10 @@ namespace http {
if (it->second.find("gzip") != std::string::npos) if (it->second.find("gzip") != std::string::npos)
return true; /* gotcha! */ return true; /* gotcha! */
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos) if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
return true; return true;
return false; return false;
} }
long int HTTPMsg::content_length() const long int HTTPMsg::content_length() const
{ {
unsigned long int length = 0; unsigned long int length = 0;
@ -385,8 +397,8 @@ namespace http {
std::string line = str.substr(pos, eol - pos); std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length () > 0) if (p.first.length () > 0)
headers.insert (p); headers.insert (p);
else else
return -1; return -1;
} }
pos = eol + strlen(CRLF); pos = eol + strlen(CRLF);
@ -400,7 +412,7 @@ namespace http {
std::string HTTPRes::to_string() { std::string HTTPRes::to_string() {
if (version == "HTTP/1.1" && headers.count("Date") == 0) { if (version == "HTTP/1.1" && headers.count("Date") == 0) {
std::string date; std::string date;
gen_rfc1123_date(date); gen_rfc7231_date(date);
add_header("Date", date.c_str()); add_header("Date", date.c_str());
} }
if (status == "OK" && code != 200) if (status == "OK" && code != 200)

View file

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

View file

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

View file

@ -12,7 +12,7 @@
#include "LeaseSet.h" #include "LeaseSet.h"
namespace i2p namespace i2p
{ {
// I2NP header // I2NP header
const size_t I2NP_HEADER_TYPEID_OFFSET = 0; const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1; 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_TYPEID_OFFSET = 0;
const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1; 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; const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
// Tunnel Gateway header // Tunnel Gateway header
const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0; 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_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4;
const size_t TUNNEL_GATEWAY_HEADER_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2; 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_MSGID_OFFSET = 0;
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4; const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8; 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_REPLY_TOKEN_OFFSET = DATABASE_STORE_TYPE_OFFSET + 1;
const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4; const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4;
// TunnelBuild // TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528; const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
//BuildRequestRecordClearText //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_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_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222; 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_TO_PEER_OFFSET = 0;
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16; const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
// BuildResponseRecord // BuildResponseRecord
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0; const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32; const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
@ -83,40 +83,40 @@ namespace i2p
eI2NPTunnelBuild = 21, eI2NPTunnelBuild = 21,
eI2NPTunnelBuildReply = 22, eI2NPTunnelBuildReply = 22,
eI2NPVariableTunnelBuild = 23, eI2NPVariableTunnelBuild = 23,
eI2NPVariableTunnelBuildReply = 24 eI2NPVariableTunnelBuildReply = 24
}; };
const int NUM_TUNNEL_BUILD_RECORDS = 8; const int NUM_TUNNEL_BUILD_RECORDS = 8;
// DatabaseLookup flags // DatabaseLookup flags
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01; 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_FLAGS_MASK = 0x0C;
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0; 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_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 const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
namespace tunnel namespace tunnel
{ {
class InboundTunnel; class InboundTunnel;
class TunnelPool; class TunnelPool;
} }
const size_t I2NP_MAX_MESSAGE_SIZE = 32768; const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096; 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_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 struct I2NPMessage
{ {
uint8_t * buf; uint8_t * buf;
size_t len, offset, maxLen; size_t len, offset, maxLen;
std::shared_ptr<i2p::tunnel::InboundTunnel> from; 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 offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
// header accessors // header accessors
uint8_t * GetHeader () { return GetBuffer (); }; uint8_t * GetHeader () { return GetBuffer (); };
const uint8_t * GetHeader () const { 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); }; uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); }; void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); }; 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 SetChks (uint8_t chks) { GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = chks; };
void UpdateChks () void UpdateChks ()
{ {
uint8_t hash[32]; uint8_t hash[32];
SHA256(GetPayload (), GetPayloadLength (), hash); SHA256(GetPayload (), GetPayloadLength (), hash);
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0]; GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
} }
// payload // payload
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; }; uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; }; const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
uint8_t * GetBuffer () { return buf + offset; }; uint8_t * GetBuffer () { return buf + offset; };
const uint8_t * GetBuffer () const { return buf + offset; }; const uint8_t * GetBuffer () const { return buf + offset; };
size_t GetLength () const { return len - offset; }; size_t GetLength () const { return len - offset; };
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; }; size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
void Align (size_t alignment) void Align (size_t alignment)
{ {
if (len + alignment > maxLen) return; if (len + alignment > maxLen) return;
size_t rem = ((size_t)GetBuffer ()) % alignment; size_t rem = ((size_t)GetBuffer ()) % alignment;
@ -153,7 +153,7 @@ namespace tunnel
{ {
offset += (alignment - rem); offset += (alignment - rem);
len += (alignment - rem); len += (alignment - rem);
} }
} }
size_t Concat (const uint8_t * buf1, size_t len1) size_t Concat (const uint8_t * buf1, size_t len1)
@ -171,10 +171,10 @@ namespace tunnel
len = offset + other.GetLength (); len = offset + other.GetLength ();
from = other.from; from = other.from;
return *this; return *this;
} }
// for SSU only // 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 void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular
{ {
const uint8_t * ssu = GetSSUHeader (); 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); 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); len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET); return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
} }
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0); void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
void RenewI2NPMessageHeader (); void RenewI2NPMessageHeader ();
bool IsExpired () const; bool IsExpired () const;
}; };
template<int sz> template<int sz>
struct I2NPMessageBuffer: public I2NPMessage struct I2NPMessageBuffer: public I2NPMessage
@ -211,35 +211,35 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPShortMessage (); std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage ();
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len); 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> 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> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID); 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); 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, 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<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> 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::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::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); 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 IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleVariableTunnelBuildReplyMsg (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 (const uint8_t * buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (); 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, 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); const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
@ -254,7 +254,7 @@ namespace tunnel
~I2NPMessagesHandler (); ~I2NPMessagesHandler ();
void PutNextMessage (std::shared_ptr<I2NPMessage> msg); void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
void Flush (); void Flush ();
private: private:
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs; 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; const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels); void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
} }
#endif #endif

View file

@ -3,9 +3,9 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#if defined(__FreeBSD__) #if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h> #include <sys/endian.h>
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__)
#include <endian.h> #include <endian.h>
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)

View file

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

View file

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

View file

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

View file

@ -14,11 +14,11 @@ namespace i2p
namespace tunnel namespace tunnel
{ {
class InboundTunnel; class InboundTunnel;
} }
namespace data namespace data
{ {
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
struct Lease struct Lease
{ {
@ -33,36 +33,36 @@ namespace data
if (endDate < expire) return true; if (endDate < expire) return true;
return (endDate - expire) < t; return (endDate - expire) < t;
} }
}; };
struct LeaseCmp struct LeaseCmp
{ {
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
{ {
if (l1->tunnelID != l2->tunnelID) if (l1->tunnelID != l2->tunnelID)
return l1->tunnelID < l2->tunnelID; return l1->tunnelID < l2->tunnelID;
else else
return l1->tunnelGateway < l2->tunnelGateway; return l1->tunnelGateway < l2->tunnelGateway;
}; };
}; };
typedef std::function<bool(const Lease & l)> LeaseInspectFunc; typedef std::function<bool(const Lease & l)> LeaseInspectFunc;
const size_t MAX_LS_BUFFER_SIZE = 3072; const size_t MAX_LS_BUFFER_SIZE = 3072;
const size_t LEASE_SIZE = 44; // 32 + 4 + 8 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 class LeaseSet: public RoutingDestination
{ {
public: public:
LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true); LeaseSet (const uint8_t * buf, size_t len, bool storeLeases = true);
~LeaseSet () { delete[] m_Buffer; }; ~LeaseSet () { delete[] m_Buffer; };
void Update (const uint8_t * buf, size_t len); void Update (const uint8_t * buf, size_t len, bool verifySignature = true);
bool IsNewer (const uint8_t * buf, size_t len) const; 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; }; 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; }; 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> > GetNonExpiredLeases (bool withThreshold = true) const;
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, 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 (); }; bool IsEmpty () const { return m_Leases.empty (); };
uint64_t GetExpirationTime () const { return m_ExpirationTime; }; uint64_t GetExpirationTime () const { return m_ExpirationTime; };
bool ExpiresSoon(const uint64_t dlt=1000 * 5, const uint64_t fudge = 0) const ; bool ExpiresSoon(const uint64_t dlt=1000 * 5, const uint64_t fudge = 0) const ;
bool operator== (const LeaseSet& other) const bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; { return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
// implements RoutingDestination // implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; }; std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
@ -81,9 +81,9 @@ namespace data
private: private:
void ReadFromBuffer (bool readIdentity = true); void ReadFromBuffer (bool readIdentity = true, bool verifySignature = true);
uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // returns max expiration time
private: private:
bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill
@ -93,7 +93,13 @@ namespace data
uint8_t m_EncryptionKey[256]; uint8_t m_EncryptionKey[256];
uint8_t * m_Buffer; uint8_t * m_Buffer;
size_t m_BufferLen; size_t m_BufferLen;
}; };
/**
validate lease set buffer signature and extract expiration timestamp
@returns true if the leaseset is well formed and signature is valid
*/
bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires);
class LocalLeaseSet class LocalLeaseSet
{ {
@ -104,27 +110,27 @@ namespace data
~LocalLeaseSet () { delete[] m_Buffer; }; ~LocalLeaseSet () { delete[] m_Buffer; };
const uint8_t * GetBuffer () const { return m_Buffer; }; const uint8_t * GetBuffer () const { return m_Buffer; };
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); }; uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); }; 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 (); }; const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
bool IsExpired () const; bool IsExpired () const;
uint64_t GetExpirationTime () const { return m_ExpirationTime; }; uint64_t GetExpirationTime () const { return m_ExpirationTime; };
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; }; void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
bool operator== (const LeaseSet& other) const bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); }; { return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
private: private:
uint64_t m_ExpirationTime; // in milliseconds uint64_t m_ExpirationTime; // in milliseconds
std::shared_ptr<const IdentityEx> m_Identity; std::shared_ptr<const IdentityEx> m_Identity;
uint8_t * m_Buffer, * m_Leases; uint8_t * m_Buffer, * m_Leases;
size_t m_BufferLen; size_t m_BufferLen;
}; };
} }
} }
#endif #endif

View file

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

View file

@ -105,6 +105,11 @@ namespace transport
transports.PeerConnected (shared_from_this ()); transports.PeerConnected (shared_from_this ());
} }
boost::asio::io_service & NTCPSession::GetService()
{
return m_Server.GetService();
}
void NTCPSession::ClientLogin () void NTCPSession::ClientLogin ()
{ {
if (!m_DHKeysPair) if (!m_DHKeysPair)
@ -171,27 +176,14 @@ namespace transport
return; return;
} }
} }
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 7)
// due the bug in gcc 4.7. std::shared_future.get() is not const
if (!m_DHKeysPair)
m_DHKeysPair = transports.GetNextDHKeysPair ();
CreateAESKey (m_Establisher->phase1.pubKey);
SendPhase2 ();
#else
// TODO: check for number of pending keys // TODO: check for number of pending keys
auto s = shared_from_this (); auto s = shared_from_this ();
auto keyCreated = std::async (std::launch::async, [s] () m_Server.Work(s, [s]() -> std::function<void(void)> {
{
if (!s->m_DHKeysPair) if (!s->m_DHKeysPair)
s->m_DHKeysPair = transports.GetNextDHKeysPair (); s->m_DHKeysPair = transports.GetNextDHKeysPair ();
s->CreateAESKey (s->m_Establisher->phase1.pubKey); s->CreateAESKey (s->m_Establisher->phase1.pubKey);
}).share (); return std::bind(&NTCPSession::SendPhase2, s);
m_Server.GetService ().post ([s, keyCreated]()
{
keyCreated.get ();
s->SendPhase2 ();
}); });
#endif
} }
} }
@ -211,9 +203,8 @@ namespace transport
m_Decryption.SetIV (m_Establisher->phase1.HXxorHI + 16); m_Decryption.SetIV (m_Establisher->phase1.HXxorHI + 16);
m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted); m_Encryption.Encrypt ((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all (), boost::asio::async_write(m_Socket, boost::asio::buffer (&m_Establisher->phase2, sizeof (NTCPPhase2)), boost::asio::transfer_all(),
std::bind(&NTCPSession::HandlePhase2Sent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsB)); std::bind(&NTCPSession::HandlePhase2Sent, shared_from_this(), std::placeholders::_1, std::placeholders::_2, tsB));
} }
void NTCPSession::HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB) void NTCPSession::HandlePhase2Sent (const boost::system::error_code& ecode, std::size_t bytes_transferred, uint32_t tsB)
@ -250,24 +241,11 @@ namespace transport
} }
else else
{ {
#if (__GNUC__ == 4) && (__GNUC_MINOR__ <= 7)
// due the bug in gcc 4.7. std::shared_future.get() is not const
CreateAESKey (m_Establisher->phase2.pubKey);
HandlePhase2 ();
#else
auto s = shared_from_this (); auto s = shared_from_this ();
// create AES key in separate thread m_Server.Work(s, [s]() -> std::function<void(void)> {
auto keyCreated = std::async (std::launch::async, [s] () s->CreateAESKey (s->m_Establisher->phase2.pubKey);
{ return std::bind(&NTCPSession::HandlePhase2, s);
s->CreateAESKey (s->m_Establisher->phase2.pubKey); });
}).share (); // TODO: use move capture in C++ 14 instead shared_future
// let other operations execute while a key gets created
m_Server.GetService ().post ([s, keyCreated]()
{
keyCreated.get (); // we might wait if no more pending operations
s->HandlePhase2 ();
});
#endif
} }
} }
@ -788,12 +766,14 @@ namespace transport
} }
//----------------------------------------- //-----------------------------------------
NTCPServer::NTCPServer (): NTCPServer::NTCPServer (int workers):
m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service), m_IsRunning (false), m_Thread (nullptr), m_Work (m_Service),
m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr), m_TerminationTimer (m_Service), m_NTCPAcceptor (nullptr), m_NTCPV6Acceptor (nullptr),
m_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr), m_ProxyType(eNoProxy), m_Resolver(m_Service), m_ProxyEndpoint(nullptr),
m_SoftLimit(0), m_HardLimit(0) m_SoftLimit(0), m_HardLimit(0)
{ {
if(workers <= 0) workers = 1;
m_CryptoPool = std::make_shared<Pool>(workers);
} }
NTCPServer::~NTCPServer () NTCPServer::~NTCPServer ()

View file

@ -12,6 +12,7 @@
#include "RouterInfo.h" #include "RouterInfo.h"
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "TransportSession.h" #include "TransportSession.h"
#include "CryptoWorker.h"
namespace i2p namespace i2p
{ {
@ -55,6 +56,7 @@ namespace transport
void Done (); void Done ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
boost::asio::io_service & GetService();
bool IsEstablished () const { return m_IsEstablished; }; bool IsEstablished () const { return m_IsEstablished; };
bool IsTerminated () const { return m_IsTerminated; }; bool IsTerminated () const { return m_IsTerminated; };
@ -131,6 +133,8 @@ namespace transport
{ {
public: public:
typedef i2p::worker::ThreadPool<NTCPSession> Pool;
enum RemoteAddressType enum RemoteAddressType
{ {
eIP4Address, eIP4Address,
@ -146,7 +150,7 @@ namespace transport
}; };
NTCPServer (); NTCPServer (int workers=4);
~NTCPServer (); ~NTCPServer ();
void Start (); void Start ();
@ -169,6 +173,10 @@ namespace transport
void SetSessionLimits(uint16_t softLimit, uint16_t hardLimit) { m_SoftLimit = softLimit; m_HardLimit = hardLimit; } void SetSessionLimits(uint16_t softLimit, uint16_t hardLimit) { m_SoftLimit = softLimit; m_HardLimit = hardLimit; }
bool ShouldLimit() const { return ShouldHardLimit() || ShouldSoftLimit(); } bool ShouldLimit() const { return ShouldHardLimit() || ShouldSoftLimit(); }
void Work(std::shared_ptr<NTCPSession> conn, Pool::WorkFunc work)
{
m_CryptoPool->Offer({conn, work});
}
private: private:
/** @brief return true for hard limit */ /** @brief return true for hard limit */
@ -210,6 +218,8 @@ namespace transport
boost::asio::ip::tcp::resolver m_Resolver; boost::asio::ip::tcp::resolver m_Resolver;
boost::asio::ip::tcp::endpoint * m_ProxyEndpoint; boost::asio::ip::tcp::endpoint * m_ProxyEndpoint;
std::shared_ptr<Pool> m_CryptoPool;
uint16_t m_SoftLimit, m_HardLimit; uint16_t m_SoftLimit, m_HardLimit;
public: public:

File diff suppressed because it is too large Load diff

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