Browse Source

Merge pull request #1019 from PurpleI2P/openssl

recent changes
pull/1036/head
orignal 7 years ago committed by GitHub
parent
commit
276a78cb2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 69
      .travis.yml
  2. 17
      ChangeLog
  3. 25
      Makefile.homebrew
  4. 24
      Makefile.osx
  5. 6
      README.md
  6. 2
      Win32/installer.iss
  7. 2
      android/AndroidManifest.xml
  8. 2
      appveyor.yml
  9. 4
      build/CMakeLists.txt
  10. 32
      contrib/certificates/reseed/r4sas_at_mail.i2p.crt
  11. 3
      contrib/i2pd.conf
  12. 16
      contrib/rpm/i2pd.spec
  13. 51
      daemon/HTTPServer.cpp
  14. 11
      daemon/UPnP.cpp
  15. 6
      debian/changelog
  16. 1
      libi2pd/Config.cpp
  17. 393
      libi2pd/Crypto.cpp
  18. 29
      libi2pd/Destination.cpp
  19. 6
      libi2pd/Destination.h
  20. 19
      libi2pd/Identity.cpp
  21. 4
      libi2pd/Identity.h
  22. 42
      libi2pd/Log.cpp
  23. 5
      libi2pd/Log.h
  24. 4
      libi2pd/NTCPSession.cpp
  25. 236
      libi2pd/Reseed.cpp
  26. 7
      libi2pd/RouterInfo.cpp
  27. 40
      libi2pd/Streaming.cpp
  28. 4
      libi2pd/Streaming.h
  29. 2
      libi2pd/version.h
  30. 30
      libi2pd_client/ClientContext.cpp
  31. 13
      libi2pd_client/ClientContext.h
  32. 48
      libi2pd_client/HTTPProxy.cpp
  33. 9
      libi2pd_client/HTTPProxy.h
  34. 12
      libi2pd_client/SAM.cpp
  35. 1
      libi2pd_client/SAM.h
  36. 7
      libi2pd_client/SOCKS.cpp
  37. 6
      libi2pd_client/SOCKS.h
  38. 4
      qt/i2pd_qt/.gitignore
  39. 7
      qt/i2pd_qt/SignatureTypeComboboxFactory.h
  40. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  41. 11
      qt/i2pd_qt/mainwindow.cpp
  42. 1
      qt/i2pd_qt/mainwindow.h

69
.travis.yml

@ -2,34 +2,53 @@ language: cpp
cache: cache:
apt: true apt: true
os: os:
- linux - linux
sudo: required - osx
dist: trusty dist: trusty
sudo: required
compiler:
- g++
- clang++
env:
global:
- MAKEFLAGS="-j 2"
matrix:
- BUILD_TYPE=make UPNP=ON MAKE_UPNP=yes
- BUILD_TYPE=make UPNP=OFF MAKE_UPNP=no
- BUILD_TYPE=cmake UPNP=ON MAKE_UPNP=yes
- BUILD_TYPE=cmake UPNP=OFF MAKE_UPNP=no
matrix:
exclude:
- os: osx
env: BUILD_TYPE=cmake UPNP=ON MAKE_UPNP=yes
- os: osx
env: BUILD_TYPE=cmake UPNP=OFF MAKE_UPNP=no
- os: linux
compiler: clang++
env: BUILD_TYPE=make UPNP=ON MAKE_UPNP=yes
- os: linux
compiler: clang++
env: BUILD_TYPE=make UPNP=OFF MAKE_UPNP=no
addons: addons:
apt: apt:
packages: packages:
- build-essential - build-essential
- cmake - cmake
- g++ - g++
- clang - clang
- libboost-chrono-dev - libboost-chrono-dev
- libboost-date-time-dev - libboost-date-time-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- libboost-program-options-dev - libboost-program-options-dev
- libboost-system-dev - libboost-system-dev
- libboost-thread-dev - libboost-thread-dev
- libminiupnpc-dev - libminiupnpc-dev
- libssl-dev - libssl-dev
compiler:
- gcc
- clang
before_install: before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl miniupnpc ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install libressl miniupnpc ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink boost openssl && brew link boost openssl -f ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew outdated boost || brew upgrade boost ; fi
env:
matrix:
- BUILD_TYPE=Release UPNP=ON
- BUILD_TYPE=Release UPNP=OFF
script: script:
- cd build && cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DWITH_UPNP=${UPNP} && make - if [[ "$TRAVIS_OS_NAME" == "linux" && "$BUILD_TYPE" == "cmake" ]]; then cd build && cmake -DCMAKE_BUILD_TYPE=Release -DWITH_UPNP=${UPNP} && make ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$BUILD_TYPE" == "make" ]]; then make USE_UPNP=${MAKE_UPNP} ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make HOMEBREW=1 USE_UPNP=${MAKE_UPNP} ; fi

17
ChangeLog

@ -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.16.0] - 2017-11-13
### Added
- https and "Connect" method for HTTP proxy
- outproxy for HTTP proxy
- initial support of ECIES crypto
- NTCP soft and hard descriptors limits
- Support full timestamps in logs
### Changed
- Faster implmentation of GOST R 34.11 hash
- Reject routers with RSA signtures
- Reload config and shudown from Windows GUI
- Update tunnels address(destination) without restart
### Fixed
- BOB crashes if destination is not set
- Correct SAM tunnel name
- QT GUI issues
## [2.15.0] - 2017-08-17 ## [2.15.0] - 2017-08-17
### Added ### Added
- QT GUI - QT GUI

25
Makefile.homebrew

@ -3,27 +3,30 @@ BREWROOT = /usr/local
BOOSTROOT = ${BREWROOT}/opt/boost BOOSTROOT = ${BREWROOT}/opt/boost
SSLROOT = ${BREWROOT}/opt/libressl SSLROOT = ${BREWROOT}/opt/libressl
UPNPROOT = ${BREWROOT}/opt/miniupnpc UPNPROOT = ${BREWROOT}/opt/miniupnpc
CXX = clang++
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
CXX = clang++
endif
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread
else else
LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDFLAGS = -L${SSLROOT}/lib -L${BOOSTROOT}/lib
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
endif endif
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
LDFLAGS += -ldl LDFLAGS += -ldl
CXXFLAGS += -DUSE_UPNP CXXFLAGS += -DUSE_UPNP
INCFLAGS += -I${UPNPROOT}/include INCFLAGS += -I${UPNPROOT}/include
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
else else
LDFLAGS += -L${UPNPROOT}/lib LDFLAGS += -L${UPNPROOT}/lib
LDLIBS += -lminiupnpc LDLIBS += -lminiupnpc
endif endif
endif endif
# OSX Notes # OSX Notes

24
Makefile.osx vendored

@ -5,29 +5,29 @@ 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)
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
else else
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
endif endif
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
LDFLAGS += -ldl LDFLAGS += -ldl
CXXFLAGS += -DUSE_UPNP CXXFLAGS += -DUSE_UPNP
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)
LDLIBS += /usr/local/lib/libminiupnpc.a LDLIBS += /usr/local/lib/libminiupnpc.a
else else
LDLIBS += -lminiupnpc LDLIBS += -lminiupnpc
endif endif
endif endif
ifeq ($(USE_AESNI),1) ifeq ($(USE_AESNI),1)
CXXFLAGS += -maes -DAESNI CXXFLAGS += -maes -DAESNI
else else
CXXFLAGS += -msse CXXFLAGS += -msse
endif endif
ifeq ($(USE_AVX),1) ifeq ($(USE_AVX),1)
CXXFLAGS += -mavx CXXFLAGS += -mavx
endif 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

6
README.md

@ -54,9 +54,9 @@ Build instructions:
**Supported systems:** **Supported systems:**
* 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 * Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
* FreeBSD * FreeBSD
* Android * Android
* iOS * iOS

2
Win32/installer.iss

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

2
android/AndroidManifest.xml

@ -2,7 +2,7 @@
<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:versionCode="1"
android:versionName="2.15.0" android:versionName="2.16.0"
android:installLocation="auto"> android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="25"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="25"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2
appveyor.yml

@ -1,4 +1,4 @@
version: 2.15.{build} version: 2.16.{build}
pull_requests: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
branches: branches:

4
build/CMakeLists.txt

@ -150,7 +150,7 @@ else()
if (MSYS OR MINGW) if (MSYS OR MINGW)
add_definitions( -DWIN32_LEAN_AND_MEAN ) add_definitions( -DWIN32_LEAN_AND_MEAN )
endif () endif ()
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic" ) set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic" )
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT. # TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
# Multiple definitions of __stack_chk_fail (libssp & libc) # Multiple definitions of __stack_chk_fail (libssp & libc)
@ -180,7 +180,7 @@ 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_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++" ) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions" )
endif() endif()
endif () endif ()

32
contrib/certificates/reseed/r4sas_at_mail.i2p.crt

@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFezCCA2OgAwIBAgIEb8xTzzANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxHjAcBgNVBAcTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEL
MAkGA1UEChMCWFgxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOcjRzYXNAbWFpbC5p
MnAwHhcNMTYwODExMjIyNDM2WhcNMjYwODExMjIyNDM2WjBuMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxHjAcBgNVBAcTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEL
MAkGA1UEChMCWFgxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOcjRzYXNAbWFpbC5p
MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDjUMy/aYd0i6Oc3rdc
24V/fM2vhviH+cNhAOXsMSrwDSVbFQkuDPIfq4fo1A25rsyULR57vy7XKA51OstX
GvREPDhth4cMZjthq0f8AVzPq2vIk8Po65uvKR190yupPQ4FhvGeRkHkqp+SqoIJ
lClD8xZEHrUHSYZotm5TLWIgSwa4DuO1q3bMRI8oIWzqhv99FtlmHlC8fjVUN4mR
2czhABr0u6RMPOtJwTVxWgT1PKXiLWfmeHb63TcPYGgpJ39iMDOjtgY9jYueoO8J
uGJJtkGRIRjOuhDFE9NUlNnljUxUDWvMU7zCO4ozaKMZgoxr1WoIO6ubI/003I53
sZ0Q5h8yfz+QreEw3wzjxnQSkejG5c3NIvJSiu0ylOqDWmnj0v1Jv/P0qAMU4bt/
ZWj0GOrYfPn9STg0VxMOQwQ2o15GAcbr6PFI56U2IJhZAeER3hIe2kOl6591jQ67
zvOjPRRh2q05Ss8yo7nEpYUiB/FrE6RssJ5tVwX6e6Tq4Z1frINanIkUkToTkypP
Fn2T/KV2lak9rLuxzvhiDobu5iGCR323zFcFEpGq4Wsopx1uRT9+71G/ejw8pKTf
kQ7XiGaaxFyZuMuOz3bFkTuoTmAkUQTlRjGw2DmKZi/apcN+VQgpq9tQpS10pEUy
DCVdtw1AdlOnwb+Hf3X0Uz6OjwIDAQABoyEwHzAdBgNVHQ4EFgQUqLBlSlnqCo25
sIduMPm4iROMqkAwDQYJKoZIhvcNAQENBQADggIBAGWv8rDTzqhHkjqDOT+Ba2bs
gVddpCNa94RQoOn2DUSu4c+yuWJLSctjpX7gswB6qvWk5Ojfafop8jJW8zuozJrO
76b9345S/VnnbHVSoVfIpF9Fve1Xc8nvU4ylRcAMwhf8N3Md5Yc1kb+P7NtTTwMZ
TBR3xY3fVxv3qTpKApWQKkUiqM7yJKOfS8xcK/pjO/3oRUwfA9DHugCUpgSidlN+
JkZmgwAcA3/WMlDdNKmKnWLGB2Ea+W6kIx5TDFfjf11rbjuwXhDLyaOK88qlN0W2
hYa31UDSEYYQd3gMG1gjVc+9vZA/Vr0+SF5ULN9QLjB18CVIdPv92mBjJQRmJSVW
b1qwZI0jf/V+1fu9H9r7sE4CId3+WGOek3UNRNZLOVZCSiFq/b9cswcQZGjw6aE+
1FNjw1HW9CLoNcg74Kr98QouOoeRSofQYZiYqaM9Sz/MsinYMIRGRGw3Uq1uNRo0
WgoOngmZSKGaW5PFR19uuuNIVB4fCShqBVyrguW4xIskta1JVFoggFeOeTwk6/kH
S5roMzyB/kzv83A2IB0VxqbiDj8khgdm1Us6HCCmU+iTRVyG28gFklCJ8dQfxgGH
W2gpIwvxYLyNP14/7E1oF7/NfHmyjAVzYnR5Xw2wE4tvSHuIrHhj6Q26VB3vze6j
E/w1AJEepnw/KfHqS3bw
-----END CERTIFICATE-----

