mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-02-05 04:23:48 +01:00
commit
305a654a37
48 changed files with 934 additions and 553 deletions
25
ChangeLog
25
ChangeLog
|
@ -1,6 +1,31 @@
|
||||||
# for this file format description,
|
# for this file format description,
|
||||||
# see https://github.com/olivierlacan/keep-a-changelog
|
# see https://github.com/olivierlacan/keep-a-changelog
|
||||||
|
|
||||||
|
## [2.33.0] - 2020-08-24
|
||||||
|
### Added
|
||||||
|
- Shared transient addresses
|
||||||
|
- crypto.ratchet.inboundTags paramater
|
||||||
|
- Multiple encryption keys through I2CP
|
||||||
|
- Pre-calculated x25519 ephemeral keys
|
||||||
|
- Change datagram routing path if nothing comes back in 10 seconds
|
||||||
|
- Shared routing path for datagram session
|
||||||
|
### Changed
|
||||||
|
- UDP tunnels send mix of repliable and raw datagrams in bulk
|
||||||
|
- Encrypt SSU packet again upon resend
|
||||||
|
- Start new tunnel message if remaining buffer is too small
|
||||||
|
- Use LeaseSet2 for ECIES-X25519-AEAD-Ratchet automatically
|
||||||
|
- Save new ECIES-X25519-AEAD-Ratchet session with NSR tagset
|
||||||
|
- Generate random padding lengths for ECIES-X25519-AEAD-Ratchet in bulk
|
||||||
|
- Webconsole layout
|
||||||
|
- Reseed servers list
|
||||||
|
### Fixed
|
||||||
|
- Don't connect through terminated SAM destination
|
||||||
|
- Differentiate UDP server sessions by port
|
||||||
|
- ECIES-X25519-AEAD-Ratchet through I2CP
|
||||||
|
- Don't save invalid address to AddressBook
|
||||||
|
- ECDSA signatures names in SAM
|
||||||
|
- AppArmor profile
|
||||||
|
|
||||||
## [2.32.1] - 2020-06-02
|
## [2.32.1] - 2020-06-02
|
||||||
### Added
|
### Added
|
||||||
- Read explicit peers in tunnels config
|
- Read explicit peers in tunnels config
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define I2Pd_AppName "i2pd"
|
#define I2Pd_AppName "i2pd"
|
||||||
#define I2Pd_ver "2.32.1"
|
#define I2Pd_ver "2.33.0"
|
||||||
#define I2Pd_Publisher "PurpleI2P"
|
#define I2Pd_Publisher "PurpleI2P"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[IRC-IRC2P]
|
#[IRC-IRC2P]
|
||||||
#type = client
|
#type = client
|
||||||
#address = 127.0.0.1
|
#address = 127.0.0.1
|
||||||
#port = 6668
|
#port = 6668
|
||||||
|
|
|
@ -30,8 +30,8 @@ android {
|
||||||
applicationId "org.purplei2p.i2pd"
|
applicationId "org.purplei2p.i2pd"
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
versionCode 2321
|
versionCode 2330
|
||||||
versionName "2.32.1"
|
versionName "2.33.0"
|
||||||
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'armeabi-v7a'
|
abiFilters 'armeabi-v7a'
|
||||||
|
|
|
@ -53,15 +53,15 @@ include $(PREBUILT_STATIC_LIBRARY)
|
||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := crypto
|
LOCAL_MODULE := crypto
|
||||||
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libcrypto.a
|
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1d-clang/$(TARGET_ARCH_ABI)/lib/libcrypto.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1d-clang/include
|
||||||
include $(PREBUILT_STATIC_LIBRARY)
|
include $(PREBUILT_STATIC_LIBRARY)
|
||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := ssl
|
LOCAL_MODULE := ssl
|
||||||
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libssl.a
|
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1d-clang/$(TARGET_ARCH_ABI)/lib/libssl.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1d-clang/include
|
||||||
LOCAL_STATIC_LIBRARIES := crypto
|
LOCAL_STATIC_LIBRARIES := crypto
|
||||||
include $(PREBUILT_STATIC_LIBRARY)
|
include $(PREBUILT_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
version: 2.32.1.{build}
|
version: 2.33.0.{build}
|
||||||
pull_requests:
|
pull_requests:
|
||||||
do_not_increment_build_number: true
|
do_not_increment_build_number: true
|
||||||
branches:
|
branches:
|
||||||
|
|
|
@ -4,34 +4,22 @@
|
||||||
#
|
#
|
||||||
#include <tunables/global>
|
#include <tunables/global>
|
||||||
|
|
||||||
/usr/sbin/i2pd {
|
profile i2pd /{usr/,}sbin/i2pd {
|
||||||
#include <abstractions/base>
|
#include <abstractions/base>
|
||||||
|
#include <abstractions/openssl>
|
||||||
network inet dgram,
|
#include <abstractions/nameservice>
|
||||||
network inet stream,
|
|
||||||
network inet6 dgram,
|
|
||||||
network inet6 stream,
|
|
||||||
network netlink raw,
|
|
||||||
|
|
||||||
/etc/gai.conf r,
|
|
||||||
/etc/host.conf r,
|
|
||||||
/etc/hosts r,
|
|
||||||
/etc/nsswitch.conf r,
|
|
||||||
/etc/resolv.conf r,
|
|
||||||
/run/resolvconf/resolv.conf r,
|
|
||||||
/run/systemd/resolve/resolv.conf r,
|
|
||||||
/run/systemd/resolve/stub-resolv.conf r,
|
|
||||||
|
|
||||||
# path specific (feel free to modify if you have another paths)
|
# path specific (feel free to modify if you have another paths)
|
||||||
/etc/i2pd/** r,
|
/etc/i2pd/** r,
|
||||||
/run/i2pd/i2pd.pid rwk,
|
|
||||||
/var/lib/i2pd/** rw,
|
/var/lib/i2pd/** rw,
|
||||||
/var/log/i2pd/i2pd.log w,
|
/var/log/i2pd/i2pd.log w,
|
||||||
/var/run/i2pd/i2pd.pid rwk,
|
/{var/,}run/i2pd/i2pd.pid rwk,
|
||||||
/usr/sbin/i2pd mr,
|
/{usr/,}sbin/i2pd mr,
|
||||||
/usr/share/i2pd/** r,
|
@{system_share_dirs}/i2pd/** r,
|
||||||
|
|
||||||
# user homedir (if started not by init.d or systemd)
|
# user homedir (if started not by init.d or systemd)
|
||||||
owner @{HOME}/.i2pd/ rw,
|
owner @{HOME}/.i2pd/ rw,
|
||||||
owner @{HOME}/.i2pd/** rwk,
|
owner @{HOME}/.i2pd/** rwk,
|
||||||
|
|
||||||
|
#include if exists <local/usr.sbin.i2pd>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFezCCA2OgAwIBAgIEUQYyQjANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY
|
|
||||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
|
||||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOYnVnbWVAbWFpbC5p
|
|
||||||
MnAwHhcNMTQxMTA2MDkxMTE0WhcNMjQxMTA1MDkxMTE0WjBuMQswCQYDVQQGEwJY
|
|
||||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
|
||||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOYnVnbWVAbWFpbC5p
|
|
||||||
MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCrThOH0eSDT0VnCSBC
|
|
||||||
sqYmAydWH+O8eNttDXr2mSvZLhvAW+6/xHTkKhaWvkIvvS0Vh8hujMnD90Cgp4Fk
|
|
||||||
TKCxMj9K527o5xIZwWW05OevbjlBwIpVLO1PjmsfsoD1nIX14eEzJSEoAulKsv7V
|
|
||||||
jGUC/6hC11mmVvH9buQLSRv6sCjuAcMszmw3TAD+XYBIs+z57KuwYXtX3+OA543c
|
|
||||||
l1/ZKLYkkwY8cwzZqWDVWqTKP5TfVae58t40HhJk3bOsr21FZsaOjlmao3GO+d/3
|
|
||||||
exKuUGJRcolSqskL3sZ1ovFqko81obvvx0upI0YA0iMr/NRGl3VPuf/LJvRppYGc
|
|
||||||
LsJHgy9TIgtHvaXRi5Nt4CbKl9sZh/7WkkTTI5YGvevu00btlabAN+DSAZZqdsB3
|
|
||||||
wY8HhM1MHiA9SWsqwU65TwErcRrjNna2FiDHEu0xk5+/iAGl6CSKHZBmNcYKXSv8
|
|
||||||
cwShB0jjmciK0a05nC638RPgj0fng7KRrSglyzfjXRrljmZ40LSBL/GGMZMWpOM7
|
|
||||||
mEsBH5UZJ/2BEmjc9X9257zBdx8BK8y1TXpAligpNBsERcTw1WP1PJ35einZvlXW
|
|
||||||
qI3GwMf0sl26sn+evcK0gDl27jVDZ45MtNQEq64M4NV3Tn9zq0eg/39YvjVeqrI5
|
|
||||||
l7sxmYqYGR6BuSncwdc4x+t6swIDAQABoyEwHzAdBgNVHQ4EFgQU/REZ7NMbVZHr
|
|
||||||
Xkao6Q8Ccqv2kAMwDQYJKoZIhvcNAQENBQADggIBACc2YjLVNbl1kJUdg2klCLJt
|
|
||||||
5LjNTiIZa2Cha5GStlC/lyoRRge6+q/y9TN3tTptlzLPS9pI9EE1GfIQaE+HAk+e
|
|
||||||
/bC3KUOAHgVuETvsNAbfpaVsPCdWpFuXmp/4b9iDN7qZy4afTKUPA/Ir/cLfNp14
|
|
||||||
JULfP4z2yFOsCQZ5viNFAs1u99FrwobV2LBzUSIJQewsksuOwj96zIyau0Y629oJ
|
|
||||||
k+og88Tifd9EH3MVZNGhdpojQDDdwHQSITnCDgfRP5yER1WIA4jg6l+mM90QkvLY
|
|
||||||
5NjWTna5kJ3X6UizvgCk365yzT2sbN3R9UGXfCJa9GBcnnviJtJF3+/gC0abwY2f
|
|
||||||
NtVYp32Xky45NY/NdRhDg0bjHP3psxmX+Sc0M9NuQcDQ+fUR+CzM0IGeiszkzXOs
|
|
||||||
RG+bOou2cZ81G4oxWdAALHIRrn7VvLGlkFMxiIZyhYcTGQZzsTPT6n18dY99+DAV
|
|
||||||
yQWZfIRdm8DOnt0G+cwfeohc/9ZwDmj4jJAAi0aeTXdY6NEGIVydk6MAycEhg2Hx
|
|
||||||
9EV96kRwZNIW0AGY8CozECFL3Eyo2ClQVV4Q35SsBibsitDjM03usc2DJ/qjynXA
|
|
||||||
C8HoOSWgbddiBvqZueqK8GdhykOy3J3ysr+MNN/lbG48LqkQr1OWxev9rGGQ6RJT
|
|
||||||
wpBgPyAFAwouPy1whmnx
|
|
||||||
-----END CERTIFICATE-----
|
|
34
contrib/certificates/reseed/reseed_at_diva.exchange.crt
Normal file
34
contrib/certificates/reseed/reseed_at_diva.exchange.crt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIF0zCCA7ugAwIBAgIQWjHyC+NRh3emuuAwcEnKSjANBgkqhkiG9w0BAQsFADB0
|
||||||
|
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
||||||
|
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEdMBsGA1UEAwwU
|
||||||
|
cmVzZWVkQGRpdmEuZXhjaGFuZ2UwHhcNMjAwNjA5MDUzNjQ1WhcNMzAwNjA5MDUz
|
||||||
|
NjQ1WjB0MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4w
|
||||||
|
HAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEdMBsG
|
||||||
|
A1UEAwwUcmVzZWVkQGRpdmEuZXhjaGFuZ2UwggIiMA0GCSqGSIb3DQEBAQUAA4IC
|
||||||
|
DwAwggIKAoICAQC6BJGeMEgoXk9dlzKVfmwHrT2VpwTT+wRJvh3eAM746u4uDT2y
|
||||||
|
NPHXhdGcQ9dRRZ63T98IshWCwOmWSlm1kdWkmKkVVb93GUoMQ3gziCi0apLJMAau
|
||||||
|
gEu/sPCbORS2dPsQeAPW2eIsJO7dSjTRiQAuquW//NcIXG4gnxDA52lgke1BvpKr
|
||||||
|
83SJlCrqECAy6OKtZ49yn75CqmPPWFn0b/E8bxruN5ffeipTTospvdEtT41gXUqk
|
||||||
|
hOz3k8ang+QTWiP//jOjk31KXZ2dbh0LOlNJOvRxCqQmBZafNxxCR4DH8RewfPlL
|
||||||
|
qOiOJVzbLSP9RjqPLwnny5BOjbLWXcaybN5Qv2Pyd4mKtN3EpqBwRu7VnzXpsuuG
|
||||||
|
gRbxNmfKJ/vBEGrZAHAxi0NkHHEEne3B7pPDc2dVZHOfTfCu31m9uDHZ4eHEsNOJ
|
||||||
|
SJRiGjq74l0chCSlBGLrD1Y9LPyqadjdwuB9bzM0tMFC1wPflanQCflhhnEzAfbN
|
||||||
|
BaU2GRXo/I1UCDW/dH1FIkqEe61eMW1Lwqr5tdlrUpdr5VIddTyNJRBJogbZ+HZE
|
||||||
|
8mcoJW2lXRAkYi7KEm4b4EQNe7sbRNTF0j+fAJ+3ZOZ3O3SMHss6ignlSa+giVim
|
||||||
|
VvL+Joc6wpSzxpeNPf6m82cEO/UvifFYeOC9TpiRriSt+vvgQVzQtfQ+fQIDAQAB
|
||||||
|
o2EwXzAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
|
||||||
|
BwMBMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHJlc2VlZEBkaXZhLmV4Y2hh
|
||||||
|
bmdlMA0GCSqGSIb3DQEBCwUAA4ICAQCFGOb1dHlwjmgFHEER6oMiGWl1mI3Hb7GX
|
||||||
|
NNI6QUhZQ+iEWGYtsOTk3Q8xejL8t6AG/ZLXfZviLIJXZc5XZfPXk0ezDSC2cYxQ
|
||||||
|
ZAyYPw2dRP14brI86sCSqNAFIax/U5SM3zXhCbBiTfaEoBPfDpvKjx+VliaITUnc
|
||||||
|
sHTRn+C5ID5M8cZIqUSGECPEMU/bDtuRNJLTKYaJ98yXtYuS2CWsMEM4o0GGcnYQ
|
||||||
|
5HOZT/lbbwfq1Ks7IyJpeIpRaS5qckGcfgkxFY4eGujDuaFeWC+HCIh9RzBJrqZR
|
||||||
|
73Aly4Pyu7Jjg8xCCf9MswDjtqAjEHgWCmRLWL7p3H6cPipFKNMY6yomYZl5urE7
|
||||||
|
q6DUAZFKwPqlZpyeaY4/SVvaHTxuPp7484s3db4kPhdmuQS/DOB/7d+cn/S580Vy
|
||||||
|
ALqlFQjtjLEaT16upceAV0gYktDInE6Rtym/OsqilrtYks/Sc0GROSz8lJhDDWbr
|
||||||
|
W3t92muSXDh0rYrEUYWl+xl1gSTpbIP75zzU+cUr1E/qlRY9qZn66FsJpOuN0I0q
|
||||||
|
UXsQS/bPDcA+IW48Hd9LfO9gtTWZslwFTimjEvQ2nJAnUlUQP6OfuPUKHoYX/CwY
|
||||||
|
2LCN8+pv2bKPDVHvp0lf6xrbbZNvFtzfR0G3AprZjYpuu2XgjVB5nJnwmbH74b9w
|
||||||
|
LD8d2z2Lgg==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -36,7 +36,7 @@ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib
|
||||||
&& cd /usr/local/bin \
|
&& cd /usr/local/bin \
|
||||||
&& strip i2pd \
|
&& strip i2pd \
|
||||||
&& rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \
|
&& rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \
|
||||||
boost-python3 python3 gdbm boost-unit_test_framework boost-python2 linux-headers boost-prg_exec_monitor \
|
boost-python3 python3 gdbm boost-unit_test_framework linux-headers boost-prg_exec_monitor \
|
||||||
boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre2 \
|
boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre2 \
|
||||||
libtool g++ gcc
|
libtool g++ gcc
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||||
|
|
||||||
Name: i2pd-git
|
Name: i2pd-git
|
||||||
Version: 2.32.1
|
Version: 2.33.0
|
||||||
Release: git%{git_hash}%{?dist}
|
Release: git%{git_hash}%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd
|
Conflicts: i2pd
|
||||||
|
@ -124,6 +124,9 @@ getent passwd i2pd >/dev/null || \
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Aug 24 2020 orignal <i2porignal@yandex.ru> - 2.33.0
|
||||||
|
- update to 2.33.0
|
||||||
|
|
||||||
* Tue Jun 02 2020 r4sas <r4sas@i2pmail.org> - 2.32.1
|
* Tue Jun 02 2020 r4sas <r4sas@i2pmail.org> - 2.32.1
|
||||||
- update to 2.32.1
|
- update to 2.32.1
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.32.1
|
Version: 2.33.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd-git
|
Conflicts: i2pd-git
|
||||||
|
@ -122,6 +122,9 @@ getent passwd i2pd >/dev/null || \
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Aug 24 2020 orignal <i2porignal@yandex.ru> - 2.33.0
|
||||||
|
- update to 2.33.0
|
||||||
|
|
||||||
* Tue Jun 02 2020 r4sas <r4sas@i2pmail.org> - 2.32.1
|
* Tue Jun 02 2020 r4sas <r4sas@i2pmail.org> - 2.32.1
|
||||||
- update to 2.32.1
|
- update to 2.32.1
|
||||||
|
|
||||||
|
|
|
@ -63,23 +63,43 @@ namespace http {
|
||||||
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n"
|
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n"
|
||||||
" a, .slide label { text-decoration: none; color: #894C84; }\r\n"
|
" a, .slide label { text-decoration: none; color: #894C84; }\r\n"
|
||||||
" a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n"
|
" a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n"
|
||||||
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial; padding: 0 5px; }\r\n"
|
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
|
||||||
" .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n"
|
" color: initial; padding: 0 5px; border: 1px solid #894C84; }\r\n"
|
||||||
" .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n"
|
" .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n"
|
||||||
" .left { float: left; position: absolute; }\r\n"
|
" .wrapper { margin: 0 auto; padding: 1em; max-width: 58em; }\r\n"
|
||||||
" .right { float: left; font-size: 1em; margin-left: 13em; max-width: 46em; overflow: auto; }\r\n"
|
" .menu { float: left; } .menu a, .commands a { display: block; }\r\n"
|
||||||
" .tunnel.established { color: #56B734; }\r\n"
|
" .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||||
" .tunnel.expiring { color: #D3AE3F; }\r\n"
|
" .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||||
" .tunnel.failed { color: #D33F3F; }\r\n"
|
" .content { float: left; font-size: 1em; margin-left: 4em; max-width: 46em; overflow: auto; }\r\n"
|
||||||
" .tunnel.building { color: #434343; }\r\n"
|
" .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n"
|
||||||
|
" .tunnel.failed { color: #D33F3F; } .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 { display: table; border-collapse: collapse; text-align: center; }\r\n"
|
" table { display: table; border-collapse: collapse; text-align: center; }\r\n"
|
||||||
" table.extaddr { text-align: left; }\r\n table.services { width: 100%; }"
|
" table.extaddr { text-align: left; } table.services { width: 100%; }\r\n"
|
||||||
|
" textarea { word-break: break-all; }\r\n"
|
||||||
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n"
|
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n"
|
||||||
" .slide div.content, .slide [type='checkbox'] { display: none; }\r\n"
|
" .slide div.slidecontent, .slide [type=\"checkbox\"] { display: none; }\r\n"
|
||||||
" .slide [type='checkbox']:checked ~ div.content { display: block; margin-top: 0; padding: 0; }\r\n"
|
" .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n"
|
||||||
" .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n"
|
" .disabled:after { color: #D33F3F; content: \"Disabled\" }\r\n"
|
||||||
" .enabled:after { color: #56B734; content: \"Enabled\" }\r\n"
|
" .enabled:after { color: #56B734; content: \"Enabled\" }\r\n"
|
||||||
|
" @media screen and (max-width: 980px) {\r\n" /* adaptive style */
|
||||||
|
" body { padding: 1.5em 0 0 0; }\r\n"
|
||||||
|
" .menu { width: 100%; display: block; float: none; position: unset; font-size: 16px;\r\n"
|
||||||
|
" text-align: center; }\r\n"
|
||||||
|
" .menu a, .commands a { padding: 2px; }\r\n"
|
||||||
|
" .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n"
|
||||||
|
" text-align: center; }\r\n"
|
||||||
|
" a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n"
|
||||||
|
" .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n"
|
||||||
|
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
|
||||||
|
" color: initial; margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n"
|
||||||
|
" input { width: 35%; text-align: center; padding: 5px;\r\n"
|
||||||
|
" border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n"
|
||||||
|
" textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n"
|
||||||
|
" -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n"
|
||||||
|
" button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n"
|
||||||
|
" -webkit-border-radius: 5px; border-radius: 5px; position: relative; height: 36px; display: -webkit-inline-box; margin-top: 10px; }\r\n"
|
||||||
|
" }\r\n" /* adaptive style */
|
||||||
"</style>\r\n";
|
"</style>\r\n";
|
||||||
|
|
||||||
const char HTTP_PAGE_TUNNELS[] = "tunnels";
|
const char HTTP_PAGE_TUNNELS[] = "tunnels";
|
||||||
|
@ -154,7 +174,7 @@ namespace http {
|
||||||
default: state = "unknown"; break;
|
default: state = "unknown"; break;
|
||||||
}
|
}
|
||||||
s << "<span class=\"tunnel " << state << "\"> " << state << ((explr) ? " (exploratory)" : "") << "</span>, ";
|
s << "<span class=\"tunnel " << state << "\"> " << state << ((explr) ? " (exploratory)" : "") << "</span>, ";
|
||||||
s << " " << (int) (bytes / 1024) << " KiB<br>\r\n";
|
s << " " << (int) (bytes / 1024) << " KiB\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetLogLevel (const std::string& level)
|
static void SetLogLevel (const std::string& level)
|
||||||
|
@ -181,36 +201,37 @@ namespace http {
|
||||||
#else
|
#else
|
||||||
" <meta charset=\"windows-1251\">\r\n"
|
" <meta charset=\"windows-1251\">\r\n"
|
||||||
#endif
|
#endif
|
||||||
|
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"
|
||||||
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
||||||
" <title>Purple I2P " VERSION " Webconsole</title>\r\n"
|
" <title>Purple I2P " VERSION " Webconsole</title>\r\n"
|
||||||
<< cssStyles <<
|
<< cssStyles <<
|
||||||
"</head>\r\n";
|
"</head>\r\n";
|
||||||
s <<
|
s <<
|
||||||
"<body>\r\n"
|
"<body>\r\n"
|
||||||
"<div class=header><b>i2pd</b> webconsole</div>\r\n"
|
"<div class=\"header\"><b>i2pd</b> webconsole</div>\r\n"
|
||||||
"<div class=wrapper>\r\n"
|
"<div class=\"wrapper\">\r\n"
|
||||||
"<div class=left>\r\n"
|
"<div class=\"menu\">\r\n"
|
||||||
" <a href=\"" << webroot << "\">Main page</a><br>\r\n<br>\r\n"
|
" <a href=\"" << webroot << "\">Main page</a><br>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n";
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a>\r\n";
|
||||||
if (i2p::context.IsFloodfill ())
|
if (i2p::context.IsFloodfill ())
|
||||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a>\r\n";
|
||||||
s <<
|
s <<
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">I2P tunnels</a><br>\r\n";
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">I2P tunnels</a>\r\n";
|
||||||
if (i2p::client::context.GetSAMBridge ())
|
if (i2p::client::context.GetSAMBridge ())
|
||||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">SAM sessions</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">SAM sessions</a>\r\n";
|
||||||
s <<
|
s <<
|
||||||
"</div>\r\n"
|
"</div>\r\n"
|
||||||
"<div class=right>";
|
"<div class=\"content\">";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowPageTail (std::stringstream& s)
|
static void ShowPageTail (std::stringstream& s)
|
||||||
{
|
{
|
||||||
s <<
|
s <<
|
||||||
"</div></div>\r\n"
|
"</div>\r\n</div>\r\n"
|
||||||
"</body>\r\n"
|
"</body>\r\n"
|
||||||
"</html>\r\n";
|
"</html>\r\n";
|
||||||
}
|
}
|
||||||
|
@ -266,7 +287,7 @@ namespace http {
|
||||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
||||||
s << "<div class='slide'>";
|
s << "<div class='slide'>";
|
||||||
if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
|
if((outputFormat==OutputFormatEnum::forWebConsole)||!includeHiddenContent) {
|
||||||
s << "<label for='slide-info'>Hidden content. Press on text to see.</label>\r\n<input type='checkbox' id='slide-info'/>\r\n<div class='content'>\r\n";
|
s << "<label for=\"slide-info\">Hidden content. Press on text to see.</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n";
|
||||||
}
|
}
|
||||||
if(includeHiddenContent) {
|
if(includeHiddenContent) {
|
||||||
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||||
|
@ -340,18 +361,19 @@ namespace http {
|
||||||
void ShowLocalDestinations (std::stringstream& s)
|
void ShowLocalDestinations (std::stringstream& s)
|
||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
s << "<b>Local Destinations:</b><br>\r\n<br>\r\n";
|
s << "<b>Local Destinations:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto& it: i2p::client::context.GetDestinations ())
|
for (auto& it: i2p::client::context.GetDestinations ())
|
||||||
{
|
{
|
||||||
auto ident = it.second->GetIdentHash ();
|
auto ident = it.second->GetIdentHash ();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a></div>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
|
|
||||||
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
||||||
if (i2cpServer && !(i2cpServer->GetSessions ().empty ()))
|
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<div class=\"list\">\r\n";
|
||||||
for (auto& it: i2cpServer->GetSessions ())
|
for (auto& it: i2cpServer->GetSessions ())
|
||||||
{
|
{
|
||||||
auto dest = it.second->GetDestination ();
|
auto dest = it.second->GetDestination ();
|
||||||
|
@ -359,21 +381,22 @@ namespace http {
|
||||||
{
|
{
|
||||||
auto ident = dest->GetIdentHash ();
|
auto ident = dest->GetIdentHash ();
|
||||||
auto& name = dest->GetNickname ();
|
auto& name = dest->GetNickname ();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">[ ";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">[ ";
|
||||||
s << name << " ]</a> ⇔ " << i2p::client::context.GetAddressBook ().ToAddress(ident) <<"<br>\r\n" << std::endl;
|
s << name << " ]</a> ⇔ " << i2p::client::context.GetAddressBook ().ToAddress(ident) <<"</div>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest)
|
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest)
|
||||||
{
|
{
|
||||||
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"11\" wrap=\"on\">";
|
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"8\" wrap=\"on\">";
|
||||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||||
if (dest->IsEncryptedLeaseSet ())
|
if (dest->IsEncryptedLeaseSet ())
|
||||||
{
|
{
|
||||||
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
|
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
|
||||||
s << "<div class='slide'><label for='slide-b33'><b>Encrypted B33 address:</b></label>\r\n<input type='checkbox' id='slide-b33'/>\r\n<div class='content'>\r\n";
|
s << "<div class='slide'><label for='slide-b33'><b>Encrypted B33 address:</b></label>\r\n<input type=\"checkbox\" id=\"slide-b33\" />\r\n<div class=\"slidecontent\">\r\n";
|
||||||
s << blinded.ToB33 () << ".b32.i2p<br>\r\n";
|
s << blinded.ToB33 () << ".b32.i2p<br>\r\n";
|
||||||
s << "</div>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
|
@ -381,29 +404,34 @@ namespace http {
|
||||||
if(dest->GetNumRemoteLeaseSets())
|
if(dest->GetNumRemoteLeaseSets())
|
||||||
{
|
{
|
||||||
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets ()
|
s << "<div class='slide'><label for='slide-lease'><b>LeaseSets:</b> <i>" << dest->GetNumRemoteLeaseSets ()
|
||||||
<< "</i></label>\r\n<input type='checkbox' id='slide-lease'/>\r\n<div class='content'>\r\n<table><thead><th>Address</th><th>Type</th><th>EncType</th></thead><tbody>";
|
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>Address</th><th>Type</th><th>EncType</th></thead><tbody class=\"tableitem\">";
|
||||||
for(auto& it: dest->GetLeaseSets ())
|
for(auto& it: dest->GetLeaseSets ())
|
||||||
s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
|
s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
|
||||||
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
||||||
} else
|
} else
|
||||||
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n<br>\r\n";
|
s << "<b>LeaseSets:</b> <i>0</i><br>\r\n<br>\r\n";
|
||||||
|
|
||||||
auto pool = dest->GetTunnelPool ();
|
auto pool = dest->GetTunnelPool ();
|
||||||
if (pool)
|
if (pool)
|
||||||
{
|
{
|
||||||
s << "<b>Inbound tunnels:</b><br>\r\n";
|
s << "<b>Inbound tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto & it : pool->GetInboundTunnels ()) {
|
for (auto & it : pool->GetInboundTunnels ()) {
|
||||||
|
s << "<div class=\"listitem\">";
|
||||||
it->Print(s);
|
it->Print(s);
|
||||||
if(it->LatencyIsKnown())
|
if(it->LatencyIsKnown())
|
||||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||||
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
|
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
s << "<b>Outbound tunnels:</b><br>\r\n";
|
s << "<b>Outbound tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto & it : pool->GetOutboundTunnels ()) {
|
for (auto & it : pool->GetOutboundTunnels ()) {
|
||||||
|
s << "<div class=\"listitem\">";
|
||||||
it->Print(s);
|
it->Print(s);
|
||||||
if(it->LatencyIsKnown())
|
if(it->LatencyIsKnown())
|
||||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||||
ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ());
|
ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ());
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
|
@ -415,8 +443,8 @@ namespace http {
|
||||||
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n";
|
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n";
|
||||||
out_tags += it.second->GetNumOutgoingTags ();
|
out_tags += it.second->GetNumOutgoingTags ();
|
||||||
}
|
}
|
||||||
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n"
|
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-tags\" />\r\n"
|
||||||
<< "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Amount</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
|
<< "<div class=\"slidecontent\">\r\n<table>\r\n<thead><th>Destination</th><th>Amount</th></thead>\r\n<tbody class=\"tableitem\">\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
|
||||||
} else
|
} else
|
||||||
s << "Outgoing: <i>0</i><br>\r\n";
|
s << "Outgoing: <i>0</i><br>\r\n";
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
|
@ -431,8 +459,8 @@ namespace http {
|
||||||
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetDestination ()) << "</td><td>" << it.second->GetState () << "</td></tr>\r\n";
|
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetDestination ()) << "</td><td>" << it.second->GetState () << "</td></tr>\r\n";
|
||||||
ecies_sessions++;
|
ecies_sessions++;
|
||||||
}
|
}
|
||||||
s << "<div class='slide'><label for='slide-ecies-sessions'>Tags sessions: <i>" << ecies_sessions << "</i></label>\r\n<input type='checkbox' id='slide-ecies-sessions'/>\r\n"
|
s << "<div class='slide'><label for='slide-ecies-sessions'>Tags sessions: <i>" << ecies_sessions << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-ecies-sessions\" />\r\n"
|
||||||
<< "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Status</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
|
<< "<div class=\"slidecontent\">\r\n<table>\r\n<thead><th>Destination</th><th>Status</th></thead>\r\n<tbody class=\"tableitem\">\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
|
||||||
} else
|
} else
|
||||||
s << "Tags sessions: <i>0</i><br>\r\n";
|
s << "Tags sessions: <i>0</i><br>\r\n";
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
|
@ -462,11 +490,12 @@ namespace http {
|
||||||
s << "<th>RTT</th>";
|
s << "<th>RTT</th>";
|
||||||
s << "<th>Window</th>";
|
s << "<th>Window</th>";
|
||||||
s << "<th>Status</th>";
|
s << "<th>Status</th>";
|
||||||
s << "</tr>\r\n</thead>\r\n<tbody>\r\n";
|
s << "</tr>\r\n</thead>\r\n<tbody class=\"tableitem\">\r\n";
|
||||||
|
|
||||||
for (const auto& it: dest->GetAllStreams ())
|
for (const auto& it: dest->GetAllStreams ())
|
||||||
{
|
{
|
||||||
auto streamDest = i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ());
|
auto streamDest = i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ());
|
||||||
|
std::string streamDestShort = streamDest.substr(0,12) + "….b32.i2p";
|
||||||
s << "<tr>";
|
s << "<tr>";
|
||||||
s << "<td>" << it->GetRecvStreamID () << "</td>";
|
s << "<td>" << it->GetRecvStreamID () << "</td>";
|
||||||
if (it->GetRecvStreamID ()) {
|
if (it->GetRecvStreamID ()) {
|
||||||
|
@ -475,7 +504,7 @@ namespace http {
|
||||||
} else {
|
} else {
|
||||||
s << "<td \\>";
|
s << "<td \\>";
|
||||||
}
|
}
|
||||||
s << "<td class=\"streamdest\" title=\"" << streamDest << "\">" << streamDest << "</td>";
|
s << "<td class=\"streamdest\" title=\"" << streamDest << "\">" << streamDestShort << "</td>";
|
||||||
s << "<td>" << it->GetNumSentBytes () << "</td>";
|
s << "<td>" << it->GetNumSentBytes () << "</td>";
|
||||||
s << "<td>" << it->GetNumReceivedBytes () << "</td>";
|
s << "<td>" << it->GetNumReceivedBytes () << "</td>";
|
||||||
s << "<td>" << it->GetSendQueueSize () << "</td>";
|
s << "<td>" << it->GetSendQueueSize () << "</td>";
|
||||||
|
@ -510,7 +539,7 @@ namespace http {
|
||||||
{
|
{
|
||||||
if (i2p::data::netdb.GetNumLeaseSets ())
|
if (i2p::data::netdb.GetNumLeaseSets ())
|
||||||
{
|
{
|
||||||
s << "<b>LeaseSets:</b><br>\r\n<br>\r\n";
|
s << "<b>LeaseSets:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
int counter = 1;
|
int counter = 1;
|
||||||
// for each lease set
|
// for each lease set
|
||||||
i2p::data::netdb.VisitLeaseSets(
|
i2p::data::netdb.VisitLeaseSets(
|
||||||
|
@ -524,14 +553,14 @@ namespace http {
|
||||||
else
|
else
|
||||||
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||||
if (!ls) return;
|
if (!ls) return;
|
||||||
s << "<div class='leaseset";
|
s << "<div class=\"leaseset listitem";
|
||||||
if (ls->IsExpired())
|
if (ls->IsExpired())
|
||||||
s << " expired"; // additional css class for expired
|
s << " expired"; // additional css class for expired
|
||||||
s << "'>\r\n";
|
s << "\">\r\n";
|
||||||
if (!ls->IsValid())
|
if (!ls->IsValid())
|
||||||
s << "<div class='invalid'>!! Invalid !! </div>\r\n";
|
s << "<div class=\"invalid\">!! Invalid !! </div>\r\n";
|
||||||
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n";
|
s << "<div class=\"slide\"><label for=\"slide" << counter << "\">" << dest.ToBase32() << "</label>\r\n";
|
||||||
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<div class='content'>\r\n";
|
s << "<input type=\"checkbox\" id=\"slide" << (counter++) << "\" />\r\n<div class=\"slidecontent\">\r\n";
|
||||||
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n";
|
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n";
|
||||||
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n";
|
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n";
|
||||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
|
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
|
||||||
|
@ -563,54 +592,59 @@ namespace http {
|
||||||
|
|
||||||
void ShowTunnels (std::stringstream& s)
|
void ShowTunnels (std::stringstream& s)
|
||||||
{
|
{
|
||||||
s << "<b>Tunnels:</b><br>\r\n<br>\r\n";
|
s << "<b>Tunnels:</b><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<br>\r\n";
|
||||||
|
|
||||||
auto ExplPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
auto ExplPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
|
|
||||||
s << "<b>Inbound tunnels:</b><br>\r\n";
|
s << "<b>Inbound tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) {
|
for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) {
|
||||||
|
s << "<div class=\"listitem\">";
|
||||||
it->Print(s);
|
it->Print(s);
|
||||||
if(it->LatencyIsKnown())
|
if(it->LatencyIsKnown())
|
||||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||||
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ());
|
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ());
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "</div>\r\n<br>\r\n";
|
||||||
s << "<b>Outbound tunnels:</b><br>\r\n";
|
s << "<b>Outbound tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) {
|
for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) {
|
||||||
|
s << "<div class=\"listitem\">";
|
||||||
it->Print(s);
|
it->Print(s);
|
||||||
if(it->LatencyIsKnown())
|
if(it->LatencyIsKnown())
|
||||||
s << " ( " << it->GetMeanLatency() << "ms )";
|
s << " ( " << it->GetMeanLatency() << "ms )";
|
||||||
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ());
|
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ());
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowCommands (std::stringstream& s, uint32_t token)
|
static void ShowCommands (std::stringstream& s, uint32_t token)
|
||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
/* commands */
|
/* commands */
|
||||||
s << "<b>Router Commands</b><br>\r\n<br>\r\n";
|
s << "<b>Router Commands</b><br>\r\n<br>\r\n<div class=\"commands\">\r\n";
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a>\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 ())
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a>\r\n";
|
||||||
else
|
else
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a>\r\n";
|
||||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||||
if (Daemon.gracefulShutdownInterval)
|
if (Daemon.gracefulShutdownInterval)
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a>\r\n";
|
||||||
else
|
else
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
|
||||||
#elif defined(WIN32_APP)
|
#elif defined(WIN32_APP)
|
||||||
if (i2p::util::DaemonWin32::Instance().isGraceful)
|
if (i2p::util::DaemonWin32::Instance().isGraceful)
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a>\r\n";
|
||||||
else
|
else
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a>\r\n";
|
||||||
#endif
|
#endif
|
||||||
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n<br>\r\n";
|
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a>\r\n";
|
||||||
|
s << "</div>";
|
||||||
|
|
||||||
s << "<small><b>Note:</b> any action done here are not persistent and not changes your config files.</small>\r\n<br>\r\n";
|
s << "<br>\r\n<small><b>Note:</b> any action done here are not persistent and not changes your config files.</small>\r\n<br>\r\n";
|
||||||
|
|
||||||
s << "<b>Logging level</b><br>\r\n";
|
s << "<b>Logging level</b><br>\r\n";
|
||||||
s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
|
s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
|
||||||
|
@ -633,17 +667,19 @@ namespace http {
|
||||||
{
|
{
|
||||||
if(i2p::tunnel::tunnels.CountTransitTunnels())
|
if(i2p::tunnel::tunnels.CountTransitTunnels())
|
||||||
{
|
{
|
||||||
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
|
s << "<b>Transit tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||||
{
|
{
|
||||||
|
s << "<div class=\"listitem\">\r\n";
|
||||||
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
||||||
s << it->GetTunnelID () << " ⇒ ";
|
s << it->GetTunnelID () << " ⇒ ";
|
||||||
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
||||||
s << " ⇒ " << it->GetTunnelID ();
|
s << " ⇒ " << it->GetTunnelID ();
|
||||||
else
|
else
|
||||||
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
||||||
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
|
s << " " << it->GetNumTransmittedBytes () << "</div>\r\n";
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -659,43 +695,44 @@ namespace http {
|
||||||
{
|
{
|
||||||
if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
|
if (it.second && it.second->IsEstablished () && !it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
|
||||||
{
|
{
|
||||||
// incoming connection doesn't have remote RI
|
tmp_s << "<div class=\"listitem\">\r\n";
|
||||||
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
if (it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||||
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||||
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
|
<< it.second->GetSocket ().remote_endpoint().address ().to_string ();
|
||||||
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
if (!it.second->IsOutgoing ()) tmp_s << " ⇒ ";
|
||||||
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
tmp_s << "<br>\r\n" << std::endl;
|
tmp_s << "</div>\r\n" << std::endl;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
|
if (it.second && it.second->IsEstablished () && it.second->GetSocket ().remote_endpoint ().address ().is_v6 ())
|
||||||
{
|
{
|
||||||
|
tmp_s6 << "<div class=\"listitem\">\r\n";
|
||||||
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
if (it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||||
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
|
||||||
<< "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]";
|
<< "[" << it.second->GetSocket ().remote_endpoint().address ().to_string () << "]";
|
||||||
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
if (!it.second->IsOutgoing ()) tmp_s6 << " ⇒ ";
|
||||||
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
tmp_s6 << "<br>\r\n" << std::endl;
|
tmp_s6 << "</div>\r\n" << std::endl;
|
||||||
cnt6++;
|
cnt6++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tmp_s.str ().empty ())
|
if (!tmp_s.str ().empty ())
|
||||||
{
|
{
|
||||||
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name
|
||||||
<< "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<div class='content'>"
|
<< "</b> ( " << cnt << " )</label>\r\n<input type=\"checkbox\" id=\"slide_" << boost::algorithm::to_lower_copy(name) << "\" />\r\n<div class=\"slidecontent list\">"
|
||||||
<< tmp_s.str () << "</div>\r\n</div>\r\n";
|
<< tmp_s.str () << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
if (!tmp_s6.str ().empty ())
|
if (!tmp_s6.str ().empty ())
|
||||||
{
|
{
|
||||||
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name
|
||||||
<< "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<div class='content'>"
|
<< "v6</b> ( " << cnt6 << " )</label>\r\n<input type=\"checkbox\" id=\"slide_" << boost::algorithm::to_lower_copy(name) << "v6\" />\r\n<div class=\"slidecontent list\">"
|
||||||
<< tmp_s6.str () << "</div>\r\n</div>\r\n";
|
<< tmp_s6.str () << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowTransports (std::stringstream& s)
|
void ShowTransports (std::stringstream& s)
|
||||||
{
|
{
|
||||||
s << "<b>Transports:</b><br>\r\n<br>\r\n";
|
s << "<b>Transports:</b><br>\r\n";
|
||||||
auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
|
auto ntcpServer = i2p::transport::transports.GetNTCPServer ();
|
||||||
if (ntcpServer)
|
if (ntcpServer)
|
||||||
{
|
{
|
||||||
|
@ -716,9 +753,10 @@ namespace http {
|
||||||
auto sessions = ssuServer->GetSessions ();
|
auto sessions = ssuServer->GetSessions ();
|
||||||
if (!sessions.empty ())
|
if (!sessions.empty ())
|
||||||
{
|
{
|
||||||
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu'/>\r\n<div class='content'>";
|
s << "<div class='slide'><label for='slide_ssu'><b>SSU</b> ( " << (int) sessions.size() << " )</label>\r\n<input type=\"checkbox\" id=\"slide_ssu\" />\r\n<div class=\"slidecontent list\">";
|
||||||
for (const auto& it: sessions)
|
for (const auto& it: sessions)
|
||||||
{
|
{
|
||||||
|
s << "<div class=\"listitem\">\r\n";
|
||||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
||||||
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
s << endpoint.address ().to_string () << ":" << endpoint.port ();
|
||||||
|
@ -726,16 +764,17 @@ namespace http {
|
||||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
if (it.second->GetRelayTag ())
|
if (it.second->GetRelayTag ())
|
||||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||||
s << "<br>\r\n" << std::endl;
|
s << "</div>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
s << "</div>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
auto sessions6 = ssuServer->GetSessionsV6 ();
|
auto sessions6 = ssuServer->GetSessionsV6 ();
|
||||||
if (!sessions6.empty ())
|
if (!sessions6.empty ())
|
||||||
{
|
{
|
||||||
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssuv6'/>\r\n<div class='content'>";
|
s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type=\"checkbox\" id=\"slide_ssuv6\" />\r\n<div class=\"slidecontent list\">";
|
||||||
for (const auto& it: sessions6)
|
for (const auto& it: sessions6)
|
||||||
{
|
{
|
||||||
|
s << "<div class=\"listitem\">\r\n";
|
||||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||||
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
if (it.second->IsOutgoing ()) s << " ⇒ ";
|
||||||
s << "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
|
s << "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
|
||||||
|
@ -743,7 +782,7 @@ namespace http {
|
||||||
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
|
||||||
if (it.second->GetRelayTag ())
|
if (it.second->GetRelayTag ())
|
||||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||||
s << "<br>\r\n" << std::endl;
|
s << "</div>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
s << "</div>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
|
@ -762,13 +801,14 @@ namespace http {
|
||||||
|
|
||||||
if(sam->GetSessions ().size ())
|
if(sam->GetSessions ().size ())
|
||||||
{
|
{
|
||||||
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
s << "<b>SAM Sessions:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto& it: sam->GetSessions ())
|
for (auto& it: sam->GetSessions ())
|
||||||
{
|
{
|
||||||
auto& name = it.second->localDestination->GetNickname ();
|
auto& name = it.second->localDestination->GetNickname ();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
||||||
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
|
s << name << " (" << it.first << ")</a></div>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
s << "<b>SAM Sessions:</b> no sessions currently running.<br>\r\n";
|
s << "<b>SAM Sessions:</b> no sessions currently running.<br>\r\n";
|
||||||
|
@ -776,25 +816,28 @@ namespace http {
|
||||||
|
|
||||||
static void ShowSAMSession (std::stringstream& s, const std::string& id)
|
static void ShowSAMSession (std::stringstream& s, const std::string& id)
|
||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
|
||||||
s << "<b>SAM Session:</b><br>\r\n<br>\r\n";
|
|
||||||
auto sam = i2p::client::context.GetSAMBridge ();
|
auto sam = i2p::client::context.GetSAMBridge ();
|
||||||
if (!sam) {
|
if (!sam) {
|
||||||
ShowError(s, "SAM disabled");
|
ShowError(s, "SAM disabled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto session = sam->FindSession (id);
|
auto session = sam->FindSession (id);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
ShowError(s, "SAM session not found");
|
ShowError(s, "SAM session not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
|
s << "<b>SAM Session:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
auto& ident = session->localDestination->GetIdentHash();
|
auto& ident = session->localDestination->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n";
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a></div>\r\n";
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
s << "<b>Streams:</b><br>\r\n";
|
s << "<b>Streams:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (const auto& it: sam->ListSockets(id))
|
for (const auto& it: sam->ListSockets(id))
|
||||||
{
|
{
|
||||||
|
s << "<div class=\"listitem\">";
|
||||||
switch (it->GetSocketType ())
|
switch (it->GetSocketType ())
|
||||||
{
|
{
|
||||||
case i2p::client::eSAMSocketTypeSession : s << "session"; break;
|
case i2p::client::eSAMSocketTypeSession : s << "session"; break;
|
||||||
|
@ -803,88 +846,95 @@ namespace http {
|
||||||
default: s << "unknown"; break;
|
default: s << "unknown"; break;
|
||||||
}
|
}
|
||||||
s << " [" << it->GetSocket ().remote_endpoint() << "]";
|
s << " [" << it->GetSocket ().remote_endpoint() << "]";
|
||||||
s << "<br>\r\n";
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowI2PTunnels (std::stringstream& s)
|
void ShowI2PTunnels (std::stringstream& s)
|
||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n";
|
s << "<b>Client Tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto& it: i2p::client::context.GetClientTunnels ())
|
for (auto& it: i2p::client::context.GetClientTunnels ())
|
||||||
{
|
{
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << it.second->GetName () << "</a> ⇐ ";
|
s << it.second->GetName () << "</a> ⇐ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << "<br>\r\n"<< std::endl;
|
s << "</div>\r\n"<< std::endl;
|
||||||
}
|
}
|
||||||
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
||||||
if (httpProxy)
|
if (httpProxy)
|
||||||
{
|
{
|
||||||
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << "HTTP Proxy" << "</a> ⇐ ";
|
s << "HTTP Proxy" << "</a> ⇐ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << "<br>\r\n"<< std::endl;
|
s << "</div>\r\n"<< std::endl;
|
||||||
}
|
}
|
||||||
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
||||||
if (socksProxy)
|
if (socksProxy)
|
||||||
{
|
{
|
||||||
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << "SOCKS Proxy" << "</a> ⇐ ";
|
s << "SOCKS Proxy" << "</a> ⇐ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << "<br>\r\n"<< std::endl;
|
s << "</div>\r\n"<< std::endl;
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
|
|
||||||
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
|
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
|
||||||
if (!serverTunnels.empty ()) {
|
if (!serverTunnels.empty ()) {
|
||||||
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<br>\r\n";
|
s << "<br>\r\n<b>Server Tunnels:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto& it: serverTunnels)
|
for (auto& it: serverTunnels)
|
||||||
{
|
{
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << it.second->GetName () << "</a> ⇒ ";
|
s << it.second->GetName () << "</a> ⇒ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << ":" << it.second->GetLocalPort ();
|
s << ":" << it.second->GetLocalPort ();
|
||||||
s << "</a><br>\r\n"<< std::endl;
|
s << "</a></div>\r\n"<< std::endl;
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& clientForwards = i2p::client::context.GetClientForwards ();
|
auto& clientForwards = i2p::client::context.GetClientForwards ();
|
||||||
if (!clientForwards.empty ())
|
if (!clientForwards.empty ())
|
||||||
{
|
{
|
||||||
s << "<br>\r\n<b>Client Forwards:</b><br>\r\n<br>\r\n";
|
s << "<br>\r\n<b>Client Forwards:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto& it: clientForwards)
|
for (auto& it: clientForwards)
|
||||||
{
|
{
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << it.second->GetName () << "</a> ⇐ ";
|
s << it.second->GetName () << "</a> ⇐ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << "<br>\r\n"<< std::endl;
|
s << "</div>\r\n"<< std::endl;
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
auto& serverForwards = i2p::client::context.GetServerForwards ();
|
auto& serverForwards = i2p::client::context.GetServerForwards ();
|
||||||
if (!serverForwards.empty ())
|
if (!serverForwards.empty ())
|
||||||
{
|
{
|
||||||
s << "<br>\r\n<b>Server Forwards:</b><br>\r\n<br>\r\n";
|
s << "<br>\r\n<b>Server Forwards:</b><br>\r\n<div class=\"list\">\r\n";
|
||||||
for (auto& it: serverForwards)
|
for (auto& it: serverForwards)
|
||||||
{
|
{
|
||||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||||
s << it.second->GetName () << "</a> ⇐ ";
|
s << it.second->GetName () << "</a> ⇐ ";
|
||||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||||
s << "<br>\r\n"<< std::endl;
|
s << "</div>\r\n"<< std::endl;
|
||||||
}
|
}
|
||||||
|
s << "</div>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ConvertTime (uint64_t time)
|
std::string ConvertTime (uint64_t time)
|
||||||
{
|
{
|
||||||
ldiv_t divTime = ldiv(time,1000);
|
lldiv_t divTime = lldiv(time, 1000);
|
||||||
time_t t = divTime.quot;
|
time_t t = divTime.quot;
|
||||||
struct tm *tm = localtime(&t);
|
struct tm *tm = localtime(&t);
|
||||||
char date[128];
|
char date[128];
|
||||||
snprintf(date, sizeof(date), "%02d/%02d/%d %02d:%02d:%02d.%03ld", tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, divTime.rem);
|
snprintf(date, sizeof(date), "%02d/%02d/%d %02d:%02d:%02d.%03lld", tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, divTime.rem);
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
debian/changelog
vendored
6
debian/changelog
vendored
|
@ -1,3 +1,9 @@
|
||||||
|
i2pd (2.33.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.33.0/0.9.47
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Mon, 24 Aug 2020 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.32.1-1) unstable; urgency=high
|
i2pd (2.32.1-1) unstable; urgency=high
|
||||||
|
|
||||||
* updated to version 2.32.1
|
* updated to version 2.32.1
|
||||||
|
|
|
@ -195,7 +195,7 @@ namespace config {
|
||||||
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
|
("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://reseed.diva.exchange/,"
|
||||||
"https://reseed.i2p2.no/,"
|
"https://reseed.i2p2.no/,"
|
||||||
"https://reseed-fr.i2pd.xyz/,"
|
"https://reseed-fr.i2pd.xyz/,"
|
||||||
"https://reseed.memcpy.io/,"
|
"https://reseed.memcpy.io/,"
|
||||||
|
|
|
@ -375,15 +375,22 @@ namespace crypto
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void X25519Keys::SetPrivateKey (const uint8_t * priv)
|
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic)
|
||||||
{
|
{
|
||||||
#if OPENSSL_X25519
|
#if OPENSSL_X25519
|
||||||
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
||||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||||
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
||||||
|
if (calculatePublic)
|
||||||
|
{
|
||||||
|
size_t len = 32;
|
||||||
|
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
memcpy (m_PrivateKey, priv, 32);
|
memcpy (m_PrivateKey, priv, 32);
|
||||||
|
if (calculatePublic)
|
||||||
|
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,9 +88,12 @@ namespace crypto
|
||||||
void GenerateKeys ();
|
void GenerateKeys ();
|
||||||
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
||||||
void GetPrivateKey (uint8_t * priv) const;
|
void GetPrivateKey (uint8_t * priv) const;
|
||||||
void SetPrivateKey (const uint8_t * priv); // wihout calculating public
|
void SetPrivateKey (const uint8_t * priv, bool calculatePublic = false);
|
||||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||||
|
|
||||||
|
bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
|
||||||
|
void SetElligatorIneligible () { m_IsElligatorIneligible = true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_PublicKey[32];
|
uint8_t m_PublicKey[32];
|
||||||
|
@ -101,6 +104,7 @@ namespace crypto
|
||||||
BN_CTX * m_Ctx;
|
BN_CTX * m_Ctx;
|
||||||
uint8_t m_PrivateKey[32];
|
uint8_t m_PrivateKey[32];
|
||||||
#endif
|
#endif
|
||||||
|
bool m_IsElligatorIneligible = false; // true if definitly ineligible
|
||||||
};
|
};
|
||||||
|
|
||||||
// ElGamal
|
// ElGamal
|
||||||
|
|
|
@ -166,9 +166,9 @@ namespace crypto
|
||||||
memcpy (pub, m_PublicKey, 32);
|
memcpy (pub, m_PublicKey, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv)
|
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv, bool calculatePublic)
|
||||||
{
|
{
|
||||||
m_StaticKeys.SetPrivateKey (priv);
|
m_StaticKeys.SetPrivateKey (priv, calculatePublic);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
|
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
|
||||||
|
|
|
@ -145,11 +145,12 @@ namespace crypto
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ECIESX25519AEADRatchetDecryptor (const uint8_t * priv);
|
ECIESX25519AEADRatchetDecryptor (const uint8_t * priv, bool calculatePublic = false);
|
||||||
~ECIESX25519AEADRatchetDecryptor () {};
|
~ECIESX25519AEADRatchetDecryptor () {};
|
||||||
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
|
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
|
||||||
// agree with static and return in sharedSecret (32 bytes)
|
// agree with static and return in sharedSecret (32 bytes)
|
||||||
size_t GetPublicKeyLen () const { return 32; };
|
size_t GetPublicKeyLen () const { return 32; };
|
||||||
|
const uint8_t * GetPubicKey () const { return m_StaticKeys.GetPublicKey (); };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,27 @@ namespace datagram
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
|
void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
|
||||||
|
{
|
||||||
|
auto session = ObtainSession(identity);
|
||||||
|
SendDatagram (session, payload, len, fromPort, toPort);
|
||||||
|
FlushSendQueue (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatagramDestination::SendRawDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
|
||||||
|
{
|
||||||
|
auto session = ObtainSession(identity);
|
||||||
|
SendRawDatagram (session, payload, len, fromPort, toPort);
|
||||||
|
FlushSendQueue (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<DatagramSession> DatagramDestination::GetSession(const i2p::data::IdentHash & ident)
|
||||||
|
{
|
||||||
|
return ObtainSession(ident);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatagramDestination::SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||||
|
{
|
||||||
|
if (session)
|
||||||
{
|
{
|
||||||
if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
|
@ -43,17 +64,22 @@ namespace datagram
|
||||||
else
|
else
|
||||||
m_Owner->Sign (payload, len, m_Signature.data ());
|
m_Owner->Sign (payload, len, m_Signature.data ());
|
||||||
|
|
||||||
auto session = ObtainSession(identity);
|
|
||||||
auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}},
|
auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}},
|
||||||
fromPort, toPort, false, !session->IsRatchets ()); // datagram
|
fromPort, toPort, false, !session->IsRatchets ()); // datagram
|
||||||
session->SendMsg(msg);
|
session->SendMsg(msg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DatagramDestination::SendRawDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
|
void DatagramDestination::SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||||
{
|
{
|
||||||
auto session = ObtainSession(identity);
|
if (session)
|
||||||
auto msg = CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ()); // raw
|
session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ())); // raw
|
||||||
session->SendMsg(msg);
|
}
|
||||||
|
|
||||||
|
void DatagramDestination::FlushSendQueue (std::shared_ptr<DatagramSession> session)
|
||||||
|
{
|
||||||
|
if (session)
|
||||||
|
session->FlushSendQueue ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len)
|
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len)
|
||||||
|
@ -126,7 +152,7 @@ namespace datagram
|
||||||
const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
|
const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
|
||||||
uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum)
|
uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum)
|
||||||
{
|
{
|
||||||
auto msg = NewI2NPMessage ();
|
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
||||||
uint8_t * buf = msg->GetPayload ();
|
uint8_t * buf = msg->GetPayload ();
|
||||||
buf += 4; // reserve for length
|
buf += 4; // reserve for length
|
||||||
size_t size = m_Gzip ? m_Deflator.Deflate (payloads, buf, msg->maxLen - msg->len) :
|
size_t size = m_Gzip ? m_Deflator.Deflate (payloads, buf, msg->maxLen - msg->len) :
|
||||||
|
@ -196,7 +222,6 @@ namespace datagram
|
||||||
const i2p::data::IdentHash & remoteIdent) :
|
const i2p::data::IdentHash & remoteIdent) :
|
||||||
m_LocalDestination(localDestination),
|
m_LocalDestination(localDestination),
|
||||||
m_RemoteIdent(remoteIdent),
|
m_RemoteIdent(remoteIdent),
|
||||||
m_SendQueueTimer(localDestination->GetService()),
|
|
||||||
m_RequestingLS(false)
|
m_RequestingLS(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -204,21 +229,21 @@ namespace datagram
|
||||||
void DatagramSession::Start ()
|
void DatagramSession::Start ()
|
||||||
{
|
{
|
||||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch ();
|
m_LastUse = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
ScheduleFlushSendQueue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSession::Stop ()
|
void DatagramSession::Stop ()
|
||||||
{
|
{
|
||||||
m_SendQueueTimer.cancel ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg)
|
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
// we used this session
|
// we used this session
|
||||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
|
m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
// schedule send
|
if (msg || m_SendQueue.empty ())
|
||||||
auto self = shared_from_this();
|
m_SendQueue.push_back(msg);
|
||||||
m_LocalDestination->GetService().post(std::bind(&DatagramSession::HandleSend, self, msg));
|
// flush queue right away if full
|
||||||
|
if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
||||||
|
FlushSendQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||||
|
@ -256,94 +281,113 @@ namespace datagram
|
||||||
|
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
||||||
{
|
{
|
||||||
if (!m_RoutingSession || !m_RoutingSession->GetOwner ())
|
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ())
|
||||||
{
|
{
|
||||||
if(!m_RemoteLeaseSet) {
|
|
||||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||||
}
|
if (!m_RemoteLeaseSet)
|
||||||
if(!m_RemoteLeaseSet) {
|
{
|
||||||
// no remote lease set
|
if(!m_RequestingLS)
|
||||||
if(!m_RequestingLS) {
|
{
|
||||||
m_RequestingLS = true;
|
m_RequestingLS = true;
|
||||||
m_LocalDestination->RequestDestination(m_RemoteIdent, std::bind(&DatagramSession::HandleLeaseSetUpdated, this, std::placeholders::_1));
|
m_LocalDestination->RequestDestination(m_RemoteIdent, std::bind(&DatagramSession::HandleLeaseSetUpdated, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_RoutingSession || !m_RoutingSession->GetOwner ())
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (auto& it: m_PendingRoutingSessions)
|
||||||
|
if (it->GetOwner ()) // found established session
|
||||||
|
{
|
||||||
|
m_RoutingSession = it;
|
||||||
|
m_PendingRoutingSessions.clear ();
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
||||||
|
if (!m_RoutingSession->GetOwner ())
|
||||||
|
m_PendingRoutingSessions.push_back (m_RoutingSession);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto path = m_RoutingSession->GetSharedRoutingPath();
|
auto path = m_RoutingSession->GetSharedRoutingPath();
|
||||||
if(path) {
|
if (path && m_RoutingSession->IsRatchets () &&
|
||||||
if (m_CurrentOutboundTunnel && !m_CurrentOutboundTunnel->IsEstablished()) {
|
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
|
||||||
// bad outbound tunnel, switch outbound tunnel
|
{
|
||||||
m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
|
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
path->outboundTunnel = m_CurrentOutboundTunnel;
|
path = nullptr;
|
||||||
}
|
}
|
||||||
if(m_CurrentRemoteLease && m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
|
||||||
|
if (path)
|
||||||
|
{
|
||||||
|
if (path->outboundTunnel && !path->outboundTunnel->IsEstablished ())
|
||||||
|
{
|
||||||
|
// bad outbound tunnel, switch outbound tunnel
|
||||||
|
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(path->outboundTunnel);
|
||||||
|
if (!path->outboundTunnel)
|
||||||
|
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path->remoteLease && path->remoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW))
|
||||||
|
{
|
||||||
// bad lease, switch to next one
|
// bad lease, switch to next one
|
||||||
if(m_RemoteLeaseSet && m_RemoteLeaseSet->IsExpired())
|
if (m_RemoteLeaseSet)
|
||||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
{
|
||||||
if(m_RemoteLeaseSet) {
|
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding(
|
||||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&](const i2p::data::Lease& l) -> bool {
|
[&](const i2p::data::Lease& l) -> bool
|
||||||
return l.tunnelID == m_CurrentRemoteLease->tunnelID;
|
{
|
||||||
|
return l.tunnelID == path->remoteLease->tunnelID;
|
||||||
});
|
});
|
||||||
auto sz = ls.size();
|
auto sz = ls.size();
|
||||||
if (sz) {
|
if (sz)
|
||||||
|
{
|
||||||
auto idx = rand() % sz;
|
auto idx = rand() % sz;
|
||||||
m_CurrentRemoteLease = ls[idx];
|
path->remoteLease = ls[idx];
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
|
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// no remote lease set?
|
// no remote lease set?
|
||||||
LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ", m_RemoteIdent.ToBase32());
|
LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ", m_RemoteIdent.ToBase32());
|
||||||
|
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
}
|
}
|
||||||
path->remoteLease = m_CurrentRemoteLease;
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// no current path, make one
|
// no current path, make one
|
||||||
path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
|
path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
|
||||||
// switch outbound tunnel if bad
|
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel();
|
||||||
if(m_CurrentOutboundTunnel == nullptr || ! m_CurrentOutboundTunnel->IsEstablished()) {
|
if (!path->outboundTunnel) return nullptr;
|
||||||
m_CurrentOutboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(m_CurrentOutboundTunnel);
|
|
||||||
}
|
if (m_RemoteLeaseSet)
|
||||||
// switch lease if bad
|
{
|
||||||
if(m_CurrentRemoteLease && m_CurrentRemoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
|
|
||||||
if(!m_RemoteLeaseSet) {
|
|
||||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
|
||||||
}
|
|
||||||
if(m_RemoteLeaseSet) {
|
|
||||||
// pick random next good lease
|
// pick random next good lease
|
||||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding([&] (const i2p::data::Lease & l) -> bool {
|
auto ls = m_RemoteLeaseSet->GetNonExpiredLeases();
|
||||||
if(m_CurrentRemoteLease)
|
|
||||||
return l.tunnelGateway == m_CurrentRemoteLease->tunnelGateway;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
auto sz = ls.size();
|
auto sz = ls.size();
|
||||||
if(sz) {
|
if (sz)
|
||||||
|
{
|
||||||
auto idx = rand() % sz;
|
auto idx = rand() % sz;
|
||||||
m_CurrentRemoteLease = ls[idx];
|
path->remoteLease = ls[idx];
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// no remote lease set currently, bail
|
// no remote lease set currently, bail
|
||||||
LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
|
LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else if (!m_CurrentRemoteLease) {
|
|
||||||
if(!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
|
||||||
if (m_RemoteLeaseSet)
|
|
||||||
{
|
|
||||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeases();
|
|
||||||
auto sz = ls.size();
|
|
||||||
if (sz) {
|
|
||||||
auto idx = rand() % sz;
|
|
||||||
m_CurrentRemoteLease = ls[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path->outboundTunnel = m_CurrentOutboundTunnel;
|
|
||||||
path->remoteLease = m_CurrentRemoteLease;
|
|
||||||
m_RoutingSession->SetSharedRoutingPath(path);
|
m_RoutingSession->SetSharedRoutingPath(path);
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)
|
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||||
|
@ -356,16 +400,9 @@ namespace datagram
|
||||||
if(ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
|
if(ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramSession::HandleSend(std::shared_ptr<I2NPMessage> msg)
|
|
||||||
{
|
|
||||||
if (msg || m_SendQueue.empty ())
|
|
||||||
m_SendQueue.push_back(msg);
|
|
||||||
// flush queue right away if full
|
|
||||||
if(m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE) FlushSendQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSession::FlushSendQueue ()
|
void DatagramSession::FlushSendQueue ()
|
||||||
{
|
{
|
||||||
|
if (m_SendQueue.empty ()) return;
|
||||||
std::vector<i2p::tunnel::TunnelMessageBlock> send;
|
std::vector<i2p::tunnel::TunnelMessageBlock> send;
|
||||||
auto routingPath = GetSharedRoutingPath();
|
auto routingPath = GetSharedRoutingPath();
|
||||||
// if we don't have a routing path we will drop all queued messages
|
// if we don't have a routing path we will drop all queued messages
|
||||||
|
@ -380,15 +417,6 @@ namespace datagram
|
||||||
routingPath->outboundTunnel->SendTunnelDataMsg(send);
|
routingPath->outboundTunnel->SendTunnelDataMsg(send);
|
||||||
}
|
}
|
||||||
m_SendQueue.clear();
|
m_SendQueue.clear();
|
||||||
ScheduleFlushSendQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSession::ScheduleFlushSendQueue()
|
|
||||||
{
|
|
||||||
boost::posix_time::milliseconds dlt(10);
|
|
||||||
m_SendQueueTimer.expires_from_now(dlt);
|
|
||||||
auto self = shared_from_this();
|
|
||||||
m_SendQueueTimer.async_wait([self](const boost::system::error_code & ec) { if(ec) return; self->FlushSendQueue(); });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ namespace datagram
|
||||||
|
|
||||||
/** send an i2np message to remote endpoint for this session */
|
/** send an i2np message to remote endpoint for this session */
|
||||||
void SendMsg(std::shared_ptr<I2NPMessage> msg);
|
void SendMsg(std::shared_ptr<I2NPMessage> msg);
|
||||||
|
void FlushSendQueue();
|
||||||
/** get the last time in milliseconds for when we used this datagram session */
|
/** get the last time in milliseconds for when we used this datagram session */
|
||||||
uint64_t LastActivity() const { return m_LastUse; }
|
uint64_t LastActivity() const { return m_LastUse; }
|
||||||
|
|
||||||
|
@ -84,11 +85,6 @@ namespace datagram
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void FlushSendQueue();
|
|
||||||
void ScheduleFlushSendQueue();
|
|
||||||
|
|
||||||
void HandleSend(std::shared_ptr<I2NPMessage> msg);
|
|
||||||
|
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
|
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
|
||||||
|
|
||||||
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
||||||
|
@ -99,9 +95,7 @@ namespace datagram
|
||||||
i2p::data::IdentHash m_RemoteIdent;
|
i2p::data::IdentHash m_RemoteIdent;
|
||||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||||
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
|
std::vector<std::shared_ptr<i2p::garlic::GarlicRoutingSession> > m_PendingRoutingSessions;
|
||||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
|
|
||||||
boost::asio::deadline_timer m_SendQueueTimer;
|
|
||||||
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
uint64_t m_LastUse;
|
uint64_t m_LastUse;
|
||||||
bool m_RequestingLS;
|
bool m_RequestingLS;
|
||||||
|
@ -122,6 +116,13 @@ namespace datagram
|
||||||
|
|
||||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||||
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||||
|
// TODO: implement calls from other thread from SAM
|
||||||
|
|
||||||
|
std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash & ident);
|
||||||
|
void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||||
|
void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||||
|
void FlushSendQueue (std::shared_ptr<DatagramSession> session);
|
||||||
|
|
||||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
||||||
|
|
||||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||||
|
@ -165,6 +166,7 @@ namespace datagram
|
||||||
i2p::data::GzipInflator m_Inflator;
|
i2p::data::GzipInflator m_Inflator;
|
||||||
i2p::data::GzipDeflator m_Deflator;
|
i2p::data::GzipDeflator m_Deflator;
|
||||||
std::vector<uint8_t> m_From, m_Signature;
|
std::vector<uint8_t> m_From, m_Signature;
|
||||||
|
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,9 @@ namespace client
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
numTags = std::stoi(it->second);
|
numTags = std::stoi(it->second);
|
||||||
LogPrint (eLogInfo, "Destination: parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags");
|
LogPrint (eLogInfo, "Destination: parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags");
|
||||||
|
it = params->find (I2CP_PARAM_RATCHET_INBOUND_TAGS);
|
||||||
|
if (it != params->end ())
|
||||||
|
SetNumRatchetInboundTags (std::stoi(it->second));
|
||||||
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
|
it = params->find (I2CP_PARAM_EXPLICIT_PEERS);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
{
|
{
|
||||||
|
@ -892,7 +895,11 @@ namespace client
|
||||||
encryptionKey->GenerateKeys ();
|
encryptionKey->GenerateKeys ();
|
||||||
encryptionKey->CreateDecryptor ();
|
encryptionKey->CreateDecryptor ();
|
||||||
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
||||||
|
{
|
||||||
m_ECIESx25519EncryptionKey.reset (encryptionKey);
|
m_ECIESx25519EncryptionKey.reset (encryptionKey);
|
||||||
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
|
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2
|
||||||
|
}
|
||||||
else
|
else
|
||||||
m_StandardEncryptionKey.reset (encryptionKey);
|
m_StandardEncryptionKey.reset (encryptionKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ namespace client
|
||||||
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
|
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
|
||||||
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
|
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
|
||||||
const int DEFAULT_TAGS_TO_SEND = 40;
|
const int DEFAULT_TAGS_TO_SEND = 40;
|
||||||
|
const char I2CP_PARAM_RATCHET_INBOUND_TAGS[] = "crypto.ratchet.inboundTags";
|
||||||
|
const char I2CP_PARAM_RATCHET_OUTBOUND_TAGS[] = "crypto.ratchet.outboundTags"; // not used yet
|
||||||
const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname";
|
const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname";
|
||||||
const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname";
|
const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname";
|
||||||
const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType";
|
const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType";
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "TunnelPool.h"
|
#include "TunnelPool.h"
|
||||||
|
#include "Transports.h"
|
||||||
#include "ECIESX25519AEADRatchetSession.h"
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -96,6 +97,7 @@ namespace garlic
|
||||||
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet):
|
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet):
|
||||||
GarlicRoutingSession (owner, attachLeaseSet)
|
GarlicRoutingSession (owner, attachLeaseSet)
|
||||||
{
|
{
|
||||||
|
RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0;
|
||||||
ResetKeys ();
|
ResetKeys ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,12 +138,38 @@ namespace garlic
|
||||||
|
|
||||||
bool ECIESX25519AEADRatchetSession::GenerateEphemeralKeysAndEncode (uint8_t * buf)
|
bool ECIESX25519AEADRatchetSession::GenerateEphemeralKeysAndEncode (uint8_t * buf)
|
||||||
{
|
{
|
||||||
|
bool ineligible = false;
|
||||||
|
while (!ineligible)
|
||||||
|
{
|
||||||
|
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||||
|
ineligible = m_EphemeralKeys->IsElligatorIneligible ();
|
||||||
|
if (!ineligible) // we haven't tried it yet
|
||||||
|
{
|
||||||
|
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf))
|
||||||
|
return true; // success
|
||||||
|
// otherwise return back
|
||||||
|
m_EphemeralKeys->SetElligatorIneligible ();
|
||||||
|
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
|
||||||
|
}
|
||||||
|
// we still didn't find elligator eligible pair
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
m_EphemeralKeys.GenerateKeys ();
|
// create new
|
||||||
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), buf))
|
m_EphemeralKeys = std::make_shared<i2p::crypto::X25519Keys>();
|
||||||
|
m_EphemeralKeys->GenerateKeys ();
|
||||||
|
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf))
|
||||||
return true; // success
|
return true; // success
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// let NTCP2 use it
|
||||||
|
m_EphemeralKeys->SetElligatorIneligible ();
|
||||||
|
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
LogPrint (eLogError, "Garlic: Can't generate elligator eligible x25519 keys");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +178,8 @@ namespace garlic
|
||||||
uint8_t tagsetKey[32];
|
uint8_t tagsetKey[32];
|
||||||
i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32)
|
i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32)
|
||||||
// Session Tag Ratchet
|
// Session Tag Ratchet
|
||||||
auto tagsetNsr = std::make_shared<RatchetTagSet>(shared_from_this ());
|
auto tagsetNsr = (m_State == eSessionStateNewSessionReceived) ? std::make_shared<RatchetTagSet>(shared_from_this ()):
|
||||||
|
std::make_shared<NSRatchetTagSet>(shared_from_this ());
|
||||||
tagsetNsr->DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey)
|
tagsetNsr->DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey)
|
||||||
tagsetNsr->NextSessionTagRatchet ();
|
tagsetNsr->NextSessionTagRatchet ();
|
||||||
return tagsetNsr;
|
return tagsetNsr;
|
||||||
|
@ -292,7 +321,7 @@ namespace garlic
|
||||||
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
|
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
|
||||||
memcpy (m_NextSendRatchet->remote, buf, 32);
|
memcpy (m_NextSendRatchet->remote, buf, 32);
|
||||||
uint8_t sharedSecret[32], tagsetKey[32];
|
uint8_t sharedSecret[32], tagsetKey[32];
|
||||||
m_NextSendRatchet->key.Agree (m_NextSendRatchet->remote, sharedSecret);
|
m_NextSendRatchet->key->Agree (m_NextSendRatchet->remote, sharedSecret);
|
||||||
i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32)
|
i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32)
|
||||||
auto newTagset = std::make_shared<RatchetTagSet> (shared_from_this ());
|
auto newTagset = std::make_shared<RatchetTagSet> (shared_from_this ());
|
||||||
newTagset->SetTagSetID (1 + m_NextSendRatchet->keyID + keyID);
|
newTagset->SetTagSetID (1 + m_NextSendRatchet->keyID + keyID);
|
||||||
|
@ -324,7 +353,7 @@ namespace garlic
|
||||||
int tagsetID = 2*keyID;
|
int tagsetID = 2*keyID;
|
||||||
if (newKey)
|
if (newKey)
|
||||||
{
|
{
|
||||||
m_NextReceiveRatchet->key.GenerateKeys ();
|
m_NextReceiveRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||||
m_NextReceiveRatchet->newKey = true;
|
m_NextReceiveRatchet->newKey = true;
|
||||||
tagsetID++;
|
tagsetID++;
|
||||||
}
|
}
|
||||||
|
@ -334,13 +363,14 @@ namespace garlic
|
||||||
memcpy (m_NextReceiveRatchet->remote, buf, 32);
|
memcpy (m_NextReceiveRatchet->remote, buf, 32);
|
||||||
|
|
||||||
uint8_t sharedSecret[32], tagsetKey[32];
|
uint8_t sharedSecret[32], tagsetKey[32];
|
||||||
m_NextReceiveRatchet->key.Agree (m_NextReceiveRatchet->remote, sharedSecret);
|
m_NextReceiveRatchet->key->Agree (m_NextReceiveRatchet->remote, sharedSecret);
|
||||||
i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32)
|
i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32)
|
||||||
auto newTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
|
auto newTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
|
||||||
newTagset->SetTagSetID (tagsetID);
|
newTagset->SetTagSetID (tagsetID);
|
||||||
newTagset->DHInitialize (receiveTagset->GetNextRootKey (), tagsetKey);
|
newTagset->DHInitialize (receiveTagset->GetNextRootKey (), tagsetKey);
|
||||||
newTagset->NextSessionTagRatchet ();
|
newTagset->NextSessionTagRatchet ();
|
||||||
GenerateMoreReceiveTags (newTagset, ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
||||||
|
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
||||||
receiveTagset->Expire ();
|
receiveTagset->Expire ();
|
||||||
LogPrint (eLogDebug, "Garlic: next receive tagset ", tagsetID, " created");
|
LogPrint (eLogDebug, "Garlic: next receive tagset ", tagsetID, " created");
|
||||||
}
|
}
|
||||||
|
@ -361,7 +391,7 @@ namespace garlic
|
||||||
else
|
else
|
||||||
m_NextSendRatchet.reset (new DHRatchet ());
|
m_NextSendRatchet.reset (new DHRatchet ());
|
||||||
if (m_NextSendRatchet->newKey)
|
if (m_NextSendRatchet->newKey)
|
||||||
m_NextSendRatchet->key.GenerateKeys ();
|
m_NextSendRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||||
|
|
||||||
m_SendForwardKey = true;
|
m_SendForwardKey = true;
|
||||||
LogPrint (eLogDebug, "Garlic: new send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created");
|
LogPrint (eLogDebug, "Garlic: new send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created");
|
||||||
|
@ -381,9 +411,9 @@ namespace garlic
|
||||||
|
|
||||||
// KDF1
|
// KDF1
|
||||||
MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk)
|
MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk)
|
||||||
MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk)
|
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk)
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk)
|
m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
// encrypt static key section
|
// encrypt static key section
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
|
@ -416,8 +446,8 @@ namespace garlic
|
||||||
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||||
{
|
{
|
||||||
// we are Bob
|
// we are Bob
|
||||||
m_NSRTagset = CreateNewSessionTagset ();
|
m_NSRSendTagset = CreateNewSessionTagset ();
|
||||||
uint64_t tag = m_NSRTagset->GetNextSessionTag ();
|
uint64_t tag = m_NSRSendTagset->GetNextSessionTag ();
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
memcpy (out + offset, &tag, 8);
|
memcpy (out + offset, &tag, 8);
|
||||||
|
@ -432,11 +462,11 @@ namespace garlic
|
||||||
offset += 32;
|
offset += 32;
|
||||||
// KDF for Reply Key Section
|
// KDF for Reply Key Section
|
||||||
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
|
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
|
||||||
MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk)
|
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk)
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
m_EphemeralKeys.Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk)
|
m_EphemeralKeys->Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
||||||
m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk)
|
m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (0, nonce);
|
CreateNonce (0, nonce);
|
||||||
|
@ -458,7 +488,8 @@ namespace garlic
|
||||||
m_SendTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
|
m_SendTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
|
||||||
m_SendTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
m_SendTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
||||||
m_SendTagset->NextSessionTagRatchet ();
|
m_SendTagset->NextSessionTagRatchet ();
|
||||||
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_MIN_NUM_GENERATED_TAGS);
|
GenerateMoreReceiveTags (receiveTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
||||||
|
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MIN_NUM_GENERATED_TAGS);
|
||||||
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
||||||
// encrypt payload
|
// encrypt payload
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt
|
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt
|
||||||
|
@ -475,13 +506,13 @@ namespace garlic
|
||||||
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||||
{
|
{
|
||||||
// we are Bob and sent NSR already
|
// we are Bob and sent NSR already
|
||||||
uint64_t tag = m_NSRTagset->GetNextSessionTag (); // next tag
|
uint64_t tag = m_NSRSendTagset->GetNextSessionTag (); // next tag
|
||||||
memcpy (out, &tag, 8);
|
memcpy (out, &tag, 8);
|
||||||
memcpy (out + 8, m_NSREncodedKey, 32);
|
memcpy (out + 8, m_NSREncodedKey, 32);
|
||||||
// recalculate h with new tag
|
// recalculate h with new tag
|
||||||
memcpy (m_H, m_NSRH, 32);
|
memcpy (m_H, m_NSRH, 32);
|
||||||
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
|
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
|
||||||
MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk)
|
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk)
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (0, nonce);
|
CreateNonce (0, nonce);
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + 40, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad)
|
if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + 40, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad)
|
||||||
|
@ -520,7 +551,7 @@ namespace garlic
|
||||||
if (m_State == eSessionStateNewSessionSent)
|
if (m_State == eSessionStateNewSessionSent)
|
||||||
{
|
{
|
||||||
// only fist time, we assume ephemeral keys the same
|
// only fist time, we assume ephemeral keys the same
|
||||||
m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk)
|
m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
||||||
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk)
|
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
@ -547,7 +578,8 @@ namespace garlic
|
||||||
auto receiveTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
|
auto receiveTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
|
||||||
receiveTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
receiveTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
||||||
receiveTagset->NextSessionTagRatchet ();
|
receiveTagset->NextSessionTagRatchet ();
|
||||||
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_MIN_NUM_GENERATED_TAGS);
|
GenerateMoreReceiveTags (receiveTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
||||||
|
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MIN_NUM_GENERATED_TAGS);
|
||||||
}
|
}
|
||||||
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
||||||
// decrypt payload
|
// decrypt payload
|
||||||
|
@ -560,6 +592,7 @@ namespace garlic
|
||||||
if (m_State == eSessionStateNewSessionSent)
|
if (m_State == eSessionStateNewSessionSent)
|
||||||
{
|
{
|
||||||
m_State = eSessionStateEstablished;
|
m_State = eSessionStateEstablished;
|
||||||
|
m_EphemeralKeys = nullptr;
|
||||||
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||||
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
||||||
}
|
}
|
||||||
|
@ -609,11 +642,23 @@ namespace garlic
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
HandlePayload (payload, len - 16, receiveTagset, index);
|
HandlePayload (payload, len - 16, receiveTagset, index);
|
||||||
int moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
|
if (GetOwner ())
|
||||||
|
{
|
||||||
|
int moreTags = 0;
|
||||||
|
if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings?
|
||||||
|
{
|
||||||
|
if (receiveTagset->GetNextIndex () - index < GetOwner ()->GetNumRatchetInboundTags ()/2)
|
||||||
|
moreTags = GetOwner ()->GetNumRatchetInboundTags ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
|
||||||
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
|
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
|
||||||
moreTags -= (receiveTagset->GetNextIndex () - index);
|
moreTags -= (receiveTagset->GetNextIndex () - index);
|
||||||
if (moreTags > 0 && GetOwner ())
|
}
|
||||||
|
if (moreTags > 0)
|
||||||
GenerateMoreReceiveTags (receiveTagset, moreTags);
|
GenerateMoreReceiveTags (receiveTagset, moreTags);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +670,8 @@ namespace garlic
|
||||||
{
|
{
|
||||||
case eSessionStateNewSessionReplySent:
|
case eSessionStateNewSessionReplySent:
|
||||||
m_State = eSessionStateEstablished;
|
m_State = eSessionStateEstablished;
|
||||||
m_NSRTagset = nullptr;
|
m_NSRSendTagset = nullptr;
|
||||||
|
m_EphemeralKeys = nullptr;
|
||||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
#endif
|
#endif
|
||||||
|
@ -693,8 +739,11 @@ namespace garlic
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
size_t payloadLen = 0;
|
size_t payloadLen = 0;
|
||||||
if (first) payloadLen += 7;// datatime
|
if (first) payloadLen += 7;// datatime
|
||||||
if (msg && m_Destination)
|
if (msg)
|
||||||
payloadLen += msg->GetPayloadLength () + 13 + 32;
|
{
|
||||||
|
payloadLen += msg->GetPayloadLength () + 13;
|
||||||
|
if (m_Destination) payloadLen += 32;
|
||||||
|
}
|
||||||
auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated ||
|
auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated ||
|
||||||
(GetLeaseSetUpdateStatus () == eLeaseSetSubmitted &&
|
(GetLeaseSetUpdateStatus () == eLeaseSetSubmitted &&
|
||||||
ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)) ?
|
ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)) ?
|
||||||
|
@ -724,13 +773,17 @@ namespace garlic
|
||||||
if (m_NextSendRatchet->newKey) payloadLen += 32;
|
if (m_NextSendRatchet->newKey) payloadLen += 32;
|
||||||
}
|
}
|
||||||
uint8_t paddingSize = 0;
|
uint8_t paddingSize = 0;
|
||||||
if (payloadLen)
|
if (payloadLen || ts > m_LastSentTimestamp + ECIESX25519_SEND_INACTIVITY_TIMEOUT)
|
||||||
{
|
{
|
||||||
int delta = (int)ECIESX25519_OPTIMAL_PAYLOAD_SIZE - (int)payloadLen;
|
int delta = (int)ECIESX25519_OPTIMAL_PAYLOAD_SIZE - (int)payloadLen;
|
||||||
if (delta < 0 || delta > 3) // don't create padding if we are close to optimal size
|
if (delta < 0 || delta > 3) // don't create padding if we are close to optimal size
|
||||||
{
|
{
|
||||||
RAND_bytes (&paddingSize, 1);
|
paddingSize = m_PaddingSizes[m_NextPaddingSize++] & 0x0F; // 0 - 15
|
||||||
paddingSize &= 0x0F; // 0 - 15
|
if (m_NextPaddingSize >= 32)
|
||||||
|
{
|
||||||
|
RAND_bytes (m_PaddingSizes, 32);
|
||||||
|
m_NextPaddingSize = 0;
|
||||||
|
}
|
||||||
if (delta > 3)
|
if (delta > 3)
|
||||||
{
|
{
|
||||||
delta -= 3;
|
delta -= 3;
|
||||||
|
@ -741,6 +794,9 @@ namespace garlic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<uint8_t> v(payloadLen);
|
std::vector<uint8_t> v(payloadLen);
|
||||||
|
if (payloadLen)
|
||||||
|
{
|
||||||
|
m_LastSentTimestamp = ts;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
// DateTime
|
// DateTime
|
||||||
if (first)
|
if (first)
|
||||||
|
@ -763,7 +819,7 @@ namespace garlic
|
||||||
}
|
}
|
||||||
// msg
|
// msg
|
||||||
if (msg && m_Destination)
|
if (msg && m_Destination)
|
||||||
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true);
|
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset);
|
||||||
// ack
|
// ack
|
||||||
if (m_AckRequests.size () > 0)
|
if (m_AckRequests.size () > 0)
|
||||||
{
|
{
|
||||||
|
@ -792,7 +848,7 @@ namespace garlic
|
||||||
htobe16buf (v.data () + offset, keyID); offset += 2; // keyid
|
htobe16buf (v.data () + offset, keyID); offset += 2; // keyid
|
||||||
if (m_NextReceiveRatchet->newKey)
|
if (m_NextReceiveRatchet->newKey)
|
||||||
{
|
{
|
||||||
memcpy (v.data () + offset, m_NextReceiveRatchet->key.GetPublicKey (), 32);
|
memcpy (v.data () + offset, m_NextReceiveRatchet->key->GetPublicKey (), 32);
|
||||||
offset += 32; // public key
|
offset += 32; // public key
|
||||||
}
|
}
|
||||||
m_SendReverseKey = false;
|
m_SendReverseKey = false;
|
||||||
|
@ -807,7 +863,7 @@ namespace garlic
|
||||||
htobe16buf (v.data () + offset, m_NextSendRatchet->keyID); offset += 2; // keyid
|
htobe16buf (v.data () + offset, m_NextSendRatchet->keyID); offset += 2; // keyid
|
||||||
if (m_NextSendRatchet->newKey)
|
if (m_NextSendRatchet->newKey)
|
||||||
{
|
{
|
||||||
memcpy (v.data () + offset, m_NextSendRatchet->key.GetPublicKey (), 32);
|
memcpy (v.data () + offset, m_NextSendRatchet->key->GetPublicKey (), 32);
|
||||||
offset += 32; // public key
|
offset += 32; // public key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -818,19 +874,20 @@ namespace garlic
|
||||||
htobe16buf (v.data () + offset, paddingSize); offset += 2;
|
htobe16buf (v.data () + offset, paddingSize); offset += 2;
|
||||||
memset (v.data () + offset, 0, paddingSize); offset += paddingSize;
|
memset (v.data () + offset, 0, paddingSize); offset += paddingSize;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ECIESX25519AEADRatchetSession::CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination)
|
size_t ECIESX25519AEADRatchetSession::CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (!msg) return 0;
|
if (!msg) return 0;
|
||||||
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1;
|
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1;
|
||||||
if (isDestination) cloveSize += 32;
|
if (m_Destination) cloveSize += 32;
|
||||||
if ((int)len < cloveSize + 3) return 0;
|
if ((int)len < cloveSize + 3) return 0;
|
||||||
buf[0] = eECIESx25519BlkGalicClove; // clove type
|
buf[0] = eECIESx25519BlkGalicClove; // clove type
|
||||||
htobe16buf (buf + 1, cloveSize); // size
|
htobe16buf (buf + 1, cloveSize); // size
|
||||||
buf += 3;
|
buf += 3;
|
||||||
if (isDestination)
|
if (m_Destination)
|
||||||
{
|
{
|
||||||
*buf = (eGarlicDeliveryTypeDestination << 5);
|
*buf = (eGarlicDeliveryTypeDestination << 5);
|
||||||
memcpy (buf + 1, *m_Destination, 32); buf += 32;
|
memcpy (buf + 1, *m_Destination, 32); buf += 32;
|
||||||
|
|
|
@ -27,7 +27,8 @@ namespace garlic
|
||||||
{
|
{
|
||||||
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
|
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
|
||||||
const int ECIESX25519_EXPIRATION_TIMEOUT = 480; // in seconds
|
const int ECIESX25519_EXPIRATION_TIMEOUT = 480; // in seconds
|
||||||
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of second we receive nothing and should restart if we can
|
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can
|
||||||
|
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||||
const int ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT = 600; // in seconds
|
const int ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
||||||
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 4096; // number of tags we request new tagset after
|
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 4096; // number of tags we request new tagset after
|
||||||
|
@ -79,6 +80,18 @@ namespace garlic
|
||||||
uint64_t m_ExpirationTimestamp = 0;
|
uint64_t m_ExpirationTimestamp = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NSRatchetTagSet: public RatchetTagSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NSRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session):
|
||||||
|
RatchetTagSet (session), m_DummySession (session) {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::shared_ptr<ECIESX25519AEADRatchetSession> m_DummySession; // we need a strong pointer for NS
|
||||||
|
};
|
||||||
|
|
||||||
enum ECIESx25519BlockType
|
enum ECIESx25519BlockType
|
||||||
{
|
{
|
||||||
eECIESx25519BlkDateTime = 0,
|
eECIESx25519BlkDateTime = 0,
|
||||||
|
@ -110,7 +123,7 @@ namespace garlic
|
||||||
struct DHRatchet
|
struct DHRatchet
|
||||||
{
|
{
|
||||||
int keyID = 0;
|
int keyID = 0;
|
||||||
i2p::crypto::X25519Keys key;
|
std::shared_ptr<i2p::crypto::X25519Keys> key;
|
||||||
uint8_t remote[32]; // last remote public key
|
uint8_t remote[32]; // last remote public key
|
||||||
bool newKey = true;
|
bool newKey = true;
|
||||||
};
|
};
|
||||||
|
@ -136,6 +149,7 @@ namespace garlic
|
||||||
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
|
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
|
||||||
|
|
||||||
bool IsRatchets () const { return true; };
|
bool IsRatchets () const { return true; };
|
||||||
|
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -157,7 +171,7 @@ namespace garlic
|
||||||
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||||
|
|
||||||
std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first);
|
std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first);
|
||||||
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false);
|
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len);
|
||||||
size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
|
size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
|
||||||
|
|
||||||
void GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags);
|
void GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags);
|
||||||
|
@ -168,14 +182,16 @@ namespace garlic
|
||||||
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32];
|
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32];
|
||||||
uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only
|
uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only
|
||||||
uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only
|
uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only
|
||||||
i2p::crypto::X25519Keys m_EphemeralKeys;
|
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||||
SessionState m_State = eSessionStateNew;
|
SessionState m_State = eSessionStateNew;
|
||||||
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0; // incoming
|
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming
|
||||||
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRTagset;
|
m_LastSentTimestamp = 0; // in milliseconds
|
||||||
|
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
|
||||||
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
|
||||||
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
|
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
|
||||||
bool m_SendReverseKey = false, m_SendForwardKey = false;
|
bool m_SendReverseKey = false, m_SendForwardKey = false;
|
||||||
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
||||||
|
uint8_t m_PaddingSizes[32], m_NextPaddingSize;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -432,7 +432,8 @@ namespace garlic
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default
|
GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
|
||||||
|
m_NumRatchetInboundTags (0) // 0 means standard
|
||||||
{
|
{
|
||||||
m_Ctx = BN_CTX_new ();
|
m_Ctx = BN_CTX_new ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ namespace garlic
|
||||||
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
||||||
virtual bool MessageConfirmed (uint32_t msgID);
|
virtual bool MessageConfirmed (uint32_t msgID);
|
||||||
virtual bool IsRatchets () const { return false; };
|
virtual bool IsRatchets () const { return false; };
|
||||||
|
virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only
|
||||||
|
|
||||||
void SetLeaseSetUpdated ()
|
void SetLeaseSetUpdated ()
|
||||||
{
|
{
|
||||||
|
@ -232,6 +233,8 @@ namespace garlic
|
||||||
void CleanUp ();
|
void CleanUp ();
|
||||||
void SetNumTags (int numTags) { m_NumTags = numTags; };
|
void SetNumTags (int numTags) { m_NumTags = numTags; };
|
||||||
int GetNumTags () const { return m_NumTags; };
|
int GetNumTags () const { return m_NumTags; };
|
||||||
|
void SetNumRatchetInboundTags (int numTags) { m_NumRatchetInboundTags = numTags; };
|
||||||
|
int GetNumRatchetInboundTags () const { return m_NumRatchetInboundTags; };
|
||||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
||||||
void CleanupExpiredTags ();
|
void CleanupExpiredTags ();
|
||||||
void RemoveDeliveryStatusSession (uint32_t msgID);
|
void RemoveDeliveryStatusSession (uint32_t msgID);
|
||||||
|
@ -278,6 +281,7 @@ namespace garlic
|
||||||
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
||||||
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
||||||
// incoming
|
// incoming
|
||||||
|
int m_NumRatchetInboundTags;
|
||||||
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
||||||
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
|
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
|
||||||
// DeliveryStatus
|
// DeliveryStatus
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace transport
|
||||||
|
|
||||||
void NTCP2Establisher::KDF1Alice ()
|
void NTCP2Establisher::KDF1Alice ()
|
||||||
{
|
{
|
||||||
KeyDerivationFunction1 (m_RemoteStaticKey, m_EphemeralKeys, m_RemoteStaticKey, GetPub ());
|
KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::KDF1Bob ()
|
void NTCP2Establisher::KDF1Bob ()
|
||||||
|
@ -102,7 +102,7 @@ namespace transport
|
||||||
|
|
||||||
// x25519 between remote pub and ephemaral priv
|
// x25519 between remote pub and ephemaral priv
|
||||||
uint8_t inputKeyMaterial[32];
|
uint8_t inputKeyMaterial[32];
|
||||||
m_EphemeralKeys.Agree (GetRemotePub (), inputKeyMaterial);
|
m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial);
|
||||||
|
|
||||||
MixKey (inputKeyMaterial);
|
MixKey (inputKeyMaterial);
|
||||||
}
|
}
|
||||||
|
@ -127,13 +127,13 @@ namespace transport
|
||||||
void NTCP2Establisher::KDF3Bob ()
|
void NTCP2Establisher::KDF3Bob ()
|
||||||
{
|
{
|
||||||
uint8_t inputKeyMaterial[32];
|
uint8_t inputKeyMaterial[32];
|
||||||
m_EphemeralKeys.Agree (m_RemoteStaticKey, inputKeyMaterial);
|
m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial);
|
||||||
MixKey (inputKeyMaterial);
|
MixKey (inputKeyMaterial);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::CreateEphemeralKey ()
|
void NTCP2Establisher::CreateEphemeralKey ()
|
||||||
{
|
{
|
||||||
m_EphemeralKeys.GenerateKeys ();
|
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::CreateSessionRequestMessage ()
|
void NTCP2Establisher::CreateSessionRequestMessage ()
|
||||||
|
@ -338,11 +338,8 @@ namespace transport
|
||||||
|
|
||||||
KDF3Bob ();
|
KDF3Bob ();
|
||||||
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
|
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, GetH (), 32, GetK (), nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
|
||||||
{
|
|
||||||
// caclulate new h again for KDF data
|
// caclulate new h again for KDF data
|
||||||
memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext
|
MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
|
||||||
SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
|
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
|
||||||
|
@ -1305,7 +1302,8 @@ namespace transport
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
|
||||||
//i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
if (conn->GetRemoteIdentity ())
|
||||||
|
i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true);
|
||||||
conn->Terminate ();
|
conn->Terminate ();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace transport
|
||||||
NTCP2Establisher ();
|
NTCP2Establisher ();
|
||||||
~NTCP2Establisher ();
|
~NTCP2Establisher ();
|
||||||
|
|
||||||
const uint8_t * GetPub () const { return m_EphemeralKeys.GetPublicKey (); };
|
const uint8_t * GetPub () const { return m_EphemeralKeys->GetPublicKey (); };
|
||||||
const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob
|
const uint8_t * GetRemotePub () const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob
|
||||||
uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set
|
uint8_t * GetRemotePub () { return m_RemoteEphemeralPublicKey; }; // to set
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ namespace transport
|
||||||
bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
||||||
bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
|
bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
|
||||||
|
|
||||||
i2p::crypto::X25519Keys m_EphemeralKeys;
|
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||||
uint8_t m_RemoteEphemeralPublicKey[32]; // x25519
|
uint8_t m_RemoteEphemeralPublicKey[32]; // x25519
|
||||||
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[64] /* [ck, k]*/;
|
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[64] /* [ck, k]*/;
|
||||||
i2p::data::IdentHash m_RemoteIdentHash;
|
i2p::data::IdentHash m_RemoteIdentHash;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
// this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs
|
// this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -138,9 +138,9 @@ namespace data
|
||||||
private:
|
private:
|
||||||
|
|
||||||
mutable std::mutex m_LeaseSetsMutex;
|
mutable std::mutex m_LeaseSetsMutex;
|
||||||
std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
|
std::unordered_map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
|
||||||
mutable std::mutex m_RouterInfosMutex;
|
mutable std::mutex m_RouterInfosMutex;
|
||||||
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
|
std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
|
||||||
mutable std::mutex m_FloodfillsMutex;
|
mutable std::mutex m_FloodfillsMutex;
|
||||||
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,7 @@ namespace transport
|
||||||
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
uint32_t msgID = msg->ToSSU ();
|
uint32_t msgID = msg->ToSSU ();
|
||||||
if (m_SentMessages.count (msgID) > 0)
|
if (m_SentMessages.find (msgID) != m_SentMessages.end())
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
|
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
|
||||||
return;
|
return;
|
||||||
|
@ -326,8 +326,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
Fragment * fragment = new Fragment;
|
Fragment * fragment = new Fragment;
|
||||||
fragment->fragmentNum = fragmentNum;
|
fragment->fragmentNum = fragmentNum;
|
||||||
uint8_t * buf = fragment->buf;
|
uint8_t * payload = fragment->buf + sizeof (SSUHeader);
|
||||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
|
||||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||||
payload++;
|
payload++;
|
||||||
*payload = 1; // always 1 message fragment per message
|
*payload = 1; // always 1 message fragment per message
|
||||||
|
@ -346,14 +345,20 @@ namespace transport
|
||||||
payload += 3;
|
payload += 3;
|
||||||
memcpy (payload, msgBuf, size);
|
memcpy (payload, msgBuf, size);
|
||||||
|
|
||||||
size += payload - buf;
|
size += payload - fragment->buf;
|
||||||
if (size & 0x0F) // make sure 16 bytes boundary
|
uint8_t rem = size & 0x0F;
|
||||||
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
|
if (rem) // make sure 16 bytes boundary
|
||||||
|
{
|
||||||
|
auto padding = 16 - rem;
|
||||||
|
memset (fragment->buf + size, 0, padding);
|
||||||
|
size += padding;
|
||||||
|
}
|
||||||
fragment->len = size;
|
fragment->len = size;
|
||||||
fragments.push_back (std::unique_ptr<Fragment> (fragment));
|
fragments.push_back (std::unique_ptr<Fragment> (fragment));
|
||||||
|
|
||||||
// encrypt message with session key
|
// encrypt message with session key
|
||||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
|
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
||||||
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Session.Send (buf, size);
|
m_Session.Send (buf, size);
|
||||||
|
@ -432,6 +437,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
|
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
int numResent = 0;
|
int numResent = 0;
|
||||||
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
||||||
|
@ -445,7 +451,8 @@ namespace transport
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Session.Send (f->buf, f->len); // resend
|
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
|
||||||
|
m_Session.Send (buf, f->len); // resend
|
||||||
numResent++;
|
numResent++;
|
||||||
}
|
}
|
||||||
catch (boost::system::system_error& ec)
|
catch (boost::system::system_error& ec)
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -124,8 +124,8 @@ namespace transport
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SSUSession& m_Session;
|
SSUSession& m_Session;
|
||||||
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
|
std::unordered_map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
|
||||||
std::map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages;
|
std::unordered_map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages;
|
||||||
std::unordered_set<uint32_t> m_ReceivedMessages;
|
std::unordered_set<uint32_t> m_ReceivedMessages;
|
||||||
boost::asio::deadline_timer m_ResendTimer, m_IncompleteMessagesCleanupTimer;
|
boost::asio::deadline_timer m_ResendTimer, m_IncompleteMessagesCleanupTimer;
|
||||||
int m_MaxPacketSize, m_PacketSize;
|
int m_MaxPacketSize, m_PacketSize;
|
||||||
|
|
|
@ -744,24 +744,30 @@ namespace transport
|
||||||
}
|
}
|
||||||
|
|
||||||
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len)
|
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
FillHeaderAndEncrypt (payloadType, buf, len, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out)
|
||||||
{
|
{
|
||||||
if (len < sizeof (SSUHeader))
|
if (len < sizeof (SSUHeader))
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SSUHeader * header = (SSUHeader *)buf;
|
SSUHeader * header = (SSUHeader *)out;
|
||||||
RAND_bytes (header->iv, 16); // random iv
|
RAND_bytes (header->iv, 16); // random iv
|
||||||
m_SessionKeyEncryption.SetIV (header->iv);
|
m_SessionKeyEncryption.SetIV (header->iv);
|
||||||
header->flag = payloadType << 4; // MSB is 0
|
SSUHeader * inHeader = (SSUHeader *)in;
|
||||||
htobe32buf (header->time, i2p::util::GetSecondsSinceEpoch ());
|
inHeader->flag = payloadType << 4; // MSB is 0
|
||||||
uint8_t * encrypted = &header->flag;
|
htobe32buf (inHeader->time, i2p::util::GetSecondsSinceEpoch ());
|
||||||
uint16_t encryptedLen = len - (encrypted - buf);
|
uint8_t * encrypted = &header->flag, * clear = &inHeader->flag;
|
||||||
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
|
uint16_t encryptedLen = len - (encrypted - out);
|
||||||
// assume actual buffer size is 18 (16 + 2) bytes more
|
m_SessionKeyEncryption.Encrypt (clear, encryptedLen, encrypted);
|
||||||
memcpy (buf + len, header->iv, 16);
|
// assume actual out buffer size is 18 (16 + 2) bytes more
|
||||||
|
memcpy (out + len, header->iv, 16);
|
||||||
uint16_t netid = i2p::context.GetNetID ();
|
uint16_t netid = i2p::context.GetNetID ();
|
||||||
htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
|
htobe16buf (out + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
|
||||||
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
|
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,7 @@ namespace transport
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
|
||||||
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
|
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
|
||||||
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
|
||||||
|
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * in, size_t len, uint8_t * out); // with session key
|
||||||
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
|
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
|
||||||
void DecryptSessionKey (uint8_t * buf, size_t len);
|
void DecryptSessionKey (uint8_t * buf, size_t len);
|
||||||
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
|
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
|
||||||
|
|
|
@ -21,23 +21,27 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
DHKeysPairSupplier::DHKeysPairSupplier (int size):
|
template<typename Keys>
|
||||||
|
EphemeralKeysSupplier<Keys>::EphemeralKeysSupplier (int size):
|
||||||
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
m_QueueSize (size), m_IsRunning (false), m_Thread (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
DHKeysPairSupplier::~DHKeysPairSupplier ()
|
template<typename Keys>
|
||||||
|
EphemeralKeysSupplier<Keys>::~EphemeralKeysSupplier ()
|
||||||
{
|
{
|
||||||
Stop ();
|
Stop ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Start ()
|
template<typename Keys>
|
||||||
|
void EphemeralKeysSupplier<Keys>::Start ()
|
||||||
{
|
{
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&DHKeysPairSupplier::Run, this));
|
m_Thread = new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Stop ()
|
template<typename Keys>
|
||||||
|
void EphemeralKeysSupplier<Keys>::Stop ()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
|
@ -52,19 +56,20 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Run ()
|
template<typename Keys>
|
||||||
|
void EphemeralKeysSupplier<Keys>::Run ()
|
||||||
{
|
{
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
int num, total = 0;
|
int num, total = 0;
|
||||||
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10)
|
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10)
|
||||||
{
|
{
|
||||||
CreateDHKeysPairs (num);
|
CreateEphemeralKeys (num);
|
||||||
total += num;
|
total += num;
|
||||||
}
|
}
|
||||||
if (total >= 10)
|
if (total >= 10)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Transports: ", total, " DH keys generated at the time");
|
LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time");
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
|
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -76,13 +81,14 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::CreateDHKeysPairs (int num)
|
template<typename Keys>
|
||||||
|
void EphemeralKeysSupplier<Keys>::CreateEphemeralKeys (int num)
|
||||||
{
|
{
|
||||||
if (num > 0)
|
if (num > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num; i++)
|
for (int i = 0; i < num; i++)
|
||||||
{
|
{
|
||||||
auto pair = std::make_shared<i2p::crypto::DHKeys> ();
|
auto pair = std::make_shared<Keys> ();
|
||||||
pair->GenerateKeys ();
|
pair->GenerateKeys ();
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
m_Queue.push (pair);
|
m_Queue.push (pair);
|
||||||
|
@ -90,7 +96,8 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::crypto::DHKeys> DHKeysPairSupplier::Acquire ()
|
template<typename Keys>
|
||||||
|
std::shared_ptr<Keys> EphemeralKeysSupplier<Keys>::Acquire ()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
std::unique_lock<std::mutex> l(m_AcquiredMutex);
|
||||||
|
@ -103,12 +110,13 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// queue is empty, create new
|
// queue is empty, create new
|
||||||
auto pair = std::make_shared<i2p::crypto::DHKeys> ();
|
auto pair = std::make_shared<Keys> ();
|
||||||
pair->GenerateKeys ();
|
pair->GenerateKeys ();
|
||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DHKeysPairSupplier::Return (std::shared_ptr<i2p::crypto::DHKeys> pair)
|
template<typename Keys>
|
||||||
|
void EphemeralKeysSupplier<Keys>::Return (std::shared_ptr<Keys> pair)
|
||||||
{
|
{
|
||||||
if (pair)
|
if (pair)
|
||||||
{
|
{
|
||||||
|
@ -126,7 +134,7 @@ namespace transport
|
||||||
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_Thread (nullptr), m_Service (nullptr),
|
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_Thread (nullptr), m_Service (nullptr),
|
||||||
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
|
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
|
||||||
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_NTCP2Server (nullptr),
|
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_NTCP2Server (nullptr),
|
||||||
m_DHKeysPairSupplier (5), // 5 pre-generated keys
|
m_DHKeysPairSupplier (5), m_X25519KeysPairSupplier (5), // 5 pre-generated keys
|
||||||
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
|
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
|
||||||
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
|
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
|
||||||
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
|
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
|
||||||
|
@ -158,6 +166,7 @@ namespace transport
|
||||||
|
|
||||||
i2p::config::GetOption("nat", m_IsNAT);
|
i2p::config::GetOption("nat", m_IsNAT);
|
||||||
m_DHKeysPairSupplier.Start ();
|
m_DHKeysPairSupplier.Start ();
|
||||||
|
m_X25519KeysPairSupplier.Start ();
|
||||||
m_IsRunning = true;
|
m_IsRunning = true;
|
||||||
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
m_Thread = new std::thread (std::bind (&Transports::Run, this));
|
||||||
std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy);
|
std::string ntcpproxy; i2p::config::GetOption("ntcpproxy", ntcpproxy);
|
||||||
|
@ -312,6 +321,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
|
|
||||||
m_DHKeysPairSupplier.Stop ();
|
m_DHKeysPairSupplier.Stop ();
|
||||||
|
m_X25519KeysPairSupplier.Stop ();
|
||||||
m_IsRunning = false;
|
m_IsRunning = false;
|
||||||
if (m_Service) m_Service->stop ();
|
if (m_Service) m_Service->stop ();
|
||||||
if (m_Thread)
|
if (m_Thread)
|
||||||
|
@ -431,6 +441,8 @@ namespace transport
|
||||||
|
|
||||||
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
|
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
|
||||||
{
|
{
|
||||||
|
if (!peer.router) // reconnect
|
||||||
|
peer.router = netdb.FindRouter (ident); // try to get new one from netdb
|
||||||
if (peer.router) // we have RI already
|
if (peer.router) // we have RI already
|
||||||
{
|
{
|
||||||
if (!peer.numAttempts) // NTCP2
|
if (!peer.numAttempts) // NTCP2
|
||||||
|
@ -440,7 +452,7 @@ namespace transport
|
||||||
{
|
{
|
||||||
// NTCP2 have priority over NTCP
|
// NTCP2 have priority over NTCP
|
||||||
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
|
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
|
||||||
if (address)
|
if (address && !peer.router->IsUnreachable ())
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
|
||||||
|
|
||||||
|
@ -628,6 +640,16 @@ namespace transport
|
||||||
m_DHKeysPairSupplier.Return (pair);
|
m_DHKeysPairSupplier.Return (pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<i2p::crypto::X25519Keys> Transports::GetNextX25519KeysPair ()
|
||||||
|
{
|
||||||
|
return m_X25519KeysPairSupplier.Acquire ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Transports::ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair)
|
||||||
|
{
|
||||||
|
m_X25519KeysPairSupplier.Return (pair);
|
||||||
|
}
|
||||||
|
|
||||||
void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
|
void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
|
||||||
{
|
{
|
||||||
m_Service->post([session, this]()
|
m_Service->post([session, this]()
|
||||||
|
@ -638,6 +660,7 @@ namespace transport
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
|
it->second.router = nullptr; // we don't need RouterInfo after successive connect
|
||||||
bool sendDatabaseStore = true;
|
bool sendDatabaseStore = true;
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (it->second.delayedMessages.size () > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -32,32 +32,36 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
class DHKeysPairSupplier
|
template<typename Keys>
|
||||||
|
class EphemeralKeysSupplier
|
||||||
{
|
{
|
||||||
|
// called from this file only, so implementation is in Transports.cpp
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DHKeysPairSupplier (int size);
|
EphemeralKeysSupplier (int size);
|
||||||
~DHKeysPairSupplier ();
|
~EphemeralKeysSupplier ();
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
std::shared_ptr<i2p::crypto::DHKeys> Acquire ();
|
std::shared_ptr<Keys> Acquire ();
|
||||||
void Return (std::shared_ptr<i2p::crypto::DHKeys> pair);
|
void Return (std::shared_ptr<Keys> pair);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
void Run ();
|
||||||
void CreateDHKeysPairs (int num);
|
void CreateEphemeralKeys (int num);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const int m_QueueSize;
|
const int m_QueueSize;
|
||||||
std::queue<std::shared_ptr<i2p::crypto::DHKeys> > m_Queue;
|
std::queue<std::shared_ptr<Keys> > m_Queue;
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::thread * m_Thread;
|
std::thread * m_Thread;
|
||||||
std::condition_variable m_Acquired;
|
std::condition_variable m_Acquired;
|
||||||
std::mutex m_AcquiredMutex;
|
std::mutex m_AcquiredMutex;
|
||||||
};
|
};
|
||||||
|
typedef EphemeralKeysSupplier<i2p::crypto::DHKeys> DHKeysPairSupplier;
|
||||||
|
typedef EphemeralKeysSupplier<i2p::crypto::X25519Keys> X25519KeysPairSupplier;
|
||||||
|
|
||||||
struct Peer
|
struct Peer
|
||||||
{
|
{
|
||||||
|
@ -97,6 +101,8 @@ namespace transport
|
||||||
boost::asio::io_service& GetService () { return *m_Service; };
|
boost::asio::io_service& GetService () { return *m_Service; };
|
||||||
std::shared_ptr<i2p::crypto::DHKeys> GetNextDHKeysPair ();
|
std::shared_ptr<i2p::crypto::DHKeys> GetNextDHKeysPair ();
|
||||||
void ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair);
|
void ReuseDHKeysPair (std::shared_ptr<i2p::crypto::DHKeys> pair);
|
||||||
|
std::shared_ptr<i2p::crypto::X25519Keys> GetNextX25519KeysPair ();
|
||||||
|
void ReuseX25519KeysPair (std::shared_ptr<i2p::crypto::X25519Keys> pair);
|
||||||
|
|
||||||
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
|
void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr<i2p::I2NPMessage> msg);
|
||||||
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
void SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs);
|
||||||
|
@ -157,9 +163,10 @@ namespace transport
|
||||||
SSUServer * m_SSUServer;
|
SSUServer * m_SSUServer;
|
||||||
NTCP2Server * m_NTCP2Server;
|
NTCP2Server * m_NTCP2Server;
|
||||||
mutable std::mutex m_PeersMutex;
|
mutable std::mutex m_PeersMutex;
|
||||||
std::map<i2p::data::IdentHash, Peer> m_Peers;
|
std::unordered_map<i2p::data::IdentHash, Peer> m_Peers;
|
||||||
|
|
||||||
DHKeysPairSupplier m_DHKeysPairSupplier;
|
DHKeysPairSupplier m_DHKeysPairSupplier;
|
||||||
|
X25519KeysPairSupplier m_X25519KeysPairSupplier;
|
||||||
|
|
||||||
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes;
|
std::atomic<uint64_t> m_TotalSentBytes, m_TotalReceivedBytes, m_TotalTransitTransmittedBytes;
|
||||||
uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; // bytes per second
|
uint32_t m_InBandwidth, m_OutBandwidth, m_TransitBandwidth; // bytes per second
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace tunnel
|
||||||
// length of bytes doesn't fit full tunnel message
|
// length of bytes doesn't fit full tunnel message
|
||||||
// every follow-on fragment adds 7 bytes
|
// every follow-on fragment adds 7 bytes
|
||||||
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||||
if (!nonFit || nonFit > m_RemainingSize)
|
if (!nonFit || nonFit > m_RemainingSize || m_RemainingSize < fullMsgLen/5)
|
||||||
{
|
{
|
||||||
CompleteCurrentTunnelDataMessage ();
|
CompleteCurrentTunnelDataMessage ();
|
||||||
CreateCurrentTunnelDataMessage ();
|
CreateCurrentTunnelDataMessage ();
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 32
|
#define I2PD_VERSION_MINOR 33
|
||||||
#define I2PD_VERSION_MICRO 1
|
#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)
|
||||||
#define VERSION I2PD_VERSION
|
#define VERSION I2PD_VERSION
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 46
|
#define I2P_VERSION_MICRO 47
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|
|
@ -197,6 +197,8 @@ namespace client
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& it: addresses)
|
for (const auto& it: addresses)
|
||||||
|
{
|
||||||
|
if (it.second->IsValid ())
|
||||||
{
|
{
|
||||||
f << it.first << ",";
|
f << it.first << ",";
|
||||||
if (it.second->IsIdentHash ())
|
if (it.second->IsIdentHash ())
|
||||||
|
@ -206,6 +208,9 @@ namespace client
|
||||||
f << std::endl;
|
f << std::endl;
|
||||||
num++;
|
num++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "Addressbook: invalid address ", it.first);
|
||||||
|
}
|
||||||
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
|
LogPrint (eLogInfo, "Addressbook: ", num, " addresses saved");
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,7 +253,8 @@ 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")
|
static const std::string transient("transient");
|
||||||
|
if (!filename.compare (0, transient.length (), transient)) // starts with transient
|
||||||
{
|
{
|
||||||
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
||||||
LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created");
|
||||||
|
@ -461,6 +462,8 @@ namespace client
|
||||||
}
|
}
|
||||||
std::string explicitPeers = GetI2CPStringOption(section, I2CP_PARAM_EXPLICIT_PEERS, "");
|
std::string explicitPeers = GetI2CPStringOption(section, I2CP_PARAM_EXPLICIT_PEERS, "");
|
||||||
if (explicitPeers.length () > 0) options[I2CP_PARAM_EXPLICIT_PEERS] = explicitPeers;
|
if (explicitPeers.length () > 0) options[I2CP_PARAM_EXPLICIT_PEERS] = explicitPeers;
|
||||||
|
std::string ratchetInboundTags = GetI2CPStringOption(section, I2CP_PARAM_RATCHET_INBOUND_TAGS, "");
|
||||||
|
if (ratchetInboundTags.length () > 0) options[I2CP_PARAM_RATCHET_INBOUND_TAGS] = ratchetInboundTags;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -531,6 +534,7 @@ namespace client
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::shared_ptr<ClientDestination> > destinations; // keys -> destination
|
||||||
for (auto& section: pt)
|
for (auto& section: pt)
|
||||||
{
|
{
|
||||||
std::string name = section.first;
|
std::string name = section.first;
|
||||||
|
@ -561,6 +565,11 @@ namespace client
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
if (keys.length () > 0)
|
if (keys.length () > 0)
|
||||||
|
{
|
||||||
|
auto it = destinations.find (keys);
|
||||||
|
if (it != destinations.end ())
|
||||||
|
localDestination = it->second;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys k;
|
i2p::data::PrivateKeys k;
|
||||||
if(LoadPrivateKeys (k, keys, sigType, cryptoType))
|
if(LoadPrivateKeys (k, keys, sigType, cryptoType))
|
||||||
|
@ -572,6 +581,8 @@ namespace client
|
||||||
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
|
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
|
||||||
else
|
else
|
||||||
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
|
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
|
||||||
|
destinations[keys] = localDestination;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,6 +672,8 @@ namespace client
|
||||||
// optional params
|
// optional params
|
||||||
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
int inPort = section.second.get (I2P_SERVER_TUNNEL_INPORT, 0);
|
||||||
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
std::string accessList = section.second.get (I2P_SERVER_TUNNEL_ACCESS_LIST, "");
|
||||||
|
if(accessList == "")
|
||||||
|
accessList=section.second.get (I2P_SERVER_TUNNEL_WHITE_LIST, "");
|
||||||
std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
|
std::string hostOverride = section.second.get (I2P_SERVER_TUNNEL_HOST_OVERRIDE, "");
|
||||||
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, "");
|
||||||
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true);
|
||||||
|
@ -675,12 +688,21 @@ namespace client
|
||||||
ReadI2CPOptions (section, options);
|
ReadI2CPOptions (section, options);
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
|
auto it = destinations.find (keys);
|
||||||
|
if (it != destinations.end ())
|
||||||
|
localDestination = it->second;
|
||||||
|
else
|
||||||
|
{
|
||||||
i2p::data::PrivateKeys k;
|
i2p::data::PrivateKeys k;
|
||||||
if(!LoadPrivateKeys (k, keys, sigType, cryptoType))
|
if(!LoadPrivateKeys (k, keys, sigType, cryptoType))
|
||||||
continue;
|
continue;
|
||||||
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
|
localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ());
|
||||||
if (!localDestination)
|
if (!localDestination)
|
||||||
|
{
|
||||||
localDestination = CreateNewLocalDestination (k, true, &options);
|
localDestination = CreateNewLocalDestination (k, true, &options);
|
||||||
|
destinations[keys] = localDestination;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
|
if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
|
||||||
{
|
{
|
||||||
// udp server tunnel
|
// udp server tunnel
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace client
|
||||||
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
const char I2P_SERVER_TUNNEL_SIGNATURE_TYPE[] = "signaturetype";
|
||||||
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
const char I2P_SERVER_TUNNEL_INPORT[] = "inport";
|
||||||
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
const char I2P_SERVER_TUNNEL_ACCESS_LIST[] = "accesslist";
|
||||||
|
const char I2P_SERVER_TUNNEL_WHITE_LIST[] = "whitelist";
|
||||||
const char I2P_SERVER_TUNNEL_GZIP[] = "gzip";
|
const char I2P_SERVER_TUNNEL_GZIP[] = "gzip";
|
||||||
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
|
const char I2P_SERVER_TUNNEL_WEBIRC_PASSWORD[] = "webircpassword";
|
||||||
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
|
const char I2P_SERVER_TUNNEL_ADDRESS[] = "address";
|
||||||
|
|
|
@ -55,12 +55,22 @@ namespace client
|
||||||
|
|
||||||
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
|
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
|
||||||
{
|
{
|
||||||
memcpy (m_EncryptionPrivateKey, key, 256);
|
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key);
|
||||||
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), m_EncryptionPrivateKey);
|
}
|
||||||
|
|
||||||
|
void I2CPDestination::SetECIESx25519EncryptionPrivateKey (const uint8_t * key)
|
||||||
|
{
|
||||||
|
if (!m_ECIESx25519Decryptor || memcmp (m_ECIESx25519PrivateKey, key, 32)) // new key?
|
||||||
|
{
|
||||||
|
m_ECIESx25519Decryptor = std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key, true); // calculate public
|
||||||
|
memcpy (m_ECIESx25519PrivateKey, key, 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||||
{
|
{
|
||||||
|
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && m_ECIESx25519Decryptor)
|
||||||
|
return m_ECIESx25519Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
if (m_Decryptor)
|
if (m_Decryptor)
|
||||||
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
else
|
else
|
||||||
|
@ -68,6 +78,19 @@ namespace client
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
|
||||||
|
{
|
||||||
|
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && m_ECIESx25519Decryptor)
|
||||||
|
return m_ECIESx25519Decryptor->GetPubicKey ();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
|
||||||
|
{
|
||||||
|
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
uint32_t length = bufbe32toh (buf);
|
uint32_t length = bufbe32toh (buf);
|
||||||
|
@ -77,7 +100,8 @@ namespace client
|
||||||
|
|
||||||
void I2CPDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
|
void I2CPDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
|
||||||
{
|
{
|
||||||
i2p::data::LocalLeaseSet ls (m_Identity, m_EncryptionPrivateKey, tunnels); // we don't care about encryption key
|
uint8_t priv[256] = {0};
|
||||||
|
i2p::data::LocalLeaseSet ls (m_Identity, priv, tunnels); // we don't care about encryption key, we need leases only
|
||||||
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
|
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
|
||||||
uint8_t * leases = ls.GetLeases ();
|
uint8_t * leases = ls.GetLeases ();
|
||||||
leases[-1] = tunnels.size ();
|
leases[-1] = tunnels.size ();
|
||||||
|
@ -572,27 +596,21 @@ namespace client
|
||||||
offset += ls.GetBufferLen ();
|
offset += ls.GetBufferLen ();
|
||||||
// private keys
|
// private keys
|
||||||
int numPrivateKeys = buf[offset]; offset++;
|
int numPrivateKeys = buf[offset]; offset++;
|
||||||
uint16_t currentKeyType = 0;
|
|
||||||
const uint8_t * currentKey = nullptr;
|
|
||||||
for (int i = 0; i < numPrivateKeys; i++)
|
for (int i = 0; i < numPrivateKeys; i++)
|
||||||
{
|
{
|
||||||
if (offset + 4 > len) return;
|
if (offset + 4 > len) return;
|
||||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
|
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
|
||||||
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
|
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
|
||||||
if (offset + keyLen > len) return;
|
if (offset + keyLen > len) return;
|
||||||
if (!currentKey || keyType > currentKeyType)
|
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
||||||
|
m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
currentKeyType = keyType;
|
m_Destination->SetEncryptionType (keyType);
|
||||||
currentKey = buf + offset;
|
m_Destination->SetEncryptionPrivateKey (buf + offset);
|
||||||
}
|
}
|
||||||
offset += keyLen;
|
offset += keyLen;
|
||||||
}
|
}
|
||||||
// TODO: support multiple keys
|
|
||||||
if (currentKey)
|
|
||||||
{
|
|
||||||
m_Destination->SetEncryptionPrivateKey (currentKey);
|
|
||||||
m_Destination->SetEncryptionType (currentKeyType);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ());
|
m_Destination->LeaseSet2Created (storeType, ls.GetBuffer (), ls.GetBufferLen ());
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,14 +75,15 @@ namespace client
|
||||||
|
|
||||||
void SetEncryptionPrivateKey (const uint8_t * key);
|
void SetEncryptionPrivateKey (const uint8_t * key);
|
||||||
void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; };
|
void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; };
|
||||||
|
void SetECIESx25519EncryptionPrivateKey (const uint8_t * key);
|
||||||
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
|
void LeaseSetCreated (const uint8_t * buf, size_t len); // called from I2CPSession
|
||||||
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
|
void LeaseSet2Created (uint8_t storeType, const uint8_t * buf, size_t len); // called from I2CPSession
|
||||||
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; };
|
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
|
||||||
// TODO: implement GetEncryptionPublicKey
|
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const; // for 4 only
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
|
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Identity; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -101,9 +102,10 @@ namespace client
|
||||||
|
|
||||||
std::shared_ptr<I2CPSession> m_Owner;
|
std::shared_ptr<I2CPSession> m_Owner;
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> m_Identity;
|
std::shared_ptr<const i2p::data::IdentityEx> m_Identity;
|
||||||
uint8_t m_EncryptionPrivateKey[256];
|
|
||||||
i2p::data::CryptoKeyType m_EncryptionKeyType;
|
i2p::data::CryptoKeyType m_EncryptionKeyType;
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor; // standard
|
||||||
|
std::shared_ptr<i2p::crypto::ECIESX25519AEADRatchetDecryptor> m_ECIESx25519Decryptor;
|
||||||
|
uint8_t m_ECIESx25519PrivateKey[32];
|
||||||
uint64_t m_LeaseSetExpirationTime;
|
uint64_t m_LeaseSetExpirationTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -610,11 +610,23 @@ namespace client
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
void I2PUDPServerTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (!m_LastSession || m_LastSession->Identity.GetLL()[0] != from.GetIdentHash ().GetLL()[0] || fromPort != m_LastSession->RemotePort)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
std::lock_guard<std::mutex> lock(m_SessionsMutex);
|
||||||
auto session = ObtainUDPSession(from, toPort, fromPort);
|
m_LastSession = ObtainUDPSession(from, toPort, fromPort);
|
||||||
session->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
|
}
|
||||||
session->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
|
m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
|
||||||
|
m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PUDPServerTunnel::HandleRecvFromI2PRaw (uint16_t, uint16_t, const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (m_LastSession)
|
||||||
|
{
|
||||||
|
m_LastSession->IPSocket.send_to(boost::asio::buffer(buf, len), m_RemoteEndpoint);
|
||||||
|
m_LastSession->LastActivity = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
|
void I2PUDPServerTunnel::ExpireStale(const uint64_t delta) {
|
||||||
|
@ -634,7 +646,7 @@ namespace client
|
||||||
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
uint64_t now = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
std::vector<uint16_t> removePorts;
|
std::vector<uint16_t> removePorts;
|
||||||
for (const auto & s : m_Sessions) {
|
for (const auto & s : m_Sessions) {
|
||||||
if (now - s.second.second >= delta)
|
if (now - s.second->second >= delta)
|
||||||
removePorts.push_back(s.first);
|
removePorts.push_back(s.first);
|
||||||
}
|
}
|
||||||
for(auto port : removePorts) {
|
for(auto port : removePorts) {
|
||||||
|
@ -647,7 +659,7 @@ namespace client
|
||||||
auto ih = from.GetIdentHash();
|
auto ih = from.GetIdentHash();
|
||||||
for (auto & s : m_Sessions )
|
for (auto & s : m_Sessions )
|
||||||
{
|
{
|
||||||
if ( s->Identity == ih)
|
if (s->Identity.GetLL()[0] == ih.GetLL()[0] && remotePort == s->RemotePort)
|
||||||
{
|
{
|
||||||
/** found existing session */
|
/** found existing session */
|
||||||
LogPrint(eLogDebug, "UDPServer: found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32());
|
LogPrint(eLogDebug, "UDPServer: found session ", s->IPSocket.local_endpoint(), " ", ih.ToBase32());
|
||||||
|
@ -680,6 +692,7 @@ namespace client
|
||||||
LocalPort(ourPort),
|
LocalPort(ourPort),
|
||||||
RemotePort(theirPort)
|
RemotePort(theirPort)
|
||||||
{
|
{
|
||||||
|
IPSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU ));
|
||||||
memcpy(Identity, to->data(), 32);
|
memcpy(Identity, to->data(), 32);
|
||||||
Receive();
|
Receive();
|
||||||
}
|
}
|
||||||
|
@ -695,12 +708,30 @@ namespace client
|
||||||
if(!ecode)
|
if(!ecode)
|
||||||
{
|
{
|
||||||
LogPrint(eLogDebug, "UDPSession: forward ", len, "B from ", FromEndpoint);
|
LogPrint(eLogDebug, "UDPSession: forward ", len, "B from ", FromEndpoint);
|
||||||
LastActivity = i2p::util::GetMillisecondsSinceEpoch();
|
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
m_Destination->SendDatagramTo(m_Buffer, len, Identity, LocalPort, RemotePort);
|
auto session = m_Destination->GetSession (Identity);
|
||||||
Receive();
|
if (ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
|
||||||
} else {
|
m_Destination->SendDatagram(session, m_Buffer, len, LocalPort, RemotePort);
|
||||||
LogPrint(eLogError, "UDPSession: ", ecode.message());
|
else
|
||||||
|
m_Destination->SendRawDatagram(session, m_Buffer, len, LocalPort, RemotePort);
|
||||||
|
size_t numPackets = 0;
|
||||||
|
while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
size_t moreBytes = IPSocket.available(ec);
|
||||||
|
if (ec || !moreBytes) break;
|
||||||
|
len = IPSocket.receive_from (boost::asio::buffer (m_Buffer, I2P_UDP_MAX_MTU), FromEndpoint, 0, ec);
|
||||||
|
m_Destination->SendRawDatagram (session, m_Buffer, len, LocalPort, RemotePort);
|
||||||
|
numPackets++;
|
||||||
}
|
}
|
||||||
|
if (numPackets > 0)
|
||||||
|
LogPrint(eLogDebug, "UDPSession: forward more ", numPackets, "packets B from ", FromEndpoint);
|
||||||
|
m_Destination->FlushSendQueue (session);
|
||||||
|
LastActivity = ts;
|
||||||
|
Receive();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogError, "UDPSession: ", ecode.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
I2PUDPServerTunnel::I2PUDPServerTunnel(const std::string & name, std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
||||||
|
@ -714,6 +745,7 @@ namespace client
|
||||||
m_LocalDest->Start();
|
m_LocalDest->Start();
|
||||||
auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
|
auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
|
||||||
dgram->SetReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
dgram->SetReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2P, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5));
|
||||||
|
dgram->SetRawReceiver(std::bind(&I2PUDPServerTunnel::HandleRecvFromI2PRaw, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
}
|
}
|
||||||
|
|
||||||
I2PUDPServerTunnel::~I2PUDPServerTunnel()
|
I2PUDPServerTunnel::~I2PUDPServerTunnel()
|
||||||
|
@ -761,14 +793,18 @@ namespace client
|
||||||
m_RemoteIdent(nullptr),
|
m_RemoteIdent(nullptr),
|
||||||
m_ResolveThread(nullptr),
|
m_ResolveThread(nullptr),
|
||||||
m_LocalSocket(localDestination->GetService(), localEndpoint),
|
m_LocalSocket(localDestination->GetService(), localEndpoint),
|
||||||
RemotePort(remotePort),
|
RemotePort(remotePort), m_LastPort (0),
|
||||||
m_cancel_resolve(false)
|
m_cancel_resolve(false)
|
||||||
{
|
{
|
||||||
|
m_LocalSocket.set_option (boost::asio::socket_base::receive_buffer_size (I2P_UDP_MAX_MTU ));
|
||||||
|
|
||||||
auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
|
auto dgram = m_LocalDest->CreateDatagramDestination(gzip);
|
||||||
dgram->SetReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2P, this,
|
dgram->SetReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2P, this,
|
||||||
std::placeholders::_1, std::placeholders::_2,
|
std::placeholders::_1, std::placeholders::_2,
|
||||||
std::placeholders::_3, std::placeholders::_4,
|
std::placeholders::_3, std::placeholders::_4,
|
||||||
std::placeholders::_5));
|
std::placeholders::_5));
|
||||||
|
dgram->SetRawReceiver(std::bind(&I2PUDPClientTunnel::HandleRecvFromI2PRaw, this,
|
||||||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2PUDPClientTunnel::Start() {
|
void I2PUDPClientTunnel::Start() {
|
||||||
|
@ -796,16 +832,45 @@ namespace client
|
||||||
return; // drop, remote not resolved
|
return; // drop, remote not resolved
|
||||||
}
|
}
|
||||||
auto remotePort = m_RecvEndpoint.port();
|
auto remotePort = m_RecvEndpoint.port();
|
||||||
|
if (!m_LastPort || m_LastPort != remotePort)
|
||||||
|
{
|
||||||
auto itr = m_Sessions.find(remotePort);
|
auto itr = m_Sessions.find(remotePort);
|
||||||
if (itr == m_Sessions.end()) {
|
if (itr != m_Sessions.end())
|
||||||
// track new udp convo
|
m_LastSession = itr->second;
|
||||||
m_Sessions[remotePort] = {boost::asio::ip::udp::endpoint(m_RecvEndpoint), 0};
|
else
|
||||||
|
{
|
||||||
|
m_LastSession = std::make_shared<UDPConvo>(boost::asio::ip::udp::endpoint(m_RecvEndpoint), 0);
|
||||||
|
m_Sessions.emplace (remotePort, m_LastSession);
|
||||||
|
}
|
||||||
|
m_LastPort = remotePort;
|
||||||
}
|
}
|
||||||
// send off to remote i2p destination
|
// send off to remote i2p destination
|
||||||
|
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
LogPrint(eLogDebug, "UDP Client: send ", transferred, " to ", m_RemoteIdent->ToBase32(), ":", RemotePort);
|
LogPrint(eLogDebug, "UDP Client: send ", transferred, " to ", m_RemoteIdent->ToBase32(), ":", RemotePort);
|
||||||
m_LocalDest->GetDatagramDestination()->SendDatagramTo(m_RecvBuff, transferred, *m_RemoteIdent, remotePort, RemotePort);
|
auto session = m_LocalDest->GetDatagramDestination()->GetSession (*m_RemoteIdent);
|
||||||
|
if (ts > m_LastSession->second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL)
|
||||||
|
m_LocalDest->GetDatagramDestination()->SendDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
|
||||||
|
else
|
||||||
|
m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
|
||||||
|
size_t numPackets = 0;
|
||||||
|
while (numPackets < i2p::datagram::DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
||||||
|
{
|
||||||
|
boost::system::error_code ec;
|
||||||
|
size_t moreBytes = m_LocalSocket.available(ec);
|
||||||
|
if (ec || !moreBytes) break;
|
||||||
|
transferred = m_LocalSocket.receive_from (boost::asio::buffer (m_RecvBuff, I2P_UDP_MAX_MTU), m_RecvEndpoint, 0, ec);
|
||||||
|
remotePort = m_RecvEndpoint.port();
|
||||||
|
// TODO: check remotePort
|
||||||
|
m_LocalDest->GetDatagramDestination()->SendRawDatagram (session, m_RecvBuff, transferred, remotePort, RemotePort);
|
||||||
|
numPackets++;
|
||||||
|
}
|
||||||
|
if (numPackets)
|
||||||
|
LogPrint(eLogDebug, "UDP Client: sent ", numPackets, " more packets to ", m_RemoteIdent->ToBase32());
|
||||||
|
m_LocalDest->GetDatagramDestination()->FlushSendQueue (session);
|
||||||
|
|
||||||
// mark convo as active
|
// mark convo as active
|
||||||
m_Sessions[remotePort].second = i2p::util::GetMillisecondsSinceEpoch();
|
if (m_LastSession)
|
||||||
|
m_LastSession->second = ts;
|
||||||
RecvFromLocal();
|
RecvFromLocal();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,25 +908,29 @@ namespace client
|
||||||
void I2PUDPClientTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
void I2PUDPClientTunnel::HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if(m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent)
|
if(m_RemoteIdent && from.GetIdentHash() == *m_RemoteIdent)
|
||||||
|
HandleRecvFromI2PRaw (fromPort, toPort, buf, len);
|
||||||
|
else
|
||||||
|
LogPrint(eLogWarning, "UDP Client: unwarranted traffic from ", from.GetIdentHash().ToBase32());
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2PUDPClientTunnel::HandleRecvFromI2PRaw(uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
auto itr = m_Sessions.find(toPort);
|
auto itr = m_Sessions.find(toPort);
|
||||||
// found convo ?
|
// found convo ?
|
||||||
if(itr != m_Sessions.end())
|
if(itr != m_Sessions.end())
|
||||||
{
|
{
|
||||||
// found convo
|
// found convo
|
||||||
if (len > 0) {
|
if (len > 0)
|
||||||
LogPrint(eLogDebug, "UDP Client: got ", len, "B from ", from.GetIdentHash().ToBase32());
|
{
|
||||||
m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second.first);
|
LogPrint(eLogDebug, "UDP Client: got ", len, "B from ", m_RemoteIdent ? m_RemoteIdent->ToBase32() : "");
|
||||||
|
m_LocalSocket.send_to(boost::asio::buffer(buf, len), itr->second->first);
|
||||||
// mark convo as active
|
// mark convo as active
|
||||||
itr->second.second = i2p::util::GetMillisecondsSinceEpoch();
|
itr->second->second = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint(eLogWarning, "UDP Client: not tracking udp session using port ", (int) toPort);
|
LogPrint(eLogWarning, "UDP Client: not tracking udp session using port ", (int) toPort);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
LogPrint(eLogWarning, "UDP Client: unwarranted traffic from ", from.GetIdentHash().ToBase32());
|
|
||||||
}
|
|
||||||
|
|
||||||
I2PUDPClientTunnel::~I2PUDPClientTunnel() {
|
I2PUDPClientTunnel::~I2PUDPClientTunnel() {
|
||||||
auto dgram = m_LocalDest->GetDatagramDestination();
|
auto dgram = m_LocalDest->GetDatagramDestination();
|
||||||
|
|
|
@ -165,9 +165,10 @@ namespace client
|
||||||
|
|
||||||
/** 2 minute timeout for udp sessions */
|
/** 2 minute timeout for udp sessions */
|
||||||
const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2;
|
const uint64_t I2P_UDP_SESSION_TIMEOUT = 1000 * 60 * 2;
|
||||||
|
const uint64_t I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL = 100; // in milliseconds
|
||||||
|
|
||||||
/** max size for i2p udp */
|
/** max size for i2p udp */
|
||||||
const size_t I2P_UDP_MAX_MTU = i2p::datagram::MAX_DATAGRAM_SIZE;
|
const size_t I2P_UDP_MAX_MTU = 64*1024;
|
||||||
|
|
||||||
struct UDPSession
|
struct UDPSession
|
||||||
{
|
{
|
||||||
|
@ -237,6 +238,7 @@ namespace client
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
void HandleRecvFromI2PRaw (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
UDPSessionPtr ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort);
|
UDPSessionPtr ObtainUDPSession(const i2p::data::IdentityEx& from, uint16_t localPort, uint16_t remotePort);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -248,6 +250,7 @@ namespace client
|
||||||
std::mutex m_SessionsMutex;
|
std::mutex m_SessionsMutex;
|
||||||
std::vector<UDPSessionPtr> m_Sessions;
|
std::vector<UDPSessionPtr> m_Sessions;
|
||||||
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
|
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
|
||||||
|
UDPSessionPtr m_LastSession;
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PUDPClientTunnel
|
class I2PUDPClientTunnel
|
||||||
|
@ -273,10 +276,14 @@ namespace client
|
||||||
void RecvFromLocal();
|
void RecvFromLocal();
|
||||||
void HandleRecvFromLocal(const boost::system::error_code & e, std::size_t transferred);
|
void HandleRecvFromLocal(const boost::system::error_code & e, std::size_t transferred);
|
||||||
void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleRecvFromI2P(const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
void HandleRecvFromI2PRaw(uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
void TryResolving();
|
void TryResolving();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
const std::string m_Name;
|
const std::string m_Name;
|
||||||
std::mutex m_SessionsMutex;
|
std::mutex m_SessionsMutex;
|
||||||
std::map<uint16_t, UDPConvo > m_Sessions; // maps i2p port -> local udp convo
|
std::unordered_map<uint16_t, std::shared_ptr<UDPConvo> > m_Sessions; // maps i2p port -> local udp convo
|
||||||
const std::string m_RemoteDest;
|
const std::string m_RemoteDest;
|
||||||
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
|
std::shared_ptr<i2p::client::ClientDestination> m_LocalDest;
|
||||||
const boost::asio::ip::udp::endpoint m_LocalEndpoint;
|
const boost::asio::ip::udp::endpoint m_LocalEndpoint;
|
||||||
|
@ -285,8 +292,9 @@ namespace client
|
||||||
boost::asio::ip::udp::socket m_LocalSocket;
|
boost::asio::ip::udp::socket m_LocalSocket;
|
||||||
boost::asio::ip::udp::endpoint m_RecvEndpoint;
|
boost::asio::ip::udp::endpoint m_RecvEndpoint;
|
||||||
uint8_t m_RecvBuff[I2P_UDP_MAX_MTU];
|
uint8_t m_RecvBuff[I2P_UDP_MAX_MTU];
|
||||||
uint16_t RemotePort;
|
uint16_t RemotePort, m_LastPort;
|
||||||
bool m_cancel_resolve;
|
bool m_cancel_resolve;
|
||||||
|
std::shared_ptr<UDPConvo> m_LastSession;
|
||||||
};
|
};
|
||||||
|
|
||||||
class I2PServerTunnel: public I2PService
|
class I2PServerTunnel: public I2PService
|
||||||
|
|
|
@ -494,7 +494,7 @@ namespace client
|
||||||
context.GetAddressBook().InsertFullAddress(dest);
|
context.GetAddressBook().InsertFullAddress(dest);
|
||||||
auto leaseSet = session->localDestination->FindLeaseSet(dest->GetIdentHash());
|
auto leaseSet = session->localDestination->FindLeaseSet(dest->GetIdentHash());
|
||||||
if (leaseSet)
|
if (leaseSet)
|
||||||
Connect(leaseSet);
|
Connect(leaseSet, session);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
session->localDestination->RequestDestination(dest->GetIdentHash(),
|
session->localDestination->RequestDestination(dest->GetIdentHash(),
|
||||||
|
@ -509,18 +509,25 @@ namespace client
|
||||||
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::Connect (std::shared_ptr<const i2p::data::LeaseSet> remote)
|
void SAMSocket::Connect (std::shared_ptr<const i2p::data::LeaseSet> remote, std::shared_ptr<SAMSession> session)
|
||||||
{
|
{
|
||||||
auto session = m_Owner.FindSession(m_ID);
|
if (!session) session = m_Owner.FindSession(m_ID);
|
||||||
if (session)
|
if (session)
|
||||||
{
|
{
|
||||||
m_SocketType = eSAMSocketTypeStream;
|
m_SocketType = eSAMSocketTypeStream;
|
||||||
m_Stream = session->localDestination->CreateStream (remote);
|
m_Stream = session->localDestination->CreateStream (remote);
|
||||||
|
if (m_Stream)
|
||||||
|
{
|
||||||
m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
|
m_Stream->Send ((uint8_t *)m_Buffer, m_BufferOffset); // connect and send
|
||||||
m_BufferOffset = 0;
|
m_BufferOffset = 0;
|
||||||
I2PReceive ();
|
I2PReceive ();
|
||||||
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMSocket::HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
void SAMSocket::HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
||||||
|
@ -1015,8 +1022,8 @@ namespace client
|
||||||
{
|
{
|
||||||
{"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1},
|
{"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1},
|
||||||
{"ECDSA_SHA256_P256", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256},
|
{"ECDSA_SHA256_P256", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256},
|
||||||
{"ECDSA_SHA256_P384", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384},
|
{"ECDSA_SHA384_P384", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384},
|
||||||
{"ECDSA_SHA256_P521", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521},
|
{"ECDSA_SHA512_P521", i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521},
|
||||||
{"EdDSA_SHA512_Ed25519", i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519},
|
{"EdDSA_SHA512_Ed25519", i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519},
|
||||||
{"GOST_GOSTR3411256_GOSTR3410CRYPTOPROA", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256},
|
{"GOST_GOSTR3411256_GOSTR3410CRYPTOPROA", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256},
|
||||||
{"GOST_GOSTR3411512_GOSTR3410TC26A512", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512},
|
{"GOST_GOSTR3411512_GOSTR3410TC26A512", i2p::data::SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512},
|
||||||
|
|
|
@ -134,7 +134,7 @@ namespace client
|
||||||
size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
|
size_t ProcessDatagramSend (char * buf, size_t len, const char * data); // from SAM 1.0
|
||||||
void ExtractParams (char * buf, std::map<std::string, std::string>& params);
|
void ExtractParams (char * buf, std::map<std::string, std::string>& params);
|
||||||
|
|
||||||
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote);
|
void Connect (std::shared_ptr<const i2p::data::LeaseSet> remote, std::shared_ptr<SAMSession> session = nullptr);
|
||||||
void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
|
void HandleConnectLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet);
|
||||||
void SendNamingLookupReply (std::shared_ptr<const i2p::data::IdentityEx> identity);
|
void SendNamingLookupReply (std::shared_ptr<const i2p::data::IdentityEx> identity);
|
||||||
void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::string name);
|
void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::string name);
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
<translation type="qt" />
|
<translation type="qt" />
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.33.0" date="2020-08-24" />
|
||||||
<release version="2.32.1" date="2020-06-02" />
|
<release version="2.32.1" date="2020-06-02" />
|
||||||
<release version="2.32.0" date="2020-05-25" />
|
<release version="2.32.0" date="2020-05-25" />
|
||||||
<release version="2.31.0" date="2020-04-10" />
|
<release version="2.31.0" date="2020-04-10" />
|
||||||
|
|
Loading…
Add table
Reference in a new issue