3
contrib/i2pd.conf

@ -23,7 +23,8 @@
# log = file # log = file
## Path to logfile (default - autodetect) ## Path to logfile (default - autodetect)
# logfile = /var/log/i2pd.log # logfile = /var/log/i2pd.log
## Log messages above this level (debug, *info, warn, error) ## Log messages above this level (debug, *info, warn, error, none)
## If you set it to none, logging will be disabled
# loglevel = info # loglevel = info
## Path to storage of i2pd data (RI, keys, peer profiles, ...) ## Path to storage of i2pd data (RI, keys, peer profiles, ...)

16
contrib/rpm/i2pd.spec

@ -1,7 +1,7 @@
%define build_timestamp %(date +"%Y%m%d") %define build_timestamp %(date +"%Y%m%d")
Name: i2pd Name: i2pd
Version: 2.15.0 Version: 2.16.0
Release: %{build_timestamp}git%{?dist} Release: %{build_timestamp}git%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
@ -103,6 +103,20 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Mon Nov 13 2017 orignal <i2porignal@yandex.ru> - 2.16.0
- Added https and "Connect" method for HTTP proxy
- 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 - Added QT GUI
- Added ability add and remove I2P tunnels without restart - Added ability add and remove I2P tunnels without restart

51
daemon/HTTPServer.cpp

@ -60,12 +60,14 @@ namespace http {
" .tunnel.established { color: #56B734; }\r\n" " .tunnel.established { color: #56B734; }\r\n"
" .tunnel.expiring { color: #D3AE3F; }\r\n" " .tunnel.expiring { color: #D3AE3F; }\r\n"
" .tunnel.failed { color: #D33F3F; }\r\n" " .tunnel.failed { color: #D33F3F; }\r\n"
" .tunnel.another { color: #434343; }\r\n" " .tunnel.building { color: #434343; }\r\n"
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
" table { width: 100%; border-collapse: collapse; text-align: center; }\r\n" " table { width: 100%; border-collapse: collapse; text-align: center; }\r\n"
" .private { background: black; color: black; } .private:hover { background: black; color: white } \r\n" " .slide label { color: #894C84 }\r\n"
" .slide p, .slide [type='checkbox']{ display:none; } \r\n" " .slide p, .slide [type='checkbox']{ display:none; }\r\n"
" .slide [type='checkbox']:checked ~ p { display:block; } \r\n" " .slide [type='checkbox']:checked ~ p { display:block; margin-top: 0; padding: 0; }\r\n"
" .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n"
" .enabled:after { color: #56B734; content: \"Enabled\" }\r\n"
"</style>\r\n"; "</style>\r\n";
const char HTTP_PAGE_TUNNELS[] = "tunnels"; const char HTTP_PAGE_TUNNELS[] = "tunnels";
@ -270,7 +272,17 @@ namespace http {
size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels(); size_t transitTunnelCount = i2p::tunnel::tunnels.CountTransitTunnels();
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " "; s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n"; s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
s << "<tr><td>" << "BOB" << "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
s << "<tr><td>" << "SAM" << "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
s << "<tr><td>" << "I2CP" << "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
s << "</table>\r\n";
} }
void ShowLocalDestinations (std::stringstream& s) void ShowLocalDestinations (std::stringstream& s)
@ -284,7 +296,7 @@ namespace http {
} }
auto i2cpServer = i2p::client::context.GetI2CPServer (); auto i2cpServer = i2p::client::context.GetI2CPServer ();
if (i2cpServer) if (i2cpServer && !(i2cpServer->GetSessions ().empty ()))
{ {
s << "<br><b>I2CP Local Destinations:</b><br>\r\n<br>\r\n"; s << "<br><b>I2CP Local Destinations:</b><br>\r\n<br>\r\n";
for (auto& it: i2cpServer->GetSessions ()) for (auto& it: i2cpServer->GetSessions ())
@ -304,14 +316,14 @@ namespace http {
{ {
s << "<b>Base64:</b><br>\r\n<textarea readonly=\"readonly\" cols=\"64\" rows=\"11\" wrap=\"on\">"; s << "<b>Base64:</b><br>\r\n<textarea readonly=\"readonly\" cols=\"64\" rows=\"11\" wrap=\"on\">";
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n"; s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
s << "<b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i><br>\r\n";
if(dest->GetNumRemoteLeaseSets()) if(dest->GetNumRemoteLeaseSets())
{ {
s << "<div class='slide'\r\n><label for='slide1'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n"; s << "<div class='slide'\r\n><label for='slide1'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets () << "</i></label>\r\n<input type='checkbox' id='slide1'/>\r\n<p class='content'>\r\n";
for(auto& it: dest->GetLeaseSets ()) for(auto& it: dest->GetLeaseSets ())
s << it.second->GetIdentHash ().ToBase32 () << "<br>\r\n"; s << it.second->GetIdentHash ().ToBase32 () << "<br>\r\n";
s << "</p>\r\n</div>\r\n"; s << "</p>\r\n</div>\r\n";
} } else
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n";
auto pool = dest->GetTunnelPool (); auto pool = dest->GetTunnelPool ();
if (pool) if (pool)
{ {
@ -401,7 +413,7 @@ namespace http {
void ShowLeasesSets(std::stringstream& s) void ShowLeasesSets(std::stringstream& s)
{ {
s << "<div id='leasesets'><b>LeaseSets (click on to show info):</b></div><br>\r\n"; s << "<b>LeaseSets:</b><br>\r\n<br>\r\n";
int counter = 1; int counter = 1;
// for each lease set // for each lease set
i2p::data::netdb.VisitLeaseSets( i2p::data::netdb.VisitLeaseSets(
@ -434,6 +446,7 @@ namespace http {
void ShowTunnels (std::stringstream& s) void ShowTunnels (std::stringstream& s)
{ {
s << "<b>Tunnels:</b><br>\r\n<br>\r\n";
s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n"; s << "<b>Queue size:</b> " << i2p::tunnel::tunnels.GetQueueSize () << "<br>\r\n";
s << "<b>Inbound tunnels:</b><br>\r\n"; s << "<b>Inbound tunnels:</b><br>\r\n";
@ -457,7 +470,7 @@ namespace http {
static void ShowCommands (std::stringstream& s, uint32_t token) static void ShowCommands (std::stringstream& s, uint32_t token)
{ {
/* commands */ /* commands */
s << "<b>Router Commands</b><br>\r\n"; s << "<b>Router Commands</b><br>\r\n<br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n";
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n"; //s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
if (i2p::context.AcceptsTunnels ()) if (i2p::context.AcceptsTunnels ())
@ -529,13 +542,13 @@ namespace http {
} }
if (!tmp_s.str ().empty ()) if (!tmp_s.str ().empty ())
{ {
s << "<b>NTCP</b> ( " << cnt << " )<br>\r\n"; s << "<div class='slide'\r\n><label for='slide_ntcp'><b>NTCP</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_ntcp'/>\r\n<p class='content'>";
s << tmp_s.str () << "<br>\r\n"; s << tmp_s.str () << "</p>\r\n</div>\r\n";
} }
if (!tmp_s6.str ().empty ()) if (!tmp_s6.str ().empty ())
{ {
s << "<b>NTCP6</b> ( " << cnt6 << " )<br>\r\n"; s << "<div class='slide'\r\n><label for='slide_ntcp6'><b>NTCP6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_ntcp6'/>\r\n<p class='content'>";
s << tmp_s6.str () << "<br>\r\n"; s << tmp_s6.str () << "</p>\r\n</div>\r\n";
} }
} }
} }
@ -545,7 +558,7 @@ namespace http {
auto sessions = ssuServer->GetSessions (); auto sessions = ssuServer->GetSessions ();
if (!sessions.empty ()) if (!sessions.empty ())
{ {
s << "<b>SSU</b> ( " << (int) sessions.size() << " )<br>\r\n"; s << "<div class='slide'\r\n><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu'/>\r\n<p class='content'>";
for (const auto& it: sessions) for (const auto& it: sessions)
{ {
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
@ -557,12 +570,12 @@ namespace http {
s << " [itag:" << it.second->GetRelayTag () << "]"; s << " [itag:" << it.second->GetRelayTag () << "]";
s << "<br>\r\n" << std::endl; s << "<br>\r\n" << std::endl;
} }
s << "<br>\r\n"; s << "</p>\r\n</div>\r\n";
} }
auto sessions6 = ssuServer->GetSessionsV6 (); auto sessions6 = ssuServer->GetSessionsV6 ();
if (!sessions6.empty ()) if (!sessions6.empty ())
{ {
s << "<b>SSU6</b> ( " << (int) sessions6.size() << " )<br>\r\n"; s << "<div class='slide'\r\n><label for='slide_ssu6'><b>SSU6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu6'/>\r\n<p class='content'>";
for (const auto& it: sessions6) for (const auto& it: sessions6)
{ {
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
@ -574,7 +587,7 @@ namespace http {
s << " [itag:" << it.second->GetRelayTag () << "]"; s << " [itag:" << it.second->GetRelayTag () << "]";
s << "<br>\r\n" << std::endl; s << "<br>\r\n" << std::endl;
} }
s << "<br>\r\n"; s << "</p>\r\n</div>\r\n";
} }
} }
} }

11
daemon/UPnP.cpp

@ -79,11 +79,14 @@ namespace transport
void UPnP::Discover () void UPnP::Discover ()
{ {
int nerror = 0;
#if MINIUPNPC_API_VERSION >= 14 #if MINIUPNPC_API_VERSION >= 14
int nerror = 0;
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror); m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
#else #elif ( MINIUPNPC_API_VERSION >= 8 || defined(UPNPDISCOVER_SUCCESS) )
int nerror = 0;
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#else
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0);
#endif #endif
{ {
// notify satrting thread // notify satrting thread
@ -155,7 +158,11 @@ namespace transport
std::string strType (GetProto (address)), strPort (std::to_string (address->port)); std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int r; int r;
std::string strDesc; i2p::config::GetOption("upnp.name", strDesc); std::string strDesc; i2p::config::GetOption("upnp.name", strDesc);
#ifdef UPNPDISCOVER_SUCCESS
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
#else
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0);
#endif
if (r!=UPNPCOMMAND_SUCCESS) if (r!=UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: AddPortMapping (", m_NetworkAddr, ":", strPort, ") failed with code ", r); LogPrint (eLogError, "UPnP: AddPortMapping (", m_NetworkAddr, ":", strPort, ") failed with code ", r);

6
debian/changelog vendored

@ -1,3 +1,9 @@
i2pd (2.16.0-1) unstable; urgency=low
* updated to version 2.16.0/0.9.32
-- orignal <orignal@i2pmail.org> Mon, 13 Nov 2017 18:00:00 +0000
i2pd (2.15.0-1) unstable; urgency=low i2pd (2.15.0-1) unstable; urgency=low
* updated to version 2.15.0/0.9.31 * updated to version 2.15.0/0.9.31

1
libi2pd/Config.cpp

@ -179,6 +179,7 @@ namespace config {
("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from") ("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from")
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from") ("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from")
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from") ("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
("reseed.urls", value<std::string>()->default_value( ("reseed.urls", value<std::string>()->default_value(
"https://reseed.i2p-projekt.de/," "https://reseed.i2p-projekt.de/,"
"https://i2p.mooo.com/netDb/," "https://i2p.mooo.com/netDb/,"

393
libi2pd/Crypto.cpp

@ -14,20 +14,20 @@
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
{ {
const uint8_t elgp_[256]= const uint8_t elgp_[256]=
{ {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
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,
0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
@ -36,7 +36,7 @@ namespace crypto
}; };
const int elgg_ = 2; const int elgg_ = 2;
const uint8_t dsap_[128]= const uint8_t dsap_[128]=
{ {
0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c, 0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c,
@ -45,7 +45,7 @@ namespace crypto
0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c, 0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c,
0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8, 0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8,
0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c, 0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c,
0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11, 0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11,
0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93 0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93
}; };
@ -63,27 +63,27 @@ namespace crypto
0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52, 0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52,
0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc, 0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc,
0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a, 0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a,
0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c, 0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c,
0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82 0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82
}; };
const int rsae_ = 65537; const int rsae_ = 65537;
struct CryptoConstants struct CryptoConstants
{ {
// DH/ElGamal // DH/ElGamal
BIGNUM * elgp; BIGNUM * elgp;
BIGNUM * elgg; BIGNUM * elgg;
// DSA // DSA
BIGNUM * dsap; BIGNUM * dsap;
BIGNUM * dsaq; BIGNUM * dsaq;
BIGNUM * dsag; BIGNUM * dsag;
// RSA // RSA
BIGNUM * rsae; BIGNUM * rsae;
CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_, CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_,
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_) const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_)
{ {
elgp = BN_new (); elgp = BN_new ();
@ -99,18 +99,18 @@ namespace crypto
rsae = BN_new (); rsae = BN_new ();
BN_set_word (rsae, rsae_); BN_set_word (rsae, rsae_);
} }
~CryptoConstants () ~CryptoConstants ()
{ {
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
} }
}; };
static const CryptoConstants& GetCryptoConstants () static const CryptoConstants& GetCryptoConstants ()
{ {
static CryptoConstants cryptoConstants (elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_); static CryptoConstants cryptoConstants (elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_);
return cryptoConstants; return cryptoConstants;
} }
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len) bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len)
{ {
@ -119,34 +119,34 @@ namespace crypto
BN_bn2bin (bn, buf + offset); BN_bn2bin (bn, buf + offset);
memset (buf, 0, offset); memset (buf, 0, offset);
return true; return true;
} }
// RSA // RSA
#define rsae GetCryptoConstants ().rsae #define rsae GetCryptoConstants ().rsae
const BIGNUM * GetRSAE () const BIGNUM * GetRSAE ()
{ {
return rsae; return rsae;
} }
// DSA // DSA
#define dsap GetCryptoConstants ().dsap #define dsap GetCryptoConstants ().dsap
#define dsaq GetCryptoConstants ().dsaq #define dsaq GetCryptoConstants ().dsaq
#define dsag GetCryptoConstants ().dsag #define dsag GetCryptoConstants ().dsag
DSA * CreateDSA () DSA * CreateDSA ()
{ {
DSA * dsa = DSA_new (); DSA * dsa = DSA_new ();
DSA_set0_pqg (dsa, BN_dup (dsap), BN_dup (dsaq), BN_dup (dsag)); DSA_set0_pqg (dsa, BN_dup (dsap), BN_dup (dsaq), BN_dup (dsag));
DSA_set0_key (dsa, NULL, NULL); DSA_set0_key (dsa, NULL, NULL);
return dsa; return dsa;
} }
// DH/ElGamal // DH/ElGamal
const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226; const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226;
const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1; const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1;
const int ELGAMAL_FULL_EXPONENT_NUM_BITS = 2048; const int ELGAMAL_FULL_EXPONENT_NUM_BITS = 2048;
const int ELGAMAL_FULL_EXPONENT_NUM_BYTES = ELGAMAL_FULL_EXPONENT_NUM_BITS/8; const int ELGAMAL_FULL_EXPONENT_NUM_BYTES = ELGAMAL_FULL_EXPONENT_NUM_BITS/8;
#define elgp GetCryptoConstants ().elgp #define elgp GetCryptoConstants ().elgp
#define elgg GetCryptoConstants ().elgg #define elgg GetCryptoConstants ().elgg
@ -156,14 +156,14 @@ namespace crypto
if (len <= 0) return; if (len <= 0) return;
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
g_MontCtx = BN_MONT_CTX_new (); g_MontCtx = BN_MONT_CTX_new ();
BN_MONT_CTX_set (g_MontCtx, elgp, ctx); BN_MONT_CTX_set (g_MontCtx, elgp, ctx);
auto montCtx = BN_MONT_CTX_new (); auto montCtx = BN_MONT_CTX_new ();
BN_MONT_CTX_copy (montCtx, g_MontCtx); BN_MONT_CTX_copy (montCtx, g_MontCtx);
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
table[i][0] = BN_new (); table[i][0] = BN_new ();
if (!i) if (!i)
BN_to_montgomery (table[0][0], elgg, montCtx, ctx); BN_to_montgomery (table[0][0], elgg, montCtx, ctx);
else else
BN_mod_mul_montgomery (table[i][0], table[i-1][254], table[i-1][0], montCtx, ctx); BN_mod_mul_montgomery (table[i][0], table[i-1][254], table[i-1][0], montCtx, ctx);
for (int j = 1; j < 255; j++) for (int j = 1; j < 255; j++)
@ -174,7 +174,7 @@ namespace crypto
} }
BN_MONT_CTX_free (montCtx); BN_MONT_CTX_free (montCtx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
static void DestroyElggTable (BIGNUM * table[][255], int len) static void DestroyElggTable (BIGNUM * table[][255], int len)
{ {
@ -186,9 +186,9 @@ namespace crypto
} }
BN_MONT_CTX_free (g_MontCtx); BN_MONT_CTX_free (g_MontCtx);
} }
static BIGNUM * ElggPow (const uint8_t * exp, int len, BIGNUM * table[][255], BN_CTX * ctx) static BIGNUM * ElggPow (const uint8_t * exp, int len, BIGNUM * table[][255], BN_CTX * ctx)
// exp is in Big Endian // exp is in Big Endian
{ {
if (len <= 0) return nullptr; if (len <= 0) return nullptr;
auto montCtx = BN_MONT_CTX_new (); auto montCtx = BN_MONT_CTX_new ();
@ -200,15 +200,15 @@ namespace crypto
{ {
if (exp[i]) if (exp[i])
BN_mod_mul_montgomery (res, res, table[len-1-i][exp[i]-1], montCtx, ctx); BN_mod_mul_montgomery (res, res, table[len-1-i][exp[i]-1], montCtx, ctx);
} }
else if (exp[i]) else if (exp[i])
res = BN_dup (table[len-i-1][exp[i]-1]); res = BN_dup (table[len-i-1][exp[i]-1]);
} }
if (res) if (res)
BN_from_montgomery (res, res, montCtx, ctx); BN_from_montgomery (res, res, montCtx, ctx);
BN_MONT_CTX_free (montCtx); BN_MONT_CTX_free (montCtx);
return res; return res;
} }
static BIGNUM * ElggPow (const BIGNUM * exp, BIGNUM * table[][255], BN_CTX * ctx) static BIGNUM * ElggPow (const BIGNUM * exp, BIGNUM * table[][255], BN_CTX * ctx)
{ {
@ -218,64 +218,64 @@ namespace crypto
auto ret = ElggPow (buf, len, table, ctx); auto ret = ElggPow (buf, len, table, ctx);
delete[] buf; delete[] buf;
return ret; return ret;
} }
static BIGNUM * (* g_ElggTable)[255] = nullptr;
static BIGNUM * (* g_ElggTable)[255] = nullptr;
// DH // DH
DHKeys::DHKeys () DHKeys::DHKeys ()
{ {
m_DH = DH_new (); m_DH = DH_new ();
DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg)); DH_set0_pqg (m_DH, BN_dup (elgp), NULL, BN_dup (elgg));
DH_set0_key (m_DH, NULL, NULL); DH_set0_key (m_DH, NULL, NULL);
} }
DHKeys::~DHKeys () DHKeys::~DHKeys ()
{ {
DH_free (m_DH); DH_free (m_DH);
} }
void DHKeys::GenerateKeys () void DHKeys::GenerateKeys ()
{ {
BIGNUM * priv_key = NULL, * pub_key = NULL; BIGNUM * priv_key = NULL, * pub_key = NULL;
#if !defined(__x86_64__) // use short exponent for non x64 #if !defined(__x86_64__) // use short exponent for non x64
priv_key = BN_new (); priv_key = BN_new ();
BN_rand (priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1); BN_rand (priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
#endif #endif
if (g_ElggTable) if (g_ElggTable)
{ {
#if defined(__x86_64__) #if defined(__x86_64__)
priv_key = BN_new (); priv_key = BN_new ();
BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1); BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1);
#endif #endif
auto ctx = BN_CTX_new (); auto ctx = BN_CTX_new ();
pub_key = ElggPow (priv_key, g_ElggTable, ctx); pub_key = ElggPow (priv_key, g_ElggTable, ctx);
DH_set0_key (m_DH, pub_key, priv_key); DH_set0_key (m_DH, pub_key, priv_key);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
else else
{ {
DH_set0_key (m_DH, NULL, priv_key); DH_set0_key (m_DH, NULL, priv_key);
DH_generate_key (m_DH); DH_generate_key (m_DH);
DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key); DH_get0_key (m_DH, (const BIGNUM **)&pub_key, (const BIGNUM **)&priv_key);
} }
bn2buf (pub_key, m_PublicKey, 256); bn2buf (pub_key, m_PublicKey, 256);
} }
void DHKeys::Agree (const uint8_t * pub, uint8_t * shared) void DHKeys::Agree (const uint8_t * pub, uint8_t * shared)
{ {
BIGNUM * pk = BN_bin2bn (pub, 256, NULL); BIGNUM * pk = BN_bin2bn (pub, 256, NULL);
DH_compute_key (shared, pk, m_DH); DH_compute_key (shared, pk, m_DH);
BN_free (pk); BN_free (pk);
} }
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
{ {
BN_CTX_start (ctx); BN_CTX_start (ctx);
// everything, but a, because a might come from table // everything, but a, because a might come from table
BIGNUM * k = BN_CTX_get (ctx); BIGNUM * k = BN_CTX_get (ctx);
BIGNUM * y = BN_CTX_get (ctx); BIGNUM * y = BN_CTX_get (ctx);
BIGNUM * b1 = BN_CTX_get (ctx); BIGNUM * b1 = BN_CTX_get (ctx);
@ -285,13 +285,13 @@ namespace crypto
BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64 BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64
#else #else
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
#endif #endif
// calculate a // calculate a
BIGNUM * a; BIGNUM * a;
if (g_ElggTable) if (g_ElggTable)
a = ElggPow (k, g_ElggTable, ctx); a = ElggPow (k, g_ElggTable, ctx);
else else
{ {
a = BN_new (); a = BN_new ();
BN_mod_exp (a, elgg, k, elgp, ctx); BN_mod_exp (a, elgg, k, elgp, ctx);
} }
@ -315,17 +315,17 @@ namespace crypto
bn2buf (a, encrypted + 1, 256); bn2buf (a, encrypted + 1, 256);
encrypted[257] = 0; encrypted[257] = 0;
bn2buf (b, encrypted + 258, 256); bn2buf (b, encrypted + 258, 256);
} }
else else
{ {
bn2buf (a, encrypted, 256); bn2buf (a, encrypted, 256);
bn2buf (b, encrypted + 256, 256); bn2buf (b, encrypted + 256, 256);
} }
BN_free (a); BN_free (a);
BN_CTX_end (ctx); BN_CTX_end (ctx);
} }
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted,
uint8_t * data, BN_CTX * ctx, bool zeroPadding) uint8_t * data, BN_CTX * ctx, bool zeroPadding)
{ {
BN_CTX_start (ctx); BN_CTX_start (ctx);
@ -334,11 +334,11 @@ namespace crypto
BN_sub (x, elgp, x); BN_sub_word (x, 1); // x = elgp - x- 1 BN_sub (x, elgp, x); BN_sub_word (x, 1); // x = elgp - x- 1
BN_bin2bn (zeroPadding ? encrypted + 1 : encrypted, 256, a); BN_bin2bn (zeroPadding ? encrypted + 1 : encrypted, 256, a);
BN_bin2bn (zeroPadding ? encrypted + 258 : encrypted + 256, 256, b); BN_bin2bn (zeroPadding ? encrypted + 258 : encrypted + 256, 256, b);
// m = b*(a^x mod p) mod p // m = b*(a^x mod p) mod p
BN_mod_exp (x, a, x, elgp, ctx); BN_mod_exp (x, a, x, elgp, ctx);
BN_mod_mul (b, b, x, elgp, ctx); BN_mod_mul (b, b, x, elgp, ctx);
uint8_t m[255]; uint8_t m[255];
bn2buf (b, m, 255); bn2buf (b, m, 255);
BN_CTX_end (ctx); BN_CTX_end (ctx);
uint8_t hash[32]; uint8_t hash[32];
SHA256 (m + 33, 222, hash); SHA256 (m + 33, 222, hash);
@ -346,14 +346,14 @@ namespace crypto
{ {
LogPrint (eLogError, "ElGamal decrypt hash doesn't match"); LogPrint (eLogError, "ElGamal decrypt hash doesn't match");
return false; return false;
} }
memcpy (data, m + 33, 222); memcpy (data, m + 33, 222);
return true; return true;
} }
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub) void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub)
{ {
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) #if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
RAND_bytes (priv, 256); RAND_bytes (priv, 256);
#else #else
// lower 226 bits (28 bytes and 2 bits) only. short exponent // lower 226 bits (28 bytes and 2 bits) only. short exponent
@ -364,10 +364,10 @@ namespace crypto
priv[numZeroBytes] &= 0x03; priv[numZeroBytes] &= 0x03;
#endif #endif
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BIGNUM * p = BN_new (); BIGNUM * p = BN_new ();
BN_bin2bn (priv, 256, p); BN_bin2bn (priv, 256, p);
BN_mod_exp (p, elgg, p, elgp, ctx); BN_mod_exp (p, elgg, p, elgp, ctx);
bn2buf (p, pub, 256); bn2buf (p, pub, 256);
BN_free (p); BN_free (p);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
@ -385,15 +385,15 @@ namespace crypto
auto p = EC_POINT_new (curve); auto p = EC_POINT_new (curve);
EC_POINT_mul (curve, p, k, nullptr, nullptr, ctx); EC_POINT_mul (curve, p, k, nullptr, nullptr, ctx);
BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx); BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx);
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
encrypted[0] = 0; encrypted[0] = 0;
bn2buf (x, encrypted + 1, len); bn2buf (x, encrypted + 1, len);
bn2buf (y, encrypted + 1 + len, len); bn2buf (y, encrypted + 1 + len, len);
RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len); RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len);
// ecryption key and iv // ecryption key and iv
EC_POINT_mul (curve, p, nullptr, key, k, ctx); EC_POINT_mul (curve, p, nullptr, key, k, ctx);
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
uint8_t keyBuf[64], iv[64], shared[32]; uint8_t keyBuf[64], iv[64], shared[32];
bn2buf (x, keyBuf, len); bn2buf (x, keyBuf, len);
bn2buf (y, iv, len); bn2buf (y, iv, len);
SHA256 (keyBuf, len, shared); SHA256 (keyBuf, len, shared);
@ -421,16 +421,16 @@ namespace crypto
int len = BN_num_bytes (q); int len = BN_num_bytes (q);
// point for shared secret // point for shared secret
BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx); BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx);
BN_bin2bn (encrypted + 1, len, x); BN_bin2bn (encrypted + 1, len, x);
BN_bin2bn (encrypted + 1 + len, len, y); BN_bin2bn (encrypted + 1 + len, len, y);
auto p = EC_POINT_new (curve); auto p = EC_POINT_new (curve);
if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr)) if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr))
{ {
auto s = EC_POINT_new (curve); auto s = EC_POINT_new (curve);
EC_POINT_mul (curve, s, nullptr, p, key, ctx); EC_POINT_mul (curve, s, nullptr, p, key, ctx);
EC_POINT_get_affine_coordinates_GFp (curve, s, x, y, nullptr); EC_POINT_get_affine_coordinates_GFp (curve, s, x, y, nullptr);
EC_POINT_free (s); EC_POINT_free (s);
uint8_t keyBuf[64], iv[64], shared[32]; uint8_t keyBuf[64], iv[64], shared[32];
bn2buf (x, keyBuf, len); bn2buf (x, keyBuf, len);
bn2buf (y, iv, len); bn2buf (y, iv, len);
SHA256 (keyBuf, len, shared); SHA256 (keyBuf, len, shared);
@ -442,21 +442,21 @@ namespace crypto
decryption.Decrypt (encrypted + 258, 256, m); decryption.Decrypt (encrypted + 258, 256, m);
// verify and copy // verify and copy
uint8_t hash[32]; uint8_t hash[32];
SHA256 (m + 33, 222, hash); SHA256 (m + 33, 222, hash);
if (!memcmp (m + 1, hash, 32)) if (!memcmp (m + 1, hash, 32))
memcpy (data, m + 33, 222); memcpy (data, m + 33, 222);
else else
{ {
LogPrint (eLogError, "ECICS decrypt hash doesn't match"); LogPrint (eLogError, "ECIES decrypt hash doesn't match");
ret = false; ret = false;
} }
} }
else else
{ {
LogPrint (eLogError, "ECICS decrypt point is invalid"); LogPrint (eLogError, "ECIES decrypt point is invalid");
ret = false; ret = false;
} }
EC_POINT_free (p); EC_POINT_free (p);
BN_CTX_end (ctx); BN_CTX_end (ctx);
return ret; return ret;
@ -468,7 +468,7 @@ namespace crypto
BIGNUM * q = BN_new (); BIGNUM * q = BN_new ();
EC_GROUP_get_order(curve, q, ctx); EC_GROUP_get_order(curve, q, ctx);
priv = BN_new (); priv = BN_new ();
BN_rand_range (priv, q); BN_rand_range (priv, q);
pub = EC_POINT_new (curve); pub = EC_POINT_new (curve);
EC_POINT_mul (curve, pub, priv, nullptr, nullptr, ctx); EC_POINT_mul (curve, pub, priv, nullptr, nullptr, ctx);
BN_free (q); BN_free (q);
@ -477,17 +477,17 @@ namespace crypto
// HMAC // HMAC
const uint64_t IPAD = 0x3636363636363636; const uint64_t IPAD = 0x3636363636363636;
const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C;
#if defined(__AVX__) #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 #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
// digest is 16 bytes // digest is 16 bytes
// block size is 64 bytes // block size is 64 bytes
{ {
uint64_t buf[256]; uint64_t buf[256];
uint64_t hash[12]; // 96 bytes uint64_t hash[12]; // 96 bytes
@ -498,53 +498,53 @@ namespace crypto
"vmovups %[ipad], %%ymm1 \n" "vmovups %[ipad], %%ymm1 \n"
"vmovups %%ymm1, 32(%[buf]) \n" "vmovups %%ymm1, 32(%[buf]) \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n" "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, (%[buf]) \n" "vmovups %%ymm1, (%[buf]) \n"
"vmovups %[opad], %%ymm1 \n" "vmovups %[opad], %%ymm1 \n"
"vmovups %%ymm1, 32(%[hash]) \n" "vmovups %%ymm1, 32(%[hash]) \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n" "vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, (%[hash]) \n" "vmovups %%ymm1, (%[hash]) \n"
"vzeroall \n" // end of AVX "vzeroall \n" // end of AVX
"movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes "movups %%xmm0, 80(%[hash]) \n" // zero last 16 bytes
: :
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads), : [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
[buf]"r"(buf), [hash]"r"(hash) [buf]"r"(buf), [hash]"r"(hash)
: "memory", "%xmm0" // TODO: change to %ymm0 later : "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
// concatenate with msg // concatenate with msg
memcpy (buf + 8, msg, len); memcpy (buf + 8, msg, len);
// calculate first hash // calculate first hash
MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
// calculate digest // calculate digest
MD5((uint8_t *)hash, 96, digest); MD5((uint8_t *)hash, 96, digest);
} }
// 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" \
@ -566,7 +566,7 @@ namespace crypto
"pslldq $4, %%xmm4 \n" \ "pslldq $4, %%xmm4 \n" \
"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"
void ECBCryptoAESNI::ExpandKey (const AESKey& key) void ECBCryptoAESNI::ExpandKey (const AESKey& key)
{ {
@ -591,7 +591,7 @@ namespace crypto
"aeskeygenassist $64, %%xmm3, %%xmm2 \n" "aeskeygenassist $64, %%xmm3, %%xmm2 \n"
// key expansion final // key expansion final
"pshufd $0xff, %%xmm2, %%xmm2 \n" "pshufd $0xff, %%xmm2, %%xmm2 \n"
"movaps %%xmm1, %%xmm4 \n" "movaps %%xmm1, %%xmm4 \n"
"pslldq $4, %%xmm4 \n" "pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n" "pxor %%xmm4, %%xmm1 \n"
"pslldq $4, %%xmm4 \n" "pslldq $4, %%xmm4 \n"
@ -622,17 +622,17 @@ 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"
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out) void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
__asm__ __asm__
( (
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
); );
} }
#define DecryptAES256(sched) \ #define DecryptAES256(sched) \
"pxor 224(%["#sched"]), %%xmm0 \n" \ "pxor 224(%["#sched"]), %%xmm0 \n" \
@ -650,22 +650,22 @@ 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"
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out) void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
__asm__ __asm__
( (
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
DecryptAES256(sched) DecryptAES256(sched)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
); );
} }
#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) void ECBDecryptionAESNI::SetKey (const AESKey& key)
{ {
@ -690,7 +690,7 @@ namespace crypto
); );
} }
#endif #endif
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
@ -698,31 +698,31 @@ namespace crypto
#ifdef AESNI #ifdef AESNI
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"1: \n" "1: \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
"movups %%xmm1, (%[iv]) \n" "movups %%xmm1, (%[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), [num]"r"(numBlocks) [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "cc", "memory" : "%xmm0", "%xmm1", "cc", "memory"
); );
#else #else
for (int i = 0; i < numBlocks; i++) for (int i = 0; i < numBlocks; i++)
{ {
*m_LastBlock.GetChipherBlock () ^= in[i]; *m_LastBlock.GetChipherBlock () ^= in[i];
m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ()); m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ());
out[i] = *m_LastBlock.GetChipherBlock (); out[i] = *m_LastBlock.GetChipherBlock ();
} }
#endif #endif
} }
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)
@ -730,7 +730,7 @@ namespace crypto
// len/16 // len/16
int numBlocks = len >> 4; int numBlocks = len >> 4;
if (numBlocks > 0) if (numBlocks > 0)
Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
} }
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
@ -740,17 +740,17 @@ namespace crypto
( (
"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
} }
@ -760,23 +760,23 @@ namespace crypto
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"1: \n" "1: \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched) DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n" "movaps %%xmm2, %%xmm1 \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
"movups %%xmm1, (%[iv]) \n" "movups %%xmm1, (%[iv]) \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), [num]"r"(numBlocks) [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory" : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
); );
#else #else
for (int i = 0; i < numBlocks; i++) for (int i = 0; i < numBlocks; i++)
{ {
@ -792,7 +792,7 @@ namespace crypto
{ {
int numBlocks = len >> 4; int numBlocks = len >> 4;
if (numBlocks > 0) if (numBlocks > 0)
Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out);
} }
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
@ -801,18 +801,18 @@ namespace crypto
__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
} }
@ -821,7 +821,7 @@ namespace crypto
#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"
@ -831,16 +831,16 @@ namespace crypto
// 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.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"
); );
@ -857,7 +857,7 @@ namespace crypto
#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"
@ -867,27 +867,27 @@ namespace crypto
// 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.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
} }
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes; /* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
static void OpensslLockingCallback(int mode, int type, const char * file, int line) static void OpensslLockingCallback(int mode, int type, const char * file, int line)
@ -898,45 +898,44 @@ namespace crypto
m_OpenSSLMutexes[type]->lock (); m_OpenSSLMutexes[type]->lock ();
else else
m_OpenSSLMutexes[type]->unlock (); m_OpenSSLMutexes[type]->unlock ();
} }
}*/ }*/
void InitCrypto (bool precomputation) void InitCrypto (bool precomputation)
{ {
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++)
m_OpenSSLMutexes.emplace_back (new std::mutex); m_OpenSSLMutexes.emplace_back (new std::mutex);
CRYPTO_set_locking_callback (OpensslLockingCallback);*/ CRYPTO_set_locking_callback (OpensslLockingCallback);*/
if (precomputation) if (precomputation)
{ {
#if defined(__x86_64__) #if defined(__x86_64__)
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255]; g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES); PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
#else #else
g_ElggTable = new BIGNUM * [ELGAMAL_SHORT_EXPONENT_NUM_BYTES][255]; g_ElggTable = new BIGNUM * [ELGAMAL_SHORT_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_SHORT_EXPONENT_NUM_BYTES); PrecalculateElggTable (g_ElggTable, ELGAMAL_SHORT_EXPONENT_NUM_BYTES);
#endif #endif
} }
} }
void TerminateCrypto () void TerminateCrypto ()
{ {
if (g_ElggTable) if (g_ElggTable)
{ {
DestroyElggTable (g_ElggTable, DestroyElggTable (g_ElggTable,
#if defined(__x86_64__) #if defined(__x86_64__)
ELGAMAL_FULL_EXPONENT_NUM_BYTES ELGAMAL_FULL_EXPONENT_NUM_BYTES
#else #else
ELGAMAL_SHORT_EXPONENT_NUM_BYTES ELGAMAL_SHORT_EXPONENT_NUM_BYTES
#endif #endif
); );
delete[] g_ElggTable; g_ElggTable = nullptr; delete[] g_ElggTable; g_ElggTable = nullptr;
} }
/* CRYPTO_set_locking_callback (nullptr); /* CRYPTO_set_locking_callback (nullptr);
m_OpenSSLMutexes.clear ();*/ m_OpenSSLMutexes.clear ();*/
} }
} }
} }

29
libi2pd/Destination.cpp

@ -483,9 +483,22 @@ namespace client
{ {
if (m_PublishReplyToken) if (m_PublishReplyToken)
{ {
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
Publish (); 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");
Publish ();
}
else
{
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ());
// Java floodfill never sends confirmantion back for unknown crypto type
// assume it successive and try to verify
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1));
}
} }
} }
} }
@ -702,8 +715,8 @@ namespace client
} }
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params): ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (isPublic, params), LeaseSetDestination (isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
m_Keys (keys), m_DatagramDestination (nullptr), m_RefCounter (0), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(GetService()) m_ReadyChecker(GetService())
{ {
if (isPublic) if (isPublic)
@ -714,6 +727,14 @@ namespace client
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
if (params)
{
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
if (it != params->end ())
m_StreamingAckDelay = std::stoi(it->second);
}
} }
ClientDestination::~ClientDestination () ClientDestination::~ClientDestination ()

6
libi2pd/Destination.h

@ -58,6 +58,10 @@ namespace client
const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max"; const char I2CP_PARAM_MAX_TUNNEL_LATENCY[] = "latency.max";
const int DEFAULT_MAX_TUNNEL_LATENCY = 0; const int DEFAULT_MAX_TUNNEL_LATENCY = 0;
// streaming
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete; typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
class LeaseSetDestination: public i2p::garlic::GarlicDestination, class LeaseSetDestination: public i2p::garlic::GarlicDestination,
@ -199,6 +203,7 @@ namespace client
void StopAcceptingStreams (); void StopAcceptingStreams ();
bool IsAcceptingStreams () const; bool IsAcceptingStreams () const;
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
// datagram // datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
@ -230,6 +235,7 @@ namespace client
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256];
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor; std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
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;

19
libi2pd/Identity.cpp

@ -324,6 +324,12 @@ namespace data
return SIGNING_KEY_TYPE_DSA_SHA1; return SIGNING_KEY_TYPE_DSA_SHA1;
} }
bool IdentityEx::IsRSA () const
{
auto sigType = GetSigningKeyType ();
return sigType <= SIGNING_KEY_TYPE_RSA_SHA512_4096 && sigType >= SIGNING_KEY_TYPE_RSA_SHA256_2048;
}
CryptoKeyType IdentityEx::GetCryptoKeyType () const CryptoKeyType IdentityEx::GetCryptoKeyType () const
{ {
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 4) if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 4)
@ -451,6 +457,7 @@ namespace data
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key); return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
break; break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key); return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key);
break; break;
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
@ -602,6 +609,7 @@ namespace data
return std::make_shared<i2p::crypto::ElGamalDecryptor>(key); return std::make_shared<i2p::crypto::ElGamalDecryptor>(key);
break; break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key); return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);
break; break;
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
@ -632,14 +640,10 @@ namespace data
i2p::crypto::CreateECDSAP521RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); i2p::crypto::CreateECDSAP521RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break; break;
case SIGNING_KEY_TYPE_RSA_SHA256_2048: case SIGNING_KEY_TYPE_RSA_SHA256_2048:
i2p::crypto::CreateRSARandomKeys (i2p::crypto::RSASHA2562048_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA384_3072:
i2p::crypto::CreateRSARandomKeys (i2p::crypto::RSASHA3843072_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey);
break;
case SIGNING_KEY_TYPE_RSA_SHA512_4096: case SIGNING_KEY_TYPE_RSA_SHA512_4096:
i2p::crypto::CreateRSARandomKeys (i2p::crypto::RSASHA5124096_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Create EdDSA");
break; // 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;
@ -650,7 +654,7 @@ namespace data
i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey); i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey);
break; break;
default: default:
LogPrint (eLogError, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1 return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1
} }
// encryption // encryption
@ -673,6 +677,7 @@ namespace data
i2p::crypto::GenerateElGamalKeyPair(priv, pub); i2p::crypto::GenerateElGamalKeyPair(priv, pub);
break; break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
i2p::crypto::CreateECIESP256RandomKeys (priv, pub); i2p::crypto::CreateECIESP256RandomKeys (priv, pub);
break; break;
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:

4
libi2pd/Identity.h

@ -53,7 +53,8 @@ namespace data
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 65280; // TODO: change to actual code const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES
const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0;
@ -102,6 +103,7 @@ namespace data
size_t GetSignatureLen () const; size_t GetSignatureLen () const;
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
SigningKeyType GetSigningKeyType () const; SigningKeyType GetSigningKeyType () const;
bool IsRSA () const; // signing key type
CryptoKeyType GetCryptoKeyType () const; CryptoKeyType GetCryptoKeyType () const;
void DropVerifier () const; // to save memory void DropVerifier () const; // to save memory

42
libi2pd/Log.cpp

@ -16,10 +16,11 @@ namespace log {
*/ */
static const char * g_LogLevelStr[eNumLogLevels] = static const char * g_LogLevelStr[eNumLogLevels] =
{ {
"none", // eLogNone
"error", // eLogError "error", // eLogError
"warn", // eLogWarn "warn", // eLogWarn
"info", // eLogInfo "info", // eLogInfo
"debug" // eLogDebug "debug" // eLogDebug
}; };
/** /**
@ -27,9 +28,10 @@ namespace log {
* @note Using ISO 6429 (ANSI) color sequences * @note Using ISO 6429 (ANSI) color sequences
*/ */
#ifdef _WIN32 #ifdef _WIN32
static const char *LogMsgColors[] = { "", "", "", "", "" }; static const char *LogMsgColors[] = { "", "", "", "", "", "" };
#else /* UNIX */ #else /* UNIX */
static const char *LogMsgColors[] = { static const char *LogMsgColors[] = {
[eLogNone] = "\033[0m", /* reset */
[eLogError] = "\033[1;31m", /* red */ [eLogError] = "\033[1;31m", /* red */
[eLogWarning] = "\033[1;33m", /* yellow */ [eLogWarning] = "\033[1;33m", /* yellow */
[eLogInfo] = "\033[1;36m", /* cyan */ [eLogInfo] = "\033[1;36m", /* cyan */
@ -46,6 +48,7 @@ namespace log {
static inline int GetSyslogPrio (enum LogLevel l) { static inline int GetSyslogPrio (enum LogLevel l) {
int priority = LOG_DEBUG; int priority = LOG_DEBUG;
switch (l) { switch (l) {
case eLogNone : priority = LOG_CRIT; break;
case eLogError : priority = LOG_ERR; break; case eLogError : priority = LOG_ERR; break;
case eLogWarning : priority = LOG_WARNING; break; case eLogWarning : priority = LOG_WARNING; break;
case eLogInfo : priority = LOG_INFO; break; case eLogInfo : priority = LOG_INFO; break;
@ -71,15 +74,15 @@ namespace log {
void Log::Start () void Log::Start ()
{ {
if (!m_IsRunning) if (!m_IsRunning)
{ {
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Log::Run, this)); m_Thread = new std::thread (std::bind (&Log::Run, this));
} }
} }
void Log::Stop () void Log::Stop ()
{ {
switch (m_Destination) switch (m_Destination)
{ {
#ifndef _WIN32 #ifndef _WIN32
case eLogSyslog : case eLogSyslog :
@ -97,15 +100,16 @@ namespace log {
m_IsRunning = false; m_IsRunning = false;
m_Queue.WakeUp (); m_Queue.WakeUp ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = nullptr; m_Thread = nullptr;
} }
} }
void Log::SetLogLevel (const std::string& level) { void Log::SetLogLevel (const std::string& level) {
if (level == "error") { m_MinLevel = eLogError; } if (level == "none") { m_MinLevel = eLogNone; }
else if (level == "error") { m_MinLevel = eLogError; }
else if (level == "warn") { m_MinLevel = eLogWarning; } else if (level == "warn") { m_MinLevel = eLogWarning; }
else if (level == "info") { m_MinLevel = eLogInfo; } else if (level == "info") { m_MinLevel = eLogInfo; }
else if (level == "debug") { m_MinLevel = eLogDebug; } else if (level == "debug") { m_MinLevel = eLogDebug; }
@ -115,7 +119,7 @@ namespace log {
} }
LogPrint(eLogInfo, "Log: min messages level set to ", level); LogPrint(eLogInfo, "Log: min messages level set to ", level);
} }
const char * Log::TimeAsString(std::time_t t) { const char * Log::TimeAsString(std::time_t t) {
if (t != m_LastTimestamp) { if (t != m_LastTimestamp) {
strftime(m_LastDateTime, sizeof(m_LastDateTime), m_TimeFormat.c_str(), localtime(&t)); strftime(m_LastDateTime, sizeof(m_LastDateTime), m_TimeFormat.c_str(), localtime(&t));
@ -129,7 +133,7 @@ namespace log {
* Unfortunately, with current startup process with late fork() this * Unfortunately, with current startup process with late fork() this
* will give us nothing but pain. Maybe later. See in NetDb as example. * will give us nothing but pain. Maybe later. See in NetDb as example.
*/ */
void Log::Process(std::shared_ptr<LogMsg> msg) void Log::Process(std::shared_ptr<LogMsg> msg)
{ {
if (!msg) return; if (!msg) return;
std::hash<std::thread::id> hasher; std::hash<std::thread::id> hasher;
@ -165,25 +169,26 @@ namespace log {
while (m_IsRunning) while (m_IsRunning)
{ {
std::shared_ptr<LogMsg> msg; std::shared_ptr<LogMsg> msg;
while (msg = m_Queue.Get ()) while ((msg = m_Queue.Get ()))
Process (msg); Process (msg);
if (m_LogStream) m_LogStream->flush(); if (m_LogStream) m_LogStream->flush();
if (m_IsRunning) if (m_IsRunning)
m_Queue.Wait (); m_Queue.Wait ();
} }
} }
void Log::Append(std::shared_ptr<i2p::log::LogMsg> & msg) void Log::Append(std::shared_ptr<i2p::log::LogMsg> & msg)
{ {
m_Queue.Put(msg); m_Queue.Put(msg);
} }
void Log::SendTo (const std::string& path) void Log::SendTo (const std::string& path)
{ {
if (m_LogStream) m_LogStream = nullptr; // close previous if (m_LogStream) m_LogStream = nullptr; // close previous
if (m_MinLevel == eLogNone) return;
auto flags = std::ofstream::out | std::ofstream::app; auto flags = std::ofstream::out | std::ofstream::app;
auto os = std::make_shared<std::ofstream> (path, flags); auto os = std::make_shared<std::ofstream> (path, flags);
if (os->is_open ()) if (os->is_open ())
{ {
m_HasColors = false; m_HasColors = false;
m_Logfile = path; m_Logfile = path;
@ -202,6 +207,7 @@ namespace log {
#ifndef _WIN32 #ifndef _WIN32
void Log::SendTo(const char *name, int facility) { void Log::SendTo(const char *name, int facility) {
if (m_MinLevel == eLogNone) return;
m_HasColors = false; m_HasColors = false;
m_Destination = eLogSyslog; m_Destination = eLogSyslog;
m_LogStream = nullptr; m_LogStream = nullptr;

5
libi2pd/Log.h

@ -25,10 +25,11 @@
enum LogLevel enum LogLevel
{ {
eLogError = 0, eLogNone = 0,
eLogError,
eLogWarning, eLogWarning,
eLogInfo, eLogInfo,
eLogDebug, eLogDebug,
eNumLogLevels eNumLogLevels
}; };

4
libi2pd/NTCPSession.cpp

@ -1247,7 +1247,7 @@ namespace transport
return; return;
} }
buff[4] = (uint8_t) addrsize; buff[4] = (uint8_t) addrsize;
memcpy(buff+4, host.c_str(), addrsize); memcpy(buff+5, host.c_str(), addrsize);
} }
htobe16buf(buff+sz, port); htobe16buf(buff+sz, port);
sz += 2; sz += 2;
@ -1259,7 +1259,7 @@ namespace transport
} }
}); });
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, sz), [=](const boost::system::error_code & e, std::size_t transferred) { boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff, 10), [=](const boost::system::error_code & e, std::size_t transferred) {
if(e) if(e)
{ {
LogPrint(eLogError, "NTCP: socks proxy read error ", e.message()); LogPrint(eLogError, "NTCP: socks proxy read error ", e.message());

236
libi2pd/Reseed.cpp

@ -489,6 +489,27 @@ namespace data
std::string Reseeder::HttpsRequest (const std::string& address) std::string Reseeder::HttpsRequest (const std::string& address)
{ {
i2p::http::URL proxyUrl;
std::string proxy; i2p::config::GetOption("reseed.proxy", proxy);
// check for proxy url
if(proxy.size()) {
// parse
if(proxyUrl.parse(proxy)) {
if (proxyUrl.schema == "http" && !proxyUrl.port) {
proxyUrl.port = 80;
} else if (proxyUrl.schema == "socks" && !proxyUrl.port) {
proxyUrl.port = 1080;
}
// check for valid proxy url schema
if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") {
LogPrint(eLogError, "Reseed: bad proxy url: ", proxy);
return "";
}
} else {
LogPrint(eLogError, "Reseed: bad proxy url: ", proxy);
return "";
}
}
i2p::http::URL url; i2p::http::URL url;
if (!url.parse(address)) { if (!url.parse(address)) {
LogPrint(eLogError, "Reseed: failed to parse url: ", address); LogPrint(eLogError, "Reseed: failed to parse url: ", address);
@ -500,68 +521,185 @@ namespace data
boost::asio::io_service service; boost::asio::io_service service;
boost::system::error_code ecode; boost::system::error_code ecode;
auto it = boost::asio::ip::tcp::resolver(service).resolve (
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode); boost::asio::ssl::context ctx(service, boost::asio::ssl::context::sslv23);
if (!ecode) ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> s(service, ctx);
if(proxyUrl.schema.size())
{ {
boost::asio::ssl::context ctx(service, boost::asio::ssl::context::sslv23); // proxy connection
ctx.set_verify_mode(boost::asio::ssl::context::verify_none); auto it = boost::asio::ip::tcp::resolver(service).resolve (
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> s(service, ctx); boost::asio::ip::tcp::resolver::query (proxyUrl.host, std::to_string(proxyUrl.port)), ecode);
s.lowest_layer().connect (*it, ecode); if(!ecode)
if (!ecode)
{ {
SSL_set_tlsext_host_name(s.native_handle(), url.host.c_str ()); s.lowest_layer().connect(*it, ecode);
s.handshake (boost::asio::ssl::stream_base::client, ecode); if(!ecode)
if (!ecode)
{ {
LogPrint (eLogDebug, "Reseed: Connected to ", url.host, ":", url.port); auto & sock = s.next_layer();
i2p::http::HTTPReq req; if(proxyUrl.schema == "http")
req.uri = url.to_string(); {
req.AddHeader("User-Agent", "Wget/1.11.4"); i2p::http::HTTPReq proxyReq;
req.AddHeader("Connection", "close"); i2p::http::HTTPRes proxyRes;
s.write_some (boost::asio::buffer (req.to_string())); proxyReq.method = "CONNECT";
// read response proxyReq.version = "HTTP/1.1";
std::stringstream rs; proxyReq.uri = url.host + ":" + std::to_string(url.port);
char recv_buf[1024]; size_t l = 0;
do { boost::asio::streambuf writebuf, readbuf;
l = s.read_some (boost::asio::buffer (recv_buf, sizeof(recv_buf)), ecode);
if (l) rs.write (recv_buf, l); std::ostream out(&writebuf);
} while (!ecode && l); out << proxyReq.to_string();
// process response
std::string data = rs.str(); boost::asio::write(sock, writebuf.data(), boost::asio::transfer_all(), ecode);
i2p::http::HTTPRes res; if (ecode)
int len = res.parse(data); {
if (len <= 0) { sock.close();
LogPrint(eLogWarning, "Reseed: incomplete/broken response from ", url.host); LogPrint(eLogError, "Reseed: HTTP CONNECT write error: ", ecode.message());
return ""; return "";
} }
if (res.code != 200) { boost::asio::read_until(sock, readbuf, "\r\n\r\n", ecode);
LogPrint(eLogError, "Reseed: failed to reseed from ", url.host, ", http code ", res.code); if (ecode)
return ""; {
sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message());
return "";
}
if(proxyRes.parse(boost::asio::buffer_cast<const char *>(readbuf.data()), readbuf.size()) <= 0)
{
sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply");
return "";
}
if(proxyRes.code != 200)
{
sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT got bad status: ", proxyRes.code);
return "";
}
} }
data.erase(0, len); /* drop http headers from response */ else
LogPrint(eLogDebug, "Reseed: got ", data.length(), " bytes of data from ", url.host); {
if (res.is_chunked()) { // assume socks if not http, is checked before this for other types
std::stringstream in(data), out; // TODO: support username/password auth etc
if (!i2p::http::MergeChunkedResponse(in, out)) { uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00};
LogPrint(eLogWarning, "Reseed: failed to merge chunked response from ", url.host); uint8_t hs_readbuf[2];
boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode);
if(ecode)
{
sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message());
return "";
}
boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode);
if(ecode)
{
sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message());
return "";
}
size_t sz = 0;
uint8_t buf[256];
buf[0] = 0x05;
buf[1] = 0x01;
buf[2] = 0x00;
buf[3] = 0x03;
sz += 4;
size_t hostsz = url.host.size();
if(1 + 2 + hostsz + sz > sizeof(buf))
{
sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host);
return "";
}
buf[4] = (uint8_t) hostsz;
memcpy(buf+5, url.host.c_str(), hostsz);
sz += hostsz + 1;
htobe16buf(buf+sz, url.port);
sz += 2;
boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode);
if(ecode)
{
sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message());
return "";
}
boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode);
if(ecode)
{
sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message());
return "";
}
if(buf[1] != 0x00)
{
sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1]));
return ""; return "";
} }
LogPrint(eLogDebug, "Reseed: got ", data.length(), "(", out.tellg(), ") bytes of data from ", url.host);
data = out.str();
} }
return data;
} }
else }
LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ()); }
else
{
// direct connection
auto it = boost::asio::ip::tcp::resolver(service).resolve (
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
if(!ecode)
s.lowest_layer().connect (*it, ecode);
}
if (!ecode)
{
SSL_set_tlsext_host_name(s.native_handle(), url.host.c_str ());
s.handshake (boost::asio::ssl::stream_base::client, ecode);
if (!ecode)
{
LogPrint (eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
i2p::http::HTTPReq req;
req.uri = url.to_string();
req.AddHeader("User-Agent", "Wget/1.11.4");
req.AddHeader("Connection", "close");
s.write_some (boost::asio::buffer (req.to_string()));
// read response
std::stringstream rs;
char recv_buf[1024]; size_t l = 0;
do {
l = s.read_some (boost::asio::buffer (recv_buf, sizeof(recv_buf)), ecode);
if (l) rs.write (recv_buf, l);
} while (!ecode && l);
// process response
std::string data = rs.str();
i2p::http::HTTPRes res;
int len = res.parse(data);
if (len <= 0) {
LogPrint(eLogWarning, "Reseed: incomplete/broken response from ", url.host);
return "";
}
if (res.code != 200) {
LogPrint(eLogError, "Reseed: failed to reseed from ", url.host, ", http code ", res.code);
return "";
}
data.erase(0, len); /* drop http headers from response */
LogPrint(eLogDebug, "Reseed: got ", data.length(), " bytes of data from ", url.host);
if (res.is_chunked()) {
std::stringstream in(data), out;
if (!i2p::http::MergeChunkedResponse(in, out)) {
LogPrint(eLogWarning, "Reseed: failed to merge chunked response from ", url.host);
return "";
}
LogPrint(eLogDebug, "Reseed: got ", data.length(), "(", out.tellg(), ") bytes of data from ", url.host);
data = out.str();
}
return data;
} }
else else
LogPrint (eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message ()); LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ());
} }
else else
LogPrint (eLogError, "Reseed: Couldn't resolve address ", url.host, ": ", ecode.message ()); LogPrint (eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message ());
return ""; return "";
} }
} }
} }

7
libi2pd/RouterInfo.cpp

@ -132,6 +132,13 @@ namespace data
} }
if (verifySignature) if (verifySignature)
{ {
// reject RSA signatures
if (m_RouterIdentity->IsRSA ())
{
LogPrint (eLogError, "RouterInfo: RSA signature type is not allowed");
m_IsUnreachable = true;
return;
}
// verify signature // verify signature
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen (); int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l)) if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))

40
libi2pd/Streaming.cpp

@ -62,6 +62,7 @@ namespace stream
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service),
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO),
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0) m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0)
{ {
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
@ -73,7 +74,8 @@ namespace stream
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_WindowSize (MIN_WINDOW_SIZE), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_WindowSize (MIN_WINDOW_SIZE),
m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0) m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0)
{ {
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
} }
@ -161,7 +163,7 @@ namespace stream
{ {
m_IsAckSendScheduled = true; m_IsAckSendScheduled = true;
auto ackTimeout = m_RTT/10; auto ackTimeout = m_RTT/10;
if (ackTimeout > ACK_SEND_TIMEOUT) ackTimeout = ACK_SEND_TIMEOUT; if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ackTimeout)); m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ackTimeout));
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
@ -199,7 +201,7 @@ namespace stream
{ {
// wait for SYN // wait for SYN
m_IsAckSendScheduled = true; m_IsAckSendScheduled = true;
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ACK_SEND_TIMEOUT)); m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(SYN_TIMEOUT));
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer, m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
@ -228,6 +230,13 @@ namespace stream
if (flags & PACKET_FLAG_FROM_INCLUDED) if (flags & PACKET_FLAG_FROM_INCLUDED)
{ {
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ()); m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, packet->GetOptionSize ());
if (m_RemoteIdentity->IsRSA ())
{
LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded");
m_LocalDestination.DeletePacket (packet);
Terminate ();
return;
}
optionData += m_RemoteIdentity->GetFullLen (); optionData += m_RemoteIdentity->GetFullLen ();
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet)
LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); LogPrint (eLogDebug, "Streaming: Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), ", sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
@ -244,16 +253,23 @@ namespace stream
{ {
uint8_t signature[256]; uint8_t signature[256];
auto signatureLen = m_RemoteIdentity->GetSignatureLen (); auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
memcpy (signature, optionData, signatureLen); if(signatureLen <= sizeof(signature))
memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature))
{ {
LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID); memcpy (signature, optionData, signatureLen);
Close (); memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
flags |= PACKET_FLAG_CLOSE; if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature))
{
LogPrint (eLogError, "Streaming: Signature verification failed, sSID=", m_SendStreamID, ", rSID=", m_RecvStreamID);
Close ();
flags |= PACKET_FLAG_CLOSE;
}
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
optionData += signatureLen;
}
else
{
LogPrint(eLogError, "Streaming: Signature too big, ", signatureLen, " bytes");
} }
memcpy (const_cast<uint8_t *>(optionData), signature, signatureLen);
optionData += signatureLen;
} }
packet->offset = packet->GetPayload () - packet->buf; packet->offset = packet->GetPayload () - packet->buf;
@ -798,7 +814,7 @@ namespace stream
{ {
if (m_LastReceivedSequenceNumber < 0) if (m_LastReceivedSequenceNumber < 0)
{ {
LogPrint (eLogWarning, "Streaming: SYN has not been received after ", ACK_SEND_TIMEOUT, " milliseconds after follow on, terminate rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID); LogPrint (eLogWarning, "Streaming: SYN has not been received after ", SYN_TIMEOUT, " milliseconds after follow on, terminate rSID=", m_RecvStreamID, ", sSID=", m_SendStreamID);
m_Status = eStreamStatusReset; m_Status = eStreamStatusReset;
Close (); Close ();
return; return;

4
libi2pd/Streaming.h

@ -42,13 +42,13 @@ namespace stream
const size_t STREAMING_MTU = 1730; const size_t STREAMING_MTU = 1730;
const size_t MAX_PACKET_SIZE = 4096; const size_t MAX_PACKET_SIZE = 4096;
const size_t COMPRESSION_THRESHOLD_SIZE = 66; const size_t COMPRESSION_THRESHOLD_SIZE = 66;
const int ACK_SEND_TIMEOUT = 200; // in milliseconds
const int MAX_NUM_RESEND_ATTEMPTS = 6; const int MAX_NUM_RESEND_ATTEMPTS = 6;
const int WINDOW_SIZE = 6; // in messages const int WINDOW_SIZE = 6; // in messages
const int MIN_WINDOW_SIZE = 1; const int MIN_WINDOW_SIZE = 1;
const int MAX_WINDOW_SIZE = 128; const int MAX_WINDOW_SIZE = 128;
const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds
const int INITIAL_RTO = 9000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds
const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds
const size_t MAX_PENDING_INCOMING_BACKLOG = 128; const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
const int MAX_RECEIVE_TIMEOUT = 30; // in seconds const int MAX_RECEIVE_TIMEOUT = 30; // in seconds
@ -242,7 +242,7 @@ namespace stream
std::mutex m_SendBufferMutex; std::mutex m_SendBufferMutex;
SendBufferQueue m_SendBuffer; SendBufferQueue m_SendBuffer;
int m_WindowSize, m_RTT, m_RTO; int m_WindowSize, m_RTT, m_RTO, m_AckDelay;
uint64_t m_LastWindowSizeIncreaseTime; uint64_t m_LastWindowSizeIncreaseTime;
int m_NumResendAttempts; int m_NumResendAttempts;
}; };

2
libi2pd/version.h

@ -7,7 +7,7 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 15 #define I2PD_VERSION_MINOR 16
#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)

30
libi2pd_client/ClientContext.cpp

@ -71,12 +71,12 @@ namespace client
} }
try try
{ {
m_HttpProxy = new i2p::proxy::HTTPProxy(httpProxyAddr, httpProxyPort, httpOutProxyURL, localDestination); m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, localDestination);
m_HttpProxy->Start(); m_HttpProxy->Start();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
} }
} }
@ -107,7 +107,8 @@ namespace client
} }
try try
{ {
m_SocksProxy = new i2p::proxy::SOCKSProxy(socksProxyAddr, socksProxyPort, socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination); m_SocksProxy = new i2p::proxy::SOCKSProxy("SOCKS", socksProxyAddr, socksProxyPort,
socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination);
m_SocksProxy->Start(); m_SocksProxy->Start();
} }
catch (std::exception& e) catch (std::exception& e)
@ -283,6 +284,13 @@ namespace client
bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename,
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType) i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType)
{ {
if (filename == "transient")
{
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
return true;
}
bool success = true; bool success = true;
std::string fullPath = i2p::fs::DataDirPath (filename); std::string fullPath = i2p::fs::DataDirPath (filename);
std::ifstream s(fullPath, std::ifstream::binary); std::ifstream s(fullPath, std::ifstream::binary);
@ -341,10 +349,11 @@ namespace client
return infos; return infos;
} }
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic,
const std::map<std::string, std::string> * params) i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
const std::map<std::string, std::string> * params)
{ {
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params); auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
std::unique_lock<std::mutex> l(m_DestinationsMutex); std::unique_lock<std::mutex> l(m_DestinationsMutex);
m_Destinations[localDestination->GetIdentHash ()] = localDestination; m_Destinations[localDestination->GetIdentHash ()] = localDestination;
@ -422,6 +431,7 @@ namespace client
options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND); options[I2CP_PARAM_TAGS_TO_SEND] = GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND);
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY); options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY);
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY); options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY);
options[I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY] = GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY);
} }
void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const
@ -438,7 +448,7 @@ namespace client
if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value)) if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value))
options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value; options[I2CP_PARAM_MIN_TUNNEL_LATENCY] = value;
if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value))
options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value; options[I2CP_PARAM_MAX_TUNNEL_LATENCY] = value;
} }
void ClientContext::ReadTunnels () void ClientContext::ReadTunnels ()
@ -533,14 +543,14 @@ namespace client
if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS) if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS)
{ {
// socks proxy // socks proxy
clientTunnel = new i2p::proxy::SOCKSProxy(address, port, false, "", destinationPort, localDestination); clientTunnel = new i2p::proxy::SOCKSProxy(name, address, port, false, "", destinationPort, localDestination);
clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint (); clientEndpoint = ((i2p::proxy::SOCKSProxy*)clientTunnel)->GetLocalEndpoint ();
} }
else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY) else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY)
{ {
// http proxy // http proxy
std::string outproxy = section.second.get("outproxy", ""); std::string outproxy = section.second.get("outproxy", "");
clientTunnel = new i2p::proxy::HTTPProxy(address, port, outproxy, localDestination); clientTunnel = new i2p::proxy::HTTPProxy(name, address, port, outproxy, localDestination);
clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint (); clientEndpoint = ((i2p::proxy::HTTPProxy*)clientTunnel)->GetLocalEndpoint ();
} }
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS) else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)

13
libi2pd_client/ClientContext.h

@ -64,10 +64,12 @@ namespace client
void ReloadConfig (); void ReloadConfig ();
std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; }; std::shared_ptr<ClientDestination> GetSharedLocalDestination () const { return m_SharedLocalDestination; };
std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1, std::shared_ptr<ClientDestination> CreateNewLocalDestination (bool isPublic = false, // transient
const std::map<std::string, std::string> * params = nullptr); // transient i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1,
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
const std::map<std::string, std::string> * params = nullptr); // used by SAM only
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
const std::map<std::string, std::string> * params = nullptr); const std::map<std::string, std::string> * params = nullptr);
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr); std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr);
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination); void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const; std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
@ -76,6 +78,7 @@ namespace client
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL);
AddressBook& GetAddressBook () { return m_AddressBook; }; AddressBook& GetAddressBook () { return m_AddressBook; };
const BOBCommandChannel * GetBOBCommandChannel () const { return m_BOBCommandChannel; };
const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; const SAMBridge * GetSAMBridge () const { return m_SamBridge; };
const I2CPServer * GetI2CPServer () const { return m_I2CPServer; }; const I2CPServer * GetI2CPServer () const { return m_I2CPServer; };
@ -87,8 +90,8 @@ namespace client
template<typename Section, typename Type> template<typename Section, typename Type>
std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const; std::string GetI2CPOption (const Section& section, const std::string& name, const Type& value) const;
template<typename Section> template<typename Section>
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const; void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const; // for tunnels
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const; void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const; // for HTTP and SOCKS proxy
void CleanupUDP(const boost::system::error_code & ecode); void CleanupUDP(const boost::system::error_code & ecode);
void ScheduleCleanupUDP(); void ScheduleCleanupUDP();

48
libi2pd_client/HTTPProxy.cpp

@ -54,7 +54,7 @@ namespace proxy {
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void Terminate(); void Terminate();
void AsyncSockRead(); void AsyncSockRead();
bool ExtractAddressHelper(i2p::http::URL & url, std::string & b64); bool ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm);
void SanitizeHTTPRequest(i2p::http::HTTPReq & req); void SanitizeHTTPRequest(i2p::http::HTTPReq & req);
void SentHTTPFailed(const boost::system::error_code & ecode); void SentHTTPFailed(const boost::system::error_code & ecode);
void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream); void HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream);
@ -182,13 +182,15 @@ namespace proxy {
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64) bool HTTPReqHandler::ExtractAddressHelper(i2p::http::URL & url, std::string & b64, bool & confirm)
{ {
confirm = false;
const char *param = "i2paddresshelper="; const char *param = "i2paddresshelper=";
std::size_t pos = url.query.find(param); std::size_t pos = url.query.find(param);
std::size_t len = std::strlen(param); std::size_t len = std::strlen(param);
std::map<std::string, std::string> params; std::map<std::string, std::string> params;
if (pos == std::string::npos) if (pos == std::string::npos)
return false; /* not found */ return false; /* not found */
if (!url.parse_query(params)) if (!url.parse_query(params))
@ -197,6 +199,8 @@ namespace proxy {
std::string value = params["i2paddresshelper"]; std::string value = params["i2paddresshelper"];
len += value.length(); len += value.length();
b64 = i2p::http::UrlDecode(value); b64 = i2p::http::UrlDecode(value);
// if we need update exists, request formed with update param
if (params["update"] == "true") { len += std::strlen("&update=true"); confirm = true; }
url.query.replace(pos, len, ""); url.query.replace(pos, len, "");
return true; return true;
} }
@ -242,24 +246,36 @@ namespace proxy {
/* parsing success, now let's look inside request */ /* parsing success, now let's look inside request */
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_ClientRequest.uri); LogPrint(eLogDebug, "HTTPProxy: requested: ", m_ClientRequest.uri);
m_RequestURL.parse(m_ClientRequest.uri); m_RequestURL.parse(m_ClientRequest.uri);
bool m_Confirm;
if (ExtractAddressHelper(m_RequestURL, b64)) if (ExtractAddressHelper(m_RequestURL, b64, m_Confirm))
{ {
bool addresshelper; i2p::config::GetOption("httpproxy.addresshelper", addresshelper); bool addresshelper; i2p::config::GetOption("httpproxy.addresshelper", addresshelper);
if (!addresshelper) if (!addresshelper)
{ {
LogPrint(eLogWarning, "HTTPProxy: addresshelper disabled"); LogPrint(eLogWarning, "HTTPProxy: addresshelper request rejected");
GenericProxyError("Invalid request", "adddresshelper is not supported"); GenericProxyError("Invalid request", "addresshelper is not supported");
return true; return true;
} }
i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, b64); if (!i2p::client::context.GetAddressBook ().FindAddress (m_RequestURL.host) || m_Confirm)
LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", m_RequestURL.host); {
std::string full_url = m_RequestURL.to_string(); i2p::client::context.GetAddressBook ().InsertAddress (m_RequestURL.host, b64);
std::stringstream ss; LogPrint (eLogInfo, "HTTPProxy: added b64 from addresshelper for ", m_RequestURL.host);
ss << "Host " << m_RequestURL.host << " added to router's addressbook from helper. " std::string full_url = m_RequestURL.to_string();
<< "Click <a href=\"" << full_url << "\">here</a> to proceed."; std::stringstream ss;
GenericProxyInfo("Addresshelper found", ss.str().c_str()); ss << "Host " << m_RequestURL.host << " added to router's addressbook from helper. "
return true; /* request processed */ << "Click <a href=\"" << full_url << "\">here</a> to proceed.";
GenericProxyInfo("Addresshelper found", ss.str().c_str());
return true; /* request processed */
}
else
{
std::stringstream ss;
ss << "Host " << m_RequestURL.host << " <font color=red>already in router's addressbook</font>. "
<< "Click <a href=\"" << m_RequestURL.query << "?i2paddresshelper=" << b64 << "&update=true\">here</a> to update record.";
GenericProxyInfo("Addresshelper found", ss.str().c_str());
return true; /* request processed */
}
} }
std::string dest_host; std::string dest_host;
uint16_t dest_port; uint16_t dest_port;
@ -570,7 +586,7 @@ namespace proxy {
{ {
if (!stream) { if (!stream) {
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
GenericProxyError("Host is down", "Can't create connection to requested host, it may be down"); GenericProxyError("Host is down", "Can't create connection to requested host, it may be down. Please try again later.");
return; return;
} }
if (Kill()) if (Kill())
@ -582,9 +598,9 @@ namespace proxy {
Done (shared_from_this()); Done (shared_from_this());
} }
HTTPProxy::HTTPProxy(const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination): HTTPProxy::HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()), TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()),
m_OutproxyUrl(outproxy) m_Name (name), m_OutproxyUrl(outproxy)
{ {
} }

9
libi2pd_client/HTTPProxy.h

@ -6,9 +6,9 @@ namespace proxy {
class HTTPProxy: public i2p::client::TCPIPAcceptor class HTTPProxy: public i2p::client::TCPIPAcceptor
{ {
public: public:
HTTPProxy(const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination); HTTPProxy(const std::string& name, const std::string& address, int port, const std::string & outproxy, std::shared_ptr<i2p::client::ClientDestination> localDestination);
HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) : HTTPProxy(const std::string& name, const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr) :
HTTPProxy(address, port, "", localDestination) {} ; HTTPProxy(name, address, port, "", localDestination) {} ;
~HTTPProxy() {}; ~HTTPProxy() {};
std::string GetOutproxyURL() const { return m_OutproxyUrl; } std::string GetOutproxyURL() const { return m_OutproxyUrl; }
@ -16,9 +16,10 @@ namespace proxy {
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket); std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "HTTP Proxy"; } const char* GetName() { return m_Name.c_str (); }
private: private:
std::string m_Name;
std::string m_OutproxyUrl; std::string m_OutproxyUrl;
}; };
} // http } // http

12
libi2pd_client/SAM.cpp

@ -489,11 +489,15 @@ namespace client
ExtractParams (buf, params); ExtractParams (buf, params);
// extract signature type // extract signature type
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1; i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
auto it = params.find (SAM_PARAM_SIGNATURE_TYPE); auto it = params.find (SAM_PARAM_SIGNATURE_TYPE);
if (it != params.end ()) if (it != params.end ())
// TODO: extract string values // TODO: extract string values
signatureType = std::stoi(it->second); signatureType = std::stoi(it->second);
auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType); it = params.find (SAM_PARAM_CRYPTO_TYPE);
if (it != params.end ())
cryptoType = std::stoi(it->second);
auto keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
#ifdef _MSC_VER #ifdef _MSC_VER
size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY,
keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ());
@ -911,14 +915,18 @@ namespace client
{ {
// extract signature type // extract signature type
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1; i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
if (params) if (params)
{ {
auto it = params->find (SAM_PARAM_SIGNATURE_TYPE); auto it = params->find (SAM_PARAM_SIGNATURE_TYPE);
if (it != params->end ()) if (it != params->end ())
// TODO: extract string values // TODO: extract string values
signatureType = std::stoi(it->second); signatureType = std::stoi(it->second);
it = params->find (SAM_PARAM_CRYPTO_TYPE);
if (it != params->end ())
cryptoType = std::stoi(it->second);
} }
localDestination = i2p::client::context.CreateNewLocalDestination (true, signatureType, params); localDestination = i2p::client::context.CreateNewLocalDestination (true, signatureType, cryptoType, params);
} }
if (localDestination) if (localDestination)
{ {

1
libi2pd_client/SAM.h

@ -53,6 +53,7 @@ namespace client
const char SAM_PARAM_DESTINATION[] = "DESTINATION"; const char SAM_PARAM_DESTINATION[] = "DESTINATION";
const char SAM_PARAM_NAME[] = "NAME"; const char SAM_PARAM_NAME[] = "NAME";
const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE"; const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
const char SAM_PARAM_CRYPTO_TYPE[] = "CRYPTO_TYPE";
const char SAM_PARAM_SIZE[] = "SIZE"; const char SAM_PARAM_SIZE[] = "SIZE";
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_STREAM[] = "STREAM";

7
libi2pd_client/SOCKS.cpp

@ -768,9 +768,10 @@ namespace proxy
shared_from_this(), std::placeholders::_1, std::placeholders::_2)); shared_from_this(), std::placeholders::_1, std::placeholders::_2));
} }
SOCKSServer::SOCKSServer(const std::string& address, int port, bool outEnable, const std::string& outAddress, uint16_t outPort, SOCKSServer::SOCKSServer(const std::string& name, const std::string& address, int port,
std::shared_ptr<i2p::client::ClientDestination> localDestination) : bool outEnable, const std::string& outAddress, uint16_t outPort,
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()) std::shared_ptr<i2p::client::ClientDestination> localDestination) :
TCPIPAcceptor (address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()), m_Name (name)
{ {
m_UseUpstreamProxy = false; m_UseUpstreamProxy = false;
if (outAddress.length() > 0 && outEnable) if (outAddress.length() > 0 && outEnable)

6
libi2pd_client/SOCKS.h

@ -14,7 +14,7 @@ namespace proxy
class SOCKSServer: public i2p::client::TCPIPAcceptor class SOCKSServer: public i2p::client::TCPIPAcceptor
{ {
public: public:
SOCKSServer(const std::string& address, int port, bool outEnable, const std::string& outAddress, uint16_t outPort, SOCKSServer(const std::string& name, const std::string& address, int port, bool outEnable, const std::string& outAddress, uint16_t outPort,
std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr); std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~SOCKSServer() {}; ~SOCKSServer() {};
@ -23,9 +23,11 @@ namespace proxy
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket); std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "SOCKS"; } const char* GetName() { return m_Name.c_str (); }
private: private:
std::string m_Name;
std::string m_UpstreamProxyAddress; std::string m_UpstreamProxyAddress;
uint16_t m_UpstreamProxyPort; uint16_t m_UpstreamProxyPort;
bool m_UseUpstreamProxy; bool m_UseUpstreamProxy;

4
qt/i2pd_qt/.gitignore vendored

@ -3,5 +3,7 @@ moc_*
ui_* ui_*
qrc_* qrc_*
i2pd_qt i2pd_qt
Makefile Makefile*
*.stash *.stash
object_script.*
i2pd_qt_plugin_import.cpp

7
qt/i2pd_qt/SignatureTypeComboboxFactory.h

@ -70,13 +70,6 @@ public:
addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_TC26_A_512_GOSTR3411_512", 0), SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512); //10 addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_TC26_A_512_GOSTR3411_512", 0), SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512); //10
if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;} if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;}
++index; ++index;
// TODO: remove later
addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST", 0), SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST); //65281
if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;}
++index;
addItem(signatureTypeCombobox, QApplication::translate("signatureTypeCombobox", "GOSTR3410_TC26_A_512_GOSTR3411_512_TEST", 0), SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST); //65282
if(selectedSigType==SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST){signatureTypeCombobox->setCurrentIndex(index);foundSelected=true;}
++index;
if(!foundSelected){ if(!foundSelected){
addItem(signatureTypeCombobox, QString::number(selectedSigType), selectedSigType); //unknown sigtype addItem(signatureTypeCombobox, QString::number(selectedSigType), selectedSigType); //unknown sigtype
signatureTypeCombobox->setCurrentIndex(index); signatureTypeCombobox->setCurrentIndex(index);

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.15.0" android:versionCode="2" android:installLocation="auto"> <manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.16.0" android:versionCode="2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/> <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" --> <!-- <application android:hardwareAccelerated="true" -->

11
qt/i2pd_qt/mainwindow.cpp

@ -155,8 +155,9 @@ MainWindow::MainWindow(QWidget *parent) :
uiSettings->logDestinationComboBox->clear(); uiSettings->logDestinationComboBox->clear();
uiSettings->logDestinationComboBox->insertItems(0, QStringList() uiSettings->logDestinationComboBox->insertItems(0, QStringList()
<< QApplication::translate("MainWindow", "stdout", 0) << QApplication::translate("MainWindow", "syslog", 0)
<< QApplication::translate("MainWindow", "file", 0) << QApplication::translate("MainWindow", "stdout", 0)
<< QApplication::translate("MainWindow", "file", 0)
); );
initLogDestinationCombobox( OPTION("","log",[]{return "";}), uiSettings->logDestinationComboBox); initLogDestinationCombobox( OPTION("","log",[]{return "";}), uiSettings->logDestinationComboBox);
@ -302,9 +303,9 @@ MainWindow::MainWindow(QWidget *parent) :
} }
void MainWindow::logDestinationComboBoxValueChanged(const QString & text) { void MainWindow::logDestinationComboBoxValueChanged(const QString & text) {
bool stdout = text==QString("stdout"); bool fileEnabled = text==QString("file");
uiSettings->logFileLineEdit->setEnabled(!stdout); uiSettings->logFileLineEdit->setEnabled(fileEnabled);
uiSettings->logFileBrowsePushButton->setEnabled(!stdout); uiSettings->logFileBrowsePushButton->setEnabled(fileEnabled);
} }

1
qt/i2pd_qt/mainwindow.h

@ -224,7 +224,6 @@ public:
} }
virtual void saveToStringStream(std::stringstream& out){ virtual void saveToStringStream(std::stringstream& out){
std::string logDest = comboBox->currentText().toStdString(); std::string logDest = comboBox->currentText().toStdString();
if(logDest==std::string("stdout"))logDest="";
optionValue=logDest; optionValue=logDest;
MainWindowItem::saveToStringStream(out); MainWindowItem::saveToStringStream(out);
} }

Loading…
Cancel
Save