mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
253 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e37df26a3 | ||
|
|
5e606573b1 | ||
|
|
b3974cb52a | ||
|
|
b7c206c44b | ||
|
|
49c1e47736 | ||
|
|
4e1319d874 | ||
|
|
a9436aa9af | ||
|
|
d503f07564 | ||
|
|
aa7750bfd3 | ||
|
|
8872d1f389 | ||
|
|
f21af4068f | ||
|
|
f4ca6bbb52 | ||
|
|
869d0156ce | ||
|
|
744e893dce | ||
|
|
fe9ac10f02 | ||
|
|
6fb80f226a | ||
|
|
ff19bab800 | ||
|
|
962c2160c7 | ||
|
|
168da33d8b | ||
|
|
b6b25dc9f3 | ||
|
|
3ca17fdc03 | ||
|
|
2249708097 | ||
|
|
2fcaa7d260 | ||
|
|
f3b0e57a54 | ||
|
|
5da92437a1 | ||
|
|
b5bc05ac2b | ||
|
|
45145fa50a | ||
|
|
dd8200e8b0 | ||
|
|
2f56547d5f | ||
|
|
82bdcfbbcb | ||
|
|
0e38e43315 | ||
|
|
63746be4d5 | ||
|
|
ee73ee365f | ||
|
|
3c53479864 | ||
|
|
4adc741de3 | ||
|
|
64da62dbe6 | ||
|
|
dd9b5faa5c | ||
|
|
51d018acc6 | ||
|
|
5eec580727 | ||
|
|
1e9a53da3f | ||
|
|
8dae044600 | ||
|
|
2d3fad2cdb | ||
|
|
a59a8f62ca | ||
|
|
35cfa7d9fb | ||
|
|
c6ccb373a2 | ||
|
|
b6368170ed | ||
|
|
35e8424293 | ||
|
|
e969d58689 | ||
|
|
ae20e3aa95 | ||
|
|
de4cb74173 | ||
|
|
4f0da87a7a | ||
|
|
97f0347715 | ||
|
|
2ffe62ba41 | ||
|
|
fe1724e7e6 | ||
|
|
2ac2da41cf | ||
|
|
ed574f9d79 | ||
|
|
e0cb26bd9e | ||
|
|
1893127e84 | ||
|
|
b02c9fb118 | ||
|
|
bca0809918 | ||
|
|
00db527377 | ||
|
|
2c6e041ae2 | ||
|
|
a0d6c654cc | ||
|
|
5115c27e72 | ||
|
|
d09c3ccb2d | ||
|
|
5c308026ac | ||
|
|
91919c6d64 | ||
|
|
7168738835 | ||
|
|
9c9b723cf5 | ||
|
|
50450923df | ||
|
|
f392edd66c | ||
|
|
24b48e5d50 | ||
|
|
47f384a0e0 | ||
|
|
88594887f9 | ||
|
|
32e2f0b1fa | ||
|
|
09ed57ad42 | ||
|
|
53a6162b0c | ||
|
|
694d851cdb | ||
|
|
8e53c30a00 | ||
|
|
63e807b0b4 | ||
|
|
012f22cc47 | ||
|
|
9d891ab5dd | ||
|
|
d0e78be867 | ||
|
|
cbedebc9dd | ||
|
|
969f9aa436 | ||
|
|
b982be5ff5 | ||
|
|
2d154ee640 | ||
|
|
49810eb153 | ||
|
|
85b88b8749 | ||
|
|
239c8b5172 | ||
|
|
8c800dc178 | ||
|
|
cdd068d99a | ||
|
|
48fa10b080 | ||
|
|
a1dbec0fcb | ||
|
|
abe668f1c3 | ||
|
|
77440c235d | ||
|
|
fd1ee48dbe | ||
|
|
205e807b66 | ||
|
|
34295adb05 | ||
|
|
7c212bef63 | ||
|
|
76f95644b7 | ||
|
|
928b90d5bc | ||
|
|
09c6c2a4f3 | ||
|
|
2b2bd733e9 | ||
|
|
0d2d7e5e71 | ||
|
|
6142e93252 | ||
|
|
ccec3376ba | ||
|
|
f497a74ec4 | ||
|
|
0e666e7d6a | ||
|
|
f498fabd27 | ||
|
|
8b49a55442 | ||
|
|
a26eb942a9 | ||
|
|
eabcafa516 | ||
|
|
6cc388c1bc | ||
|
|
62e39ddfbd | ||
|
|
80373623cd | ||
|
|
451c3945f0 | ||
|
|
00cb15d9b4 | ||
|
|
67dd59125e | ||
|
|
b6800dd125 | ||
|
|
dc9da69509 | ||
|
|
d7d964bf57 | ||
|
|
bcfe44db54 | ||
|
|
376bf6ba72 | ||
|
|
f651baab25 | ||
|
|
61752e2aab | ||
|
|
b7d3fd959e | ||
|
|
7ac05f8487 | ||
|
|
4f70822b13 | ||
|
|
0007f304d0 | ||
|
|
4afef91359 | ||
|
|
815b6db0bf | ||
|
|
433d3bf582 | ||
|
|
a335841509 | ||
|
|
26ad793d82 | ||
|
|
5337aa10f7 | ||
|
|
9f79bdae9b | ||
|
|
db84be2488 | ||
|
|
599ec62bb0 | ||
|
|
19a88300c6 | ||
|
|
b5d55e1ffb | ||
|
|
521fb83e38 | ||
|
|
553d59c32b | ||
|
|
9ed58e5186 | ||
|
|
36eaaa748c | ||
|
|
4d7b86ca26 | ||
|
|
5faf84c732 | ||
|
|
d7b819267f | ||
|
|
7417867d0f | ||
|
|
8d74905257 | ||
|
|
c38298c06e | ||
|
|
3100d587d1 | ||
|
|
ba849d0300 | ||
|
|
95df3e4b39 | ||
|
|
72492e33a0 | ||
|
|
934f1269f5 | ||
|
|
e6956d9bb0 | ||
|
|
2877900233 | ||
|
|
df1aa52e08 | ||
|
|
5fa2485a7d | ||
|
|
29f0e10411 | ||
|
|
39300a5bbf | ||
|
|
35d6268675 | ||
|
|
0abb871f3f | ||
|
|
704fca969f | ||
|
|
95debf8c80 | ||
|
|
dd94b77b2a | ||
|
|
6cfe4fa580 | ||
|
|
515c086099 | ||
|
|
34ce06ac17 | ||
|
|
a104c9881e | ||
|
|
c3e3c091cc | ||
|
|
651240113c | ||
|
|
77189bf8e9 | ||
|
|
60fd3a4542 | ||
|
|
c66f9c8d6d | ||
|
|
569088eaca | ||
|
|
a7e8dd04fe | ||
|
|
dfdd76a1bb | ||
|
|
28aac6f93b | ||
|
|
c2f47119ce | ||
|
|
d6b1d0d4fb | ||
|
|
03a861745b | ||
|
|
9a7aed20e9 | ||
|
|
b7f17d4cb1 | ||
|
|
2497c3d187 | ||
|
|
f7a084969a | ||
|
|
2900bc26a5 | ||
|
|
2334c56a96 | ||
|
|
90a5d02bf6 | ||
|
|
81d9626da9 | ||
|
|
44a2549b81 | ||
|
|
a2b8d468bc | ||
|
|
d523f0cadd | ||
|
|
99116ff097 | ||
|
|
3939ca9eb4 | ||
|
|
b5aa67b491 | ||
|
|
e42efec220 | ||
|
|
9d06aa2f6a | ||
|
|
80765a797b | ||
|
|
0b5509a1ed | ||
|
|
478d7b4a83 | ||
|
|
9d3b38141a | ||
|
|
ab3a4d902e | ||
|
|
5eab5f2437 | ||
|
|
80f632c19a | ||
|
|
6e4f18543d | ||
|
|
54586c9076 | ||
|
|
351c899807 | ||
|
|
fe45d431d7 | ||
|
|
488c2f6d05 | ||
|
|
75ab0909b3 | ||
|
|
8f82d563c1 | ||
|
|
9bbce5dba6 | ||
|
|
099adab9ed | ||
|
|
c8cbf425ac | ||
|
|
ad9c11cd92 | ||
|
|
3872c2a3f5 | ||
|
|
e6a09b49c9 | ||
|
|
db107602bd | ||
|
|
a6558a61a7 | ||
|
|
254d2b82b3 | ||
|
|
97d9795fc9 | ||
|
|
54071b0e5d | ||
|
|
925e8316c7 | ||
|
|
99e1b74023 | ||
|
|
7d68ccca53 | ||
|
|
a090114066 | ||
|
|
a204841abb | ||
|
|
cc451809cc | ||
|
|
a605e4bab6 | ||
|
|
3f0534134d | ||
|
|
3acfb129cd | ||
|
|
6ccef66920 | ||
|
|
e9fa4e94a6 | ||
|
|
fecc0c4640 | ||
|
|
b759294975 | ||
|
|
a23e845c03 | ||
|
|
cb8373e487 | ||
|
|
8e919ddc8e | ||
|
|
832a9ab6b5 | ||
|
|
13732ac333 | ||
|
|
3e932a55f4 | ||
|
|
74e8610ec9 | ||
|
|
089a60ded6 | ||
|
|
c8eeefe194 | ||
|
|
85eeba14c1 | ||
|
|
f6f45eab39 | ||
|
|
a74065f775 | ||
|
|
48d02f7e09 | ||
|
|
e60549f8df | ||
|
|
41f4f4713e | ||
|
|
213a292fd5 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -258,9 +258,15 @@ build/Makefile
|
|||||||
|
|
||||||
# qt
|
# qt
|
||||||
|
|
||||||
qt/i2pd_qt/*.ui.autosave
|
qt/i2pd_qt/*.autosave
|
||||||
qt/i2pd_qt/*.ui.bk*
|
qt/i2pd_qt/*.ui.bk*
|
||||||
qt/i2pd_qt/*.ui_*
|
qt/i2pd_qt/*.ui_*
|
||||||
|
|
||||||
#unknown android stuff
|
#unknown android stuff
|
||||||
android/libs/
|
android/libs/
|
||||||
|
|
||||||
|
#various logs
|
||||||
|
*LOGS/
|
||||||
|
|
||||||
|
qt/build-*.sh*
|
||||||
|
|
||||||
|
|||||||
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
@@ -4,7 +4,7 @@ cache:
|
|||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
#- osx
|
#- osx
|
||||||
dist: trusty
|
dist: xenial
|
||||||
sudo: required
|
sudo: required
|
||||||
compiler:
|
compiler:
|
||||||
- g++
|
- g++
|
||||||
|
|||||||
71
ChangeLog
71
ChangeLog
@@ -1,6 +1,77 @@
|
|||||||
# 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.31.0] - 2020-04-10
|
||||||
|
### Added
|
||||||
|
- NTCP2 through HTTP proxy
|
||||||
|
- Publish LeaseSet2 for I2CP destinations
|
||||||
|
- Show status page on main activity for android
|
||||||
|
- Handle ECIESFlag in DatabaseLookup at floodfill
|
||||||
|
- C++17 features for eligible compilers
|
||||||
|
### Changed
|
||||||
|
- Droped Websockets and Lua support
|
||||||
|
- Send DeliveryStatusMsg for LeaseSet for ECIES-X25519-AEAD-Ratchet
|
||||||
|
- Keep sending new session reply until established for ECIES-X25519-AEAD-Ratchet
|
||||||
|
- Updated SSU log messages
|
||||||
|
- Reopen SSU socket on exception
|
||||||
|
- Security hardening headers in web console
|
||||||
|
- Various web console changes
|
||||||
|
- Various QT changes
|
||||||
|
### Fixed
|
||||||
|
- NTCP2 socket descriptors leak
|
||||||
|
- Race condition with router's identity in transport sessions
|
||||||
|
- Not terminated streams remain forever
|
||||||
|
|
||||||
|
## [2.30.0] - 2020-02-25
|
||||||
|
### Added
|
||||||
|
- Single threaded SAM
|
||||||
|
- Experimental support of ECIES-X25519-AEAD-Ratchet crypto type
|
||||||
|
### Changed
|
||||||
|
- Minimal MTU size is 1280 for ipv6
|
||||||
|
- Use unordered_map instead map for destination's sessions and tags list
|
||||||
|
- Use std::shuffle instead std::random_shuffle
|
||||||
|
- SAM is single threaded by default
|
||||||
|
- Reseeds list
|
||||||
|
### Fixed
|
||||||
|
- Correct termination of streaming destination
|
||||||
|
- Extra ',' in RouterInfo response in I2PControl
|
||||||
|
- SAM crash on session termination
|
||||||
|
- Storage for Android 10
|
||||||
|
|
||||||
|
## [2.29.0] - 2019-10-21
|
||||||
|
### Added
|
||||||
|
- Client auth flag for b33 address
|
||||||
|
### Changed
|
||||||
|
- Remove incoming NTCP2 session from pending list when established
|
||||||
|
- Handle errors for NTCP2 SessionConfrimed send
|
||||||
|
### Fixed
|
||||||
|
- Failure to start on Windows XP
|
||||||
|
- SAM crash if invalid lookup address
|
||||||
|
- Possible crash when UPnP enabled on shutdown
|
||||||
|
|
||||||
|
## [2.28.0] - 2019-08-27
|
||||||
|
### Added
|
||||||
|
- RAW datagrams in SAM
|
||||||
|
- Publishing encrypted LeaseSet2 with DH or PSH authentication
|
||||||
|
- Ability to disable battery optimization for Android
|
||||||
|
- Transport Network ID Check
|
||||||
|
### Changed
|
||||||
|
- Set and handle published encrypted flag for LeaseSet2
|
||||||
|
### Fixed
|
||||||
|
- ReceiveID changes in the same stream
|
||||||
|
- "\r\n" command terminator in SAM
|
||||||
|
- Addressbook lines with signatures
|
||||||
|
|
||||||
|
## [2.27.0] - 2019-07-03
|
||||||
|
### Added
|
||||||
|
- Support of PSK and DH authentication for encrypted LeaseSet2
|
||||||
|
### Changed
|
||||||
|
- Uptime is based on monotonic timer
|
||||||
|
### Fixed
|
||||||
|
- BOB status command response
|
||||||
|
- Correct NTCP2 port if NTCP is disabled
|
||||||
|
- Flood encrypted LeaseSet2 with store hash
|
||||||
|
|
||||||
## [2.26.0] - 2019-06-07
|
## [2.26.0] - 2019-06-07
|
||||||
### Added
|
### Added
|
||||||
- HTTP method "PROPFIND"
|
- HTTP method "PROPFIND"
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -27,10 +27,6 @@ else
|
|||||||
LD_DEBUG = -s
|
LD_DEBUG = -s
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(WEBSOCKETS),1)
|
|
||||||
NEEDED_CXXFLAGS += -DWITH_EVENTS
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq (, $(findstring darwin, $(SYS)))
|
ifneq (, $(findstring darwin, $(SYS)))
|
||||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||||
ifeq ($(HOMEBREW),1)
|
ifeq ($(HOMEBREW),1)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# set defaults instead redefine
|
# set defaults instead redefine
|
||||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation
|
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -Wno-psabi
|
||||||
LDFLAGS ?= ${LD_DEBUG}
|
LDFLAGS ?= ${LD_DEBUG}
|
||||||
|
|
||||||
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
||||||
@@ -15,13 +15,14 @@ ifeq ($(shell expr match $(CXX) 'clang'),5)
|
|||||||
NEEDED_CXXFLAGS += -std=c++11
|
NEEDED_CXXFLAGS += -std=c++11
|
||||||
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
|
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
|
||||||
NEEDED_CXXFLAGS += -std=c++11
|
NEEDED_CXXFLAGS += -std=c++11
|
||||||
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # gcc 4.7 - 4.9
|
||||||
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
NEEDED_CXXFLAGS += -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1
|
||||||
else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6
|
else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6
|
||||||
NEEDED_CXXFLAGS += -std=c++0x
|
|
||||||
else ifeq ($(shell expr match ${CXXVER} "[5-9]"),1) # gcc >= 5
|
|
||||||
NEEDED_CXXFLAGS += -std=c++11
|
NEEDED_CXXFLAGS += -std=c++11
|
||||||
LDLIBS = -latomic
|
LDLIBS = -latomic
|
||||||
|
else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc >= 7
|
||||||
|
NEEDED_CXXFLAGS += -std=c++17
|
||||||
|
LDLIBS = -latomic
|
||||||
else # not supported
|
else # not supported
|
||||||
$(error Compiler too old)
|
$(error Compiler too old)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ ifeq ($(USE_WIN32_APP), yes)
|
|||||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_WINXP_FLAGS), yes)
|
||||||
|
CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||||
|
endif
|
||||||
|
|
||||||
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
||||||
ifeq ($(USE_AESNI),1)
|
ifeq ($(USE_AESNI),1)
|
||||||
CPU_FLAGS += -maes
|
CPU_FLAGS += -maes
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ CXX = clang++
|
|||||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
|
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
|
||||||
INCFLAGS = -I/usr/local/include
|
INCFLAGS = -I/usr/local/include
|
||||||
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||||
|
LDFLAGS += -Wl,-dead_strip
|
||||||
|
LDFLAGS += -Wl,-dead_strip_dylibs
|
||||||
|
LDFLAGS += -Wl,-bind_at_load
|
||||||
|
|
||||||
ifeq ($(USE_STATIC),yes)
|
ifeq ($(USE_STATIC),yes)
|
||||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -1,5 +1,7 @@
|
|||||||

|
[](https://github.com/PurpleI2P/i2pd/releases/latest)
|
||||||

|
[](https://snapcraft.io/i2pd)
|
||||||
|
[](https://github.com/PurpleI2P/i2pd/blob/openssl/LICENSE)
|
||||||
|
[](https://repology.org/project/i2pd/versions)
|
||||||
|
|
||||||
i2pd
|
i2pd
|
||||||
====
|
====
|
||||||
@@ -62,10 +64,12 @@ Build instructions:
|
|||||||
**Supported systems:**
|
**Supported systems:**
|
||||||
|
|
||||||
* GNU/Linux - [](https://travis-ci.org/PurpleI2P/i2pd)
|
* GNU/Linux - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||||
|
* CentOS / Fedora / Mageia - [](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
||||||
|
* Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc.
|
||||||
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
* Windows - [](https://ci.appveyor.com/project/PurpleI2P/i2pd)
|
||||||
* Mac OS X - [](https://travis-ci.org/PurpleI2P/i2pd)
|
* Mac OS X - [](https://travis-ci.org/PurpleI2P/i2pd)
|
||||||
* CentOS / Fedora / Mageia - [](https://copr.fedorainfracloud.org/coprs/supervillain/i2pd/package/i2pd-git/)
|
|
||||||
* Docker image - [](https://hub.docker.com/r/meeh/i2pd/builds/)
|
* Docker image - [](https://hub.docker.com/r/meeh/i2pd/builds/)
|
||||||
|
* Snap - [](https://build.snapcraft.io/user/PurpleI2P/i2pd-snap)
|
||||||
* FreeBSD
|
* FreeBSD
|
||||||
* Android
|
* Android
|
||||||
* iOS
|
* iOS
|
||||||
|
|||||||
@@ -13,10 +13,6 @@
|
|||||||
#include "Win32App.h"
|
#include "Win32App.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ID_ABOUT 2000
|
#define ID_ABOUT 2000
|
||||||
#define ID_EXIT 2001
|
#define ID_EXIT 2001
|
||||||
#define ID_CONSOLE 2002
|
#define ID_CONSOLE 2002
|
||||||
@@ -39,6 +35,9 @@ namespace i2p
|
|||||||
namespace win32
|
namespace win32
|
||||||
{
|
{
|
||||||
static DWORD GracefulShutdownEndtime = 0;
|
static DWORD GracefulShutdownEndtime = 0;
|
||||||
|
|
||||||
|
typedef DWORD (* IPN)();
|
||||||
|
IPN GetTickCountLocal = (IPN)GetProcAddress (GetModuleHandle ("KERNEL32.dll"), "GetTickCount");
|
||||||
|
|
||||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||||
{
|
{
|
||||||
@@ -53,7 +52,7 @@ namespace win32
|
|||||||
ID_ACCEPT_TRANSIT, "Accept &transit");
|
ID_ACCEPT_TRANSIT, "Accept &transit");
|
||||||
else
|
else
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload tunnels config");
|
||||||
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
||||||
else
|
else
|
||||||
@@ -161,7 +160,7 @@ namespace win32
|
|||||||
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
||||||
if (GracefulShutdownEndtime != 0)
|
if (GracefulShutdownEndtime != 0)
|
||||||
{
|
{
|
||||||
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCount()) / 1000;
|
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCountLocal()) / 1000;
|
||||||
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -239,7 +238,7 @@ namespace win32
|
|||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
||||||
GracefulShutdownEndtime = GetTickCount() + 10*60*1000;
|
GracefulShutdownEndtime = GetTickCountLocal() + 10*60*1000;
|
||||||
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#define I2Pd_AppName "i2pd"
|
#define I2Pd_AppName "i2pd"
|
||||||
#define I2Pd_ver "2.26.0"
|
#define I2Pd_ver "2.31.0"
|
||||||
#define I2Pd_Publisher "PurpleI2P"
|
#define I2Pd_Publisher "PurpleI2P"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
|
|||||||
4
android/.gitignore
vendored
4
android/.gitignore
vendored
@@ -12,5 +12,5 @@ local.properties
|
|||||||
build.sh
|
build.sh
|
||||||
android.iml
|
android.iml
|
||||||
build
|
build
|
||||||
|
*.iml
|
||||||
|
*.local
|
||||||
|
|||||||
@@ -9,12 +9,15 @@
|
|||||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
||||||
|
android:requestLegacyExternalStorage="true"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
>
|
>
|
||||||
<receiver android:name=".NetworkStateChangeReceiver">
|
<receiver android:name=".NetworkStateChangeReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|||||||
19
android/README.md
Normal file
19
android/README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# how to compile?
|
||||||
|
## Install the gradle + NDK or use android-studio
|
||||||
|
[https://gradle.org/install/](https://gradle.org/install/)
|
||||||
|
|
||||||
|
## Install the depencies
|
||||||
|
```
|
||||||
|
git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
|
||||||
|
git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||||
|
git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||||
|
git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||||
|
```
|
||||||
|
## Set libs in jni/Application.mk on 24 line:
|
||||||
|
```
|
||||||
|
# change to your own
|
||||||
|
I2PD_LIBS_PATH = /home/user/i2pd/android/
|
||||||
|
```
|
||||||
|
|
||||||
|
## compile apk file
|
||||||
|
gradle clean assembleRelease
|
||||||
@@ -5,7 +5,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.3.2'
|
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,21 +16,23 @@ repositories {
|
|||||||
maven {
|
maven {
|
||||||
url 'https://maven.google.com'
|
url 'https://maven.google.com'
|
||||||
}
|
}
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.android.support:support-compat:28.0.0'
|
implementation 'androidx.core:core:1.0.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 29
|
||||||
buildToolsVersion "28.0.3"
|
buildToolsVersion "28.0.3"
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "org.purplei2p.i2pd"
|
applicationId "org.purplei2p.i2pd"
|
||||||
targetSdkVersion 28
|
targetSdkVersion 29
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
versionCode 2260
|
versionCode 2310
|
||||||
versionName "2.26.0"
|
versionName "2.31.0"
|
||||||
|
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'armeabi-v7a'
|
abiFilters 'armeabi-v7a'
|
||||||
abiFilters 'x86'
|
abiFilters 'x86'
|
||||||
@@ -55,9 +57,10 @@ android {
|
|||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
// change that to true if you need splitted apk
|
// change that to true if you need splitted apk
|
||||||
enable false
|
enable true
|
||||||
reset()
|
reset()
|
||||||
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
//include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||||
|
include "armeabi-v7a", "x86"
|
||||||
universalApk true
|
universalApk true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +74,7 @@ android {
|
|||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled false
|
||||||
signingConfig signingConfigs.orignal
|
signingConfig signingConfigs.orignal
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
|
||||||
}
|
}
|
||||||
@@ -81,4 +84,21 @@ android {
|
|||||||
path './jni/Android.mk'
|
path './jni/Android.mk'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = '1.8'
|
||||||
|
targetCompatibility = '1.8'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ext.abiCodes = ['armeabi-v7a':1, 'x86':2, 'arm64-v8a':3, 'x86_64':4]
|
||||||
|
import com.android.build.OutputFile
|
||||||
|
|
||||||
|
android.applicationVariants.all { variant ->
|
||||||
|
variant.outputs.each { output ->
|
||||||
|
def baseAbiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
|
||||||
|
|
||||||
|
if (baseAbiVersionCode != null) {
|
||||||
|
output.versionCodeOverride = baseAbiVersionCode + variant.versionCode
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
|
android.enableJetifier=true
|
||||||
|
android.useAndroidX=true
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#Thu Mar 14 18:21:08 MSK 2019
|
#Tue Aug 20 14:39:08 MSK 2019
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||||
|
|||||||
@@ -25,29 +25,29 @@ include $(BUILD_SHARED_LIBRARY)
|
|||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := boost_system
|
LOCAL_MODULE := boost_system
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/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 := boost_date_time
|
LOCAL_MODULE := boost_date_time
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/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 := boost_filesystem
|
LOCAL_MODULE := boost_filesystem
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/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 := boost_program_options
|
LOCAL_MODULE := boost_program_options
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||||
include $(PREBUILT_STATIC_LIBRARY)
|
include $(PREBUILT_STATIC_LIBRARY)
|
||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|||||||
@@ -9,15 +9,15 @@ NDK_TOOLCHAIN_VERSION := clang
|
|||||||
#APP_STL := c++_shared
|
#APP_STL := c++_shared
|
||||||
APP_STL := c++_static
|
APP_STL := c++_static
|
||||||
|
|
||||||
# Enable c++11 extensions in source code
|
# Enable c++17 extensions in source code
|
||||||
APP_CPPFLAGS += -std=c++11 -fexceptions -frtti
|
APP_CPPFLAGS += -std=c++17 -fexceptions -frtti
|
||||||
|
|
||||||
APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP
|
APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||||
APP_CPPFLAGS += -DANDROID_ARM7A
|
APP_CPPFLAGS += -DANDROID_ARM7A
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
|
||||||
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||||
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||||
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||||
|
|||||||
@@ -11,4 +11,4 @@
|
|||||||
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-28
|
target=android-29
|
||||||
|
|||||||
13
android/res/layout/webview.xml
Normal file
13
android/res/layout/webview.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<LinearLayout android:id="@+id/layout_prompt"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
tools:context=".I2PDActivity">
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:id="@+id/webview1"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -3,14 +3,23 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context=".I2PDActivity">
|
tools:context=".I2PDActivity">
|
||||||
<item
|
<group android:id="@+id/group_i2pd_control" >
|
||||||
android:id="@+id/action_graceful_stop"
|
<item
|
||||||
android:title="@string/action_graceful_stop"
|
android:id="@+id/action_stop"
|
||||||
android:orderInCategory="98"
|
android:orderInCategory="99"
|
||||||
/>
|
android:title="@string/action_stop" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_stop"
|
android:id="@+id/action_graceful_stop"
|
||||||
android:title="@string/action_stop"
|
android:orderInCategory="98"
|
||||||
android:orderInCategory="99"
|
android:title="@string/action_graceful_stop" />
|
||||||
/>
|
<item
|
||||||
|
android:id="@+id/action_start_webview"
|
||||||
|
android:orderInCategory="97"
|
||||||
|
android:title="@string/action_start_webview" />
|
||||||
|
</group>
|
||||||
|
<group android:id="@+id/group_various" >
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_battery_otimizations"
|
||||||
|
android:title="@string/menu_item_battery_optimizations_str" />
|
||||||
|
</group>
|
||||||
</menu>
|
</menu>
|
||||||
|
|||||||
@@ -17,4 +17,12 @@
|
|||||||
<string name="remaining">осталось</string>
|
<string name="remaining">осталось</string>
|
||||||
<string name="title_activity_i2_pdperms_asker_prompt">Запрос</string>
|
<string name="title_activity_i2_pdperms_asker_prompt">Запрос</string>
|
||||||
<string name="permDenied">Права для записи на SD карту отклонены, вам необходимо предоставить их для продолжения</string>
|
<string name="permDenied">Права для записи на SD карту отклонены, вам необходимо предоставить их для продолжения</string>
|
||||||
|
<string name="menu_item_battery_optimizations_str">Оптимизации аккумулятора</string>
|
||||||
|
<string name="battery_optimizations_enabled">Оптимизации аккумулятора включены</string>
|
||||||
|
<string name="device_does_not_support_disabling_battery_optimizations">Ваша версия Андроид не поддерживает отключение оптимизаций аккумулятора</string>
|
||||||
|
<string name="battery_optimizations_enabled_explained">Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\nРекомендуется отключить эти оптимизации.</string>
|
||||||
|
<string name="battery_optimizations_enabled_dialog" >Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\n\nВам сейчас будет предложено разрешить отключение этих оптимизаций.</string>
|
||||||
|
<string name="continue_str">Продолжить</string>
|
||||||
|
<string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Ваша версия Андроид не поддерживает показ диалога об оптимизациях аккумулятора для приложений.</string>
|
||||||
|
<string name="shutdown_canceled">Плановая остановка отменена</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -17,4 +17,13 @@
|
|||||||
<string name="remaining">remaining</string>
|
<string name="remaining">remaining</string>
|
||||||
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
|
||||||
<string name="permDenied">SD card write permission denied, you need to allow this to continue</string>
|
<string name="permDenied">SD card write permission denied, you need to allow this to continue</string>
|
||||||
|
<string name="battery_optimizations_enabled">Battery optimizations enabled</string>
|
||||||
|
<string name="battery_optimizations_enabled_explained">Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\nIt is recommended to allow disabling those battery optimizations.</string>
|
||||||
|
<string name="battery_optimizations_enabled_dialog" >Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\n\nYou will now be asked to allow to disable those.</string>
|
||||||
|
<string name="continue_str">Continue</string>
|
||||||
|
<string name="device_does_not_support_disabling_battery_optimizations">Your Android version does not support opting out of battery optimizations</string>
|
||||||
|
<string name="menu_item_battery_optimizations_str">Battery Optimizations</string>
|
||||||
|
<string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Your Android OS version does not support showing the dialog for battery optimizations for applications.</string>
|
||||||
|
<string name="shutdown_canceled">Planned shutdown canceled</string>
|
||||||
|
<string name="action_start_webview">Start webview</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.purplei2p.i2pd;
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
@@ -11,10 +10,9 @@ import android.content.Intent;
|
|||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
public class ForegroundService extends Service {
|
public class ForegroundService extends Service {
|
||||||
private static final String TAG="FgService";
|
private static final String TAG="FgService";
|
||||||
@@ -112,14 +110,15 @@ public class ForegroundService extends Service {
|
|||||||
|
|
||||||
// If earlier version channel ID is not used
|
// If earlier version channel ID is not used
|
||||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||||
String channelId = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? createNotificationChannel() : "";
|
String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
|
||||||
|
|
||||||
// Set the info for the views that show in the notification panel.
|
// Set the info for the views that show in the notification panel.
|
||||||
Notification notification = new NotificationCompat.Builder(this, channelId)
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setSmallIcon(R.drawable.itoopie_notification_icon) // the status icon
|
.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
|
||||||
.setPriority(Notification.PRIORITY_DEFAULT)
|
if(Build.VERSION.SDK_INT >= 16) builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
||||||
.setCategory(Notification.CATEGORY_SERVICE)
|
if(Build.VERSION.SDK_INT >= 21) builder = builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||||
|
Notification notification = builder
|
||||||
.setTicker(text) // the status text
|
.setTicker(text) // the status text
|
||||||
.setWhen(System.currentTimeMillis()) // the time stamp
|
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||||
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
||||||
@@ -141,9 +140,10 @@ public class ForegroundService extends Service {
|
|||||||
//chan.setLightColor(Color.PURPLE);
|
//chan.setLightColor(Color.PURPLE);
|
||||||
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||||
NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager service = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
service.createNotificationChannel(chan);
|
if(service!=null)service.createNotificationChannel(chan);
|
||||||
|
else Log.e(TAG, "error: NOTIFICATION_SERVICE is null");
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,36 +14,57 @@ import java.util.Timer;
|
|||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.PowerManager;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import android.support.v4.app.ActivityCompat;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
// For future package update checking
|
// For future package update checking
|
||||||
import org.purplei2p.i2pd.BuildConfig;
|
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
|
||||||
|
import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS;
|
||||||
|
|
||||||
public class I2PDActivity extends Activity {
|
public class I2PDActivity extends Activity {
|
||||||
|
private WebView webView;
|
||||||
|
|
||||||
private static final String TAG = "i2pdActvt";
|
private static final String TAG = "i2pdActvt";
|
||||||
private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
|
private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
|
||||||
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
|
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
|
||||||
|
public static final String PACKAGE_URI_SCHEME = "package:";
|
||||||
|
|
||||||
private TextView textView;
|
private TextView textView;
|
||||||
private boolean assetsCopied;
|
private boolean assetsCopied;
|
||||||
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
|
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
|
||||||
|
//private ConfigParser parser = new ConfigParser(i2pdpath); // TODO:
|
||||||
|
|
||||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||||
|
|
||||||
@@ -53,32 +74,27 @@ public class I2PDActivity extends Activity {
|
|||||||
public void daemonStateUpdate()
|
public void daemonStateUpdate()
|
||||||
{
|
{
|
||||||
processAssets();
|
processAssets();
|
||||||
runOnUiThread(new Runnable(){
|
runOnUiThread(() -> {
|
||||||
|
try {
|
||||||
@Override
|
if(textView==null) return;
|
||||||
public void run() {
|
Throwable tr = daemon.getLastThrowable();
|
||||||
try {
|
if(tr!=null) {
|
||||||
if(textView==null) return;
|
textView.setText(throwableToString(tr));
|
||||||
Throwable tr = daemon.getLastThrowable();
|
return;
|
||||||
if(tr!=null) {
|
}
|
||||||
textView.setText(throwableToString(tr));
|
DaemonSingleton.State state = daemon.getState();
|
||||||
return;
|
String startResultStr = DaemonSingleton.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : "";
|
||||||
}
|
String graceStr = DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : "";
|
||||||
DaemonSingleton.State state = daemon.getState();
|
textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr));
|
||||||
textView.setText(
|
} catch (Throwable tr) {
|
||||||
String.valueOf(getText(state.getStatusStringResourceId()))+
|
Log.e(TAG,"error ignored",tr);
|
||||||
(DaemonSingleton.State.startFailed.equals(state) ? ": "+daemon.getDaemonStartResult() : "")+
|
}
|
||||||
(DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? ": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining) : "")
|
});
|
||||||
);
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
Log.e(TAG,"error ignored",tr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private static volatile long graceStartedMillis;
|
private static volatile long graceStartedMillis;
|
||||||
private static final Object graceStartedMillis_LOCK=new Object();
|
private static final Object graceStartedMillis_LOCK=new Object();
|
||||||
|
private Menu optionsMenu;
|
||||||
|
|
||||||
private static String formatGraceTimeRemaining() {
|
private static String formatGraceTimeRemaining() {
|
||||||
long remainingSeconds;
|
long remainingSeconds;
|
||||||
@@ -92,6 +108,7 @@ public class I2PDActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
Log.i(TAG, "onCreate");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
textView = new TextView(this);
|
textView = new TextView(this);
|
||||||
@@ -121,6 +138,8 @@ public class I2PDActivity extends Activity {
|
|||||||
}
|
}
|
||||||
rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis);
|
rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openBatteryOptimizationDialogIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -128,7 +147,7 @@ public class I2PDActivity extends Activity {
|
|||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
textView = null;
|
textView = null;
|
||||||
daemon.removeStateChangeListener(daemonStateUpdatedListener);
|
daemon.removeStateChangeListener(daemonStateUpdatedListener);
|
||||||
//cancelGracefulStop();
|
//cancelGracefulStop0();
|
||||||
try{
|
try{
|
||||||
doUnbindService();
|
doUnbindService();
|
||||||
}catch(Throwable tr){
|
}catch(Throwable tr){
|
||||||
@@ -137,24 +156,20 @@ public class I2PDActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
|
||||||
{
|
{
|
||||||
switch (requestCode)
|
if (requestCode == MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) {
|
||||||
{
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||||
case MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE:
|
Log.e(TAG, "WR_EXT_STORAGE perm granted");
|
||||||
{
|
else {
|
||||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
Log.e(TAG, "WR_EXT_STORAGE perm declined, stopping i2pd");
|
||||||
Log.e(TAG, "Memory permission granted");
|
i2pdStop();
|
||||||
else
|
//TODO must work w/o this perm, ask orignal
|
||||||
Log.e(TAG, "Memory permission declined");
|
}
|
||||||
// TODO: terminate
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
default: ;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void cancelGracefulStop() {
|
private void cancelGracefulStop0() {
|
||||||
Timer gracefulQuitTimer = getGracefulQuitTimer();
|
Timer gracefulQuitTimer = getGracefulQuitTimer();
|
||||||
if(gracefulQuitTimer!=null) {
|
if(gracefulQuitTimer!=null) {
|
||||||
gracefulQuitTimer.cancel();
|
gracefulQuitTimer.cancel();
|
||||||
@@ -225,11 +240,17 @@ public class I2PDActivity extends Activity {
|
|||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
getMenuInflater().inflate(R.menu.options_main, menu);
|
getMenuInflater().inflate(R.menu.options_main, menu);
|
||||||
|
menu.findItem(R.id.action_battery_otimizations).setVisible(isBatteryOptimizationsOpenOsDialogApiAvailable());
|
||||||
|
this.optionsMenu = menu;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isBatteryOptimizationsOpenOsDialogApiAvailable() {
|
||||||
|
return android.os.Build.VERSION.SDK_INT >= 23;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
// Handle action bar item clicks here. The action bar will
|
// Handle action bar item clicks here. The action bar will
|
||||||
// automatically handle clicks on the Home/Up button, so long
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
// as you specify a parent activity in AndroidManifest.xml.
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
@@ -240,37 +261,53 @@ public class I2PDActivity extends Activity {
|
|||||||
i2pdStop();
|
i2pdStop();
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_graceful_stop:
|
case R.id.action_graceful_stop:
|
||||||
if (getGracefulQuitTimer()!= null)
|
synchronized (graceStartedMillis_LOCK) {
|
||||||
{
|
if (getGracefulQuitTimer() != null)
|
||||||
item.setTitle(R.string.action_graceful_stop);
|
cancelGracefulStop();
|
||||||
i2pdCancelGracefulStop ();
|
else
|
||||||
|
i2pdGracefulStop();
|
||||||
}
|
}
|
||||||
else
|
return true;
|
||||||
{
|
case R.id.action_battery_otimizations:
|
||||||
item.setTitle(R.string.action_cancel_graceful_stop);
|
onActionBatteryOptimizations();
|
||||||
i2pdGracefulStop();
|
return true;
|
||||||
}
|
case R.id.action_start_webview:
|
||||||
return true;
|
setContentView(R.layout.webview);
|
||||||
|
this.webView = (WebView) findViewById(R.id.webview1);
|
||||||
|
this.webView.setWebViewClient(new WebViewClient());
|
||||||
|
|
||||||
|
WebSettings webSettings = this.webView.getSettings();
|
||||||
|
webSettings.setBuiltInZoomControls(true);
|
||||||
|
webSettings.setJavaScriptEnabled(false);
|
||||||
|
this.webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void i2pdStop() {
|
private void onActionBatteryOptimizations() {
|
||||||
cancelGracefulStop();
|
if (isBatteryOptimizationsOpenOsDialogApiAvailable()) {
|
||||||
new Thread(new Runnable(){
|
try {
|
||||||
|
startActivity(new Intent(ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS));
|
||||||
@Override
|
} catch (ActivityNotFoundException e) {
|
||||||
public void run() {
|
Log.e(TAG,"BATT_OPTIM_DIALOG_ActvtNotFound", e);
|
||||||
Log.d(TAG, "stopping");
|
Toast.makeText(this, R.string.os_version_does_not_support_battery_optimizations_show_os_dialog_api, Toast.LENGTH_SHORT).show();
|
||||||
try{
|
|
||||||
daemon.stopDaemon();
|
|
||||||
}catch (Throwable tr) {
|
|
||||||
Log.e(TAG, "", tr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
},"stop").start();
|
private void i2pdStop() {
|
||||||
|
cancelGracefulStop0();
|
||||||
|
new Thread(() -> {
|
||||||
|
Log.d(TAG, "stopping");
|
||||||
|
try {
|
||||||
|
daemon.stopDaemon();
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "", tr);
|
||||||
|
}
|
||||||
|
quit(); //TODO make menu items for starting i2pd. On my Android, I need to reboot the OS to restart i2pd.
|
||||||
|
},"stop").start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static volatile Timer gracefulQuitTimer;
|
private static volatile Timer gracefulQuitTimer;
|
||||||
@@ -288,55 +325,45 @@ public class I2PDActivity extends Activity {
|
|||||||
}
|
}
|
||||||
Toast.makeText(this, R.string.graceful_stop_is_in_progress,
|
Toast.makeText(this, R.string.graceful_stop_is_in_progress,
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
new Thread(new Runnable(){
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
@Override
|
Log.d(TAG, "grac stopping");
|
||||||
public void run() {
|
if(daemon.isStartedOkay()) {
|
||||||
try {
|
daemon.stopAcceptingTunnels();
|
||||||
Log.d(TAG, "grac stopping");
|
long gracefulStopAtMillis;
|
||||||
if(daemon.isStartedOkay()) {
|
synchronized (graceStartedMillis_LOCK) {
|
||||||
daemon.stopAcceptingTunnels();
|
graceStartedMillis = System.currentTimeMillis();
|
||||||
long gracefulStopAtMillis;
|
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
|
||||||
synchronized (graceStartedMillis_LOCK) {
|
}
|
||||||
graceStartedMillis = System.currentTimeMillis();
|
rescheduleGraceStop(null,gracefulStopAtMillis);
|
||||||
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
|
} else {
|
||||||
}
|
i2pdStop();
|
||||||
rescheduleGraceStop(null,gracefulStopAtMillis);
|
}
|
||||||
} else {
|
} catch(Throwable tr) {
|
||||||
i2pdStop();
|
Log.e(TAG,"",tr);
|
||||||
}
|
}
|
||||||
} catch(Throwable tr) {
|
},"gracInit").start();
|
||||||
Log.e(TAG,"",tr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
},"gracInit").start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void i2pdCancelGracefulStop()
|
private void cancelGracefulStop()
|
||||||
{
|
{
|
||||||
cancelGracefulStop();
|
cancelGracefulStop0();
|
||||||
Toast.makeText(this, R.string.startedOkay, Toast.LENGTH_SHORT).show();
|
new Thread(() -> {
|
||||||
new Thread(new Runnable()
|
try
|
||||||
{
|
{
|
||||||
@Override
|
Log.d(TAG, "canceling grac stop");
|
||||||
public void run()
|
if(daemon.isStartedOkay()) {
|
||||||
{
|
daemon.startAcceptingTunnels();
|
||||||
try
|
runOnUiThread(() -> Toast.makeText(this, R.string.shutdown_canceled, Toast.LENGTH_SHORT).show());
|
||||||
{
|
|
||||||
Log.d(TAG, "grac stopping cancel");
|
|
||||||
if(daemon.isStartedOkay())
|
|
||||||
daemon.startAcceptingTunnels();
|
|
||||||
else
|
|
||||||
i2pdStop();
|
|
||||||
}
|
}
|
||||||
catch(Throwable tr)
|
else
|
||||||
{
|
i2pdStop();
|
||||||
Log.e(TAG,"",tr);
|
}
|
||||||
}
|
catch(Throwable tr)
|
||||||
}
|
{
|
||||||
|
Log.e(TAG,"",tr);
|
||||||
},"gracCancel").start();
|
}
|
||||||
|
},"gracCancel").start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
|
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
|
||||||
@@ -364,8 +391,19 @@ public class I2PDActivity extends Activity {
|
|||||||
return gracefulQuitTimer;
|
return gracefulQuitTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void setGracefulQuitTimer(Timer gracefulQuitTimer) {
|
private void setGracefulQuitTimer(Timer gracefulQuitTimer) {
|
||||||
I2PDActivity.gracefulQuitTimer = gracefulQuitTimer;
|
I2PDActivity.gracefulQuitTimer = gracefulQuitTimer;
|
||||||
|
runOnUiThread(()-> {
|
||||||
|
Menu menu = optionsMenu;
|
||||||
|
if (menu != null) {
|
||||||
|
MenuItem item = menu.findItem(R.id.action_graceful_stop);
|
||||||
|
if (item != null) {
|
||||||
|
synchronized (graceStartedMillis_LOCK) {
|
||||||
|
item.setTitle(getGracefulQuitTimer() != null ? R.string.action_cancel_graceful_stop : R.string.action_graceful_stop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -388,19 +426,22 @@ public class I2PDActivity extends Activity {
|
|||||||
// to a file. That doesn't appear to be the case. If the returned array is
|
// to a file. That doesn't appear to be the case. If the returned array is
|
||||||
// null or has 0 length, we assume the path is to a file. This means empty
|
// null or has 0 length, we assume the path is to a file. This means empty
|
||||||
// directories will get turned into files.
|
// directories will get turned into files.
|
||||||
if (contents == null || contents.length == 0)
|
if (contents == null || contents.length == 0) {
|
||||||
throw new IOException();
|
copyFileAsset(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Make the directory.
|
// Make the directory.
|
||||||
File dir = new File(i2pdpath, path);
|
File dir = new File(i2pdpath, path);
|
||||||
dir.mkdirs();
|
boolean result = dir.mkdirs();
|
||||||
|
Log.d(TAG, "dir.mkdirs() returned " + result);
|
||||||
|
|
||||||
// Recurse on the contents.
|
// Recurse on the contents.
|
||||||
for (String entry : contents) {
|
for (String entry : contents) {
|
||||||
copyAsset(path + "/" + entry);
|
copyAsset(path + '/' + entry);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
copyFileAsset(path);
|
Log.e(TAG, "ex ignored for path='" + path + "'", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,63 +454,89 @@ public class I2PDActivity extends Activity {
|
|||||||
*/
|
*/
|
||||||
private void copyFileAsset(String path) {
|
private void copyFileAsset(String path) {
|
||||||
File file = new File(i2pdpath, path);
|
File file = new File(i2pdpath, path);
|
||||||
if(!file.exists()) try {
|
if(!file.exists()) {
|
||||||
InputStream in = getAssets().open(path);
|
try {
|
||||||
OutputStream out = new FileOutputStream(file);
|
try (InputStream in = getAssets().open(path) ) {
|
||||||
byte[] buffer = new byte[1024];
|
try (OutputStream out = new FileOutputStream(file)) {
|
||||||
int read = in.read(buffer);
|
byte[] buffer = new byte[1024];
|
||||||
while (read != -1) {
|
int read = in.read(buffer);
|
||||||
out.write(buffer, 0, read);
|
while (read != -1) {
|
||||||
read = in.read(buffer);
|
out.write(buffer, 0, read);
|
||||||
|
read = in.read(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
}
|
}
|
||||||
out.close();
|
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteRecursive(File fileOrDirectory) {
|
private void deleteRecursive(File fileOrDirectory) {
|
||||||
if (fileOrDirectory.isDirectory()) {
|
if (fileOrDirectory.isDirectory()) {
|
||||||
for (File child : fileOrDirectory.listFiles()) {
|
File[] files = fileOrDirectory.listFiles();
|
||||||
deleteRecursive(child);
|
if(files!=null) {
|
||||||
|
for (File child : files) {
|
||||||
|
deleteRecursive(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fileOrDirectory.delete();
|
boolean deleteResult = fileOrDirectory.delete();
|
||||||
|
if(!deleteResult)Log.e(TAG, "fileOrDirectory.delete() returned "+deleteResult+", absolute path='"+fileOrDirectory.getAbsolutePath()+"'");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processAssets() {
|
private void processAssets() {
|
||||||
if (!assetsCopied) try {
|
if (!assetsCopied) try {
|
||||||
assetsCopied = true; // prevent from running on every state update
|
assetsCopied = true; // prevent from running on every state update
|
||||||
|
|
||||||
File holderfile = new File(i2pdpath, "assets.ready");
|
File holderFile = new File(i2pdpath, "assets.ready");
|
||||||
String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
|
String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
|
||||||
StringBuilder text = new StringBuilder();
|
StringBuilder text = new StringBuilder();
|
||||||
|
|
||||||
if (holderfile.exists()) try { // if holder file exists, read assets version string
|
if (holderFile.exists()) {
|
||||||
BufferedReader br = new BufferedReader(new FileReader(holderfile));
|
try { // if holder file exists, read assets version string
|
||||||
String line;
|
FileReader fileReader = new FileReader(holderFile);
|
||||||
|
|
||||||
while ((line = br.readLine()) != null) {
|
try {
|
||||||
text.append(line);
|
BufferedReader br = new BufferedReader(fileReader);
|
||||||
}
|
|
||||||
br.close();
|
try {
|
||||||
}
|
String line;
|
||||||
catch (IOException e) {
|
|
||||||
Log.e(TAG, "", e);
|
while ((line = br.readLine()) != null) {
|
||||||
}
|
text.append(line);
|
||||||
|
}
|
||||||
|
}finally {
|
||||||
|
try{
|
||||||
|
br.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try{
|
||||||
|
fileReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if version differs from current app version or null, try to delete certificates folder
|
// if version differs from current app version or null, try to delete certificates folder
|
||||||
if (!text.toString().contains(versionName)) try {
|
if (!text.toString().contains(versionName)) try {
|
||||||
holderfile.delete();
|
boolean deleteResult = holderFile.delete();
|
||||||
File certpath = new File(i2pdpath, "certificates");
|
if(!deleteResult)Log.e(TAG, "holderFile.delete() returned "+deleteResult+", absolute path='"+holderFile.getAbsolutePath()+"'");
|
||||||
deleteRecursive(certpath);
|
File certPath = new File(i2pdpath, "certificates");
|
||||||
|
deleteRecursive(certPath);
|
||||||
}
|
}
|
||||||
catch (Throwable tr) {
|
catch (Throwable tr) {
|
||||||
Log.e(TAG, "", tr);
|
Log.e(TAG, "", tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy assets. If processed file exists, it won't be overwrited
|
// copy assets. If processed file exists, it won't be overwritten
|
||||||
copyAsset("addressbook");
|
copyAsset("addressbook");
|
||||||
copyAsset("certificates");
|
copyAsset("certificates");
|
||||||
copyAsset("tunnels.d");
|
copyAsset("tunnels.d");
|
||||||
@@ -478,14 +545,95 @@ public class I2PDActivity extends Activity {
|
|||||||
copyAsset("tunnels.conf");
|
copyAsset("tunnels.conf");
|
||||||
|
|
||||||
// update holder file about successful copying
|
// update holder file about successful copying
|
||||||
FileWriter writer = new FileWriter(holderfile);
|
FileWriter writer = new FileWriter(holderFile);
|
||||||
writer.append(versionName);
|
try {
|
||||||
writer.flush();
|
writer.append(versionName);
|
||||||
writer.close();
|
} finally {
|
||||||
|
try{
|
||||||
|
writer.close();
|
||||||
|
}catch (IOException e){
|
||||||
|
Log.e(TAG,"on writer close", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable tr)
|
catch (Throwable tr)
|
||||||
{
|
{
|
||||||
Log.e(TAG,"copy assets",tr);
|
Log.e(TAG,"on assets copying", tr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("BatteryLife")
|
||||||
|
private void openBatteryOptimizationDialogIfNeeded() {
|
||||||
|
boolean questionEnabled = getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true);
|
||||||
|
Log.i(TAG,"BATT_OPTIM_questionEnabled=="+questionEnabled);
|
||||||
|
if (!isKnownIgnoringBatteryOptimizations()
|
||||||
|
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M
|
||||||
|
&& questionEnabled) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle(R.string.battery_optimizations_enabled);
|
||||||
|
builder.setMessage(R.string.battery_optimizations_enabled_dialog);
|
||||||
|
builder.setPositiveButton(R.string.continue_str, (dialog, which) -> {
|
||||||
|
try {
|
||||||
|
startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(PACKAGE_URI_SCHEME + getPackageName())));
|
||||||
|
} catch (ActivityNotFoundException e) {
|
||||||
|
Log.e(TAG,"BATT_OPTIM_ActvtNotFound", e);
|
||||||
|
Toast.makeText(this, R.string.device_does_not_support_disabling_battery_optimizations, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setOnDismissListener(dialog -> setNeverAskForBatteryOptimizationsAgain());
|
||||||
|
final AlertDialog dialog = builder.create();
|
||||||
|
dialog.setCanceledOnTouchOutside(false);
|
||||||
|
dialog.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setNeverAskForBatteryOptimizationsAgain() {
|
||||||
|
getPreferences().edit().putBoolean(getBatteryOptimizationPreferenceKey(), false).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isKnownIgnoringBatteryOptimizations() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
final PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
|
||||||
|
if (pm == null) {
|
||||||
|
Log.i(TAG, "BATT_OPTIM: POWER_SERVICE==null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean ignoring = pm.isIgnoringBatteryOptimizations(getPackageName());
|
||||||
|
Log.i(TAG, "BATT_OPTIM: ignoring==" + ignoring);
|
||||||
|
return ignoring;
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "BATT_OPTIM: old sdk version=="+Build.VERSION.SDK_INT);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SharedPreferences getPreferences() {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getBatteryOptimizationPreferenceKey() {
|
||||||
|
@SuppressLint("HardwareIds") String device = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||||
|
return "show_battery_optimization" + (device == null ? "" : device);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void quit() {
|
||||||
|
try {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
finishAndRemoveTask();
|
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||||
|
finishAffinity();
|
||||||
|
} else {
|
||||||
|
//moveTaskToBack(true);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "", tr);
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
daemon.stopDaemon();
|
||||||
|
}catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "", tr);
|
||||||
|
}
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,29 +26,29 @@ include $(BUILD_EXECUTABLE)
|
|||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := boost_system
|
LOCAL_MODULE := boost_system
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/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 := boost_date_time
|
LOCAL_MODULE := boost_date_time
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/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 := boost_filesystem
|
LOCAL_MODULE := boost_filesystem
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/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 := boost_program_options
|
LOCAL_MODULE := boost_program_options
|
||||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_68_0-clang/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
|
||||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_68_0-clang/include
|
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||||
include $(PREBUILT_STATIC_LIBRARY)
|
include $(PREBUILT_STATIC_LIBRARY)
|
||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ APP_PLATFORM := android-14
|
|||||||
NDK_TOOLCHAIN_VERSION := clang
|
NDK_TOOLCHAIN_VERSION := clang
|
||||||
APP_STL := c++_static
|
APP_STL := c++_static
|
||||||
|
|
||||||
# Enable c++11 extensions in source code
|
# Enable c++17 extensions in source code
|
||||||
APP_CPPFLAGS += -std=c++11 -fvisibility=default -fPIE
|
APP_CPPFLAGS += -std=c++17 -fvisibility=default -fPIE
|
||||||
|
|
||||||
APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
|
APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||||
APP_LDFLAGS += -rdynamic -fPIE -pie
|
APP_LDFLAGS += -rdynamic -fPIE -pie
|
||||||
@@ -21,7 +21,7 @@ endif
|
|||||||
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
|
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
|
||||||
#APP_OPTIM := debug
|
#APP_OPTIM := debug
|
||||||
|
|
||||||
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
|
||||||
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
|
||||||
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
|
||||||
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
version: 2.26.0.{build}
|
version: 2.31.0.{build}
|
||||||
pull_requests:
|
pull_requests:
|
||||||
do_not_increment_build_number: true
|
do_not_increment_build_number: true
|
||||||
branches:
|
branches:
|
||||||
@@ -18,9 +18,9 @@ environment:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc"
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu --force"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
|
||||||
|
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu --force"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
|
||||||
|
|
||||||
- if "%MSYSTEM%" == "MINGW64" (
|
- if "%MSYSTEM%" == "MINGW64" (
|
||||||
c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
|
c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ option(WITH_GUI "Include GUI (currently MS Windows only)" ON)
|
|||||||
option(WITH_MESHNET "Build for cjdns test network" OFF)
|
option(WITH_MESHNET "Build for cjdns test network" OFF)
|
||||||
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
||||||
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
||||||
option(WITH_I2LUA "Build for i2lua" OFF)
|
|
||||||
option(WITH_WEBSOCKETS "Build with websocket ui" OFF)
|
|
||||||
|
|
||||||
# paths
|
# paths
|
||||||
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
|
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" )
|
||||||
@@ -75,28 +73,20 @@ set (LIBI2PD_SRC
|
|||||||
"${LIBI2PD_SRC_DIR}/Signature.cpp"
|
"${LIBI2PD_SRC_DIR}/Signature.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Timestamp.cpp"
|
"${LIBI2PD_SRC_DIR}/Timestamp.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/api.cpp"
|
"${LIBI2PD_SRC_DIR}/api.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Event.cpp"
|
|
||||||
"${LIBI2PD_SRC_DIR}/Gost.cpp"
|
"${LIBI2PD_SRC_DIR}/Gost.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/ChaCha20.cpp"
|
"${LIBI2PD_SRC_DIR}/ChaCha20.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Poly1305.cpp"
|
"${LIBI2PD_SRC_DIR}/Poly1305.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Ed25519.cpp"
|
"${LIBI2PD_SRC_DIR}/Ed25519.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/NTCP2.cpp"
|
"${LIBI2PD_SRC_DIR}/NTCP2.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Blinding.cpp"
|
"${LIBI2PD_SRC_DIR}/Blinding.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/Elligator.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WITH_WEBSOCKETS)
|
|
||||||
add_definitions(-DWITH_EVENTS)
|
|
||||||
find_package(websocketpp REQUIRED)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (WIN32 OR MSYS)
|
if (WIN32 OR MSYS)
|
||||||
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
|
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (WITH_I2LUA)
|
|
||||||
add_definitions(-DI2LUA)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(libi2pd ${LIBI2PD_SRC})
|
add_library(libi2pd ${LIBI2PD_SRC})
|
||||||
set_target_properties(libi2pd PROPERTIES PREFIX "")
|
set_target_properties(libi2pd PROPERTIES PREFIX "")
|
||||||
|
|
||||||
@@ -122,13 +112,8 @@ set (CLIENT_SRC
|
|||||||
"${LIBI2PD_CLIENT_SRC_DIR}/SOCKS.cpp"
|
"${LIBI2PD_CLIENT_SRC_DIR}/SOCKS.cpp"
|
||||||
"${LIBI2PD_CLIENT_SRC_DIR}/HTTPProxy.cpp"
|
"${LIBI2PD_CLIENT_SRC_DIR}/HTTPProxy.cpp"
|
||||||
"${LIBI2PD_CLIENT_SRC_DIR}/I2CP.cpp"
|
"${LIBI2PD_CLIENT_SRC_DIR}/I2CP.cpp"
|
||||||
"${LIBI2PD_CLIENT_SRC_DIR}/WebSocks.cpp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WITH_WEBSOCKETS)
|
|
||||||
list (APPEND CLIENT_SRC "${LIBI2PD_CLIENT_SRC_DIR}/Websocket.cpp")
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
add_library(libi2pdclient ${CLIENT_SRC})
|
add_library(libi2pdclient ${CLIENT_SRC})
|
||||||
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
|
set_target_properties(libi2pdclient PROPERTIES PREFIX "")
|
||||||
|
|
||||||
@@ -182,17 +167,17 @@ else()
|
|||||||
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above
|
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# check for c++11 support
|
# check for c++17 & c++11 support
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
|
||||||
CHECK_CXX_COMPILER_FLAG("-std=c++0x" CXX0X_SUPPORTED)
|
if(CXX17_SUPPORTED)
|
||||||
if (CXX11_SUPPORTED)
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
|
||||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
|
elseif(CXX11_SUPPORTED)
|
||||||
elseif (CXX0X_SUPPORTED) # gcc 4.6
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x" )
|
else()
|
||||||
elseif (NOT MSVC)
|
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
|
||||||
message(SEND_ERROR "C++11 standard not seems to be supported by compiler. Too old version?")
|
endif()
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
|
||||||
@@ -424,8 +409,6 @@ message(STATUS " PCH : ${WITH_PCH}")
|
|||||||
message(STATUS " MESHNET : ${WITH_MESHNET}")
|
message(STATUS " MESHNET : ${WITH_MESHNET}")
|
||||||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||||
message(STATUS " I2LUA : ${WITH_I2LUA}")
|
|
||||||
message(STATUS " WEBSOCKETS : ${WITH_WEBSOCKETS}")
|
|
||||||
message(STATUS "---------------------------------------")
|
message(STATUS "---------------------------------------")
|
||||||
|
|
||||||
#Handle paths nicely
|
#Handle paths nicely
|
||||||
|
|||||||
@@ -54,6 +54,14 @@ set bitness=64
|
|||||||
call :BUILDING
|
call :BUILDING
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
|
REM building for WinXP
|
||||||
|
set "WD=C:\msys64-xp\usr\bin\"
|
||||||
|
set MSYSTEM=MINGW32
|
||||||
|
set bitness=32
|
||||||
|
set "xSH=%WD%bash -lc"
|
||||||
|
call :BUILDING_XP
|
||||||
|
echo.
|
||||||
|
|
||||||
del README.txt >> nul
|
del README.txt >> nul
|
||||||
|
|
||||||
echo Build complete...
|
echo Build complete...
|
||||||
@@ -71,5 +79,11 @@ echo Build AESNI...
|
|||||||
%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1
|
%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1
|
||||||
echo Build without extensions...
|
echo Build without extensions...
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1
|
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1
|
||||||
|
goto EOF
|
||||||
|
|
||||||
|
:BUILDING_XP
|
||||||
|
%xSH% "make clean" >> nul
|
||||||
|
echo Building i2pd %tag% for winxp...
|
||||||
|
%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1
|
||||||
|
|
||||||
:EOF
|
:EOF
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFfTCCA2WgAwIBAgIEOprmhjANBgkqhkiG9w0BAQ0FADBvMQswCQYDVQQGEwJY
|
|
||||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
|
||||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEYMBYGA1UEAwwPYmFja3VwQG1haWwu
|
|
||||||
aTJwMB4XDTEzMTAxMzEzNDQ1NVoXDTIzMTAxMzEzNDQ1NVowbzELMAkGA1UEBhMC
|
|
||||||
WFgxCzAJBgNVBAgTAlhYMQswCQYDVQQHEwJYWDEeMBwGA1UEChMVSTJQIEFub255
|
|
||||||
bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGDAWBgNVBAMMD2JhY2t1cEBtYWls
|
|
||||||
LmkycDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIoAkobXwk/Enf1d
|
|
||||||
roHyqCyvcJfZJVTwb/LgYWAvCBMCr+RGqlSgtk3g69Y3I0xU08fD2kGt3r5Pwsbr
|
|
||||||
omXIbJAcccyLqmQ5QX6QgL+X9VpMDp9C4h2RogCrqLBAWw4cuZ4RS9VCpP1Yis7H
|
|
||||||
uejYqENP86p7BsRnuW/4cYnfunAdMpss4LpRGQXt1nTX+kfgCYgnKFbFqwAHt7yV
|
|
||||||
Ds+Pe6FuBHPlp+sc1amKRcUnSvhXLsv43VicnT7xYL/kUsN83wrtHA3B4aGDx3aA
|
|
||||||
3/EzuRmIXQB0BlTZILMEyYwG/nc4OsW82QYrvEZ9BIg9A4lF/wS/KZCICPxLF2zo
|
|
||||||
dGjnmlgkiA4s8eO+va/ElHyELjckVXqmG1eXHhSkEsDvOQJy01IUuwLinvq7cUbJ
|
|
||||||
HfJBZJllEg+sLDCv3FkEqN+XjBNFfQN4oNew4w6IPY6YH1INVB9LL0Cmdu4DudLv
|
|
||||||
TY8OcI8eSfez3hmm+pYQ23PJRYYnvRDnRECyIWBegkckWRh8U/WvZUYUvETK6EDl
|
|
||||||
/0KpTtfzX6MqHA5D6bTAB8Y3ijGMLrZ/B5vj5yCoZbLiGme9X2moR2k1LEhdhtzV
|
|
||||||
exsqezCpg6dn48FTX7mHjvR5/r4kz2jqBGmdPUWIIxnjFUzDUK3llVQiHihleHpe
|
|
||||||
jL4LqnhBGKWFRTaVwaIkBG4zAfIzAgMBAAGjITAfMB0GA1UdDgQWBBQNkfW7bSMl
|
|
||||||
1/4KDbgwrkf9x1Zu/TANBgkqhkiG9w0BAQ0FAAOCAgEAGg3a3rTf0EznQocmio0T
|
|
||||||
5gCoL0n8h6yKW/PyPAIELrd9wiYjhJFcWvMTcJJJnVqmAL5vpvhaAFVtAfx70MGa
|
|
||||||
0DZ7FvytK5hEfF4IqOFDyEEVGJR5rIpVK4MeI1nmwEsxdbW+FhODjtRzgYO8XBME
|
|
||||||
Xj4aY1FWg9vxc3reUj6PSFsZtsB0aLiRgL9JDovJIiRw0Uqr1v2wXBte5yVCxDge
|
|
||||||
vTREZtpK4cKetoOa68pwSXI32JwKE18j6bfdKVBCcYQKlKP/3gHGduaDrQv3w32S
|
|
||||||
DRym5s6MREeTUOtAw4wq46KpdOX8yyAqJPrCfMwS6ORd3t+egqOw0PUnsqb97w4O
|
|
||||||
lUtrRYvb2cOj60SmRx4vJvItyuHbKqIK7o2e1RcUZPXYoAVx2ww4XB2Wk4D7LSAs
|
|
||||||
cS7nLj8yAqzJ2qqtBzxu+zILJtkVa12dKF0xmS0BxBp4sCYiBtmAVE8AWQqEuSHA
|
|
||||||
FrMWqoXcjcfdvvyX487FFWWUE7ZBIn0hee2sK9J9+SPtqczJaN7TF3K3nzo65WJG
|
|
||||||
1epltmq2Ugjb67Gz7v4y7H23DJ/qhm8yLtCHTj69HTta5I08j6Kut924WLZaiMO/
|
|
||||||
4YoEL5AE63X0sxYibKFQiq7FW5nUJA280GRlY3xSMFzlB2ggazrUV3YAWVDhfdnI
|
|
||||||
flpzWXkFM2D36OUaubfe9YY=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIF3DCCA8SgAwIBAgIQPxUlcrbHX/xdyJ09E36rJzANBgkqhkiG9w0BAQsFADB3
|
|
||||||
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
|
||||||
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEgMB4GA1UEAwwX
|
|
||||||
cmVzZWVkaTJwbmV0aW5AbWFpbC5pMnAwHhcNMTgxMjA3MTYzNDIxWhcNMjgxMjA3
|
|
||||||
MTYzNDIxWjB3MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhY
|
|
||||||
MR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEg
|
|
||||||
MB4GA1UEAwwXcmVzZWVkaTJwbmV0aW5AbWFpbC5pMnAwggIiMA0GCSqGSIb3DQEB
|
|
||||||
AQUAA4ICDwAwggIKAoICAQC912NDk6x85uqB4gyQQcded0RVrbWehWOanDRv7kC3
|
|
||||||
92jeziPbeMtqrLsfU1MdDtQiGijpNkQ/IIitPw+6vJAIh82gyOUZvsn2XOyb/Fz0
|
|
||||||
Fu8OrDghwl39yK8kwtqCFw3VAgafgKxz2oRge9mxFBECi50vYEPIBwNhr4yc/opu
|
|
||||||
wWUmzmRyX4gD7vKmRU6ZTwX4LXnwdl+5VbW3updcZKsDuTnKvC9FGhDRR9kIk2G9
|
|
||||||
43sLN263nCYPykP7DaB1cUdi1vDEMw5dot+eu16qTIbuypEvYNvbB/9FyCQllm1h
|
|
||||||
vBbSku3IYpcnRPmoeyhoR/MmCySRbK5R4SrSsVD1YBpwxgn0Q4+fzEgFzT9P4oez
|
|
||||||
HkDGKVP2HdgmXx9j36fEqqvjqzRleWDwEWwIZVRLCFO+hhhT3JAjnNGJTWv1SQGB
|
|
||||||
8tz9nyYTJuhvyHE/CO5owFeCdeOGMq2KPge9w34T+mvewTEEhGU8yRAt8Xp8s5Y9
|
|
||||||
RCUGvuQ79+edRtj7FJg7yVB8pAQ+VB9msNQvzrTnPYC9Wo7chJhBiraMiIabzIhC
|
|
||||||
f34Gg9lkX1N0dVND5rnZWwzBM6JhNG1iZZCRHVPnXdZRixUlqmFpCP/eekshksj/
|
|
||||||
6UP/WeGA6X4HyEsC6QEf7eMhcHYjyyTzYagKrwCHg77fmIjF8rmpP2LqWSQW8bDD
|
|
||||||
uQIDAQABo2QwYjAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
|
|
||||||
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wIAYDVR0OBBkEF3Jlc2VlZGkycG5l
|
|
||||||
dGluQG1haWwuaTJwMA0GCSqGSIb3DQEBCwUAA4ICAQCWpXs6iuTy/w2R7q7Ua6vl
|
|
||||||
JYZwbQ+czk5ydzkBgcNkMMMNRT7sZR9xYvV+ftiL4bFQP/3ZJyo7cYz2Q6+M3oAm
|
|
||||||
YDcZWBkLUVihSlMxhWwmeFTKV2EL+bzwY1V/cy7wgukKnFIes75dLP/v25jgjdlw
|
|
||||||
Xe6R+fQM0EoHeVzzrWk/qYp6oEwtQXfZnUu/Bf45hRnnHBzzh1wCql41vbEs3Niq
|
|
||||||
+SVwY1wLT0yC1L8HqjCLX1/L5PAXxbvEGzwnXSkLKK4bPxdmVDZvS9uzXrWmTbNi
|
|
||||||
HpKIFnOif16zSgyeaOM7HETIJuVzgooUMtt+Vsr1VGdtm6K7I9J5C+rX/ckU8oaX
|
|
||||||
UjmzhWXudN0VTslogsKUCV6xG2CskeE3wnuT8HYXz9NMw6c/kIGH4hY7LcfU8Teu
|
|
||||||
QjSy2RRvy6InmZNV5sY9lzzO6romEycSoUlpCa3Ltb/5KKoYZFTsXr8suqJk89lC
|
|
||||||
e+TVMHqOZdLK/usqQDcafLypHpw9SH2Tg4jrzV/zLqacbjx6bZD5IrpY0Gf7BXg/
|
|
||||||
pikwyA9c490G6ZcWrSEP8bzh6LL2rA2AwxaeJJNVyLHCSLrn/7DezM5J/qhd90Qg
|
|
||||||
kcZGJrUOCSWl6mDvUZn5XiQ955XwOnZQ+wsM85B3CVX22x5bp0SYWHCQBPnthPwP
|
|
||||||
Q5DD3jExbpwG5n35HEcHYw==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
@@ -36,8 +36,8 @@ 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-python linux-headers boost-prg_exec_monitor \
|
boost-python3 python3 gdbm boost-unit_test_framework linux-headers boost-prg_exec_monitor \
|
||||||
boost-serialization boost-signals boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \
|
boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \
|
||||||
libtool g++ gcc pkgconfig
|
libtool g++ gcc pkgconfig
|
||||||
|
|
||||||
# 2. Adding required libraries to run i2pd to ensure it will run.
|
# 2. Adding required libraries to run i2pd to ensure it will run.
|
||||||
|
|||||||
@@ -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.26.0
|
Version: 2.31.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
|
||||||
@@ -55,14 +55,22 @@ cd build
|
|||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?mageia} > 7
|
||||||
|
pushd build
|
||||||
make %{?_smp_mflags}
|
make %{?_smp_mflags}
|
||||||
|
popd
|
||||||
|
%else
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
%endif
|
||||||
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
cd build
|
pushd build
|
||||||
|
|
||||||
%if 0%{?mageia}
|
%if 0%{?mageia}
|
||||||
cd build
|
pushd build
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
chrpath -d i2pd
|
chrpath -d i2pd
|
||||||
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
||||||
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
||||||
@@ -110,6 +118,21 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Apr 10 2020 orignal <i2porignal@yandex.ru> - 2.31.0
|
||||||
|
- update to 2.31.0
|
||||||
|
|
||||||
|
* Tue Feb 25 2020 orignal <i2porignal@yandex.ru> - 2.30.0
|
||||||
|
- update to 2.30.0
|
||||||
|
|
||||||
|
* Mon Oct 21 2019 orignal <i2porignal@yandex.ru> - 2.29.0
|
||||||
|
- update to 2.29.0
|
||||||
|
|
||||||
|
* Tue Aug 27 2019 orignal <i2porignal@yandex.ru> - 2.28.0
|
||||||
|
- update to 2.28.0
|
||||||
|
|
||||||
|
* Wed Jul 3 2019 orignal <i2porignal@yandex.ru> - 2.27.0
|
||||||
|
- update to 2.27.0
|
||||||
|
|
||||||
* Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0
|
* Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0
|
||||||
- update to 2.26.0
|
- update to 2.26.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.26.0
|
Version: 2.31.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
|
||||||
@@ -53,14 +53,22 @@ cd build
|
|||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?mageia} > 7
|
||||||
|
pushd build
|
||||||
make %{?_smp_mflags}
|
make %{?_smp_mflags}
|
||||||
|
popd
|
||||||
|
%else
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
%endif
|
||||||
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
cd build
|
pushd build
|
||||||
|
|
||||||
%if 0%{?mageia}
|
%if 0%{?mageia}
|
||||||
cd build
|
pushd build
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
chrpath -d i2pd
|
chrpath -d i2pd
|
||||||
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
|
||||||
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
||||||
@@ -108,6 +116,21 @@ getent passwd i2pd >/dev/null || \
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Apr 10 2020 orignal <i2porignal@yandex.ru> - 2.31.0
|
||||||
|
- update to 2.31.0
|
||||||
|
|
||||||
|
* Tue Feb 25 2020 orignal <i2porignal@yandex.ru> - 2.30.0
|
||||||
|
- update to 2.30.0
|
||||||
|
|
||||||
|
* Mon Oct 21 2019 orignal <i2porignal@yandex.ru> - 2.29.0
|
||||||
|
- update to 2.29.0
|
||||||
|
|
||||||
|
* Tue Aug 27 2019 orignal <i2porignal@yandex.ru> - 2.28.0
|
||||||
|
- update to 2.28.0
|
||||||
|
|
||||||
|
* Wed Jul 3 2019 orignal <i2porignal@yandex.ru> - 2.27.0
|
||||||
|
- update to 2.27.0
|
||||||
|
|
||||||
* Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0
|
* Fri Jun 7 2019 orignal <i2porignal@yandex.ru> - 2.26.0
|
||||||
- update to 2.26.0
|
- update to 2.26.0
|
||||||
|
|
||||||
@@ -124,7 +147,7 @@ getent passwd i2pd >/dev/null || \
|
|||||||
- update to 2.22.0
|
- update to 2.22.0
|
||||||
- add support of tunnelsdir option
|
- add support of tunnelsdir option
|
||||||
|
|
||||||
* Thu Oct 22 2018 orignal <i2porignal@yandex.ru> - 2.21.1
|
* Mon Oct 22 2018 orignal <i2porignal@yandex.ru> - 2.21.1
|
||||||
- update to 2.21.1
|
- update to 2.21.1
|
||||||
|
|
||||||
* Thu Oct 4 2018 orignal <i2porignal@yandex.ru> - 2.21.0
|
* Thu Oct 4 2018 orignal <i2porignal@yandex.ru> - 2.21.0
|
||||||
|
|||||||
@@ -26,9 +26,6 @@
|
|||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include "Event.h"
|
|
||||||
#include "Websocket.h"
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
@@ -43,9 +40,6 @@ namespace i2p
|
|||||||
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
||||||
std::unique_ptr<i2p::transport::UPnP> UPnP;
|
std::unique_ptr<i2p::transport::UPnP> UPnP;
|
||||||
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
|
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), d(*new Daemon_Singleton_Private()) {}
|
Daemon_Singleton::Daemon_Singleton() : isDaemon(false), running(true), d(*new Daemon_Singleton_Private()) {}
|
||||||
@@ -62,12 +56,12 @@ namespace i2p
|
|||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::init(int argc, char* argv[]) {
|
bool Daemon_Singleton::init(int argc, char* argv[]) {
|
||||||
return init(argc, argv, nullptr);
|
return init(argc, argv, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
|
bool Daemon_Singleton::init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream)
|
||||||
{
|
{
|
||||||
i2p::config::Init();
|
i2p::config::Init();
|
||||||
i2p::config::ParseCmdline(argc, argv);
|
i2p::config::ParseCmdline(argc, argv);
|
||||||
|
|
||||||
@@ -110,10 +104,10 @@ namespace i2p
|
|||||||
logs = "file";
|
logs = "file";
|
||||||
|
|
||||||
i2p::log::Logger().SetLogLevel(loglevel);
|
i2p::log::Logger().SetLogLevel(loglevel);
|
||||||
if (logstream) {
|
if (logstream) {
|
||||||
LogPrint(eLogInfo, "Log: will send messages to std::ostream");
|
LogPrint(eLogInfo, "Log: will send messages to std::ostream");
|
||||||
i2p::log::Logger().SendTo (logstream);
|
i2p::log::Logger().SendTo (logstream);
|
||||||
} else if (logs == "file") {
|
} else if (logs == "file") {
|
||||||
if (logfile == "")
|
if (logfile == "")
|
||||||
logfile = i2p::fs::DataDirPath("i2pd.log");
|
logfile = i2p::fs::DataDirPath("i2pd.log");
|
||||||
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
|
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
|
||||||
@@ -127,7 +121,7 @@ namespace i2p
|
|||||||
// use stdout -- default
|
// use stdout -- default
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
|
LogPrint(eLogInfo, "i2pd v", VERSION, " starting");
|
||||||
LogPrint(eLogDebug, "FS: main config file: ", config);
|
LogPrint(eLogDebug, "FS: main config file: ", config);
|
||||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||||
|
|
||||||
@@ -151,8 +145,8 @@ namespace i2p
|
|||||||
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
|
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
|
||||||
i2p::context.UpdatePort (port);
|
i2p::context.UpdatePort (port);
|
||||||
}
|
}
|
||||||
i2p::context.SetSupportsV6 (ipv6);
|
i2p::context.SetSupportsV6 (ipv6);
|
||||||
i2p::context.SetSupportsV4 (ipv4);
|
i2p::context.SetSupportsV4 (ipv4);
|
||||||
|
|
||||||
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
||||||
i2p::context.PublishNTCPAddress (ntcp, !ipv6);
|
i2p::context.PublishNTCPAddress (ntcp, !ipv6);
|
||||||
@@ -233,15 +227,15 @@ namespace i2p
|
|||||||
if (family.length () > 0)
|
if (family.length () > 0)
|
||||||
LogPrint(eLogInfo, "Daemon: family set to ", family);
|
LogPrint(eLogInfo, "Daemon: family set to ", family);
|
||||||
|
|
||||||
bool trust; i2p::config::GetOption("trust.enabled", trust);
|
bool trust; i2p::config::GetOption("trust.enabled", trust);
|
||||||
if (trust)
|
if (trust)
|
||||||
{
|
{
|
||||||
LogPrint(eLogInfo, "Daemon: explicit trust enabled");
|
LogPrint(eLogInfo, "Daemon: explicit trust enabled");
|
||||||
std::string fam; i2p::config::GetOption("trust.family", fam);
|
std::string fam; i2p::config::GetOption("trust.family", fam);
|
||||||
std::string routers; i2p::config::GetOption("trust.routers", routers);
|
std::string routers; i2p::config::GetOption("trust.routers", routers);
|
||||||
bool restricted = false;
|
bool restricted = false;
|
||||||
if (fam.length() > 0)
|
if (fam.length() > 0)
|
||||||
{
|
{
|
||||||
std::set<std::string> fams;
|
std::set<std::string> fams;
|
||||||
size_t pos = 0, comma;
|
size_t pos = 0, comma;
|
||||||
do
|
do
|
||||||
@@ -253,7 +247,7 @@ namespace i2p
|
|||||||
while (comma != std::string::npos);
|
while (comma != std::string::npos);
|
||||||
i2p::transport::transports.RestrictRoutesToFamilies(fams);
|
i2p::transport::transports.RestrictRoutesToFamilies(fams);
|
||||||
restricted = fams.size() > 0;
|
restricted = fams.size() > 0;
|
||||||
}
|
}
|
||||||
if (routers.length() > 0) {
|
if (routers.length() > 0) {
|
||||||
std::set<i2p::data::IdentHash> idents;
|
std::set<i2p::data::IdentHash> idents;
|
||||||
size_t pos = 0, comma;
|
size_t pos = 0, comma;
|
||||||
@@ -272,14 +266,15 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
if(!restricted)
|
if(!restricted)
|
||||||
LogPrint(eLogError, "Daemon: no trusted routers of families specififed");
|
LogPrint(eLogError, "Daemon: no trusted routers of families specififed");
|
||||||
}
|
}
|
||||||
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
|
|
||||||
if (hidden)
|
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
|
||||||
{
|
if (hidden)
|
||||||
LogPrint(eLogInfo, "Daemon: using hidden mode");
|
{
|
||||||
i2p::data::netdb.SetHidden(true);
|
LogPrint(eLogInfo, "Daemon: using hidden mode");
|
||||||
}
|
i2p::data::netdb.SetHidden(true);
|
||||||
return true;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::start()
|
bool Daemon_Singleton::start()
|
||||||
@@ -322,7 +317,7 @@ namespace i2p
|
|||||||
bool http; i2p::config::GetOption("http.enabled", http);
|
bool http; i2p::config::GetOption("http.enabled", http);
|
||||||
if (http) {
|
if (http) {
|
||||||
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
|
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
|
||||||
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
||||||
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
|
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
|
||||||
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
|
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
|
||||||
d.httpServer->Start();
|
d.httpServer->Start();
|
||||||
@@ -344,26 +339,11 @@ namespace i2p
|
|||||||
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
|
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
|
||||||
d.m_I2PControlService->Start ();
|
d.m_I2PControlService->Start ();
|
||||||
}
|
}
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
|
|
||||||
bool websocket; i2p::config::GetOption("websockets.enabled", websocket);
|
|
||||||
if(websocket) {
|
|
||||||
std::string websocketAddr; i2p::config::GetOption("websockets.address", websocketAddr);
|
|
||||||
uint16_t websocketPort; i2p::config::GetOption("websockets.port", websocketPort);
|
|
||||||
LogPrint(eLogInfo, "Daemon: starting Websocket server at ", websocketAddr, ":", websocketPort);
|
|
||||||
d.m_WebsocketServer = std::unique_ptr<i2p::event::WebsocketServer>(new i2p::event::WebsocketServer (websocketAddr, websocketPort));
|
|
||||||
d.m_WebsocketServer->Start();
|
|
||||||
i2p::event::core.SetListener(d.m_WebsocketServer->ToListener());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Daemon_Singleton::stop()
|
bool Daemon_Singleton::stop()
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
i2p::event::core.SetListener(nullptr);
|
|
||||||
#endif
|
|
||||||
LogPrint(eLogInfo, "Daemon: shutting down");
|
LogPrint(eLogInfo, "Daemon: shutting down");
|
||||||
LogPrint(eLogInfo, "Daemon: stopping Client");
|
LogPrint(eLogInfo, "Daemon: stopping Client");
|
||||||
i2p::client::context.Stop();
|
i2p::client::context.Stop();
|
||||||
@@ -397,13 +377,6 @@ namespace i2p
|
|||||||
d.m_I2PControlService->Stop ();
|
d.m_I2PControlService->Stop ();
|
||||||
d.m_I2PControlService = nullptr;
|
d.m_I2PControlService = nullptr;
|
||||||
}
|
}
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
if (d.m_WebsocketServer) {
|
|
||||||
LogPrint(eLogInfo, "Daemon: stopping Websocket server");
|
|
||||||
d.m_WebsocketServer->Stop();
|
|
||||||
d.m_WebsocketServer = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
i2p::crypto::TerminateCrypto ();
|
i2p::crypto::TerminateCrypto ();
|
||||||
i2p::log::Logger().Stop();
|
i2p::log::Logger().Stop();
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ 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; width: 1.5em;}\r\n"
|
||||||
" .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n"
|
" .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n"
|
||||||
" .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n"
|
" .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n"
|
||||||
" .left { float: left; position: absolute; }\r\n"
|
" .left { float: left; position: absolute; }\r\n"
|
||||||
@@ -63,9 +64,11 @@ namespace http {
|
|||||||
" .tunnel.failed { color: #D33F3F; }\r\n"
|
" .tunnel.failed { color: #D33F3F; }\r\n"
|
||||||
" .tunnel.building { color: #434343; }\r\n"
|
" .tunnel.building { color: #434343; }\r\n"
|
||||||
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
|
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
|
||||||
" table { width: 100%; border-collapse: collapse; text-align: center; }\r\n"
|
" table { display: table; border-collapse: collapse; text-align: center; }\r\n"
|
||||||
" .slide p, .slide [type='checkbox']{ display:none; }\r\n"
|
" table.extaddr { text-align: left; }\r\n table.services { width: 100%; }"
|
||||||
" .slide [type='checkbox']:checked ~ p { display:block; margin-top: 0; padding: 0; }\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 [type='checkbox']:checked ~ div.content { 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"
|
||||||
"</style>\r\n";
|
"</style>\r\n";
|
||||||
@@ -89,10 +92,12 @@ namespace http {
|
|||||||
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
|
const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test";
|
||||||
const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
|
const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
|
||||||
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
|
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
|
||||||
|
const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
|
||||||
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
||||||
const char HTTP_PARAM_ADDRESS[] = "address";
|
const char HTTP_PARAM_ADDRESS[] = "address";
|
||||||
|
|
||||||
static std::string ConvertTime (uint64_t time);
|
static std::string ConvertTime (uint64_t time);
|
||||||
|
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
|
||||||
|
|
||||||
static void ShowUptime (std::stringstream& s, int seconds)
|
static void ShowUptime (std::stringstream& s, int seconds)
|
||||||
{
|
{
|
||||||
@@ -177,8 +182,10 @@ namespace http {
|
|||||||
"<div class=left>\r\n"
|
"<div class=left>\r\n"
|
||||||
" <a href=\"" << webroot << "\">Main page</a><br>\r\n<br>\r\n"
|
" <a href=\"" << webroot << "\">Main page</a><br>\r\n<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><br>\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><br>\r\n";
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n"
|
if (i2p::context.IsFloodfill ())
|
||||||
|
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n";
|
||||||
|
s <<
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\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><br>\r\n"
|
||||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n"
|
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n"
|
||||||
@@ -203,10 +210,7 @@ namespace http {
|
|||||||
s << "<b>ERROR:</b> " << string << "<br>\r\n";
|
s << "<b>ERROR:</b> " << string << "<br>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowStatus (
|
void ShowStatus (std::stringstream& s, bool includeHiddenContent, i2p::http::OutputFormatEnum outputFormat)
|
||||||
std::stringstream& s,
|
|
||||||
bool includeHiddenContent,
|
|
||||||
i2p::http::OutputFormatEnum outputFormat)
|
|
||||||
{
|
{
|
||||||
s << "<b>Uptime:</b> ";
|
s << "<b>Uptime:</b> ";
|
||||||
ShowUptime(s, i2p::context.GetUptime ());
|
ShowUptime(s, i2p::context.GetUptime ());
|
||||||
@@ -233,11 +237,8 @@ namespace http {
|
|||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "<br>\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 (auto remains = Daemon.gracefulShutdownInterval) {
|
if (auto remains = Daemon.gracefulShutdownInterval)
|
||||||
s << "<b>Stopping in:</b> ";
|
s << "<b>Stopping in:</b> " << remains << " seconds<br>\r\n";
|
||||||
s << remains << " seconds";
|
|
||||||
s << "<br>\r\n";
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
auto family = i2p::context.GetFamily ();
|
auto family = i2p::context.GetFamily ();
|
||||||
if (family.length () > 0)
|
if (family.length () > 0)
|
||||||
@@ -253,51 +254,56 @@ namespace http {
|
|||||||
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
ShowTraffic (s, i2p::transport::transports.GetTotalTransitTransmittedBytes ());
|
||||||
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
|
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " KiB/s)<br>\r\n";
|
||||||
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
s << "<b>Data path:</b> " << i2p::fs::GetDataDir() << "<br>\r\n";
|
||||||
s << "<div class='slide'>";
|
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<p 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='content'>\r\n";
|
||||||
}
|
}
|
||||||
if(includeHiddenContent) {
|
if(includeHiddenContent) {
|
||||||
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
s << "<b>Router Ident:</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||||
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
|
||||||
|
s << "<b>Router Family:</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||||
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
|
s << "<b>Router Caps:</b> " << i2p::context.GetRouterInfo().GetProperty("caps") << "<br>\r\n";
|
||||||
s << "<b>Our external address:</b>" << "<br>\r\n" ;
|
s << "<b>Our external address:</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
|
||||||
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
||||||
{
|
{
|
||||||
|
s << "<tr>\r\n";
|
||||||
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ())
|
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ())
|
||||||
{
|
{
|
||||||
s << "NTCP2";
|
s << "<td>NTCP2";
|
||||||
if (address->host.is_v6 ()) s << "v6";
|
if (address->host.is_v6 ()) s << "v6";
|
||||||
s << " supported <br>\r\n";
|
s << "</td><td>supported</td>\r\n</tr>\r\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (address->transportStyle)
|
switch (address->transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
case i2p::data::RouterInfo::eTransportNTCP:
|
||||||
{
|
{
|
||||||
s << "NTCP";
|
s << "<td>NTCP";
|
||||||
if (address->IsPublishedNTCP2 ()) s << "2";
|
if (address->IsPublishedNTCP2 ()) s << "2";
|
||||||
if (address->host.is_v6 ()) s << "v6";
|
if (address->host.is_v6 ()) s << "v6";
|
||||||
s << " ";
|
s << "</td>\r\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case i2p::data::RouterInfo::eTransportSSU:
|
case i2p::data::RouterInfo::eTransportSSU:
|
||||||
|
{
|
||||||
|
s << "<td>SSU";
|
||||||
if (address->host.is_v6 ())
|
if (address->host.is_v6 ())
|
||||||
s << "SSUv6 ";
|
s << "v6";
|
||||||
else
|
s << "</td>\r\n";
|
||||||
s << "SSU ";
|
break;
|
||||||
break;
|
}
|
||||||
default:
|
default:
|
||||||
s << "Unknown ";
|
s << "<td>Unknown</td>\r\n";
|
||||||
}
|
}
|
||||||
s << address->host.to_string() << ":" << address->port << "<br>\r\n";
|
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n</tr>\r\n";
|
||||||
}
|
}
|
||||||
}
|
s << "</tbody></table>\r\n";
|
||||||
s << "</p>\r\n</div>\r\n";
|
}
|
||||||
if(outputFormat==OutputFormatEnum::forQtUi) {
|
s << "</div>\r\n</div>\r\n";
|
||||||
s << "<br>";
|
if(outputFormat==OutputFormatEnum::forQtUi) {
|
||||||
}
|
s << "<br>";
|
||||||
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
}
|
||||||
|
s << "<b>Routers:</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||||
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
s << "<b>Floodfills:</b> " << i2p::data::netdb.GetNumFloodfills () << " ";
|
||||||
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
s << "<b>LeaseSets:</b> " << i2p::data::netdb.GetNumLeaseSets () << "<br>\r\n";
|
||||||
|
|
||||||
@@ -308,17 +314,17 @@ namespace http {
|
|||||||
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
s << "<b>Client Tunnels:</b> " << std::to_string(clientTunnelCount) << " ";
|
||||||
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
|
s << "<b>Transit Tunnels:</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
|
||||||
|
|
||||||
if(outputFormat==OutputFormatEnum::forWebConsole) {
|
if(outputFormat==OutputFormatEnum::forWebConsole) {
|
||||||
s << "<table><caption>Services</caption><tr><th>Service</th><th>State</th></tr>\r\n";
|
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||||
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<table class=\"services\"><caption>Services</caption><tbody>\r\n";
|
||||||
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "HTTP Proxy" << "</td><td><div class='" << ((i2p::client::context.GetHttpProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "<tr><td>" << "BOB" << "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "SOCKS Proxy" << "</td><td><div class='" << ((i2p::client::context.GetSocksProxy ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "<tr><td>" << "SAM" << "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "BOB" << "</td><td><div class='" << ((i2p::client::context.GetBOBCommandChannel ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "<tr><td>" << "I2CP" << "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "SAM" << "</td><td><div class='" << ((i2p::client::context.GetSAMBridge ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
s << "<tr><td>" << "I2CP" << "</td><td><div class='" << ((i2p::client::context.GetI2CPServer ()) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
s << "<tr><td>" << "I2PControl" << "</td><td><div class='" << ((i2pcontrol) ? "enabled" : "disabled") << "'></div></td></tr>\r\n";
|
||||||
s << "</table>\r\n";
|
s << "</tbody></table>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowLocalDestinations (std::stringstream& s)
|
void ShowLocalDestinations (std::stringstream& s)
|
||||||
@@ -352,24 +358,25 @@ namespace http {
|
|||||||
|
|
||||||
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=\"readonly\" cols=\"64\" rows=\"11\" wrap=\"on\">";
|
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"11\" wrap=\"on\">";
|
||||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||||
if (dest->IsEncryptedLeaseSet ())
|
if (dest->IsEncryptedLeaseSet ())
|
||||||
{
|
{
|
||||||
i2p::data::BlindedPublicKey blinded (dest->GetIdentity ());
|
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<p 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='content'>\r\n";
|
||||||
s << blinded.ToB33 () << ".b32.i2p<br>\r\n";
|
s << blinded.ToB33 () << ".b32.i2p<br>\r\n";
|
||||||
s << "</p>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dest->GetNumRemoteLeaseSets())
|
if(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<p class='content'>\r\n";
|
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>";
|
||||||
for(auto& it: dest->GetLeaseSets ())
|
for(auto& it: dest->GetLeaseSets ())
|
||||||
s << it.first.ToBase32 () << " " << (int)it.second->GetStoreType () << "<br>\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 << "</p>\r\n</div>\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";
|
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)
|
||||||
{
|
{
|
||||||
@@ -394,28 +401,31 @@ namespace http {
|
|||||||
if (!dest->GetSessions ().empty ()) {
|
if (!dest->GetSessions ().empty ()) {
|
||||||
std::stringstream tmp_s; uint32_t out_tags = 0;
|
std::stringstream tmp_s; uint32_t out_tags = 0;
|
||||||
for (const auto& it: dest->GetSessions ()) {
|
for (const auto& it: dest->GetSessions ()) {
|
||||||
tmp_s << i2p::client::context.GetAddressBook ().ToAddress(it.first) << " " << it.second->GetNumOutgoingTags () << "<br>\r\n";
|
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n";
|
||||||
out_tags = out_tags + it.second->GetNumOutgoingTags ();
|
out_tags = 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<p class='content'>\r\n" << tmp_s.str () << "</p>\r\n</div>\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";
|
||||||
} 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";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32)
|
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token)
|
||||||
{
|
{
|
||||||
s << "<b>Local Destination:</b><br>\r\n<br>\r\n";
|
s << "<b>Local Destination:</b><br>\r\n<br>\r\n";
|
||||||
i2p::data::IdentHash ident;
|
i2p::data::IdentHash ident;
|
||||||
ident.FromBase32 (b32);
|
ident.FromBase32 (b32);
|
||||||
auto dest = i2p::client::context.FindLocalDestination (ident);
|
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||||
|
|
||||||
if (dest)
|
if (dest)
|
||||||
{
|
{
|
||||||
ShowLeaseSetDestination (s, dest);
|
ShowLeaseSetDestination (s, dest);
|
||||||
// show streams
|
// show streams
|
||||||
s << "<table><caption>Streams</caption>\r\n<tr>";
|
s << "<table>\r\n<caption>Streams</caption>\r\n<thead>\r\n<tr>";
|
||||||
s << "<th>StreamID</th>";
|
s << "<th style=\"width:25px;\">StreamID</th>";
|
||||||
s << "<th>Destination</th>";
|
s << "<th style=\"width:5px;\" \\>"; // Stream closing button column
|
||||||
|
s << "<th class=\"streamdest\">Destination</th>";
|
||||||
s << "<th>Sent</th>";
|
s << "<th>Sent</th>";
|
||||||
s << "<th>Received</th>";
|
s << "<th>Received</th>";
|
||||||
s << "<th>Out</th>";
|
s << "<th>Out</th>";
|
||||||
@@ -424,13 +434,20 @@ 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";
|
s << "</tr>\r\n</thead>\r\n<tbody>\r\n";
|
||||||
|
|
||||||
for (const auto& it: dest->GetAllStreams ())
|
for (const auto& it: dest->GetAllStreams ())
|
||||||
{
|
{
|
||||||
|
auto streamDest = i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ());
|
||||||
s << "<tr>";
|
s << "<tr>";
|
||||||
s << "<td>" << it->GetSendStreamID () << "</td>";
|
s << "<td>" << it->GetRecvStreamID () << "</td>";
|
||||||
s << "<td>" << i2p::client::context.GetAddressBook ().ToAddress(it->GetRemoteIdentity ()) << "</td>";
|
if (it->GetRecvStreamID ()) {
|
||||||
|
s << "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_KILLSTREAM << "&b32=" << b32 << "&streamID="
|
||||||
|
<< it->GetRecvStreamID () << "&token=" << token << "\" title=\"Close stream\"> ✘ </a></td>";
|
||||||
|
} else {
|
||||||
|
s << "<td \\>";
|
||||||
|
}
|
||||||
|
s << "<td class=\"streamdest\" title=\"" << streamDest << "\">" << streamDest << "</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>";
|
||||||
@@ -441,7 +458,7 @@ namespace http {
|
|||||||
s << "<td>" << (int)it->GetStatus () << "</td>";
|
s << "<td>" << (int)it->GetStatus () << "</td>";
|
||||||
s << "</tr>\r\n";
|
s << "</tr>\r\n";
|
||||||
}
|
}
|
||||||
s << "</table>";
|
s << "</tbody>\r\n</table>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,46 +480,57 @@ namespace http {
|
|||||||
|
|
||||||
void ShowLeasesSets(std::stringstream& s)
|
void ShowLeasesSets(std::stringstream& s)
|
||||||
{
|
{
|
||||||
s << "<b>LeaseSets:</b><br>\r\n<br>\r\n";
|
if (i2p::data::netdb.GetNumLeaseSets ())
|
||||||
int counter = 1;
|
{
|
||||||
// for each lease set
|
s << "<b>LeaseSets:</b><br>\r\n<br>\r\n";
|
||||||
i2p::data::netdb.VisitLeaseSets(
|
int counter = 1;
|
||||||
[&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
// for each lease set
|
||||||
{
|
i2p::data::netdb.VisitLeaseSets(
|
||||||
// create copy of lease set so we extract leases
|
[&s, &counter](const i2p::data::IdentHash dest, std::shared_ptr<i2p::data::LeaseSet> leaseSet)
|
||||||
auto storeType = leaseSet->GetStoreType ();
|
{
|
||||||
std::unique_ptr<i2p::data::LeaseSet> ls;
|
// create copy of lease set so we extract leases
|
||||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
auto storeType = leaseSet->GetStoreType ();
|
||||||
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
std::unique_ptr<i2p::data::LeaseSet> ls;
|
||||||
else
|
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||||
if (!ls) return;
|
else
|
||||||
s << "<div class='leaseset";
|
ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
|
||||||
if (ls->IsExpired())
|
if (!ls) return;
|
||||||
s << " expired"; // additional css class for expired
|
s << "<div class='leaseset";
|
||||||
s << "'>\r\n";
|
if (ls->IsExpired())
|
||||||
if (!ls->IsValid())
|
s << " expired"; // additional css class for expired
|
||||||
s << "<div class='invalid'>!! Invalid !! </div>\r\n";
|
s << "'>\r\n";
|
||||||
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n";
|
if (!ls->IsValid())
|
||||||
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<p class='content'>\r\n";
|
s << "<div class='invalid'>!! Invalid !! </div>\r\n";
|
||||||
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n";
|
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n";
|
||||||
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n";
|
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<div class='content'>\r\n";
|
||||||
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
|
s << "<b>Store type:</b> " << (int)storeType << "<br>\r\n";
|
||||||
{
|
s << "<b>Expires:</b> " << ConvertTime(ls->GetExpirationTime()) << "<br>\r\n";
|
||||||
// leases information is available
|
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET || storeType == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
|
||||||
auto leases = ls->GetNonExpiredLeases();
|
|
||||||
s << "<b>Non Expired Leases: " << leases.size() << "</b><br>\r\n";
|
|
||||||
for ( auto & l : leases )
|
|
||||||
{
|
{
|
||||||
s << "<b>Gateway:</b> " << l->tunnelGateway.ToBase64() << "<br>\r\n";
|
// leases information is available
|
||||||
s << "<b>TunnelID:</b> " << l->tunnelID << "<br>\r\n";
|
auto leases = ls->GetNonExpiredLeases();
|
||||||
s << "<b>EndDate:</b> " << ConvertTime(l->endDate) << "<br>\r\n";
|
s << "<b>Non Expired Leases: " << leases.size() << "</b><br>\r\n";
|
||||||
|
for ( auto & l : leases )
|
||||||
|
{
|
||||||
|
s << "<b>Gateway:</b> " << l->tunnelGateway.ToBase64() << "<br>\r\n";
|
||||||
|
s << "<b>TunnelID:</b> " << l->tunnelID << "<br>\r\n";
|
||||||
|
s << "<b>EndDate:</b> " << ConvertTime(l->endDate) << "<br>\r\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
s << "</div>\r\n</div>\r\n</div>\r\n";
|
||||||
s << "</p>\r\n</div>\r\n</div>\r\n";
|
}
|
||||||
}
|
);
|
||||||
);
|
// end for each lease set
|
||||||
// end for each lease set
|
}
|
||||||
|
else if (!i2p::context.IsFloodfill ())
|
||||||
|
{
|
||||||
|
s << "<b>LeaseSets:</b> not floodfill.<br>\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s << "<b>LeaseSets:</b> 0<br>\r\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowTunnels (std::stringstream& s)
|
void ShowTunnels (std::stringstream& s)
|
||||||
@@ -564,16 +592,23 @@ namespace http {
|
|||||||
|
|
||||||
void ShowTransitTunnels (std::stringstream& s)
|
void ShowTransitTunnels (std::stringstream& s)
|
||||||
{
|
{
|
||||||
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
|
if(i2p::tunnel::tunnels.CountTransitTunnels())
|
||||||
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
|
||||||
{
|
{
|
||||||
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
s << "<b>Transit tunnels:</b><br>\r\n<br>\r\n";
|
||||||
s << it->GetTunnelID () << " ⇒ ";
|
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||||
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
{
|
||||||
s << " ⇒ " << it->GetTunnelID ();
|
if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelGateway>(it))
|
||||||
else
|
s << it->GetTunnelID () << " ⇒ ";
|
||||||
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
else if (std::dynamic_pointer_cast<i2p::tunnel::TransitTunnelEndpoint>(it))
|
||||||
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
|
s << " ⇒ " << it->GetTunnelID ();
|
||||||
|
else
|
||||||
|
s << " ⇒ " << it->GetTunnelID () << " ⇒ ";
|
||||||
|
s << " " << it->GetNumTransmittedBytes () << "<br>\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s << "<b>Transit tunnels:</b> no transit tunnels currently built.<br>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,13 +642,15 @@ namespace http {
|
|||||||
}
|
}
|
||||||
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 << "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<p class='content'>";
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "'><b>" << name
|
||||||
s << tmp_s.str () << "</p>\r\n</div>\r\n";
|
<< "</b> ( " << cnt << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "'/>\r\n<div class='content'>"
|
||||||
|
<< 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 << "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<p class='content'>";
|
s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name
|
||||||
s << tmp_s6.str () << "</p>\r\n</div>\r\n";
|
<< "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<div class='content'>"
|
||||||
|
<< tmp_s6.str () << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,7 +677,7 @@ 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<p 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='content'>";
|
||||||
for (const auto& it: sessions)
|
for (const auto& it: sessions)
|
||||||
{
|
{
|
||||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||||
@@ -652,12 +689,12 @@ namespace http {
|
|||||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||||
s << "<br>\r\n" << std::endl;
|
s << "<br>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
s << "</p>\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<p 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='content'>";
|
||||||
for (const auto& it: sessions6)
|
for (const auto& it: sessions6)
|
||||||
{
|
{
|
||||||
auto endpoint = it.second->GetRemoteEndpoint ();
|
auto endpoint = it.second->GetRemoteEndpoint ();
|
||||||
@@ -669,7 +706,7 @@ namespace http {
|
|||||||
s << " [itag:" << it.second->GetRelayTag () << "]";
|
s << " [itag:" << it.second->GetRelayTag () << "]";
|
||||||
s << "<br>\r\n" << std::endl;
|
s << "<br>\r\n" << std::endl;
|
||||||
}
|
}
|
||||||
s << "</p>\r\n</div>\r\n";
|
s << "</div>\r\n</div>\r\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -678,17 +715,24 @@ namespace http {
|
|||||||
{
|
{
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
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;
|
||||||
}
|
}
|
||||||
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
|
||||||
for (auto& it: sam->GetSessions ())
|
if(sam->GetSessions ().size ())
|
||||||
{
|
{
|
||||||
auto& name = it.second->localDestination->GetNickname ();
|
s << "<b>SAM Sessions:</b><br>\r\n<br>\r\n";
|
||||||
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
for (auto& it: sam->GetSessions ())
|
||||||
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
|
{
|
||||||
|
auto& name = it.second->localDestination->GetNickname ();
|
||||||
|
s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
|
||||||
|
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
s << "<b>SAM Sessions:</b> no sessions currently running.<br>\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ShowSAMSession (std::stringstream& s, const std::string& id)
|
static void ShowSAMSession (std::stringstream& s, const std::string& id)
|
||||||
@@ -858,7 +902,8 @@ namespace http {
|
|||||||
m_Socket->close ();
|
m_Socket->close ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HTTPConnection::CheckAuth (const HTTPReq & req) {
|
bool HTTPConnection::CheckAuth (const HTTPReq & req)
|
||||||
|
{
|
||||||
/* method #1: http://user:pass@127.0.0.1:7070/ */
|
/* method #1: http://user:pass@127.0.0.1:7070/ */
|
||||||
if (req.uri.find('@') != std::string::npos) {
|
if (req.uri.find('@') != std::string::npos) {
|
||||||
URL url;
|
URL url;
|
||||||
@@ -920,7 +965,7 @@ namespace http {
|
|||||||
} else if (req.uri.find("cmd=") != std::string::npos) {
|
} else if (req.uri.find("cmd=") != std::string::npos) {
|
||||||
HandleCommand (req, res, s);
|
HandleCommand (req, res, s);
|
||||||
} else {
|
} else {
|
||||||
ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
|
ShowStatus (s, true, i2p::http::OutputFormatEnum::forWebConsole);
|
||||||
res.add_header("Refresh", "10");
|
res.add_header("Refresh", "10");
|
||||||
}
|
}
|
||||||
ShowPageTail (s);
|
ShowPageTail (s);
|
||||||
@@ -930,7 +975,23 @@ namespace http {
|
|||||||
SendReply (res, content);
|
SendReply (res, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<uint32_t, uint32_t> HTTPConnection::m_Tokens;
|
uint32_t HTTPConnection::CreateToken ()
|
||||||
|
{
|
||||||
|
uint32_t token;
|
||||||
|
RAND_bytes ((uint8_t *)&token, 4);
|
||||||
|
token &= 0x7FFFFFFF; // clear first bit
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
|
||||||
|
{
|
||||||
|
if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
|
||||||
|
it = m_Tokens.erase (it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
m_Tokens[token] = ts;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
void HTTPConnection::HandlePage (const HTTPReq& req, HTTPRes& res, std::stringstream& s)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
@@ -947,18 +1008,7 @@ namespace http {
|
|||||||
ShowTunnels (s);
|
ShowTunnels (s);
|
||||||
else if (page == HTTP_PAGE_COMMANDS)
|
else if (page == HTTP_PAGE_COMMANDS)
|
||||||
{
|
{
|
||||||
uint32_t token;
|
uint32_t token = CreateToken ();
|
||||||
RAND_bytes ((uint8_t *)&token, 4);
|
|
||||||
token &= 0x7FFFFFFF; // clear first bit
|
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
for (auto it = m_Tokens.begin (); it != m_Tokens.end (); )
|
|
||||||
{
|
|
||||||
if (ts > it->second + TOKEN_EXPIRATION_TIMEOUT)
|
|
||||||
it = m_Tokens.erase (it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
m_Tokens[token] = ts;
|
|
||||||
ShowCommands (s, token);
|
ShowCommands (s, token);
|
||||||
}
|
}
|
||||||
else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
|
else if (page == HTTP_PAGE_TRANSIT_TUNNELS)
|
||||||
@@ -966,7 +1016,10 @@ namespace http {
|
|||||||
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
|
else if (page == HTTP_PAGE_LOCAL_DESTINATIONS)
|
||||||
ShowLocalDestinations (s);
|
ShowLocalDestinations (s);
|
||||||
else if (page == HTTP_PAGE_LOCAL_DESTINATION)
|
else if (page == HTTP_PAGE_LOCAL_DESTINATION)
|
||||||
ShowLocalDestination (s, params["b32"]);
|
{
|
||||||
|
uint32_t token = CreateToken ();
|
||||||
|
ShowLocalDestination (s, params["b32"], token);
|
||||||
|
}
|
||||||
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
|
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
|
||||||
ShowI2CPLocalDestination (s, params["i2cp_id"]);
|
ShowI2CPLocalDestination (s, params["i2cp_id"]);
|
||||||
else if (page == HTTP_PAGE_SAM_SESSIONS)
|
else if (page == HTTP_PAGE_SAM_SESSIONS)
|
||||||
@@ -992,7 +1045,10 @@ namespace http {
|
|||||||
url.parse(req.uri);
|
url.parse(req.uri);
|
||||||
url.parse_query(params);
|
url.parse_query(params);
|
||||||
|
|
||||||
|
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||||
|
std::string redirect = "5; url=" + webroot + "?page=commands";
|
||||||
std::string token = params["token"];
|
std::string token = params["token"];
|
||||||
|
|
||||||
if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
|
if (token.empty () || m_Tokens.find (std::stoi (token)) == m_Tokens.end ())
|
||||||
{
|
{
|
||||||
ShowError(s, "Invalid token");
|
ShowError(s, "Invalid token");
|
||||||
@@ -1008,36 +1064,74 @@ namespace http {
|
|||||||
i2p::context.SetAcceptsTunnels (true);
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
else if (cmd == HTTP_COMMAND_DISABLE_TRANSIT)
|
else if (cmd == HTTP_COMMAND_DISABLE_TRANSIT)
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_START) {
|
else if (cmd == HTTP_COMMAND_SHUTDOWN_START)
|
||||||
|
{
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||||
Daemon.gracefulShutdownInterval = 10*60;
|
Daemon.gracefulShutdownInterval = 10*60;
|
||||||
#elif defined(WIN32_APP)
|
#elif defined(WIN32_APP)
|
||||||
i2p::win32::GracefulShutdown ();
|
i2p::win32::GracefulShutdown ();
|
||||||
#endif
|
#endif
|
||||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) {
|
}
|
||||||
|
else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL)
|
||||||
|
{
|
||||||
i2p::context.SetAcceptsTunnels (true);
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||||
Daemon.gracefulShutdownInterval = 0;
|
Daemon.gracefulShutdownInterval = 0;
|
||||||
#elif defined(WIN32_APP)
|
#elif defined(WIN32_APP)
|
||||||
i2p::win32::StopGracefulShutdown ();
|
i2p::win32::StopGracefulShutdown ();
|
||||||
#endif
|
#endif
|
||||||
} else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) {
|
}
|
||||||
|
else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW)
|
||||||
|
{
|
||||||
#ifndef WIN32_APP
|
#ifndef WIN32_APP
|
||||||
Daemon.running = false;
|
Daemon.running = false;
|
||||||
#else
|
#else
|
||||||
i2p::win32::StopWin32App ();
|
i2p::win32::StopWin32App ();
|
||||||
#endif
|
#endif
|
||||||
} else if (cmd == HTTP_COMMAND_LOGLEVEL){
|
}
|
||||||
|
else if (cmd == HTTP_COMMAND_LOGLEVEL)
|
||||||
|
{
|
||||||
std::string level = params["level"];
|
std::string level = params["level"];
|
||||||
SetLogLevel (level);
|
SetLogLevel (level);
|
||||||
} else {
|
}
|
||||||
|
else if (cmd == HTTP_COMMAND_KILLSTREAM)
|
||||||
|
{
|
||||||
|
std::string b32 = params["b32"];
|
||||||
|
uint32_t streamID = std::stoul(params["streamID"], nullptr);
|
||||||
|
|
||||||
|
i2p::data::IdentHash ident;
|
||||||
|
ident.FromBase32 (b32);
|
||||||
|
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||||
|
|
||||||
|
if (streamID)
|
||||||
|
{
|
||||||
|
if (dest)
|
||||||
|
{
|
||||||
|
if(dest->DeleteStream (streamID))
|
||||||
|
s << "<b>SUCCESS</b>: Stream closed<br><br>\r\n";
|
||||||
|
else
|
||||||
|
s << "<b>ERROR</b>: Stream not found or already was closed<br><br>\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s << "<b>ERROR</b>: Destination not found<br><br>\r\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s << "<b>ERROR</b>: StreamID can be null<br><br>\r\n";
|
||||||
|
|
||||||
|
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">Return to destination page</a><br>\r\n";
|
||||||
|
s << "<p>You will be redirected back in 5 seconds</b>";
|
||||||
|
redirect = "5; url=" + webroot + "?page=local_destination&b32=" + b32;
|
||||||
|
res.add_header("Refresh", redirect.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
res.code = 400;
|
res.code = 400;
|
||||||
ShowError(s, "Unknown command: " + cmd);
|
ShowError(s, "Unknown command: " + cmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
|
||||||
std::string redirect = "5; url=" + webroot + "?page=commands";
|
|
||||||
s << "<b>SUCCESS</b>: Command accepted<br><br>\r\n";
|
s << "<b>SUCCESS</b>: Command accepted<br><br>\r\n";
|
||||||
s << "<a href=\"" << webroot << "?page=commands\">Back to commands list</a><br>\r\n";
|
s << "<a href=\"" << webroot << "?page=commands\">Back to commands list</a><br>\r\n";
|
||||||
s << "<p>You will be redirected in 5 seconds</b>";
|
s << "<p>You will be redirected in 5 seconds</b>";
|
||||||
@@ -1047,6 +1141,8 @@ namespace http {
|
|||||||
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)
|
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)
|
||||||
{
|
{
|
||||||
reply.add_header("X-Frame-Options", "SAMEORIGIN");
|
reply.add_header("X-Frame-Options", "SAMEORIGIN");
|
||||||
|
reply.add_header("X-Content-Type-Options", "nosniff");
|
||||||
|
reply.add_header("X-XSS-Protection", "1; mode=block");
|
||||||
reply.add_header("Content-Type", "text/html");
|
reply.add_header("Content-Type", "text/html");
|
||||||
reply.body = content;
|
reply.body = content;
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace http
|
|||||||
void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data);
|
void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data);
|
||||||
void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data);
|
void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data);
|
||||||
void SendReply (HTTPRes & res, std::string & content);
|
void SendReply (HTTPRes & res, std::string & content);
|
||||||
|
uint32_t CreateToken ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ namespace http
|
|||||||
void ShowTransports (std::stringstream& s);
|
void ShowTransports (std::stringstream& s);
|
||||||
void ShowSAMSessions (std::stringstream& s);
|
void ShowSAMSessions (std::stringstream& s);
|
||||||
void ShowI2PTunnels (std::stringstream& s);
|
void ShowI2PTunnels (std::stringstream& s);
|
||||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32);
|
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
|
||||||
} // http
|
} // http
|
||||||
} // i2p
|
} // i2p
|
||||||
|
|
||||||
|
|||||||
@@ -394,13 +394,15 @@ namespace client
|
|||||||
|
|
||||||
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
void I2PControlService::RouterInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||||
{
|
{
|
||||||
|
bool first = true;
|
||||||
for (auto it = params.begin (); it != params.end (); it++)
|
for (auto it = params.begin (); it != params.end (); it++)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
|
LogPrint (eLogDebug, "I2PControl: RouterInfo request: ", it->first);
|
||||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||||
if (it1 != m_RouterInfoHandlers.end ())
|
if (it1 != m_RouterInfoHandlers.end ())
|
||||||
{
|
{
|
||||||
if (it != params.begin ()) results << ",";
|
if (!first) results << ",";
|
||||||
|
else first = false;
|
||||||
(this->*(it1->second))(results);
|
(this->*(it1->second))(results);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
147
daemon/UPnP.cpp
147
daemon/UPnP.cpp
@@ -79,43 +79,59 @@ namespace transport
|
|||||||
|
|
||||||
void UPnP::Discover ()
|
void UPnP::Discover ()
|
||||||
{
|
{
|
||||||
#if MINIUPNPC_API_VERSION >= 14
|
bool isError;
|
||||||
int nerror = 0;
|
int err;
|
||||||
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
|
|
||||||
#elif ( MINIUPNPC_API_VERSION >= 8 || defined(UPNPDISCOVER_SUCCESS) )
|
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
||||||
int nerror = 0;
|
err = UPNPDISCOVER_SUCCESS;
|
||||||
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
|
|
||||||
|
#if (MINIUPNPC_API_VERSION >= 14)
|
||||||
|
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err);
|
||||||
#else
|
#else
|
||||||
m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0);
|
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, &err);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
isError = err != UPNPDISCOVER_SUCCESS;
|
||||||
|
#else // MINIUPNPC_API_VERSION >= 8
|
||||||
|
err = 0;
|
||||||
|
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
|
||||||
|
isError = m_Devlist == NULL;
|
||||||
|
#endif // MINIUPNPC_API_VERSION >= 8
|
||||||
{
|
{
|
||||||
// notify satrting thread
|
// notify starting thread
|
||||||
std::unique_lock<std::mutex> l(m_StartedMutex);
|
std::unique_lock<std::mutex> l(m_StartedMutex);
|
||||||
m_Started.notify_all ();
|
m_Started.notify_all ();
|
||||||
}
|
}
|
||||||
|
|
||||||
int r;
|
if (isError)
|
||||||
r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
|
||||||
if (r == 1)
|
|
||||||
{
|
{
|
||||||
r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err);
|
||||||
if(r != UPNPCOMMAND_SUCCESS)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
|
||||||
|
m_upnpUrlsInitialized=err!=0;
|
||||||
|
if (err == UPNP_IGD_VALID_CONNECTED)
|
||||||
|
{
|
||||||
|
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||||
|
if(err != UPNPCOMMAND_SUCCESS)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress() returned ", r);
|
LogPrint (eLogError, "UPnP: unable to get external address: error ", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL);
|
||||||
if (!m_externalIPAddress[0])
|
if (!m_externalIPAddress[0])
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: GetExternalIPAddress() failed.");
|
LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "UPnP: GetValidIGD() failed.");
|
LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +142,20 @@ namespace transport
|
|||||||
PortMapping ();
|
PortMapping ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int UPnP::CheckMapping (const char* port, const char* type)
|
||||||
|
{
|
||||||
|
int err = UPNPCOMMAND_SUCCESS;
|
||||||
|
|
||||||
|
#if (MINIUPNPC_API_VERSION >= 10)
|
||||||
|
err = UPNP_GetSpecificPortMappingEntry(m_upnpUrls.controlURL, m_upnpData.first.servicetype, port, type, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
#elif ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
||||||
|
err = UPNP_GetSpecificPortMappingEntry(m_upnpUrls.controlURL, m_upnpData.first.servicetype, port, type, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
#else
|
||||||
|
err = UPNP_GetSpecificPortMappingEntry(m_upnpUrls.controlURL, m_upnpData.first.servicetype, port, type, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
void UPnP::PortMapping ()
|
void UPnP::PortMapping ()
|
||||||
{
|
{
|
||||||
const auto& a = context.GetRouterInfo().GetAddresses();
|
const auto& a = context.GetRouterInfo().GetAddresses();
|
||||||
@@ -134,13 +164,47 @@ namespace transport
|
|||||||
if (!address->host.is_v6 () && address->port)
|
if (!address->host.is_v6 () && address->port)
|
||||||
TryPortMapping (address);
|
TryPortMapping (address);
|
||||||
}
|
}
|
||||||
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
|
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
|
||||||
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
|
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
|
||||||
{
|
{
|
||||||
if (ecode != boost::asio::error::operation_aborted)
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
PortMapping ();
|
PortMapping ();
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
||||||
|
{
|
||||||
|
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
||||||
|
std::string strDesc; i2p::config::GetOption("upnp.name", strDesc);
|
||||||
|
int err = UPNPCOMMAND_SUCCESS;
|
||||||
|
|
||||||
|
// check for existing mapping
|
||||||
|
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
||||||
|
if (err != UPNPCOMMAND_SUCCESS) // if mapping not found
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err);
|
||||||
|
|
||||||
|
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
|
||||||
|
err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL);
|
||||||
|
#else
|
||||||
|
err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL);
|
||||||
|
#endif
|
||||||
|
if (err != UPNPCOMMAND_SUCCESS)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "UPnP: port forwarding to ", m_NetworkAddr, ":", strPort, " failed: return code ", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "UPnP: port successfully forwarded (", m_externalIPAddress ,":", strPort, " type ", strType, " -> ", m_NetworkAddr ,":", strPort ,")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPnP::CloseMapping ()
|
void UPnP::CloseMapping ()
|
||||||
@@ -153,53 +217,42 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPnP::TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
|
||||||
{
|
|
||||||
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
|
||||||
int r;
|
|
||||||
std::string strDesc; i2p::config::GetOption("upnp.name", strDesc);
|
|
||||||
#ifdef UPNPDISCOVER_SUCCESS
|
|
||||||
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
|
|
||||||
#else
|
|
||||||
r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0);
|
|
||||||
#endif
|
|
||||||
if (r!=UPNPCOMMAND_SUCCESS)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "UPnP: AddPortMapping (", m_NetworkAddr, ":", strPort, ") failed with code ", r);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogPrint (eLogDebug, "UPnP: Port Mapping successful. (", m_NetworkAddr ,":", strPort, " type ", strType, " -> ", m_externalIPAddress ,":", strPort ,")");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
||||||
{
|
{
|
||||||
|
if(!m_upnpUrlsInitialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
||||||
int r = 0;
|
int err = UPNPCOMMAND_SUCCESS;
|
||||||
r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
|
|
||||||
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r);
|
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
||||||
|
if (err == UPNPCOMMAND_SUCCESS)
|
||||||
|
{
|
||||||
|
err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL);
|
||||||
|
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPnP::Close ()
|
void UPnP::Close ()
|
||||||
{
|
{
|
||||||
freeUPNPDevlist (m_Devlist);
|
freeUPNPDevlist (m_Devlist);
|
||||||
m_Devlist = 0;
|
m_Devlist = 0;
|
||||||
FreeUPNPUrls (&m_upnpUrls);
|
if(m_upnpUrlsInitialized){
|
||||||
}
|
FreeUPNPUrls (&m_upnpUrls);
|
||||||
|
m_upnpUrlsInitialized=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
|
||||||
{
|
{
|
||||||
switch (address->transportStyle)
|
switch (address->transportStyle)
|
||||||
{
|
{
|
||||||
case i2p::data::RouterInfo::eTransportNTCP:
|
case i2p::data::RouterInfo::eTransportNTCP:
|
||||||
return "TCP";
|
return "TCP";
|
||||||
break;
|
break;
|
||||||
case i2p::data::RouterInfo::eTransportSSU:
|
case i2p::data::RouterInfo::eTransportSSU:
|
||||||
default:
|
default:
|
||||||
return "UDP";
|
return "UDP";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,20 +19,31 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UPNP_IGD_NONE = 0,
|
||||||
|
UPNP_IGD_VALID_CONNECTED = 1,
|
||||||
|
UPNP_IGD_VALID_NOT_CONNECTED = 2,
|
||||||
|
UPNP_IGD_INVALID = 3
|
||||||
|
};
|
||||||
|
|
||||||
class UPnP
|
class UPnP
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
UPnP ();
|
UPnP ();
|
||||||
~UPnP ();
|
~UPnP ();
|
||||||
void Close ();
|
void Close ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Discover ();
|
void Discover ();
|
||||||
|
int CheckMapping (const char* port, const char* type);
|
||||||
void PortMapping ();
|
void PortMapping ();
|
||||||
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
|
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
|
||||||
void CloseMapping ();
|
void CloseMapping ();
|
||||||
@@ -41,23 +52,22 @@ namespace transport
|
|||||||
void Run ();
|
void Run ();
|
||||||
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
|
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
bool m_IsRunning;
|
||||||
std::unique_ptr<std::thread> m_Thread;
|
std::unique_ptr<std::thread> m_Thread;
|
||||||
std::condition_variable m_Started;
|
std::condition_variable m_Started;
|
||||||
std::mutex m_StartedMutex;
|
std::mutex m_StartedMutex;
|
||||||
boost::asio::io_service m_Service;
|
boost::asio::io_service m_Service;
|
||||||
boost::asio::deadline_timer m_Timer;
|
boost::asio::deadline_timer m_Timer;
|
||||||
struct UPNPUrls m_upnpUrls;
|
bool m_upnpUrlsInitialized=false;
|
||||||
struct IGDdatas m_upnpData;
|
struct UPNPUrls m_upnpUrls;
|
||||||
|
struct IGDdatas m_upnpData;
|
||||||
|
|
||||||
// For miniupnpc
|
// For miniupnpc
|
||||||
char * m_MulticastIf = 0;
|
struct UPNPDev * m_Devlist = 0;
|
||||||
char * m_Minissdpdpath = 0;
|
char m_NetworkAddr[64];
|
||||||
struct UPNPDev * m_Devlist = 0;
|
char m_externalIPAddress[40];
|
||||||
char m_NetworkAddr[64];
|
|
||||||
char m_externalIPAddress[40];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,14 +75,15 @@ namespace transport
|
|||||||
#else // USE_UPNP
|
#else // USE_UPNP
|
||||||
namespace i2p {
|
namespace i2p {
|
||||||
namespace transport {
|
namespace transport {
|
||||||
/* class stub */
|
/* class stub */
|
||||||
class UPnP {
|
class UPnP {
|
||||||
public:
|
public:
|
||||||
UPnP () {};
|
|
||||||
~UPnP () {};
|
UPnP () {};
|
||||||
void Start () { LogPrint(eLogWarning, "UPnP: this module was disabled at compile-time"); }
|
~UPnP () {};
|
||||||
void Stop () {};
|
void Start () { LogPrint(eLogWarning, "UPnP: this module was disabled at compile-time"); }
|
||||||
};
|
void Stop () {};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // USE_UPNP
|
#endif // USE_UPNP
|
||||||
|
|||||||
32
debian/changelog
vendored
32
debian/changelog
vendored
@@ -1,3 +1,33 @@
|
|||||||
|
i2pd (2.31.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.31.0
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Fri, 10 Apr 2020 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.30.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.30.0/0.9.45
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Tue, 25 Feb 2020 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.29.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.29.0/0.9.43
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Mon, 21 Oct 2019 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.28.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.28.0/0.9.42
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Tue, 27 Aug 2019 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.27.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.27.0/0.9.41
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Wed, 3 Jul 2019 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.26.0-1) unstable; urgency=medium
|
i2pd (2.26.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* updated to version 2.26.0
|
* updated to version 2.26.0
|
||||||
@@ -36,7 +66,7 @@ i2pd (2.21.1-1) unstable; urgency=medium
|
|||||||
|
|
||||||
* updated to version 2.21.1
|
* updated to version 2.21.1
|
||||||
|
|
||||||
-- orignal <orignal@i2pmail.org> Thu, 22 Oct 2018 16:00:00 +0000
|
-- orignal <orignal@i2pmail.org> Mon, 22 Oct 2018 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.21.0-1) unstable; urgency=medium
|
i2pd (2.21.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
# SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
# SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \
|
||||||
# Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
|
# Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \
|
||||||
# Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
|
# Destination.cpp Base.cpp I2PEndian.cpp FS.cpp Config.cpp Family.cpp \
|
||||||
# Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Event.cpp Gost.cpp
|
# Config.cpp HTTP.cpp Timestamp.cpp util.cpp api.cpp Gost.cpp
|
||||||
|
|
||||||
LIB_SRC = $(wildcard $(LIB_SRC_DIR)/*.cpp)
|
LIB_SRC = $(wildcard $(LIB_SRC_DIR)/*.cpp)
|
||||||
|
|
||||||
#LIB_CLIENT_SRC = \
|
#LIB_CLIENT_SRC = \
|
||||||
# AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
|
# AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp MatchedDestination.cpp \
|
||||||
# SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp WebSocks.cpp
|
# SAM.cpp SOCKS.cpp HTTPProxy.cpp I2CP.cpp
|
||||||
|
|
||||||
LIB_CLIENT_SRC = $(wildcard $(LIB_CLIENT_SRC_DIR)/*.cpp)
|
LIB_CLIENT_SRC = $(wildcard $(LIB_CLIENT_SRC_DIR)/*.cpp)
|
||||||
|
|
||||||
|
|||||||
@@ -124,8 +124,14 @@ namespace data
|
|||||||
return publicKeyLength;
|
return publicKeyLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
||||||
BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity)
|
const uint8_t B33_TWO_BYTES_SIGTYPE_FLAG = 0x01;
|
||||||
|
const uint8_t B33_PER_SECRET_FLAG = 0x02; // not used for now
|
||||||
|
const uint8_t B33_PER_CLIENT_AUTH_FLAG = 0x04;
|
||||||
|
|
||||||
|
BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth):
|
||||||
|
m_IsClientAuth (clientAuth)
|
||||||
{
|
{
|
||||||
if (!identity) return;
|
if (!identity) return;
|
||||||
auto len = identity->GetSigningPublicKeyLen ();
|
auto len = identity->GetSigningPublicKeyLen ();
|
||||||
@@ -135,16 +141,22 @@ namespace data
|
|||||||
m_BlindedSigType = m_SigType;
|
m_BlindedSigType = m_SigType;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlindedPublicKey::BlindedPublicKey (const std::string& b33)
|
BlindedPublicKey::BlindedPublicKey (const std::string& b33):
|
||||||
|
m_SigType (0) // 0 means invalid, we can't blind DSA, set it later
|
||||||
{
|
{
|
||||||
uint8_t addr[40]; // TODO: define length from b33
|
uint8_t addr[40]; // TODO: define length from b33
|
||||||
size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40);
|
size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40);
|
||||||
|
if (l < 32)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Blinding: malformed b33 ", b33);
|
||||||
|
return;
|
||||||
|
}
|
||||||
uint32_t checksum = crc32 (0, addr + 3, l - 3);
|
uint32_t checksum = crc32 (0, addr + 3, l - 3);
|
||||||
// checksum is Little Endian
|
// checksum is Little Endian
|
||||||
addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16);
|
addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16);
|
||||||
uint8_t flag = addr[0];
|
uint8_t flags = addr[0];
|
||||||
size_t offset = 1;
|
size_t offset = 1;
|
||||||
if (flag & 0x01) // two bytes signatures
|
if (flags & B33_TWO_BYTES_SIGTYPE_FLAG) // two bytes signatures
|
||||||
{
|
{
|
||||||
m_SigType = bufbe16toh (addr + offset); offset += 2;
|
m_SigType = bufbe16toh (addr + offset); offset += 2;
|
||||||
m_BlindedSigType = bufbe16toh (addr + offset); offset += 2;
|
m_BlindedSigType = bufbe16toh (addr + offset); offset += 2;
|
||||||
@@ -154,6 +166,8 @@ namespace data
|
|||||||
m_SigType = addr[offset]; offset++;
|
m_SigType = addr[offset]; offset++;
|
||||||
m_BlindedSigType = addr[offset]; offset++;
|
m_BlindedSigType = addr[offset]; offset++;
|
||||||
}
|
}
|
||||||
|
m_IsClientAuth = flags & B33_PER_CLIENT_AUTH_FLAG;
|
||||||
|
|
||||||
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (m_SigType));
|
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (m_SigType));
|
||||||
if (blindedVerifier)
|
if (blindedVerifier)
|
||||||
{
|
{
|
||||||
@@ -174,7 +188,9 @@ namespace data
|
|||||||
{
|
{
|
||||||
if (m_PublicKey.size () > 32) return ""; // assume 25519
|
if (m_PublicKey.size () > 32) return ""; // assume 25519
|
||||||
uint8_t addr[35]; char str[60]; // TODO: define actual length
|
uint8_t addr[35]; char str[60]; // TODO: define actual length
|
||||||
addr[0] = 0; // flags
|
uint8_t flags = 0;
|
||||||
|
if (m_IsClientAuth) flags |= B33_PER_CLIENT_AUTH_FLAG;
|
||||||
|
addr[0] = flags; // flags
|
||||||
addr[1] = m_SigType; // sig type
|
addr[1] = m_SigType; // sig type
|
||||||
addr[2] = m_BlindedSigType; // blinded sig type
|
addr[2] = m_BlindedSigType; // blinded sig type
|
||||||
memcpy (addr + 3, m_PublicKey.data (), m_PublicKey.size ());
|
memcpy (addr + 3, m_PublicKey.data (), m_PublicKey.size ());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace data
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BlindedPublicKey (std::shared_ptr<const IdentityEx> identity);
|
BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth = false);
|
||||||
BlindedPublicKey (const std::string& b33); // from b33 without .b32.i2p
|
BlindedPublicKey (const std::string& b33); // from b33 without .b32.i2p
|
||||||
std::string ToB33 () const;
|
std::string ToB33 () const;
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ namespace data
|
|||||||
size_t GetPublicKeyLen () const { return m_PublicKey.size (); };
|
size_t GetPublicKeyLen () const { return m_PublicKey.size (); };
|
||||||
SigningKeyType GetSigType () const { return m_SigType; };
|
SigningKeyType GetSigType () const { return m_SigType; };
|
||||||
SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; };
|
SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; };
|
||||||
|
bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid
|
||||||
|
|
||||||
void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes
|
void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes
|
||||||
size_t GetBlindedKey (const char * date, uint8_t * blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length
|
size_t GetBlindedKey (const char * date, uint8_t * blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length
|
||||||
@@ -38,6 +39,7 @@ namespace data
|
|||||||
|
|
||||||
std::vector<uint8_t> m_PublicKey;
|
std::vector<uint8_t> m_PublicKey;
|
||||||
i2p::data::SigningKeyType m_SigType, m_BlindedSigType;
|
i2p::data::SigningKeyType m_SigType, m_BlindedSigType;
|
||||||
|
bool m_IsClientAuth = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace config {
|
|||||||
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
|
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
|
||||||
("ntcp", value<bool>()->default_value(false), "Enable NTCP transport (default: disabled)")
|
("ntcp", value<bool>()->default_value(false), "Enable NTCP transport (default: disabled)")
|
||||||
("ssu", value<bool>()->default_value(true), "Enable SSU transport (default: enabled)")
|
("ssu", value<bool>()->default_value(true), "Enable SSU transport (default: enabled)")
|
||||||
("ntcpproxy", value<std::string>()->default_value(""), "Proxy URL for NTCP transport")
|
("ntcpproxy", value<std::string>()->default_value(""), "Proxy URL for NTCP transport")
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
||||||
("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)")
|
("insomnia", bool_switch()->default_value(false), "Prevent system from sleeping (default: disabled)")
|
||||||
@@ -131,6 +131,7 @@ namespace config {
|
|||||||
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
|
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
|
||||||
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
|
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
|
||||||
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
|
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
|
||||||
|
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description bob("BOB options");
|
options_description bob("BOB options");
|
||||||
@@ -190,10 +191,10 @@ namespace config {
|
|||||||
"https://reseed.i2p-projekt.de/,"
|
"https://reseed.i2p-projekt.de/,"
|
||||||
"https://i2p.mooo.com/netDb/,"
|
"https://i2p.mooo.com/netDb/,"
|
||||||
"https://netdb.i2p2.no/,"
|
"https://netdb.i2p2.no/,"
|
||||||
|
"https://reseed.i2p2.no/,"
|
||||||
|
"https://reseed2.i2p2.no/,"
|
||||||
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
|
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
|
||||||
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
||||||
"https://reseed.i2p.net.in/,"
|
|
||||||
"https://download.xxlspeed.com/,"
|
|
||||||
"https://reseed-fr.i2pd.xyz/,"
|
"https://reseed-fr.i2pd.xyz/,"
|
||||||
"https://reseed.memcpy.io/,"
|
"https://reseed.memcpy.io/,"
|
||||||
"https://reseed.onion.im/,"
|
"https://reseed.onion.im/,"
|
||||||
@@ -217,13 +218,6 @@ namespace config {
|
|||||||
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?")
|
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description websocket("Websocket Options");
|
|
||||||
websocket.add_options()
|
|
||||||
("websockets.enabled", value<bool>()->default_value(false), "Enable websocket server")
|
|
||||||
("websockets.address", value<std::string>()->default_value("127.0.0.1"), "Address to bind websocket server on")
|
|
||||||
("websockets.port", value<uint16_t>()->default_value(7666), "Port to bind websocket server on")
|
|
||||||
;
|
|
||||||
|
|
||||||
options_description exploratory("Exploratory Options");
|
options_description exploratory("Exploratory Options");
|
||||||
exploratory.add_options()
|
exploratory.add_options()
|
||||||
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
|
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
|
||||||
@@ -238,6 +232,7 @@ namespace config {
|
|||||||
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)")
|
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)")
|
||||||
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
|
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
|
||||||
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to bind NTCP2 on")
|
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to bind NTCP2 on")
|
||||||
|
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_description nettime("Time sync options");
|
options_description nettime("Time sync options");
|
||||||
@@ -273,7 +268,6 @@ namespace config {
|
|||||||
.add(reseed)
|
.add(reseed)
|
||||||
.add(addressbook)
|
.add(addressbook)
|
||||||
.add(trust)
|
.add(trust)
|
||||||
.add(websocket)
|
|
||||||
.add(exploratory)
|
.add(exploratory)
|
||||||
.add(ntcp2)
|
.add(ntcp2)
|
||||||
.add(nettime)
|
.add(nettime)
|
||||||
@@ -304,16 +298,16 @@ namespace config {
|
|||||||
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
|
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
|
||||||
std::cout << m_OptionsDesc;
|
std::cout << m_OptionsDesc;
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
else if (m_Options.count("version"))
|
else if (m_Options.count("version"))
|
||||||
{
|
{
|
||||||
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
|
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
|
||||||
std::cout << "Boost version "
|
std::cout << "Boost version "
|
||||||
<< BOOST_VERSION / 100000 << "." // maj. version
|
<< BOOST_VERSION / 100000 << "." // maj. version
|
||||||
<< BOOST_VERSION / 100 % 1000 << "." // min. version
|
<< BOOST_VERSION / 100 % 1000 << "." // min. version
|
||||||
<< BOOST_VERSION % 100 // patch version
|
<< BOOST_VERSION % 100 // patch version
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#if defined(OPENSSL_VERSION_TEXT)
|
#if defined(OPENSSL_VERSION_TEXT)
|
||||||
std::cout << OPENSSL_VERSION_TEXT << std::endl;
|
std::cout << OPENSSL_VERSION_TEXT << std::endl;
|
||||||
#endif
|
#endif
|
||||||
#if defined(LIBRESSL_VERSION_TEXT)
|
#if defined(LIBRESSL_VERSION_TEXT)
|
||||||
|
|||||||
@@ -296,11 +296,20 @@ namespace crypto
|
|||||||
#if OPENSSL_X25519
|
#if OPENSSL_X25519
|
||||||
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);
|
||||||
memcpy (m_PublicKey, pub, 32); // TODO: verify against m_Pkey
|
if (pub)
|
||||||
|
memcpy (m_PublicKey, pub, 32); // TODO: verify against m_Pkey
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t len = 32;
|
||||||
|
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
m_Ctx = BN_CTX_new ();
|
||||||
memcpy (m_PrivateKey, priv, 32);
|
memcpy (m_PrivateKey, priv, 32);
|
||||||
memcpy (m_PublicKey, pub, 32);
|
if (pub)
|
||||||
m_Ctx = BN_CTX_new ();
|
memcpy (m_PublicKey, pub, 32);
|
||||||
|
else
|
||||||
|
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,6 +367,18 @@ namespace crypto
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void X25519Keys::SetPrivateKey (const uint8_t * priv)
|
||||||
|
{
|
||||||
|
#if OPENSSL_X25519
|
||||||
|
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
||||||
|
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||||
|
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||||
|
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
||||||
|
#else
|
||||||
|
memcpy (m_PrivateKey, priv, 32);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// ElGamal
|
// ElGamal
|
||||||
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
@@ -1250,18 +1271,29 @@ namespace crypto
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out)
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
|
||||||
|
uint8_t * out, size_t outLen)
|
||||||
{
|
{
|
||||||
#if OPENSSL_HKDF
|
#if OPENSSL_HKDF
|
||||||
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, NULL);
|
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
|
||||||
EVP_PKEY_derive_init (pctx);
|
EVP_PKEY_derive_init (pctx);
|
||||||
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
||||||
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
|
if (key && keyLen)
|
||||||
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
|
{
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// zerolen
|
||||||
|
EVP_PKEY_CTX_hkdf_mode (pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
|
||||||
|
uint8_t tempKey[32]; unsigned int len;
|
||||||
|
HMAC(EVP_sha256(), salt, 32, nullptr, 0, tempKey, &len);
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_key (pctx, tempKey, len);
|
||||||
|
}
|
||||||
if (info.length () > 0)
|
if (info.length () > 0)
|
||||||
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ());
|
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ());
|
||||||
size_t outlen = 64;
|
EVP_PKEY_derive (pctx, out, &outLen);
|
||||||
EVP_PKEY_derive (pctx, out, &outlen);
|
|
||||||
EVP_PKEY_CTX_free (pctx);
|
EVP_PKEY_CTX_free (pctx);
|
||||||
#else
|
#else
|
||||||
uint8_t prk[32]; unsigned int len;
|
uint8_t prk[32]; unsigned int len;
|
||||||
@@ -1269,8 +1301,11 @@ namespace crypto
|
|||||||
auto l = info.length ();
|
auto l = info.length ();
|
||||||
memcpy (out, info.c_str (), l); out[l] = 0x01;
|
memcpy (out, info.c_str (), l); out[l] = 0x01;
|
||||||
HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len);
|
HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len);
|
||||||
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
|
if (outLen > 32) // 64
|
||||||
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
|
{
|
||||||
|
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
|
||||||
|
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
# define X509_getm_notAfter X509_get_notAfter
|
# define X509_getm_notAfter X509_get_notAfter
|
||||||
#else
|
#else
|
||||||
# define LEGACY_OPENSSL 0
|
# define LEGACY_OPENSSL 0
|
||||||
# define OPENSSL_HKDF 1
|
|
||||||
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
|
||||||
|
# define OPENSSL_HKDF 1
|
||||||
# define OPENSSL_EDDSA 1
|
# define OPENSSL_EDDSA 1
|
||||||
# define OPENSSL_X25519 1
|
# define OPENSSL_X25519 1
|
||||||
# define OPENSSL_SIPHASH 1
|
# define OPENSSL_SIPHASH 1
|
||||||
@@ -74,12 +74,13 @@ namespace crypto
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
X25519Keys ();
|
X25519Keys ();
|
||||||
X25519Keys (const uint8_t * priv, const uint8_t * pub); // for RouterContext
|
X25519Keys (const uint8_t * priv, const uint8_t * pub); // if pub is null, derive from priv
|
||||||
~X25519Keys ();
|
~X25519Keys ();
|
||||||
|
|
||||||
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 Agree (const uint8_t * pub, uint8_t * shared);
|
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -296,7 +297,7 @@ namespace crypto
|
|||||||
|
|
||||||
// HKDF
|
// HKDF
|
||||||
|
|
||||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out); // salt - 32, out - 64, info <= 32
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
void InitCrypto (bool precomputation);
|
void InitCrypto (bool precomputation);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace crypto
|
|||||||
|
|
||||||
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
|
if (!ctx) return;
|
||||||
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding);
|
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ namespace crypto
|
|||||||
|
|
||||||
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
|
if (!ctx) return false;
|
||||||
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +148,34 @@ namespace crypto
|
|||||||
BN_free (x); BN_free (y);
|
BN_free (x); BN_free (y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetEncryptor::ECIESX25519AEADRatchetEncryptor (const uint8_t * pub)
|
||||||
|
{
|
||||||
|
memcpy (m_PublicKey, pub, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool)
|
||||||
|
{
|
||||||
|
memcpy (pub, m_PublicKey, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv)
|
||||||
|
{
|
||||||
|
m_StaticKeys.SetPrivateKey (priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
|
||||||
|
{
|
||||||
|
m_StaticKeys.Agree (epub, sharedSecret);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub)
|
||||||
|
{
|
||||||
|
X25519Keys k;
|
||||||
|
k.GenerateKeys ();
|
||||||
|
k.GetPrivateKey (priv);
|
||||||
|
memcpy (pub, k.GetPublicKey (), 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,39 @@ namespace crypto
|
|||||||
};
|
};
|
||||||
|
|
||||||
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub);
|
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub);
|
||||||
|
|
||||||
|
// ECIES-X25519-AEAD-Ratchet
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetEncryptor: public CryptoKeyEncryptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetEncryptor (const uint8_t * pub);
|
||||||
|
~ECIESX25519AEADRatchetEncryptor () {};
|
||||||
|
void Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool);
|
||||||
|
// copies m_PublicKey to pub
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint8_t m_PublicKey[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetDecryptor: public CryptoKeyDecryptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetDecryptor (const uint8_t * priv);
|
||||||
|
~ECIESX25519AEADRatchetDecryptor () {};
|
||||||
|
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
// agree with static and return in sharedSecret (32 bytes)
|
||||||
|
size_t GetPublicKeyLen () const { return 32; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
X25519Keys m_StaticKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ namespace i2p
|
|||||||
namespace datagram
|
namespace datagram
|
||||||
{
|
{
|
||||||
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner):
|
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner):
|
||||||
m_Owner (owner.get()),
|
m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr)
|
||||||
m_Receiver (nullptr)
|
|
||||||
{
|
{
|
||||||
m_Identity.FromBase64 (owner->GetIdentity()->ToBase64());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DatagramDestination::~DatagramDestination ()
|
DatagramDestination::~DatagramDestination ()
|
||||||
@@ -28,14 +26,15 @@ namespace datagram
|
|||||||
auto owner = m_Owner;
|
auto owner = m_Owner;
|
||||||
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
|
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
|
||||||
uint8_t * buf = v.data();
|
uint8_t * buf = v.data();
|
||||||
auto identityLen = m_Identity.ToBuffer (buf, MAX_DATAGRAM_SIZE);
|
auto localIdentity = m_Owner->GetIdentity ();
|
||||||
|
auto identityLen = localIdentity->ToBuffer (buf, MAX_DATAGRAM_SIZE);
|
||||||
uint8_t * signature = buf + identityLen;
|
uint8_t * signature = buf + identityLen;
|
||||||
auto signatureLen = m_Identity.GetSignatureLen ();
|
auto signatureLen = localIdentity->GetSignatureLen ();
|
||||||
uint8_t * buf1 = signature + signatureLen;
|
uint8_t * buf1 = signature + signatureLen;
|
||||||
size_t headerLen = identityLen + signatureLen;
|
size_t headerLen = identityLen + signatureLen;
|
||||||
|
|
||||||
memcpy (buf1, payload, len);
|
memcpy (buf1, payload, len);
|
||||||
if (m_Identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
if (localIdentity->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
uint8_t hash[32];
|
uint8_t hash[32];
|
||||||
SHA256(buf1, len, hash);
|
SHA256(buf1, len, hash);
|
||||||
@@ -49,7 +48,13 @@ namespace 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)
|
||||||
|
{
|
||||||
|
auto msg = CreateDataMessage (payload, len, fromPort, toPort, true); // raw
|
||||||
|
auto session = ObtainSession(identity);
|
||||||
|
session->SendMsg(msg);
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
i2p::data::IdentityEx identity;
|
i2p::data::IdentityEx identity;
|
||||||
@@ -82,6 +87,14 @@ namespace datagram
|
|||||||
LogPrint (eLogWarning, "Datagram signature verification failed");
|
LogPrint (eLogWarning, "Datagram signature verification failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (m_RawReceiver)
|
||||||
|
m_RawReceiver (fromPort, toPort, buf, len);
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
|
||||||
|
}
|
||||||
|
|
||||||
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
|
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||||
@@ -92,18 +105,24 @@ namespace datagram
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw)
|
||||||
{
|
{
|
||||||
// unzip it
|
// unzip it
|
||||||
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
||||||
size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE);
|
size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE);
|
||||||
if (uncompressedLen)
|
if (uncompressedLen)
|
||||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
{
|
||||||
|
if (isRaw)
|
||||||
|
HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||||
|
else
|
||||||
|
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Datagram: decompression failed");
|
LogPrint (eLogWarning, "Datagram: decompression failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
|
||||||
|
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort, bool isRaw)
|
||||||
{
|
{
|
||||||
auto msg = NewI2NPMessage ();
|
auto msg = NewI2NPMessage ();
|
||||||
uint8_t * buf = msg->GetPayload ();
|
uint8_t * buf = msg->GetPayload ();
|
||||||
@@ -114,7 +133,7 @@ namespace datagram
|
|||||||
htobe32buf (msg->GetPayload (), size); // length
|
htobe32buf (msg->GetPayload (), size); // length
|
||||||
htobe16buf (buf + 4, fromPort); // source port
|
htobe16buf (buf + 4, fromPort); // source port
|
||||||
htobe16buf (buf + 6, toPort); // destination port
|
htobe16buf (buf + 6, toPort); // destination port
|
||||||
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
|
buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol
|
||||||
msg->len += size + 4;
|
msg->len += size + 4;
|
||||||
msg->FillI2NPMessageHeader (eI2NPData);
|
msg->FillI2NPMessageHeader (eI2NPData);
|
||||||
}
|
}
|
||||||
@@ -170,7 +189,7 @@ namespace datagram
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
|
DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
||||||
const i2p::data::IdentHash & remoteIdent) :
|
const i2p::data::IdentHash & remoteIdent) :
|
||||||
m_LocalDestination(localDestination),
|
m_LocalDestination(localDestination),
|
||||||
m_RemoteIdent(remoteIdent),
|
m_RemoteIdent(remoteIdent),
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace datagram
|
|||||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DatagramSession(i2p::client::ClientDestination * localDestination, const i2p::data::IdentHash & remoteIdent);
|
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent);
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
@@ -81,7 +81,7 @@ namespace datagram
|
|||||||
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
i2p::client::ClientDestination * m_LocalDestination;
|
std::shared_ptr<i2p::client::ClientDestination> m_LocalDestination;
|
||||||
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;
|
||||||
@@ -99,22 +99,28 @@ namespace datagram
|
|||||||
class DatagramDestination
|
class DatagramDestination
|
||||||
{
|
{
|
||||||
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
|
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
|
||||||
|
typedef std::function<void (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
||||||
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
|
||||||
~DatagramDestination ();
|
~DatagramDestination ();
|
||||||
|
|
||||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||||
|
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
||||||
|
|
||||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||||
void ResetReceiver () { m_Receiver = nullptr; };
|
void ResetReceiver () { m_Receiver = nullptr; };
|
||||||
|
|
||||||
void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; };
|
void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; };
|
||||||
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
|
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
|
||||||
|
|
||||||
|
void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; };
|
||||||
|
void ResetRawReceiver () { m_RawReceiver = nullptr; };
|
||||||
|
|
||||||
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
|
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
|
||||||
|
|
||||||
// clean up stale sessions
|
// clean up stale sessions
|
||||||
@@ -124,17 +130,19 @@ namespace datagram
|
|||||||
|
|
||||||
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
|
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort, bool isRaw = false);
|
||||||
|
|
||||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
||||||
|
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
|
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
|
||||||
Receiver FindReceiver(uint16_t port);
|
Receiver FindReceiver(uint16_t port);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
i2p::client::ClientDestination * m_Owner;
|
|
||||||
i2p::data::IdentityEx m_Identity;
|
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
||||||
Receiver m_Receiver; // default
|
Receiver m_Receiver; // default
|
||||||
|
RawReceiver m_RawReceiver; // default
|
||||||
std::mutex m_SessionsMutex;
|
std::mutex m_SessionsMutex;
|
||||||
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
|
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
|
||||||
std::mutex m_ReceiversMutex;
|
std::mutex m_ReceiversMutex;
|
||||||
|
|||||||
@@ -7,17 +7,17 @@
|
|||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace client
|
namespace client
|
||||||
{
|
{
|
||||||
LeaseSetDestination::LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params):
|
LeaseSetDestination::LeaseSetDestination (boost::asio::io_service& service,
|
||||||
m_IsRunning (false), m_Thread (nullptr), m_IsPublic (isPublic),
|
bool isPublic, const std::map<std::string, std::string> * params):
|
||||||
m_PublishReplyToken (0), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service),
|
m_Service (service), m_IsPublic (isPublic), m_PublishReplyToken (0),
|
||||||
|
m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service),
|
||||||
m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service),
|
m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service),
|
||||||
m_LeaseSetType (DEFAULT_LEASESET_TYPE)
|
m_LeaseSetType (DEFAULT_LEASESET_TYPE), m_AuthType (i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE)
|
||||||
{
|
{
|
||||||
int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
|
int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH;
|
||||||
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY;
|
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY;
|
||||||
@@ -70,6 +70,29 @@ namespace client
|
|||||||
it = params->find (I2CP_PARAM_LEASESET_TYPE);
|
it = params->find (I2CP_PARAM_LEASESET_TYPE);
|
||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
m_LeaseSetType = std::stoi(it->second);
|
m_LeaseSetType = std::stoi(it->second);
|
||||||
|
if (m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
|
{
|
||||||
|
// authentication for encrypted LeaseSet
|
||||||
|
it = params->find (I2CP_PARAM_LEASESET_AUTH_TYPE);
|
||||||
|
if (it != params->end ())
|
||||||
|
{
|
||||||
|
auto authType = std::stoi (it->second);
|
||||||
|
if (authType >= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE && authType <= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
|
||||||
|
m_AuthType = authType;
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Destination: Unknown auth type ", authType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it = params->find (I2CP_PARAM_LEASESET_PRIV_KEY);
|
||||||
|
if (it != params->end ())
|
||||||
|
{
|
||||||
|
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
|
||||||
|
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
|
||||||
|
{
|
||||||
|
LogPrint(eLogError, "Destination: invalid value i2cp.leaseSetPrivKey ", it->second);
|
||||||
|
m_LeaseSetPrivKey.reset (nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception & ex)
|
catch (std::exception & ex)
|
||||||
@@ -100,77 +123,36 @@ namespace client
|
|||||||
|
|
||||||
LeaseSetDestination::~LeaseSetDestination ()
|
LeaseSetDestination::~LeaseSetDestination ()
|
||||||
{
|
{
|
||||||
if (m_IsRunning)
|
|
||||||
Stop ();
|
|
||||||
if (m_Pool)
|
if (m_Pool)
|
||||||
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
|
i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool);
|
||||||
for (auto& it: m_LeaseSetRequests)
|
for (auto& it: m_LeaseSetRequests)
|
||||||
it.second->Complete (nullptr);
|
it.second->Complete (nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::Run ()
|
void LeaseSetDestination::Start ()
|
||||||
{
|
{
|
||||||
while (m_IsRunning)
|
if (m_Nickname.empty ())
|
||||||
{
|
m_Nickname = i2p::data::GetIdentHashAbbreviation (GetIdentHash ()); // set default nickname
|
||||||
try
|
LoadTags ();
|
||||||
{
|
m_Pool->SetLocalDestination (shared_from_this ());
|
||||||
m_Service.run ();
|
m_Pool->SetActive (true);
|
||||||
}
|
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
||||||
catch (std::exception& ex)
|
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
||||||
{
|
shared_from_this (), std::placeholders::_1));
|
||||||
LogPrint (eLogError, "Destination: runtime exception: ", ex.what ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LeaseSetDestination::Start ()
|
void LeaseSetDestination::Stop ()
|
||||||
{
|
{
|
||||||
if (!m_IsRunning)
|
m_CleanupTimer.cancel ();
|
||||||
|
m_PublishConfirmationTimer.cancel ();
|
||||||
|
m_PublishVerificationTimer.cancel ();
|
||||||
|
if (m_Pool)
|
||||||
{
|
{
|
||||||
if (m_Nickname.empty ())
|
m_Pool->SetLocalDestination (nullptr);
|
||||||
m_Nickname = i2p::data::GetIdentHashAbbreviation (GetIdentHash ()); // set default nickname
|
i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
|
||||||
LoadTags ();
|
|
||||||
m_IsRunning = true;
|
|
||||||
m_Pool->SetLocalDestination (shared_from_this ());
|
|
||||||
m_Pool->SetActive (true);
|
|
||||||
m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT));
|
|
||||||
m_CleanupTimer.async_wait (std::bind (&LeaseSetDestination::HandleCleanupTimer,
|
|
||||||
shared_from_this (), std::placeholders::_1));
|
|
||||||
m_Thread = new std::thread (std::bind (&LeaseSetDestination::Run, shared_from_this ()));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
SaveTags ();
|
||||||
return false;
|
CleanUp (); // GarlicDestination
|
||||||
}
|
|
||||||
|
|
||||||
bool LeaseSetDestination::Stop ()
|
|
||||||
{
|
|
||||||
if (m_IsRunning)
|
|
||||||
{
|
|
||||||
m_CleanupTimer.cancel ();
|
|
||||||
m_PublishConfirmationTimer.cancel ();
|
|
||||||
m_PublishVerificationTimer.cancel ();
|
|
||||||
|
|
||||||
m_IsRunning = false;
|
|
||||||
if (m_Pool)
|
|
||||||
{
|
|
||||||
m_Pool->SetLocalDestination (nullptr);
|
|
||||||
i2p::tunnel::tunnels.StopTunnelPool (m_Pool);
|
|
||||||
}
|
|
||||||
m_Service.stop ();
|
|
||||||
if (m_Thread)
|
|
||||||
{
|
|
||||||
m_Thread->join ();
|
|
||||||
delete m_Thread;
|
|
||||||
m_Thread = 0;
|
|
||||||
}
|
|
||||||
SaveTags ();
|
|
||||||
CleanUp (); // GarlicDestination
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params)
|
bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params)
|
||||||
@@ -330,30 +312,38 @@ namespace client
|
|||||||
|
|
||||||
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg));
|
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||||
|
m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
I2NPMessageType typeID = (I2NPMessageType)(buf[I2NP_HEADER_TYPEID_OFFSET]);
|
||||||
|
LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LeaseSetDestination::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET];
|
|
||||||
switch (typeID)
|
switch (typeID)
|
||||||
{
|
{
|
||||||
case eI2NPData:
|
case eI2NPData:
|
||||||
HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
HandleDataMessage (payload, len);
|
||||||
break;
|
break;
|
||||||
case eI2NPDeliveryStatus:
|
case eI2NPDeliveryStatus:
|
||||||
// we assume tunnel tests non-encrypted
|
// we assume tunnel tests non-encrypted
|
||||||
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseStore:
|
case eI2NPDatabaseStore:
|
||||||
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
HandleDatabaseStoreMessage (payload, len);
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseSearchReply:
|
case eI2NPDatabaseSearchReply:
|
||||||
HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
HandleDatabaseSearchReplyMessage (payload, len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
|
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
|
||||||
@@ -398,7 +388,7 @@ namespace client
|
|||||||
if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
if (buf[DATABASE_STORE_TYPE_OFFSET] == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset); // LeaseSet
|
leaseSet = std::make_shared<i2p::data::LeaseSet> (buf + offset, len - offset); // LeaseSet
|
||||||
else
|
else
|
||||||
leaseSet = std::make_shared<i2p::data::LeaseSet2> (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset); // LeaseSet2
|
leaseSet = std::make_shared<i2p::data::LeaseSet2> (buf[DATABASE_STORE_TYPE_OFFSET], buf + offset, len - offset, true, GetPreferredCryptoType () ); // LeaseSet2
|
||||||
if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key)
|
if (leaseSet->IsValid () && leaseSet->GetIdentHash () == key)
|
||||||
{
|
{
|
||||||
if (leaseSet->GetIdentHash () != GetIdentHash ())
|
if (leaseSet->GetIdentHash () != GetIdentHash ())
|
||||||
@@ -422,7 +412,7 @@ namespace client
|
|||||||
auto it2 = m_LeaseSetRequests.find (key);
|
auto it2 = m_LeaseSetRequests.find (key);
|
||||||
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
|
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
|
||||||
{
|
{
|
||||||
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey);
|
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr, GetPreferredCryptoType ());
|
||||||
if (ls2->IsValid ())
|
if (ls2->IsValid ())
|
||||||
{
|
{
|
||||||
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
|
||||||
@@ -488,9 +478,8 @@ namespace client
|
|||||||
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||||
{
|
{
|
||||||
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
|
||||||
if (msgID == m_PublishReplyToken)
|
if (msgID == m_PublishReplyToken)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed for ", GetIdentHash().ToBase32());
|
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed for ", GetIdentHash().ToBase32());
|
||||||
@@ -502,7 +491,7 @@ namespace client
|
|||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
|
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::SetLeaseSetUpdated ()
|
void LeaseSetDestination::SetLeaseSetUpdated ()
|
||||||
@@ -833,10 +822,19 @@ namespace client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientDestination::ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
|
i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const
|
||||||
LeaseSetDestination (isPublic, params), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
{
|
||||||
|
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET))
|
||||||
|
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET;
|
||||||
|
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||||
|
bool isPublic, const std::map<std::string, std::string> * params):
|
||||||
|
LeaseSetDestination (service, isPublic, params),
|
||||||
|
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
m_DatagramDestination (nullptr), m_RefCounter (0),
|
||||||
m_ReadyChecker(GetService())
|
m_ReadyChecker(service)
|
||||||
{
|
{
|
||||||
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only
|
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only
|
||||||
@@ -849,21 +847,54 @@ namespace client
|
|||||||
if (it != params->end ())
|
if (it != params->end ())
|
||||||
m_EncryptionKeyType = std::stoi(it->second);
|
m_EncryptionKeyType = std::stoi(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPublic && m_EncryptionKeyType == GetIdentity ()->GetCryptoKeyType ()) // TODO: presist key type
|
memset (m_EncryptionPrivateKey, 0, 256);
|
||||||
|
memset (m_EncryptionPublicKey, 0, 256);
|
||||||
|
if (isPublic)
|
||||||
PersistTemporaryKeys ();
|
PersistTemporaryKeys ();
|
||||||
else
|
else
|
||||||
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||||
|
|
||||||
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_EncryptionKeyType, m_EncryptionPrivateKey);
|
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_EncryptionKeyType, m_EncryptionPrivateKey);
|
||||||
if (isPublic)
|
if (isPublic)
|
||||||
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
||||||
|
|
||||||
// extract streaming params
|
try
|
||||||
if (params)
|
{
|
||||||
|
if (params)
|
||||||
|
{
|
||||||
|
// extract streaming params
|
||||||
|
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
|
||||||
|
if (it != params->end ())
|
||||||
|
m_StreamingAckDelay = std::stoi(it->second);
|
||||||
|
|
||||||
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
|
{
|
||||||
|
// authentication for encrypted LeaseSet
|
||||||
|
auto authType = GetAuthType ();
|
||||||
|
if (authType > 0)
|
||||||
|
{
|
||||||
|
m_AuthKeys = std::make_shared<std::vector<i2p::data::AuthPublicKey> >();
|
||||||
|
if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_DH)
|
||||||
|
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_DH, params);
|
||||||
|
else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
|
||||||
|
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params);
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Destination: Unexpected auth type ", authType);
|
||||||
|
if (m_AuthKeys->size ())
|
||||||
|
LogPrint (eLogInfo, "Destination: ", m_AuthKeys->size (), " auth keys read");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType);
|
||||||
|
m_AuthKeys = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception & ex)
|
||||||
{
|
{
|
||||||
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
|
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
|
||||||
if (it != params->end ())
|
|
||||||
m_StreamingAckDelay = std::stoi(it->second);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,71 +902,35 @@ namespace client
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientDestination::Start ()
|
void ClientDestination::Start ()
|
||||||
{
|
{
|
||||||
if (LeaseSetDestination::Start ())
|
LeaseSetDestination::Start ();
|
||||||
|
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis ()); // TODO:
|
||||||
|
m_StreamingDestination->Start ();
|
||||||
|
for (auto& it: m_StreamingDestinationsByPorts)
|
||||||
|
it.second->Start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientDestination::Stop ()
|
||||||
|
{
|
||||||
|
LeaseSetDestination::Stop ();
|
||||||
|
m_ReadyChecker.cancel();
|
||||||
|
m_StreamingDestination->Stop ();
|
||||||
|
//m_StreamingDestination->SetOwner (nullptr);
|
||||||
|
m_StreamingDestination = nullptr;
|
||||||
|
for (auto& it: m_StreamingDestinationsByPorts)
|
||||||
{
|
{
|
||||||
m_StreamingDestination = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis ()); // TODO:
|
it.second->Stop ();
|
||||||
m_StreamingDestination->Start ();
|
//it.second->SetOwner (nullptr);
|
||||||
for (auto& it: m_StreamingDestinationsByPorts)
|
|
||||||
it.second->Start ();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
m_StreamingDestinationsByPorts.clear ();
|
||||||
return false;
|
if (m_DatagramDestination)
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientDestination::Stop ()
|
|
||||||
{
|
|
||||||
if (LeaseSetDestination::Stop ())
|
|
||||||
{
|
{
|
||||||
m_ReadyChecker.cancel();
|
delete m_DatagramDestination;
|
||||||
m_StreamingDestination->Stop ();
|
m_DatagramDestination = nullptr;
|
||||||
//m_StreamingDestination->SetOwner (nullptr);
|
|
||||||
m_StreamingDestination = nullptr;
|
|
||||||
for (auto& it: m_StreamingDestinationsByPorts)
|
|
||||||
{
|
|
||||||
it.second->Stop ();
|
|
||||||
//it.second->SetOwner (nullptr);
|
|
||||||
}
|
|
||||||
m_StreamingDestinationsByPorts.clear ();
|
|
||||||
if (m_DatagramDestination)
|
|
||||||
{
|
|
||||||
delete m_DatagramDestination;
|
|
||||||
m_DatagramDestination = nullptr;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef I2LUA
|
|
||||||
void ClientDestination::Ready(ReadyPromise & p)
|
|
||||||
{
|
|
||||||
ScheduleCheckForReady(&p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientDestination::ScheduleCheckForReady(ReadyPromise * p)
|
|
||||||
{
|
|
||||||
// tick every 100ms
|
|
||||||
m_ReadyChecker.expires_from_now(boost::posix_time::milliseconds(100));
|
|
||||||
m_ReadyChecker.async_wait([&, p] (const boost::system::error_code & ecode) {
|
|
||||||
HandleCheckForReady(ecode, p);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientDestination::HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p)
|
|
||||||
{
|
|
||||||
if(ecode) // error happened
|
|
||||||
p->set_value(nullptr);
|
|
||||||
else if(IsReady()) // we are ready
|
|
||||||
p->set_value(std::shared_ptr<ClientDestination>(this));
|
|
||||||
else // we are not ready
|
|
||||||
ScheduleCheckForReady(p);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
uint32_t length = bufbe32toh (buf);
|
uint32_t length = bufbe32toh (buf);
|
||||||
@@ -967,6 +962,13 @@ namespace client
|
|||||||
else
|
else
|
||||||
LogPrint (eLogError, "Destination: Missing datagram destination");
|
LogPrint (eLogError, "Destination: Missing datagram destination");
|
||||||
break;
|
break;
|
||||||
|
case PROTOCOL_TYPE_RAW:
|
||||||
|
// raw datagram
|
||||||
|
if (m_DatagramDestination)
|
||||||
|
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, true);
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Destination: Missing raw datagram destination");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
|
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
|
||||||
}
|
}
|
||||||
@@ -1105,8 +1107,8 @@ namespace client
|
|||||||
LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p");
|
LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p");
|
||||||
memset (m_EncryptionPrivateKey, 0, 256);
|
memset (m_EncryptionPrivateKey, 0, 256);
|
||||||
memset (m_EncryptionPublicKey, 0, 256);
|
memset (m_EncryptionPublicKey, 0, 256);
|
||||||
i2p::data::PrivateKeys::GenerateCryptoKeyPair (GetIdentity ()->GetCryptoKeyType (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||||
|
// TODO:: persist crypto key type
|
||||||
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
|
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
|
||||||
if (f1) {
|
if (f1) {
|
||||||
f1.write ((char *)m_EncryptionPublicKey, 256);
|
f1.write ((char *)m_EncryptionPublicKey, 256);
|
||||||
@@ -1128,11 +1130,13 @@ namespace client
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// standard LS2 (type 3) first
|
// standard LS2 (type 3) first
|
||||||
auto keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
|
uint16_t keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256;
|
||||||
|
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
||||||
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
|
||||||
m_Keys, m_EncryptionKeyType, keyLen, m_EncryptionPublicKey, tunnels);
|
m_Keys, i2p::data::LocalLeaseSet2::KeySections { {m_EncryptionKeyType, keyLen, m_EncryptionPublicKey} },
|
||||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) // encrypt if type 5
|
tunnels, IsPublic (), isPublishedEncrypted);
|
||||||
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys);
|
if (isPublishedEncrypted) // encrypt if type 5
|
||||||
|
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys);
|
||||||
leaseSet = ls2;
|
leaseSet = ls2;
|
||||||
}
|
}
|
||||||
SetLeaseSet (leaseSet);
|
SetLeaseSet (leaseSet);
|
||||||
@@ -1143,7 +1147,7 @@ namespace client
|
|||||||
if (m_DatagramDestination) m_DatagramDestination->CleanUp ();
|
if (m_DatagramDestination) m_DatagramDestination->CleanUp ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||||
{
|
{
|
||||||
if (m_Decryptor)
|
if (m_Decryptor)
|
||||||
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
@@ -1151,5 +1155,63 @@ namespace client
|
|||||||
LogPrint (eLogError, "Destinations: decryptor is not set");
|
LogPrint (eLogError, "Destinations: decryptor is not set");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientDestination::ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params)
|
||||||
|
{
|
||||||
|
for (auto it: *params)
|
||||||
|
if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group))
|
||||||
|
{
|
||||||
|
auto pos = it.second.find (':');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
i2p::data::AuthPublicKey pubKey;
|
||||||
|
if (pubKey.FromBase64 (it.second.substr (pos+1)))
|
||||||
|
m_AuthKeys->push_back (pubKey);
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientDestination::DeleteStream (uint32_t recvStreamID)
|
||||||
|
{
|
||||||
|
if (m_StreamingDestination->DeleteStream (recvStreamID))
|
||||||
|
return true;
|
||||||
|
for (auto it: m_StreamingDestinationsByPorts)
|
||||||
|
if (it.second->DeleteStream (recvStreamID))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunnableClientDestination::RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
|
||||||
|
RunnableService ("Destination"),
|
||||||
|
ClientDestination (GetIOService (), keys, isPublic, params)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RunnableClientDestination::~RunnableClientDestination ()
|
||||||
|
{
|
||||||
|
if (IsRunning ())
|
||||||
|
Stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunnableClientDestination::Start ()
|
||||||
|
{
|
||||||
|
if (!IsRunning ())
|
||||||
|
{
|
||||||
|
ClientDestination::Start ();
|
||||||
|
StartIOService ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunnableClientDestination::Stop ()
|
||||||
|
{
|
||||||
|
if (IsRunning ())
|
||||||
|
{
|
||||||
|
ClientDestination::Stop ();
|
||||||
|
StopIOService ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,6 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#ifdef I2LUA
|
|
||||||
#include <future>
|
|
||||||
#endif
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "TunnelPool.h"
|
#include "TunnelPool.h"
|
||||||
@@ -20,6 +17,7 @@
|
|||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "Streaming.h"
|
#include "Streaming.h"
|
||||||
#include "Datagram.h"
|
#include "Datagram.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -55,7 +53,11 @@ namespace client
|
|||||||
const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType";
|
const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType";
|
||||||
const int DEFAULT_LEASESET_TYPE = 1;
|
const int DEFAULT_LEASESET_TYPE = 1;
|
||||||
const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType";
|
const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType";
|
||||||
|
const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64
|
||||||
|
const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType";
|
||||||
|
const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn
|
||||||
|
const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn
|
||||||
|
|
||||||
// latency
|
// latency
|
||||||
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
|
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
|
||||||
const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
|
const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
|
||||||
@@ -94,18 +96,17 @@ namespace client
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LeaseSetDestination (bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||||
~LeaseSetDestination ();
|
~LeaseSetDestination ();
|
||||||
const std::string& GetNickname () const { return m_Nickname; };
|
const std::string& GetNickname () const { return m_Nickname; };
|
||||||
|
boost::asio::io_service& GetService () { return m_Service; };
|
||||||
|
|
||||||
virtual bool Start ();
|
virtual void Start ();
|
||||||
virtual bool Stop ();
|
virtual void Stop ();
|
||||||
|
|
||||||
/** i2cp reconfigure */
|
/** i2cp reconfigure */
|
||||||
virtual bool Reconfigure(std::map<std::string, std::string> i2cpOpts);
|
virtual bool Reconfigure(std::map<std::string, std::string> i2cpOpts);
|
||||||
|
|
||||||
bool IsRunning () const { return m_IsRunning; };
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
|
||||||
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
|
||||||
std::shared_ptr<i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
std::shared_ptr<i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
|
||||||
@@ -117,7 +118,6 @@ namespace client
|
|||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
|
||||||
|
|
||||||
// override GarlicDestination
|
// override GarlicDestination
|
||||||
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
||||||
@@ -127,9 +127,15 @@ namespace client
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
// implements GarlicDestination
|
||||||
|
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||||
|
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len);
|
||||||
|
|
||||||
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
||||||
int GetLeaseSetType () const { return m_LeaseSetType; };
|
int GetLeaseSetType () const { return m_LeaseSetType; };
|
||||||
void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; };
|
void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; };
|
||||||
|
int GetAuthType () const { return m_AuthType; };
|
||||||
|
bool IsPublic () const { return m_IsPublic; };
|
||||||
virtual void CleanupDestination () {}; // additional clean up in derived classes
|
virtual void CleanupDestination () {}; // additional clean up in derived classes
|
||||||
// I2CP
|
// I2CP
|
||||||
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
|
virtual void HandleDataMessage (const uint8_t * buf, size_t len) = 0;
|
||||||
@@ -137,7 +143,6 @@ namespace client
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
|
||||||
void UpdateLeaseSet ();
|
void UpdateLeaseSet ();
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSetMt ();
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSetMt ();
|
||||||
void Publish ();
|
void Publish ();
|
||||||
@@ -146,19 +151,18 @@ namespace client
|
|||||||
void HandlePublishDelayTimer (const boost::system::error_code& ecode);
|
void HandlePublishDelayTimer (const boost::system::error_code& ecode);
|
||||||
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (uint32_t msgID);
|
||||||
|
|
||||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||||
void CleanupRemoteLeaseSets ();
|
void CleanupRemoteLeaseSets ();
|
||||||
|
i2p::data::CryptoKeyType GetPreferredCryptoType () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
volatile bool m_IsRunning;
|
boost::asio::io_service& m_Service;
|
||||||
std::thread * m_Thread;
|
|
||||||
boost::asio::io_service m_Service;
|
|
||||||
mutable std::mutex m_RemoteLeaseSetsMutex;
|
mutable std::mutex m_RemoteLeaseSetsMutex;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||||
@@ -174,7 +178,8 @@ namespace client
|
|||||||
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
|
||||||
m_PublishDelayTimer, m_CleanupTimer;
|
m_PublishDelayTimer, m_CleanupTimer;
|
||||||
std::string m_Nickname;
|
std::string m_Nickname;
|
||||||
int m_LeaseSetType;
|
int m_LeaseSetType, m_AuthType;
|
||||||
|
std::unique_ptr<i2p::data::Tag<32> > m_LeaseSetPrivKey; // non-null if presented
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -182,24 +187,19 @@ namespace client
|
|||||||
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
int GetNumRemoteLeaseSets () const { return m_RemoteLeaseSets.size (); };
|
||||||
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; };
|
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; };
|
||||||
bool IsEncryptedLeaseSet () const { return m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; };
|
bool IsEncryptedLeaseSet () const { return m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; };
|
||||||
|
bool IsPerClientAuth () const { return m_AuthType > 0; };
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClientDestination: public LeaseSetDestination
|
class ClientDestination: public LeaseSetDestination
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#ifdef I2LUA
|
|
||||||
// type for informing that a client destination is ready
|
|
||||||
typedef std::promise<std::shared_ptr<ClientDestination> > ReadyPromise;
|
|
||||||
// informs promise with shared_from_this() when this destination is ready to use
|
|
||||||
// if cancelled before ready, informs promise with nullptr
|
|
||||||
void Ready(ReadyPromise & p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||||
|
bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||||
~ClientDestination ();
|
~ClientDestination ();
|
||||||
|
|
||||||
virtual bool Start ();
|
void Start ();
|
||||||
virtual bool Stop ();
|
void Stop ();
|
||||||
|
|
||||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||||
@@ -223,12 +223,14 @@ namespace client
|
|||||||
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
||||||
|
|
||||||
// datagram
|
// datagram
|
||||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||||
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
i2p::datagram::DatagramDestination * CreateDatagramDestination ();
|
||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||||
|
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; };
|
||||||
|
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { return m_EncryptionPublicKey; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -239,13 +241,12 @@ namespace client
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> GetSharedFromThis ()
|
std::shared_ptr<ClientDestination> GetSharedFromThis () {
|
||||||
{ return std::static_pointer_cast<ClientDestination>(shared_from_this ()); }
|
return std::static_pointer_cast<ClientDestination>(shared_from_this ());
|
||||||
|
}
|
||||||
void PersistTemporaryKeys ();
|
void PersistTemporaryKeys ();
|
||||||
#ifdef I2LUA
|
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
||||||
void ScheduleCheckForReady(ReadyPromise * p);
|
|
||||||
void HandleCheckForReady(const boost::system::error_code & ecode, ReadyPromise * p);
|
|
||||||
#endif
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
@@ -261,11 +262,26 @@ namespace client
|
|||||||
|
|
||||||
boost::asio::deadline_timer m_ReadyChecker;
|
boost::asio::deadline_timer m_ReadyChecker;
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<i2p::data::AuthPublicKey> > m_AuthKeys; // we don't need them for I2CP
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
|
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
|
||||||
|
bool DeleteStream (uint32_t recvStreamID);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RunnableClientDestination: private i2p::util::RunnableService, public ClientDestination
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||||
|
~RunnableClientDestination ();
|
||||||
|
|
||||||
|
void Start ();
|
||||||
|
void Stop ();
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
664
libi2pd/ECIESX25519AEADRatchetSession.cpp
Normal file
664
libi2pd/ECIESX25519AEADRatchetSession.cpp
Normal file
@@ -0,0 +1,664 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "Elligator.h"
|
||||||
|
#include "Tag.h"
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
#include "Timestamp.h"
|
||||||
|
#include "Tunnel.h"
|
||||||
|
#include "TunnelPool.h"
|
||||||
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace garlic
|
||||||
|
{
|
||||||
|
|
||||||
|
void RatchetTagSet::DHInitialize (const uint8_t * rootKey, const uint8_t * k)
|
||||||
|
{
|
||||||
|
// DH_INITIALIZE(rootKey, k)
|
||||||
|
uint8_t keydata[64];
|
||||||
|
i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64)
|
||||||
|
// nextRootKey = keydata[0:31]
|
||||||
|
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_KeyData.buf);
|
||||||
|
// [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64)
|
||||||
|
memcpy (m_SymmKeyCK, m_KeyData.buf + 32, 32);
|
||||||
|
m_NextSymmKeyIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RatchetTagSet::NextSessionTagRatchet ()
|
||||||
|
{
|
||||||
|
i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), nullptr, 0, "STInitialization", m_KeyData.buf); // [sessTag_ck, sesstag_constant] = HKDF(sessTag_ck, ZEROLEN, "STInitialization", 64)
|
||||||
|
memcpy (m_SessTagConstant, m_KeyData.GetSessTagConstant (), 32);
|
||||||
|
m_NextIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t RatchetTagSet::GetNextSessionTag ()
|
||||||
|
{
|
||||||
|
i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64)
|
||||||
|
m_NextIndex++;
|
||||||
|
if (m_NextIndex >= 65535) m_NextIndex = 0; // TODO: dirty hack, should create new tagset
|
||||||
|
return m_KeyData.GetTag ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RatchetTagSet::GetSymmKey (int index, uint8_t * key)
|
||||||
|
{
|
||||||
|
if (m_NextSymmKeyIndex > 0 && index >= m_NextSymmKeyIndex)
|
||||||
|
{
|
||||||
|
auto num = index + 1 - m_NextSymmKeyIndex;
|
||||||
|
for (int i = 0; i < num; i++)
|
||||||
|
i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK);
|
||||||
|
m_NextSymmKeyIndex += num;
|
||||||
|
memcpy (key, m_CurrentSymmKeyCK + 32, 32);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CalculateSymmKeyCK (index, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RatchetTagSet::CalculateSymmKeyCK (int index, uint8_t * key)
|
||||||
|
{
|
||||||
|
// TODO: store intermediate keys
|
||||||
|
uint8_t currentSymmKeyCK[64];
|
||||||
|
i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
|
||||||
|
for (int i = 0; i < index; i++)
|
||||||
|
i2p::crypto::HKDF (currentSymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_n = HKDF(symmKey_chainKey_(n-1), SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
|
||||||
|
memcpy (key, currentSymmKeyCK + 32, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner):
|
||||||
|
GarlicRoutingSession (owner, true)
|
||||||
|
{
|
||||||
|
ResetKeys ();
|
||||||
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetSession::~ECIESX25519AEADRatchetSession ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::ResetKeys ()
|
||||||
|
{
|
||||||
|
// TODO : use precalculated hashes
|
||||||
|
static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes
|
||||||
|
SHA256 ((const uint8_t *)protocolName, 40, m_H);
|
||||||
|
memcpy (m_CK, m_H, 32);
|
||||||
|
SHA256 (m_H, 32, m_H);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
SHA256_CTX ctx;
|
||||||
|
SHA256_Init (&ctx);
|
||||||
|
SHA256_Update (&ctx, m_H, 32);
|
||||||
|
SHA256_Update (&ctx, buf, len);
|
||||||
|
SHA256_Final (m_H, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::CreateNonce (uint64_t seqn, uint8_t * nonce)
|
||||||
|
{
|
||||||
|
memset (nonce, 0, 4);
|
||||||
|
htole64buf (nonce + 4, seqn);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::GenerateEphemeralKeysAndEncode (uint8_t * buf)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
m_EphemeralKeys.GenerateKeys ();
|
||||||
|
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys.GetPublicKey (), buf))
|
||||||
|
return true; // success
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t ECIESX25519AEADRatchetSession::CreateNewSessionTag () const
|
||||||
|
{
|
||||||
|
uint8_t tagsetKey[32];
|
||||||
|
i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32)
|
||||||
|
// Session Tag Ratchet
|
||||||
|
RatchetTagSet tagsetNsr;
|
||||||
|
tagsetNsr.DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey)
|
||||||
|
tagsetNsr.NextSessionTagRatchet ();
|
||||||
|
return tagsetNsr.GetNextSessionTag ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
if (!GetOwner ()) return false;
|
||||||
|
// we are Bob
|
||||||
|
// KDF1
|
||||||
|
MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET), 32); // h = SHA256(h || bpk)
|
||||||
|
|
||||||
|
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Can't decode elligator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buf += 32; len -= 32;
|
||||||
|
MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
|
||||||
|
|
||||||
|
uint8_t sharedSecret[32];
|
||||||
|
GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519(bsk, aepk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
|
||||||
|
// decrypt flags/static
|
||||||
|
uint8_t nonce[12], fs[32];
|
||||||
|
CreateNonce (0, nonce);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, m_CK + 32, nonce, fs, 32, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MixHash (buf, 48); // h = SHA256(h || ciphertext)
|
||||||
|
buf += 48; len -= 48; // 32 data + 16 poly
|
||||||
|
|
||||||
|
// decrypt payload
|
||||||
|
std::vector<uint8_t> payload (len - 16);
|
||||||
|
// KDF2 for payload
|
||||||
|
bool isStatic = !i2p::data::Tag<32> (fs).IsZero ();
|
||||||
|
if (isStatic)
|
||||||
|
{
|
||||||
|
// static key, fs is apk
|
||||||
|
memcpy (m_RemoteStaticKey, fs, 32);
|
||||||
|
GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519(bsk, apk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
}
|
||||||
|
else // all zeros flags
|
||||||
|
CreateNonce (1, nonce);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext)
|
||||||
|
m_State = eSessionStateNewSessionReceived;
|
||||||
|
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
||||||
|
|
||||||
|
HandlePayload (payload.data (), len - 16);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, int index)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < len)
|
||||||
|
{
|
||||||
|
uint8_t blk = buf[offset];
|
||||||
|
offset++;
|
||||||
|
auto size = bufbe16toh (buf + offset);
|
||||||
|
offset += 2;
|
||||||
|
LogPrint (eLogDebug, "Garlic: Block type ", (int)blk, " of size ", size);
|
||||||
|
if (size > len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Unexpected block length ", size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (blk)
|
||||||
|
{
|
||||||
|
case eECIESx25519BlkGalicClove:
|
||||||
|
GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size);
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkDateTime:
|
||||||
|
LogPrint (eLogDebug, "Garlic: datetime");
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkOptions:
|
||||||
|
LogPrint (eLogDebug, "Garlic: options");
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkPadding:
|
||||||
|
LogPrint (eLogDebug, "Garlic: padding");
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkAckRequest:
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Garlic: ack request");
|
||||||
|
m_AckRequests.push_back ({0, index}); // TODO: use actual tagsetid
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk);
|
||||||
|
}
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||||
|
{
|
||||||
|
ResetKeys ();
|
||||||
|
// we are Alice, bpk is m_RemoteStaticKey
|
||||||
|
size_t offset = 0;
|
||||||
|
if (!GenerateEphemeralKeysAndEncode (out + offset))
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Can't encode elligator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset += 32;
|
||||||
|
|
||||||
|
// KDF1
|
||||||
|
MixHash (m_RemoteStaticKey, 32); // h = SHA256(h || bpk)
|
||||||
|
MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || aepk)
|
||||||
|
uint8_t sharedSecret[32];
|
||||||
|
m_EphemeralKeys.Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
// encrypt static key section
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (0, nonce);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
|
||||||
|
offset += 48;
|
||||||
|
// KDF2
|
||||||
|
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519 (ask, bpk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
// encrypt payload
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext)
|
||||||
|
|
||||||
|
m_State = eSessionStateNewSessionSent;
|
||||||
|
if (GetOwner ())
|
||||||
|
GetOwner ()->AddECIESx25519SessionTag (0, CreateNewSessionTag (), shared_from_this ());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||||
|
{
|
||||||
|
// we are Bob
|
||||||
|
uint64_t tag = CreateNewSessionTag ();
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
memcpy (out + offset, &tag, 8);
|
||||||
|
offset += 8;
|
||||||
|
if (!GenerateEphemeralKeysAndEncode (out + offset)) // bepk
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Can't encode elligator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset += 32;
|
||||||
|
// KDF for Reply Key Section
|
||||||
|
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
|
||||||
|
MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk)
|
||||||
|
uint8_t sharedSecret[32];
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (0, nonce);
|
||||||
|
// calulate hash for zero length
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (sharedSecret /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad)
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MixHash (out + offset, 16); // h = SHA256(h || ciphertext)
|
||||||
|
offset += 16;
|
||||||
|
memcpy (m_NSRHeader, out, 56); // for possible next NSR
|
||||||
|
// KDF for payload
|
||||||
|
uint8_t keydata[64];
|
||||||
|
i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
|
||||||
|
// k_ab = keydata[0:31], k_ba = keydata[32:63]
|
||||||
|
m_ReceiveTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab)
|
||||||
|
m_ReceiveTagset.NextSessionTagRatchet ();
|
||||||
|
m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
||||||
|
m_SendTagset.NextSessionTagRatchet ();
|
||||||
|
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ());
|
||||||
|
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
||||||
|
// encrypt payload
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: NSR payload section AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_State = eSessionStateNewSessionReplySent;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||||
|
{
|
||||||
|
// we are Bob and sent NSR already
|
||||||
|
memcpy (out, m_NSRHeader, 56);
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (0, nonce);
|
||||||
|
// encrypt payload
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + 56, len + 16, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Next NSR payload section AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
// we are Alice
|
||||||
|
LogPrint (eLogDebug, "Garlic: reply received");
|
||||||
|
const uint8_t * tag = buf;
|
||||||
|
buf += 8; len -= 8; // tag
|
||||||
|
uint8_t bepk[32]; // Bob's ephemeral key
|
||||||
|
if (!i2p::crypto::GetElligator ()->Decode (buf, bepk))
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Can't decode elligator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buf += 32; len -= 32;
|
||||||
|
// KDF for Reply Key Section
|
||||||
|
MixHash (tag, 8); // h = SHA256(h || tag)
|
||||||
|
MixHash (bepk, 32); // h = SHA256(h || bepk)
|
||||||
|
uint8_t sharedSecret[32];
|
||||||
|
m_EphemeralKeys.Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk)
|
||||||
|
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_RARCHET); // x25519 (ask, bepk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (0, nonce);
|
||||||
|
// calulate hash for zero length
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anyting */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Reply key section AEAD decryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MixHash (buf, 16); // h = SHA256(h || ciphertext)
|
||||||
|
buf += 16; len -= 16;
|
||||||
|
// KDF for payload
|
||||||
|
uint8_t keydata[64];
|
||||||
|
i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
|
||||||
|
// k_ab = keydata[0:31], k_ba = keydata[32:63]
|
||||||
|
m_SendTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab)
|
||||||
|
m_SendTagset.NextSessionTagRatchet ();
|
||||||
|
m_ReceiveTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
|
||||||
|
m_ReceiveTagset.NextSessionTagRatchet ();
|
||||||
|
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ());
|
||||||
|
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
|
||||||
|
// decrypt payload
|
||||||
|
std::vector<uint8_t> payload (len - 16);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keydata, nonce, payload.data (), len - 16, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_State = eSessionStateEstablished;
|
||||||
|
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
||||||
|
HandlePayload (payload.data (), len - 16);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||||
|
{
|
||||||
|
uint8_t nonce[12];
|
||||||
|
auto index = m_SendTagset.GetNextIndex ();
|
||||||
|
CreateNonce (index, nonce); // tag's index
|
||||||
|
uint64_t tag = m_SendTagset.GetNextSessionTag ();
|
||||||
|
memcpy (out, &tag, 8);
|
||||||
|
// ad = The session tag, 8 bytes
|
||||||
|
// ciphertext = ENCRYPT(k, n, payload, ad)
|
||||||
|
uint8_t key[32];
|
||||||
|
m_SendTagset.GetSymmKey (index, key);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index)
|
||||||
|
{
|
||||||
|
uint8_t nonce[12];
|
||||||
|
CreateNonce (index, nonce); // tag's index
|
||||||
|
len -= 8; // tag
|
||||||
|
std::vector<uint8_t> payload (len - 16);
|
||||||
|
uint8_t key[32];
|
||||||
|
m_ReceiveTagset.GetSymmKey (index, key);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, key, nonce, payload.data (), len - 16, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
HandlePayload (payload.data (), len - 16, index);
|
||||||
|
if (m_ReceiveTagset.GetNextIndex () - index <= GetOwner ()->GetNumTags ()*2/3)
|
||||||
|
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len, int index)
|
||||||
|
{
|
||||||
|
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
switch (m_State)
|
||||||
|
{
|
||||||
|
case eSessionStateNewSessionReplySent:
|
||||||
|
m_State = eSessionStateEstablished;
|
||||||
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
[[fallthrough]];
|
||||||
|
#endif
|
||||||
|
case eSessionStateEstablished:
|
||||||
|
return HandleExistingSessionMessage (buf, len, index);
|
||||||
|
case eSessionStateNew:
|
||||||
|
return HandleNewIncomingSession (buf, len);
|
||||||
|
case eSessionStateNewSessionSent:
|
||||||
|
return HandleNewOutgoingSessionReply (buf, len);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
auto m = NewI2NPMessage ();
|
||||||
|
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||||
|
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||||
|
auto payload = CreatePayload (msg);
|
||||||
|
size_t len = payload.size ();
|
||||||
|
|
||||||
|
switch (m_State)
|
||||||
|
{
|
||||||
|
case eSessionStateEstablished:
|
||||||
|
if (!NewExistingSessionMessage (payload.data (), payload.size (), buf, m->maxLen))
|
||||||
|
return nullptr;
|
||||||
|
len += 24;
|
||||||
|
break;
|
||||||
|
case eSessionStateNew:
|
||||||
|
if (!NewOutgoingSessionMessage (payload.data (), payload.size (), buf, m->maxLen))
|
||||||
|
return nullptr;
|
||||||
|
len += 96;
|
||||||
|
break;
|
||||||
|
case eSessionStateNewSessionReceived:
|
||||||
|
if (!NewSessionReplyMessage (payload.data (), payload.size (), buf, m->maxLen))
|
||||||
|
return nullptr;
|
||||||
|
len += 72;
|
||||||
|
break;
|
||||||
|
case eSessionStateNewSessionReplySent:
|
||||||
|
if (!NextNewSessionReplyMessage (payload.data (), payload.size (), buf, m->maxLen))
|
||||||
|
return nullptr;
|
||||||
|
len += 72;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
htobe32buf (m->GetPayload (), len);
|
||||||
|
m->len += len + 4;
|
||||||
|
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
size_t payloadLen = 7; // datatime
|
||||||
|
if (msg && m_Destination)
|
||||||
|
payloadLen += msg->GetPayloadLength () + 13 + 32;
|
||||||
|
auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated) ? CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()) : nullptr;
|
||||||
|
std::shared_ptr<I2NPMessage> deliveryStatus;
|
||||||
|
if (leaseSet)
|
||||||
|
{
|
||||||
|
payloadLen += leaseSet->GetPayloadLength () + 13;
|
||||||
|
deliveryStatus = CreateEncryptedDeliveryStatusMsg (leaseSet->GetMsgID ());
|
||||||
|
payloadLen += deliveryStatus->GetPayloadLength () + 49;
|
||||||
|
if (GetLeaseSetUpdateMsgID ()) GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); // remove previous
|
||||||
|
SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
|
||||||
|
SetLeaseSetUpdateMsgID (leaseSet->GetMsgID ());
|
||||||
|
SetLeaseSetSubmissionTime (ts);
|
||||||
|
GetOwner ()->DeliveryStatusSent (shared_from_this (), leaseSet->GetMsgID ());
|
||||||
|
}
|
||||||
|
if (m_AckRequests.size () > 0)
|
||||||
|
payloadLen += m_AckRequests.size ()*4 + 3;
|
||||||
|
uint8_t paddingSize;
|
||||||
|
RAND_bytes (&paddingSize, 1);
|
||||||
|
paddingSize &= 0x0F; paddingSize++; // 1 - 16
|
||||||
|
payloadLen += paddingSize + 3;
|
||||||
|
std::vector<uint8_t> v(payloadLen);
|
||||||
|
size_t offset = 0;
|
||||||
|
// DateTime
|
||||||
|
v[offset] = eECIESx25519BlkDateTime; offset++;
|
||||||
|
htobe16buf (v.data () + offset, 4); offset += 2;
|
||||||
|
htobe32buf (v.data () + offset, ts/1000); offset += 4; // in seconds
|
||||||
|
// LeaseSet
|
||||||
|
if (leaseSet)
|
||||||
|
offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset);
|
||||||
|
// DeliveryStatus
|
||||||
|
if (deliveryStatus)
|
||||||
|
offset += CreateDeliveryStatusClove (deliveryStatus, v.data () + offset, payloadLen - offset);
|
||||||
|
// msg
|
||||||
|
if (msg && m_Destination)
|
||||||
|
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true);
|
||||||
|
// ack
|
||||||
|
if (m_AckRequests.size () > 0)
|
||||||
|
{
|
||||||
|
v[offset] = eECIESx25519BlkAck; offset++;
|
||||||
|
htobe16buf (v.data () + offset, m_AckRequests.size ()*4); offset += 2;
|
||||||
|
for (auto& it: m_AckRequests)
|
||||||
|
{
|
||||||
|
htobe16buf (v.data () + offset, it.first); offset += 2;
|
||||||
|
htobe16buf (v.data () + offset, it.second); offset += 2;
|
||||||
|
}
|
||||||
|
m_AckRequests.clear ();
|
||||||
|
}
|
||||||
|
// padding
|
||||||
|
v[offset] = eECIESx25519BlkPadding; offset++;
|
||||||
|
htobe16buf (v.data () + offset, paddingSize); offset += 2;
|
||||||
|
memset (v.data () + offset, 0, paddingSize); offset += paddingSize;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ECIESX25519AEADRatchetSession::CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination)
|
||||||
|
{
|
||||||
|
if (!msg) return 0;
|
||||||
|
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1;
|
||||||
|
if (isDestination) cloveSize += 32;
|
||||||
|
if ((int)len < cloveSize + 3) return 0;
|
||||||
|
buf[0] = eECIESx25519BlkGalicClove; // clove type
|
||||||
|
htobe16buf (buf + 1, cloveSize); // size
|
||||||
|
buf += 3;
|
||||||
|
if (isDestination)
|
||||||
|
{
|
||||||
|
*buf = (eGarlicDeliveryTypeDestination << 5);
|
||||||
|
memcpy (buf + 1, *m_Destination, 32); buf += 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buf = 0;
|
||||||
|
buf++; // flag and delivery instructions
|
||||||
|
*buf = msg->GetTypeID (); // I2NP msg type
|
||||||
|
htobe32buf (buf + 1, msg->GetMsgID ()); // msgID
|
||||||
|
htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds
|
||||||
|
memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ());
|
||||||
|
return cloveSize + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ECIESX25519AEADRatchetSession::CreateDeliveryStatusClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 37 /* delivery instruction */;
|
||||||
|
if ((int)len < cloveSize + 3) return 0;
|
||||||
|
buf[0] = eECIESx25519BlkGalicClove; // clove type
|
||||||
|
htobe16buf (buf + 1, cloveSize); // size
|
||||||
|
buf += 3;
|
||||||
|
if (GetOwner ())
|
||||||
|
{
|
||||||
|
auto inboundTunnel = GetOwner ()->GetTunnelPool ()->GetNextInboundTunnel ();
|
||||||
|
if (inboundTunnel)
|
||||||
|
{
|
||||||
|
// delivery instructions
|
||||||
|
*buf = eGarlicDeliveryTypeTunnel << 5; buf++; // delivery instructions flag tunnel
|
||||||
|
// hash and tunnelID sequence is reversed for Garlic
|
||||||
|
memcpy (buf, inboundTunnel->GetNextIdentHash (), 32); buf += 32;// To Hash
|
||||||
|
htobe32buf (buf, inboundTunnel->GetNextTunnelID ()); buf += 4;// tunnelID
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*buf = msg->GetTypeID (); // I2NP msg type
|
||||||
|
htobe32buf (buf + 1, msg->GetMsgID ()); // msgID
|
||||||
|
htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds
|
||||||
|
memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
return cloveSize + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (int numTags)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numTags; i++)
|
||||||
|
{
|
||||||
|
auto index = m_ReceiveTagset.GetNextIndex ();
|
||||||
|
uint64_t tag = m_ReceiveTagset.GetNextSessionTag ();
|
||||||
|
GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
||||||
|
{
|
||||||
|
CleanupUnconfirmedLeaseSet (ts);
|
||||||
|
return ts > m_LastActivityTimestamp + ECIESX25519_EXPIRATION_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||||
|
{
|
||||||
|
auto m = NewI2NPMessage ();
|
||||||
|
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||||
|
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||||
|
uint8_t nonce[12];
|
||||||
|
memset (nonce, 0, 12); // n = 0
|
||||||
|
size_t offset = 0;
|
||||||
|
memcpy (buf + offset, &tag, 8); offset += 8;
|
||||||
|
auto payload = buf + offset;
|
||||||
|
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 1;
|
||||||
|
size_t len = cloveSize + 3;
|
||||||
|
payload[0] = eECIESx25519BlkGalicClove; // clove type
|
||||||
|
htobe16buf (payload + 1, cloveSize); // size
|
||||||
|
payload += 3;
|
||||||
|
*payload = 0; payload++; // flag and delivery instructions
|
||||||
|
*payload = msg->GetTypeID (); // I2NP msg type
|
||||||
|
htobe32buf (payload + 1, msg->GetMsgID ()); // msgID
|
||||||
|
htobe32buf (payload + 5, msg->GetExpiration ()/1000); // expiration in seconds
|
||||||
|
memcpy (payload + 9, msg->GetPayload (), msg->GetPayloadLength ());
|
||||||
|
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len, buf, 8, key, nonce, buf + offset, len + 16, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
offset += len + 16;
|
||||||
|
|
||||||
|
htobe32buf (m->GetPayload (), offset);
|
||||||
|
m->len += offset + 4;
|
||||||
|
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
136
libi2pd/ECIESX25519AEADRatchetSession.h
Normal file
136
libi2pd/ECIESX25519AEADRatchetSession.h
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#ifndef ECIES_X25519_AEAD_RATCHET_SESSION_H__
|
||||||
|
#define ECIES_X25519_AEAD_RATCHET_SESSION_H__
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include "Identity.h"
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "Garlic.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace garlic
|
||||||
|
{
|
||||||
|
class RatchetTagSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
|
||||||
|
void NextSessionTagRatchet ();
|
||||||
|
uint64_t GetNextSessionTag ();
|
||||||
|
int GetNextIndex () const { return m_NextIndex; };
|
||||||
|
void GetSymmKey (int index, uint8_t * key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void CalculateSymmKeyCK (int index, uint8_t * key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint64_t ll[8];
|
||||||
|
uint8_t buf[64];
|
||||||
|
|
||||||
|
const uint8_t * GetSessTagCK () const { return buf; }; // sessTag_chainKey = keydata[0:31]
|
||||||
|
const uint8_t * GetSessTagConstant () const { return buf + 32; }; // SESSTAG_CONSTANT = keydata[32:63]
|
||||||
|
uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39]
|
||||||
|
|
||||||
|
} m_KeyData;
|
||||||
|
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64];
|
||||||
|
int m_NextIndex, m_NextSymmKeyIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ECIESx25519BlockType
|
||||||
|
{
|
||||||
|
eECIESx25519BlkDateTime = 0,
|
||||||
|
eECIESx25519BlkSessionID = 1,
|
||||||
|
eECIESx25519BlkTermination = 4,
|
||||||
|
eECIESx25519BlkOptions = 5,
|
||||||
|
eECIESx25519BlkNextSessionKey = 7,
|
||||||
|
eECIESx25519BlkAck = 8,
|
||||||
|
eECIESx25519BlkAckRequest = 9,
|
||||||
|
eECIESx25519BlkGalicClove = 11,
|
||||||
|
eECIESx25519BlkPadding = 254
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second of inactivity we should restart after
|
||||||
|
const int ECIESX25519_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
|
||||||
|
{
|
||||||
|
enum SessionState
|
||||||
|
{
|
||||||
|
eSessionStateNew =0,
|
||||||
|
eSessionStateNewSessionReceived,
|
||||||
|
eSessionStateNewSessionSent,
|
||||||
|
eSessionStateNewSessionReplySent,
|
||||||
|
eSessionStateEstablished
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetSession (GarlicDestination * owner);
|
||||||
|
~ECIESX25519AEADRatchetSession ();
|
||||||
|
|
||||||
|
bool HandleNextMessage (const uint8_t * buf, size_t len, int index = 0);
|
||||||
|
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
|
||||||
|
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
|
||||||
|
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
||||||
|
|
||||||
|
void SetDestination (const i2p::data::IdentHash& dest) // TODO:
|
||||||
|
{
|
||||||
|
if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckExpired (uint64_t ts); // true is expired
|
||||||
|
bool CanBeRestarted (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_RESTART_TIMEOUT; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void ResetKeys ();
|
||||||
|
void MixHash (const uint8_t * buf, size_t len);
|
||||||
|
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||||
|
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
||||||
|
uint64_t CreateNewSessionTag () const;
|
||||||
|
|
||||||
|
bool HandleNewIncomingSession (const uint8_t * buf, size_t len);
|
||||||
|
bool HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len);
|
||||||
|
bool HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index);
|
||||||
|
void HandlePayload (const uint8_t * buf, size_t len, int index = 0);
|
||||||
|
|
||||||
|
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||||
|
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||||
|
bool NextNewSessionReplyMessage (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);
|
||||||
|
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false);
|
||||||
|
size_t CreateDeliveryStatusClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len);
|
||||||
|
|
||||||
|
void GenerateMoreReceiveTags (int numTags);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
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_NSRHeader[56], m_NSRKey[32]; // new session reply, for incoming only
|
||||||
|
i2p::crypto::X25519Keys m_EphemeralKeys;
|
||||||
|
SessionState m_State = eSessionStateNew;
|
||||||
|
uint64_t m_LastActivityTimestamp = 0; // incoming
|
||||||
|
RatchetTagSet m_SendTagset, m_ReceiveTagset;
|
||||||
|
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::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -31,7 +31,7 @@ namespace crypto
|
|||||||
BN_mod_inverse (tmp, tmp, q, ctx);
|
BN_mod_inverse (tmp, tmp, q, ctx);
|
||||||
BN_set_word (d, 121665);
|
BN_set_word (d, 121665);
|
||||||
BN_set_negative (d, 1);
|
BN_set_negative (d, 1);
|
||||||
BN_mul (d, d, tmp, ctx);
|
BN_mod_mul (d, d, tmp, q, ctx);
|
||||||
|
|
||||||
// 2^((q-1)/4)
|
// 2^((q-1)/4)
|
||||||
I = BN_new ();
|
I = BN_new ();
|
||||||
|
|||||||
207
libi2pd/Elligator.cpp
Normal file
207
libi2pd/Elligator.cpp
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
#include <openssl/rand.h>
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "Elligator.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace crypto
|
||||||
|
{
|
||||||
|
|
||||||
|
Elligator2::Elligator2 ()
|
||||||
|
{
|
||||||
|
// TODO: share with Ed22519
|
||||||
|
p = BN_new ();
|
||||||
|
// 2^255-19
|
||||||
|
BN_set_bit (p, 255); // 2^255
|
||||||
|
BN_sub_word (p, 19);
|
||||||
|
p38 = BN_dup (p); BN_add_word (p38, 3); BN_div_word (p38, 8); // (p+3)/8
|
||||||
|
p12 = BN_dup (p); BN_sub_word (p12, 1); BN_div_word (p12, 2); // (p-1)/2
|
||||||
|
p14 = BN_dup (p); BN_sub_word (p14, 1); BN_div_word (p14, 4); // (p-1)/4
|
||||||
|
|
||||||
|
A = BN_new (); BN_set_word (A, 486662);
|
||||||
|
nA = BN_new (); BN_sub (nA, p, A);
|
||||||
|
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
// calculate sqrt(-1)
|
||||||
|
sqrtn1 = BN_new ();
|
||||||
|
BN_set_word (sqrtn1, 2);
|
||||||
|
BN_mod_exp (sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4
|
||||||
|
|
||||||
|
u = BN_new (); BN_set_word (u, 2);
|
||||||
|
iu = BN_new (); BN_mod_inverse (iu, u, p, ctx);
|
||||||
|
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Elligator2::~Elligator2 ()
|
||||||
|
{
|
||||||
|
BN_free (p); BN_free (p38); BN_free (p12); BN_free (p14);
|
||||||
|
BN_free (sqrtn1); BN_free (A); BN_free (nA);
|
||||||
|
BN_free (u); BN_free (iu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY, bool random) const
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
BN_CTX_start (ctx);
|
||||||
|
|
||||||
|
uint8_t key1[32];
|
||||||
|
for (size_t i = 0; i < 16; i++) // from Little Endian
|
||||||
|
{
|
||||||
|
key1[i] = key[31 - i];
|
||||||
|
key1[31 - i] = key[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
BIGNUM * x = BN_CTX_get (ctx); BN_bin2bn (key1, 32, x);
|
||||||
|
BIGNUM * xA = BN_CTX_get (ctx); BN_add (xA, x, A); // x + A
|
||||||
|
BN_sub (xA, p, xA); // p - (x + A)
|
||||||
|
|
||||||
|
BIGNUM * uxxA = BN_CTX_get (ctx); // u*x*xA
|
||||||
|
BN_mod_mul (uxxA, u, x, p, ctx);
|
||||||
|
BN_mod_mul (uxxA, uxxA, xA, p, ctx);
|
||||||
|
|
||||||
|
if (Legendre (uxxA, ctx) != -1)
|
||||||
|
{
|
||||||
|
uint8_t randByte = 0; // random highest bits and high y
|
||||||
|
if (random)
|
||||||
|
{
|
||||||
|
RAND_bytes (&randByte, 1);
|
||||||
|
highY = randByte & 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
BIGNUM * r = BN_CTX_get (ctx);
|
||||||
|
if (highY)
|
||||||
|
{
|
||||||
|
BN_mod_inverse (r, x, p, ctx);
|
||||||
|
BN_mod_mul (r, r, xA, p, ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BN_mod_inverse (r, xA, p, ctx);
|
||||||
|
BN_mod_mul (r, r, x, p, ctx);
|
||||||
|
}
|
||||||
|
BN_mod_mul (r, r, iu, p, ctx);
|
||||||
|
|
||||||
|
SquareRoot (r, r, ctx);
|
||||||
|
bn2buf (r, encoded, 32);
|
||||||
|
|
||||||
|
if (random)
|
||||||
|
encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte
|
||||||
|
for (size_t i = 0; i < 16; i++) // To Little Endian
|
||||||
|
{
|
||||||
|
uint8_t tmp = encoded[i];
|
||||||
|
encoded[i] = encoded[31 - i];
|
||||||
|
encoded[31 - i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
|
||||||
|
BN_CTX_end (ctx);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Elligator2::Decode (const uint8_t * encoded, uint8_t * key) const
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
BN_CTX_start (ctx);
|
||||||
|
|
||||||
|
uint8_t encoded1[32];
|
||||||
|
for (size_t i = 0; i < 16; i++) // from Little Endian
|
||||||
|
{
|
||||||
|
encoded1[i] = encoded[31 - i];
|
||||||
|
encoded1[31 - i] = encoded[i];
|
||||||
|
}
|
||||||
|
encoded1[0] &= 0x3F; // drop two highest bits
|
||||||
|
|
||||||
|
BIGNUM * r = BN_CTX_get (ctx); BN_bin2bn (encoded1, 32, r);
|
||||||
|
|
||||||
|
if (BN_cmp (r, p12) <= 0) // r < (p-1)/2
|
||||||
|
{
|
||||||
|
// v = -A/(1+u*r^2)
|
||||||
|
BIGNUM * v = BN_CTX_get (ctx); BN_mod_sqr (v, r, p, ctx);
|
||||||
|
BN_mod_mul (v, v, u, p, ctx);
|
||||||
|
BN_add_word (v, 1);
|
||||||
|
BN_mod_inverse (v, v, p, ctx);
|
||||||
|
BN_mod_mul (v, v, nA, p, ctx);
|
||||||
|
|
||||||
|
BIGNUM * vpA = BN_CTX_get (ctx);
|
||||||
|
BN_add (vpA, v, A); // v + A
|
||||||
|
// t = v^3+A*v^2+v = v^2*(v+A)+v
|
||||||
|
BIGNUM * t = BN_CTX_get (ctx); BN_mod_sqr (t, v, p, ctx);
|
||||||
|
BN_mod_mul (t, t, vpA, p, ctx);
|
||||||
|
BN_mod_add (t, t, v, p, ctx);
|
||||||
|
|
||||||
|
int legendre = Legendre (t, ctx);
|
||||||
|
BIGNUM * x = BN_CTX_get (ctx);
|
||||||
|
if (legendre == 1)
|
||||||
|
BN_copy (x, v);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BN_sub (x, p, v);
|
||||||
|
BN_mod_sub (x, x, A, p, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bn2buf (x, key, 32);
|
||||||
|
for (size_t i = 0; i < 16; i++) // To Little Endian
|
||||||
|
{
|
||||||
|
uint8_t tmp = key[i];
|
||||||
|
key[i] = key[31 - i];
|
||||||
|
key[31 - i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
|
||||||
|
BN_CTX_end (ctx);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Elligator2::SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const
|
||||||
|
{
|
||||||
|
BIGNUM * t = BN_CTX_get (ctx);
|
||||||
|
BN_mod_exp (t, x, p14, p, ctx); // t = x^((p-1)/4)
|
||||||
|
BN_mod_exp (r, x, p38, p, ctx); // r = x^((p+3)/8)
|
||||||
|
BN_add_word (t, 1);
|
||||||
|
|
||||||
|
if (!BN_cmp (t, p))
|
||||||
|
BN_mod_mul (r, r, sqrtn1, p, ctx);
|
||||||
|
|
||||||
|
if (BN_cmp (r, p12) > 0) // r > (p-1)/2
|
||||||
|
BN_sub (r, p, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Elligator2::Legendre (const BIGNUM * a, BN_CTX * ctx) const
|
||||||
|
{
|
||||||
|
// assume a < p, so don't check for a % p = 0, but a = 0 only
|
||||||
|
if (BN_is_zero(a)) return 0;
|
||||||
|
BIGNUM * r = BN_CTX_get (ctx);
|
||||||
|
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
|
||||||
|
if (BN_is_word(r, 1))
|
||||||
|
return 1;
|
||||||
|
else if (BN_is_zero(r))
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Elligator2> g_Elligator;
|
||||||
|
std::unique_ptr<Elligator2>& GetElligator ()
|
||||||
|
{
|
||||||
|
if (!g_Elligator)
|
||||||
|
{
|
||||||
|
auto el = new Elligator2();
|
||||||
|
if (!g_Elligator) // make sure it was not created already
|
||||||
|
g_Elligator.reset (el);
|
||||||
|
else
|
||||||
|
delete el;
|
||||||
|
}
|
||||||
|
return g_Elligator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
39
libi2pd/Elligator.h
Normal file
39
libi2pd/Elligator.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef ELLIGATOR_H__
|
||||||
|
#define ELLIGATOR_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace crypto
|
||||||
|
{
|
||||||
|
|
||||||
|
class Elligator2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Elligator2 ();
|
||||||
|
~Elligator2 ();
|
||||||
|
|
||||||
|
bool Encode (const uint8_t * key, uint8_t * encoded, bool highY = false, bool random = true) const;
|
||||||
|
bool Decode (const uint8_t * encoded, uint8_t * key) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const;
|
||||||
|
int Legendre (const BIGNUM * a, BN_CTX * ctx) const; // a/p
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
BIGNUM * p, * p38, * p12, * p14, * sqrtn1, * A, * nA, * u, * iu;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Elligator2>& GetElligator ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#include "Event.h"
|
|
||||||
#include "Log.h"
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace event
|
|
||||||
{
|
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EventCore core;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void EventCore::SetListener(EventListener * l)
|
|
||||||
{
|
|
||||||
m_listener = l;
|
|
||||||
LogPrint(eLogInfo, "Event: listener set");
|
|
||||||
}
|
|
||||||
|
|
||||||
void EventCore::QueueEvent(const EventType & ev)
|
|
||||||
{
|
|
||||||
if(m_listener) m_listener->HandleEvent(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EventCore::CollectEvent(const std::string & type, const std::string & ident, uint64_t val)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_collect_mutex);
|
|
||||||
std::string key = type + "." + ident;
|
|
||||||
if (m_collected.find(key) == m_collected.end())
|
|
||||||
{
|
|
||||||
m_collected[key] = {type, key, 0};
|
|
||||||
}
|
|
||||||
m_collected[key].Val += val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EventCore::PumpCollected(EventListener * listener)
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(m_collect_mutex);
|
|
||||||
if(listener)
|
|
||||||
{
|
|
||||||
for(const auto & ev : m_collected) {
|
|
||||||
listener->HandlePumpEvent({{"type", ev.second.Key}, {"ident", ev.second.Ident}}, ev.second.Val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_collected.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QueueIntEvent(const std::string & type, const std::string & ident, uint64_t val)
|
|
||||||
{
|
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
i2p::event::core.CollectEvent(type, ident, val);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitEvent(const EventType & e)
|
|
||||||
{
|
|
||||||
#if WITH_EVENTS
|
|
||||||
i2p::event::core.QueueEvent(e);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
#ifndef EVENT_H__
|
|
||||||
#define EVENT_H__
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
|
|
||||||
typedef std::map<std::string, std::string> EventType;
|
|
||||||
|
|
||||||
namespace i2p
|
|
||||||
{
|
|
||||||
namespace event
|
|
||||||
{
|
|
||||||
class EventListener {
|
|
||||||
public:
|
|
||||||
virtual ~EventListener() {};
|
|
||||||
virtual void HandleEvent(const EventType & ev) = 0;
|
|
||||||
/** @brief handle collected event when pumped */
|
|
||||||
virtual void HandlePumpEvent(const EventType & ev, const uint64_t & val) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class EventCore
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void QueueEvent(const EventType & ev);
|
|
||||||
void CollectEvent(const std::string & type, const std::string & ident, uint64_t val);
|
|
||||||
void SetListener(EventListener * l);
|
|
||||||
void PumpCollected(EventListener * l);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::mutex m_collect_mutex;
|
|
||||||
struct CollectedEvent
|
|
||||||
{
|
|
||||||
std::string Key;
|
|
||||||
std::string Ident;
|
|
||||||
uint64_t Val;
|
|
||||||
};
|
|
||||||
std::map<std::string, CollectedEvent> m_collected;
|
|
||||||
EventListener * m_listener = nullptr;
|
|
||||||
};
|
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
extern EventCore core;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QueueIntEvent(const std::string & type, const std::string & ident, uint64_t val);
|
|
||||||
void EmitEvent(const EventType & ev);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -11,30 +11,22 @@
|
|||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
#include "Garlic.h"
|
#include "Garlic.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace garlic
|
namespace garlic
|
||||||
{
|
{
|
||||||
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
|
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, bool attachLeaseSet):
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
|
m_Owner (owner), m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
|
||||||
m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
|
|
||||||
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
|
|
||||||
m_LeaseSetUpdateMsgID (0)
|
m_LeaseSetUpdateMsgID (0)
|
||||||
{
|
{
|
||||||
// create new session tags and session key
|
|
||||||
RAND_bytes (m_SessionKey, 32);
|
|
||||||
m_Encryption.SetKey (m_SessionKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
|
GarlicRoutingSession::GarlicRoutingSession ():
|
||||||
m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
|
m_Owner (nullptr), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
|
||||||
{
|
{
|
||||||
memcpy (m_SessionKey, sessionKey, 32);
|
|
||||||
m_Encryption.SetKey (m_SessionKey);
|
|
||||||
m_SessionTags.push_back (sessionTag);
|
|
||||||
m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GarlicRoutingSession::~GarlicRoutingSession ()
|
GarlicRoutingSession::~GarlicRoutingSession ()
|
||||||
@@ -66,88 +58,64 @@ namespace garlic
|
|||||||
m_SharedRoutingPath = path;
|
m_SharedRoutingPath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags ()
|
bool GarlicRoutingSession::MessageConfirmed (uint32_t msgID)
|
||||||
{
|
{
|
||||||
auto tags = new UnconfirmedTags (m_NumTags);
|
if (msgID == GetLeaseSetUpdateMsgID ())
|
||||||
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
for (int i = 0; i < m_NumTags; i++)
|
|
||||||
{
|
{
|
||||||
RAND_bytes (tags->sessionTags[i], 32);
|
SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
|
||||||
tags->sessionTags[i].creationTime = tags->tagsCreationTime;
|
SetLeaseSetUpdateMsgID (0);
|
||||||
}
|
|
||||||
return tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GarlicRoutingSession::MessageConfirmed (uint32_t msgID)
|
|
||||||
{
|
|
||||||
TagsConfirmed (msgID);
|
|
||||||
if (msgID == m_LeaseSetUpdateMsgID)
|
|
||||||
{
|
|
||||||
m_LeaseSetUpdateStatus = eLeaseSetUpToDate;
|
|
||||||
m_LeaseSetUpdateMsgID = 0;
|
|
||||||
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
|
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
return false;
|
||||||
CleanupExpiredTags ();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void GarlicRoutingSession::TagsConfirmed (uint32_t msgID)
|
void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts)
|
||||||
{
|
{
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
auto it = m_UnconfirmedTagsMsgs.find (msgID);
|
|
||||||
if (it != m_UnconfirmedTagsMsgs.end ())
|
|
||||||
{
|
|
||||||
auto& tags = it->second;
|
|
||||||
if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < tags->numTags; i++)
|
|
||||||
m_SessionTags.push_back (tags->sessionTags[i]);
|
|
||||||
}
|
|
||||||
m_UnconfirmedTagsMsgs.erase (it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GarlicRoutingSession::CleanupExpiredTags ()
|
|
||||||
{
|
|
||||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
for (auto it = m_SessionTags.begin (); it != m_SessionTags.end ();)
|
|
||||||
{
|
|
||||||
if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
|
|
||||||
it = m_SessionTags.erase (it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
CleanupUnconfirmedTags ();
|
|
||||||
if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
|
if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
if (m_Owner)
|
if (GetOwner ())
|
||||||
m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
|
GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
|
||||||
m_LeaseSetUpdateMsgID = 0;
|
m_LeaseSetUpdateMsgID = 0;
|
||||||
}
|
}
|
||||||
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
|
}
|
||||||
}
|
|
||||||
|
std::shared_ptr<I2NPMessage> GarlicRoutingSession::CreateEncryptedDeliveryStatusMsg (uint32_t msgID)
|
||||||
bool GarlicRoutingSession::CleanupUnconfirmedTags ()
|
|
||||||
{
|
{
|
||||||
bool ret = false;
|
auto msg = CreateDeliveryStatusMsg (msgID);
|
||||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
if (GetOwner ())
|
||||||
// delete expired unconfirmed tags
|
|
||||||
for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();)
|
|
||||||
{
|
{
|
||||||
if (ts >= it->second->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT)
|
//encrypt
|
||||||
{
|
uint8_t key[32], tag[32];
|
||||||
if (m_Owner)
|
RAND_bytes (key, 32); // random session key
|
||||||
m_Owner->RemoveDeliveryStatusSession (it->first);
|
RAND_bytes (tag, 32); // random session tag
|
||||||
it = m_UnconfirmedTagsMsgs.erase (it);
|
GetOwner ()->SubmitSessionKey (key, tag);
|
||||||
ret = true;
|
ElGamalAESSession garlic (key, tag);
|
||||||
}
|
msg = garlic.WrapSingleMessage (msg);
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner,
|
||||||
|
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
|
||||||
|
GarlicRoutingSession (owner, attachLeaseSet),
|
||||||
|
m_Destination (destination), m_NumTags (numTags)
|
||||||
|
{
|
||||||
|
// create new session tags and session key
|
||||||
|
RAND_bytes (m_SessionKey, 32);
|
||||||
|
m_Encryption.SetKey (m_SessionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> GarlicRoutingSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
|
ElGamalAESSession::ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
|
||||||
|
m_NumTags(1)
|
||||||
|
{
|
||||||
|
memcpy (m_SessionKey, sessionKey, 32);
|
||||||
|
m_Encryption.SetKey (m_SessionKey);
|
||||||
|
m_SessionTags.push_back (sessionTag);
|
||||||
|
m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<I2NPMessage> ElGamalAESSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
auto m = NewI2NPMessage ();
|
auto m = NewI2NPMessage ();
|
||||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||||
@@ -213,10 +181,10 @@ namespace garlic
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg)
|
size_t ElGamalAESSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
size_t blockSize = 0;
|
size_t blockSize = 0;
|
||||||
bool createNewTags = m_Owner && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3);
|
bool createNewTags = GetOwner () && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3);
|
||||||
UnconfirmedTags * newTags = createNewTags ? GenerateSessionTags () : nullptr;
|
UnconfirmedTags * newTags = createNewTags ? GenerateSessionTags () : nullptr;
|
||||||
htobuf16 (buf, newTags ? htobe16 (newTags->numTags) : 0); // tag count
|
htobuf16 (buf, newTags ? htobe16 (newTags->numTags) : 0); // tag count
|
||||||
blockSize += 2;
|
blockSize += 2;
|
||||||
@@ -245,7 +213,7 @@ namespace garlic
|
|||||||
return blockSize;
|
return blockSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags)
|
size_t ElGamalAESSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags)
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
uint32_t msgID;
|
uint32_t msgID;
|
||||||
@@ -255,17 +223,17 @@ namespace garlic
|
|||||||
*numCloves = 0;
|
*numCloves = 0;
|
||||||
size++;
|
size++;
|
||||||
|
|
||||||
if (m_Owner)
|
if (GetOwner ())
|
||||||
{
|
{
|
||||||
// resubmit non-confirmed LeaseSet
|
// resubmit non-confirmed LeaseSet
|
||||||
if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
|
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
|
||||||
{
|
{
|
||||||
m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
SetLeaseSetUpdateStatus (eLeaseSetUpdated);
|
||||||
SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed
|
SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach DeviveryStatus if necessary
|
// attach DeviveryStatus if necessary
|
||||||
if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated
|
if (newTags || GetLeaseSetUpdateStatus () == eLeaseSetUpdated) // new tags created or leaseset updated
|
||||||
{
|
{
|
||||||
// clove is DeliveryStatus
|
// clove is DeliveryStatus
|
||||||
auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID);
|
auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID);
|
||||||
@@ -279,20 +247,20 @@ namespace garlic
|
|||||||
m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags)));
|
m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags)));
|
||||||
newTags = nullptr; // got acquired
|
newTags = nullptr; // got acquired
|
||||||
}
|
}
|
||||||
m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
|
GetOwner ()->DeliveryStatusSent (shared_from_this (), msgID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
|
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
|
||||||
}
|
}
|
||||||
// attach LeaseSet
|
// attach LeaseSet
|
||||||
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
|
if (GetLeaseSetUpdateStatus () == eLeaseSetUpdated)
|
||||||
{
|
{
|
||||||
if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous
|
if (GetLeaseSetUpdateMsgID ()) GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); // remove previous
|
||||||
m_LeaseSetUpdateStatus = eLeaseSetSubmitted;
|
SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
|
||||||
m_LeaseSetUpdateMsgID = msgID;
|
SetLeaseSetUpdateMsgID (msgID);
|
||||||
m_LeaseSetSubmissionTime = ts;
|
SetLeaseSetSubmissionTime (ts);
|
||||||
// clove if our leaseSet must be attached
|
// clove if our leaseSet must be attached
|
||||||
auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ());
|
auto leaseSet = CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ());
|
||||||
size += CreateGarlicClove (payload + size, leaseSet, false);
|
size += CreateGarlicClove (payload + size, leaseSet, false);
|
||||||
(*numCloves)++;
|
(*numCloves)++;
|
||||||
}
|
}
|
||||||
@@ -313,7 +281,7 @@ namespace garlic
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination)
|
size_t ElGamalAESSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination)
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@@ -343,12 +311,12 @@ namespace garlic
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID)
|
size_t ElGamalAESSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
if (m_Owner)
|
if (GetOwner ())
|
||||||
{
|
{
|
||||||
auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel ();
|
auto inboundTunnel = GetOwner ()->GetTunnelPool ()->GetNextInboundTunnel ();
|
||||||
if (inboundTunnel)
|
if (inboundTunnel)
|
||||||
{
|
{
|
||||||
buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel
|
buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel
|
||||||
@@ -359,19 +327,12 @@ namespace garlic
|
|||||||
htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
|
htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
|
||||||
size += 4;
|
size += 4;
|
||||||
// create msg
|
// create msg
|
||||||
auto msg = CreateDeliveryStatusMsg (msgID);
|
auto msg = CreateEncryptedDeliveryStatusMsg (msgID);
|
||||||
if (m_Owner)
|
if (msg)
|
||||||
{
|
{
|
||||||
//encrypt
|
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
|
||||||
uint8_t key[32], tag[32];
|
size += msg->GetLength ();
|
||||||
RAND_bytes (key, 32); // random session key
|
}
|
||||||
RAND_bytes (tag, 32); // random session tag
|
|
||||||
m_Owner->SubmitSessionKey (key, tag);
|
|
||||||
GarlicRoutingSession garlic (key, tag);
|
|
||||||
msg = garlic.WrapSingleMessage (msg);
|
|
||||||
}
|
|
||||||
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
|
|
||||||
size += msg->GetLength ();
|
|
||||||
// fill clove
|
// fill clove
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
|
||||||
uint32_t cloveID;
|
uint32_t cloveID;
|
||||||
@@ -392,6 +353,77 @@ namespace garlic
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ElGamalAESSession::UnconfirmedTags * ElGamalAESSession::GenerateSessionTags ()
|
||||||
|
{
|
||||||
|
auto tags = new UnconfirmedTags (m_NumTags);
|
||||||
|
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
for (int i = 0; i < m_NumTags; i++)
|
||||||
|
{
|
||||||
|
RAND_bytes (tags->sessionTags[i], 32);
|
||||||
|
tags->sessionTags[i].creationTime = tags->tagsCreationTime;
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElGamalAESSession::MessageConfirmed (uint32_t msgID)
|
||||||
|
{
|
||||||
|
TagsConfirmed (msgID);
|
||||||
|
if (!GarlicRoutingSession::MessageConfirmed (msgID))
|
||||||
|
CleanupExpiredTags ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ElGamalAESSession::TagsConfirmed (uint32_t msgID)
|
||||||
|
{
|
||||||
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
auto it = m_UnconfirmedTagsMsgs.find (msgID);
|
||||||
|
if (it != m_UnconfirmedTagsMsgs.end ())
|
||||||
|
{
|
||||||
|
auto& tags = it->second;
|
||||||
|
if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tags->numTags; i++)
|
||||||
|
m_SessionTags.push_back (tags->sessionTags[i]);
|
||||||
|
}
|
||||||
|
m_UnconfirmedTagsMsgs.erase (it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElGamalAESSession::CleanupExpiredTags ()
|
||||||
|
{
|
||||||
|
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
for (auto it = m_SessionTags.begin (); it != m_SessionTags.end ();)
|
||||||
|
{
|
||||||
|
if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
|
||||||
|
it = m_SessionTags.erase (it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
CleanupUnconfirmedTags ();
|
||||||
|
CleanupUnconfirmedLeaseSet (ts);
|
||||||
|
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ElGamalAESSession::CleanupUnconfirmedTags ()
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
// delete expired unconfirmed tags
|
||||||
|
for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();)
|
||||||
|
{
|
||||||
|
if (ts >= it->second->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT)
|
||||||
|
{
|
||||||
|
if (GetOwner ())
|
||||||
|
GetOwner ()->RemoveDeliveryStatusSession (it->first);
|
||||||
|
it = m_UnconfirmedTagsMsgs.erase (it);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default
|
GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default
|
||||||
{
|
{
|
||||||
m_Ctx = BN_CTX_new ();
|
m_Ctx = BN_CTX_new ();
|
||||||
@@ -407,6 +439,8 @@ namespace garlic
|
|||||||
m_Sessions.clear ();
|
m_Sessions.clear ();
|
||||||
m_DeliveryStatusSessions.clear ();
|
m_DeliveryStatusSessions.clear ();
|
||||||
m_Tags.clear ();
|
m_Tags.clear ();
|
||||||
|
m_ECIESx25519Sessions.clear ();
|
||||||
|
m_ECIESx25519Tags.clear ();
|
||||||
}
|
}
|
||||||
void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
|
void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
|
||||||
{
|
{
|
||||||
@@ -434,6 +468,7 @@ namespace garlic
|
|||||||
}
|
}
|
||||||
buf += 4; // length
|
buf += 4; // length
|
||||||
auto it = m_Tags.find (SessionTag(buf));
|
auto it = m_Tags.find (SessionTag(buf));
|
||||||
|
// AES tag might be used even if encryption type is not ElGamal/AES
|
||||||
if (it != m_Tags.end ())
|
if (it != m_Tags.end ())
|
||||||
{
|
{
|
||||||
// tag found. Use AES
|
// tag found. Use AES
|
||||||
@@ -452,9 +487,15 @@ namespace garlic
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// tag not found. Use ElGamal
|
// tag not found. Handle depending on encryption type
|
||||||
|
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET))
|
||||||
|
{
|
||||||
|
HandleECIESx25519 (buf, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// otherwise assume ElGamal/AES
|
||||||
ElGamalBlock elGamal;
|
ElGamalBlock elGamal;
|
||||||
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
|
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL))
|
||||||
{
|
{
|
||||||
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
|
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
|
||||||
uint8_t iv[32]; // IV is first 16 bytes
|
uint8_t iv[32]; // IV is first 16 bytes
|
||||||
@@ -543,7 +584,7 @@ namespace garlic
|
|||||||
LogPrint (eLogError, "Garlic: message is too short");
|
LogPrint (eLogError, "Garlic: message is too short");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HandleI2NPMessage (buf, len - offset, from);
|
HandleI2NPMessage (buf, len - offset);
|
||||||
break;
|
break;
|
||||||
case eGarlicDeliveryTypeDestination:
|
case eGarlicDeliveryTypeDestination:
|
||||||
LogPrint (eLogDebug, "Garlic: type destination");
|
LogPrint (eLogDebug, "Garlic: type destination");
|
||||||
@@ -554,7 +595,7 @@ namespace garlic
|
|||||||
LogPrint (eLogError, "Garlic: message is too short");
|
LogPrint (eLogError, "Garlic: message is too short");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HandleI2NPMessage (buf, len - offset, from);
|
HandleI2NPMessage (buf, len - offset);
|
||||||
break;
|
break;
|
||||||
case eGarlicDeliveryTypeTunnel:
|
case eGarlicDeliveryTypeTunnel:
|
||||||
{
|
{
|
||||||
@@ -638,21 +679,41 @@ namespace garlic
|
|||||||
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
||||||
{
|
{
|
||||||
GarlicRoutingSessionPtr session;
|
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET &&
|
||||||
{
|
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET))
|
||||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
{
|
||||||
auto it = m_Sessions.find (destination->GetIdentHash ());
|
ECIESX25519AEADRatchetSessionPtr session;
|
||||||
if (it != m_Sessions.end ())
|
uint8_t staticKey[32];
|
||||||
session = it->second;
|
destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key
|
||||||
}
|
auto it = m_ECIESx25519Sessions.find (staticKey);
|
||||||
if (!session)
|
if (it != m_ECIESx25519Sessions.end ())
|
||||||
{
|
session = it->second;
|
||||||
session = std::make_shared<GarlicRoutingSession> (this, destination,
|
if (!session)
|
||||||
attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests
|
{
|
||||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
session = std::make_shared<ECIESX25519AEADRatchetSession> (this);
|
||||||
m_Sessions[destination->GetIdentHash ()] = session;
|
session->SetRemoteStaticKey (staticKey);
|
||||||
}
|
}
|
||||||
return session;
|
session->SetDestination (destination->GetIdentHash ()); // TODO: remove
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ElGamalAESSessionPtr session;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||||
|
auto it = m_Sessions.find (destination->GetIdentHash ());
|
||||||
|
if (it != m_Sessions.end ())
|
||||||
|
session = it->second;
|
||||||
|
}
|
||||||
|
if (!session)
|
||||||
|
{
|
||||||
|
session = std::make_shared<ElGamalAESSession> (this, destination,
|
||||||
|
attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests
|
||||||
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||||
|
m_Sessions[destination->GetIdentHash ()] = session;
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::CleanupExpiredTags ()
|
void GarlicDestination::CleanupExpiredTags ()
|
||||||
@@ -700,6 +761,25 @@ namespace garlic
|
|||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ECIESx25519
|
||||||
|
for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();)
|
||||||
|
{
|
||||||
|
if (ts > it->second.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
||||||
|
it = m_ECIESx25519Tags.erase (it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = m_ECIESx25519Sessions.begin (); it != m_ECIESx25519Sessions.end ();)
|
||||||
|
{
|
||||||
|
if (it->second->CheckExpired (ts))
|
||||||
|
{
|
||||||
|
it->second->SetOwner (nullptr);
|
||||||
|
it = m_ECIESx25519Sessions.erase (it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID)
|
void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID)
|
||||||
@@ -714,9 +794,8 @@ namespace garlic
|
|||||||
m_DeliveryStatusSessions[msgID] = session;
|
m_DeliveryStatusSessions[msgID] = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void GarlicDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||||
{
|
{
|
||||||
uint32_t msgID = bufbe32toh (msg->GetPayload ());
|
|
||||||
GarlicRoutingSessionPtr session;
|
GarlicRoutingSessionPtr session;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
||||||
@@ -736,8 +815,12 @@ namespace garlic
|
|||||||
|
|
||||||
void GarlicDestination::SetLeaseSetUpdated ()
|
void GarlicDestination::SetLeaseSetUpdated ()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
{
|
||||||
for (auto& it: m_Sessions)
|
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||||
|
for (auto& it: m_Sessions)
|
||||||
|
it.second->SetLeaseSetUpdated ();
|
||||||
|
}
|
||||||
|
for (auto& it: m_ECIESx25519Sessions)
|
||||||
it.second->SetLeaseSetUpdated ();
|
it.second->SetLeaseSetUpdated ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,7 +831,8 @@ namespace garlic
|
|||||||
|
|
||||||
void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
HandleDeliveryStatusMessage (msg);
|
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||||
|
HandleDeliveryStatusMessage (msgID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::SaveTags ()
|
void GarlicDestination::SaveTags ()
|
||||||
@@ -806,7 +890,7 @@ namespace garlic
|
|||||||
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
|
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
|
||||||
}
|
}
|
||||||
if (!m_Tags.empty ())
|
if (!m_Tags.empty ())
|
||||||
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
|
LogPrint (eLogInfo, "Garlic: ", m_Tags.size (), " tags loaded for ", ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i2p::fs::Remove (path);
|
i2p::fs::Remove (path);
|
||||||
@@ -821,5 +905,107 @@ namespace garlic
|
|||||||
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
||||||
i2p::fs::Remove (it);
|
i2p::fs::Remove (it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
uint64_t tag;
|
||||||
|
memcpy (&tag, buf, 8);
|
||||||
|
ECIESX25519AEADRatchetSessionPtr session;
|
||||||
|
int index = 0;
|
||||||
|
auto it = m_ECIESx25519Tags.find (tag);
|
||||||
|
if (it != m_ECIESx25519Tags.end ())
|
||||||
|
{
|
||||||
|
session = it->second.session;
|
||||||
|
index = it->second.index;
|
||||||
|
m_ECIESx25519Tags.erase (tag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
session = std::make_shared<ECIESX25519AEADRatchetSession> (this); // incoming
|
||||||
|
|
||||||
|
if (!session->HandleNextMessage (buf, len, index))
|
||||||
|
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
const uint8_t * buf1 = buf;
|
||||||
|
uint8_t flag = buf[0]; buf++; // flag
|
||||||
|
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
|
||||||
|
switch (deliveryType)
|
||||||
|
{
|
||||||
|
case eGarlicDeliveryTypeDestination:
|
||||||
|
LogPrint (eLogDebug, "Garlic: type destination");
|
||||||
|
buf += 32; // TODO: check destination
|
||||||
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
[[fallthrough]];
|
||||||
|
#endif
|
||||||
|
// no break here
|
||||||
|
case eGarlicDeliveryTypeLocal:
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Garlic: type local");
|
||||||
|
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
|
||||||
|
buf += (4 + 4); // msgID + expiration
|
||||||
|
ptrdiff_t offset = buf - buf1;
|
||||||
|
if (offset <= (int)len)
|
||||||
|
HandleCloveI2NPMessage (typeID, buf, len - offset);
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Garlic: clove is too long");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eGarlicDeliveryTypeTunnel:
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Garlic: type tunnel");
|
||||||
|
// gwHash and gwTunnel sequence is reverted
|
||||||
|
const uint8_t * gwHash = buf;
|
||||||
|
buf += 32;
|
||||||
|
ptrdiff_t offset = buf - buf1;
|
||||||
|
if (offset + 13 > (int)len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: message is too short");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint32_t gwTunnel = bufbe32toh (buf); buf += 4;
|
||||||
|
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
|
||||||
|
buf += (4 + 4); // msgID + expiration
|
||||||
|
offset += 13;
|
||||||
|
if (GetTunnelPool ())
|
||||||
|
{
|
||||||
|
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||||
|
if (tunnel)
|
||||||
|
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset));
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GarlicDestination::AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session)
|
||||||
|
{
|
||||||
|
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexSession{index, session, i2p::util::GetSecondsSinceEpoch ()});
|
||||||
|
}
|
||||||
|
|
||||||
|
void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session)
|
||||||
|
{
|
||||||
|
i2p::data::Tag<32> staticKeyTag (staticKey);
|
||||||
|
auto it = m_ECIESx25519Sessions.find (staticKeyTag);
|
||||||
|
if (it != m_ECIESx25519Sessions.end ())
|
||||||
|
{
|
||||||
|
if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ()))
|
||||||
|
m_ECIESx25519Sessions.erase (it);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_ECIESx25519Sessions.emplace (staticKeyTag, session);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
146
libi2pd/Garlic.h
146
libi2pd/Garlic.h
@@ -2,7 +2,7 @@
|
|||||||
#define GARLIC_H__
|
#define GARLIC_H__
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -85,8 +85,10 @@ namespace garlic
|
|||||||
};
|
};
|
||||||
|
|
||||||
class GarlicDestination;
|
class GarlicDestination;
|
||||||
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
|
class GarlicRoutingSession
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
enum LeaseSetUpdateStatus
|
enum LeaseSetUpdateStatus
|
||||||
{
|
{
|
||||||
eLeaseSetUpToDate = 0,
|
eLeaseSetUpToDate = 0,
|
||||||
@@ -95,7 +97,60 @@ namespace garlic
|
|||||||
eLeaseSetDoNotSend
|
eLeaseSetDoNotSend
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UnconfirmedTags
|
public:
|
||||||
|
|
||||||
|
GarlicRoutingSession (GarlicDestination * owner, bool attachLeaseSet);
|
||||||
|
GarlicRoutingSession ();
|
||||||
|
virtual ~GarlicRoutingSession ();
|
||||||
|
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
|
||||||
|
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
||||||
|
virtual bool MessageConfirmed (uint32_t msgID);
|
||||||
|
|
||||||
|
void SetLeaseSetUpdated ()
|
||||||
|
{
|
||||||
|
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
||||||
|
};
|
||||||
|
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
|
||||||
|
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
|
||||||
|
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
|
||||||
|
void CleanupUnconfirmedLeaseSet (uint64_t ts);
|
||||||
|
|
||||||
|
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
|
||||||
|
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
|
||||||
|
|
||||||
|
GarlicDestination * GetOwner () const { return m_Owner; }
|
||||||
|
void SetOwner (GarlicDestination * owner) { m_Owner = owner; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
LeaseSetUpdateStatus GetLeaseSetUpdateStatus () const { return m_LeaseSetUpdateStatus; }
|
||||||
|
void SetLeaseSetUpdateStatus (LeaseSetUpdateStatus status) { m_LeaseSetUpdateStatus = status; }
|
||||||
|
uint32_t GetLeaseSetUpdateMsgID () const { return m_LeaseSetUpdateMsgID; }
|
||||||
|
void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; }
|
||||||
|
void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; }
|
||||||
|
|
||||||
|
std::shared_ptr<I2NPMessage> CreateEncryptedDeliveryStatusMsg (uint32_t msgID);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
GarlicDestination * m_Owner;
|
||||||
|
|
||||||
|
LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
|
||||||
|
uint32_t m_LeaseSetUpdateMsgID;
|
||||||
|
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
||||||
|
|
||||||
|
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// for HTTP only
|
||||||
|
virtual size_t GetNumOutgoingTags () const { return 0; };
|
||||||
|
};
|
||||||
|
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
|
||||||
|
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
|
||||||
|
|
||||||
|
class ElGamalAESSession: public GarlicRoutingSession, public std::enable_shared_from_this<ElGamalAESSession>
|
||||||
|
{
|
||||||
|
struct UnconfirmedTags
|
||||||
{
|
{
|
||||||
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
|
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
|
||||||
~UnconfirmedTags () { delete[] sessionTags; };
|
~UnconfirmedTags () { delete[] sessionTags; };
|
||||||
@@ -105,32 +160,20 @@ namespace garlic
|
|||||||
uint32_t tagsCreationTime;
|
uint32_t tagsCreationTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
ElGamalAESSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||||
int numTags, bool attachLeaseSet);
|
int numTags, bool attachLeaseSet);
|
||||||
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
|
ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
|
||||||
~GarlicRoutingSession ();
|
~ElGamalAESSession () {};
|
||||||
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
|
||||||
void MessageConfirmed (uint32_t msgID);
|
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
|
||||||
|
bool MessageConfirmed (uint32_t msgID);
|
||||||
bool CleanupExpiredTags (); // returns true if something left
|
bool CleanupExpiredTags (); // returns true if something left
|
||||||
bool CleanupUnconfirmedTags (); // returns true if something has been deleted
|
bool CleanupUnconfirmedTags (); // returns true if something has been deleted
|
||||||
|
|
||||||
void SetLeaseSetUpdated ()
|
private:
|
||||||
{
|
|
||||||
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
|
||||||
};
|
|
||||||
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
|
|
||||||
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
|
|
||||||
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
|
|
||||||
|
|
||||||
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
|
|
||||||
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
|
|
||||||
|
|
||||||
const GarlicDestination * GetOwner () const { return m_Owner; }
|
|
||||||
void SetOwner (GarlicDestination * owner) { m_Owner = owner; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
size_t CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg);
|
size_t CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg);
|
||||||
size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags);
|
size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags);
|
||||||
@@ -139,31 +182,32 @@ namespace garlic
|
|||||||
|
|
||||||
void TagsConfirmed (uint32_t msgID);
|
void TagsConfirmed (uint32_t msgID);
|
||||||
UnconfirmedTags * GenerateSessionTags ();
|
UnconfirmedTags * GenerateSessionTags ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
||||||
|
|
||||||
private:
|
i2p::crypto::AESKey m_SessionKey;
|
||||||
|
|
||||||
GarlicDestination * m_Owner;
|
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
|
||||||
|
|
||||||
i2p::crypto::AESKey m_SessionKey;
|
|
||||||
std::list<SessionTag> m_SessionTags;
|
std::list<SessionTag> m_SessionTags;
|
||||||
int m_NumTags;
|
int m_NumTags;
|
||||||
std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags
|
std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags
|
||||||
|
|
||||||
LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
|
i2p::crypto::CBCEncryption m_Encryption;
|
||||||
uint32_t m_LeaseSetUpdateMsgID;
|
|
||||||
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
|
||||||
|
|
||||||
i2p::crypto::CBCEncryption m_Encryption;
|
public:
|
||||||
|
|
||||||
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// for HTTP only
|
// for HTTP only
|
||||||
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
|
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
|
||||||
|
};
|
||||||
|
typedef std::shared_ptr<ElGamalAESSession> ElGamalAESSessionPtr;
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetSession;
|
||||||
|
typedef std::shared_ptr<ECIESX25519AEADRatchetSession> ECIESX25519AEADRatchetSessionPtr;
|
||||||
|
struct ECIESX25519AEADRatchetIndexSession
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
ECIESX25519AEADRatchetSessionPtr session;
|
||||||
|
uint64_t creationTime; // seconds since epoch
|
||||||
};
|
};
|
||||||
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
|
|
||||||
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
|
|
||||||
|
|
||||||
class GarlicDestination: public i2p::data::LocalDestination
|
class GarlicDestination: public i2p::data::LocalDestination
|
||||||
{
|
{
|
||||||
@@ -174,6 +218,7 @@ 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; };
|
||||||
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);
|
||||||
@@ -183,6 +228,9 @@ namespace garlic
|
|||||||
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
||||||
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
|
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
|
||||||
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
|
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
|
||||||
|
void AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session);
|
||||||
|
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);
|
||||||
|
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
@@ -190,12 +238,13 @@ namespace garlic
|
|||||||
|
|
||||||
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
||||||
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
||||||
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only
|
||||||
|
virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) = 0;
|
||||||
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (uint32_t msgID);
|
||||||
|
|
||||||
void SaveTags ();
|
void SaveTags ();
|
||||||
void LoadTags ();
|
void LoadTags ();
|
||||||
@@ -206,18 +255,23 @@ namespace garlic
|
|||||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
|
|
||||||
|
// ECIES-X25519-AEAD-Ratchet
|
||||||
|
void HandleECIESx25519 (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
BN_CTX * m_Ctx; // incoming
|
BN_CTX * m_Ctx; // incoming
|
||||||
// outgoing sessions
|
// outgoing sessions
|
||||||
int m_NumTags;
|
int m_NumTags;
|
||||||
std::mutex m_SessionsMutex;
|
std::mutex m_SessionsMutex;
|
||||||
std::map<i2p::data::IdentHash, GarlicRoutingSessionPtr> m_Sessions;
|
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
||||||
|
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
||||||
// incoming
|
// incoming
|
||||||
std::map<SessionTag, std::shared_ptr<AESDecryption> > m_Tags;
|
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
||||||
|
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexSession> m_ECIESx25519Tags; // session tag -> session
|
||||||
// DeliveryStatus
|
// DeliveryStatus
|
||||||
std::mutex m_DeliveryStatusSessionsMutex;
|
std::mutex m_DeliveryStatusSessionsMutex;
|
||||||
std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
@@ -258,12 +258,12 @@ namespace i2p
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
|
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (const i2p::data::IdentHash& storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
|
||||||
{
|
{
|
||||||
if (!leaseSet) return nullptr;
|
if (!leaseSet) return nullptr;
|
||||||
auto m = NewI2NPShortMessage ();
|
auto m = NewI2NPShortMessage ();
|
||||||
uint8_t * payload = m->GetPayload ();
|
uint8_t * payload = m->GetPayload ();
|
||||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
|
memcpy (payload + DATABASE_STORE_KEY_OFFSET, storeHash, 32);
|
||||||
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // 1 for LeaseSet
|
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // 1 for LeaseSet
|
||||||
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
|
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
|
||||||
size_t size = DATABASE_STORE_HEADER_SIZE;
|
size_t size = DATABASE_STORE_HEADER_SIZE;
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ namespace i2p
|
|||||||
// DatabaseLookup flags
|
// DatabaseLookup flags
|
||||||
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
|
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
|
||||||
const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02;
|
const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02;
|
||||||
|
const uint8_t DATABASE_LOOKUP_ECIES_FLAG = 0x10;
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
|
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
|
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
|
||||||
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
|
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
|
||||||
@@ -247,7 +248,7 @@ namespace tunnel
|
|||||||
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
|
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
|
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (const i2p::data::IdentHash& storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
|
||||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
|
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
|
||||||
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
|
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,11 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdentityEx::IdentityEx ():
|
IdentityEx::IdentityEx ():
|
||||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType):
|
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
||||||
m_IsVerifierCreated (false)
|
|
||||||
{
|
{
|
||||||
memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of
|
memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of
|
||||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
@@ -141,19 +140,19 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdentityEx::IdentityEx (const uint8_t * buf, size_t len):
|
IdentityEx::IdentityEx (const uint8_t * buf, size_t len):
|
||||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||||
{
|
{
|
||||||
FromBuffer (buf, len);
|
FromBuffer (buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityEx::IdentityEx (const IdentityEx& other):
|
IdentityEx::IdentityEx (const IdentityEx& other):
|
||||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityEx::IdentityEx (const Identity& standard):
|
IdentityEx::IdentityEx (const Identity& standard):
|
||||||
m_IsVerifierCreated (false), m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||||
{
|
{
|
||||||
*this = standard;
|
*this = standard;
|
||||||
}
|
}
|
||||||
@@ -161,6 +160,7 @@ namespace data
|
|||||||
IdentityEx::~IdentityEx ()
|
IdentityEx::~IdentityEx ()
|
||||||
{
|
{
|
||||||
delete[] m_ExtendedBuffer;
|
delete[] m_ExtendedBuffer;
|
||||||
|
delete m_Verifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
IdentityEx& IdentityEx::operator=(const IdentityEx& other)
|
IdentityEx& IdentityEx::operator=(const IdentityEx& other)
|
||||||
@@ -178,8 +178,8 @@ namespace data
|
|||||||
else
|
else
|
||||||
m_ExtendedBuffer = nullptr;
|
m_ExtendedBuffer = nullptr;
|
||||||
|
|
||||||
|
delete m_Verifier;
|
||||||
m_Verifier = nullptr;
|
m_Verifier = nullptr;
|
||||||
m_IsVerifierCreated = false;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -193,8 +193,8 @@ namespace data
|
|||||||
m_ExtendedBuffer = nullptr;
|
m_ExtendedBuffer = nullptr;
|
||||||
m_ExtendedLen = 0;
|
m_ExtendedLen = 0;
|
||||||
|
|
||||||
|
delete m_Verifier;
|
||||||
m_Verifier = nullptr;
|
m_Verifier = nullptr;
|
||||||
m_IsVerifierCreated = false;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -233,6 +233,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
SHA256(buf, GetFullLen (), m_IdentHash);
|
SHA256(buf, GetFullLen (), m_IdentHash);
|
||||||
|
|
||||||
|
delete m_Verifier;
|
||||||
m_Verifier = nullptr;
|
m_Verifier = nullptr;
|
||||||
|
|
||||||
return GetFullLen ();
|
return GetFullLen ();
|
||||||
@@ -381,33 +382,27 @@ namespace data
|
|||||||
|
|
||||||
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
||||||
{
|
{
|
||||||
if (!m_Verifier)
|
bool del = false;
|
||||||
{
|
{
|
||||||
auto created = m_IsVerifierCreated.exchange (true);
|
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||||
if (!created)
|
if (!m_Verifier)
|
||||||
m_Verifier.reset (verifier);
|
m_Verifier = verifier;
|
||||||
else
|
else
|
||||||
{
|
del = true;
|
||||||
delete verifier;
|
|
||||||
int count = 0;
|
|
||||||
while (!m_Verifier && count < 500) // 5 seconds
|
|
||||||
{
|
|
||||||
std::this_thread::sleep_for (std::chrono::milliseconds(10));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
if (!m_Verifier)
|
|
||||||
LogPrint (eLogError, "Identity: couldn't get verifier in 5 seconds");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
if (del)
|
||||||
delete verifier;
|
delete verifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IdentityEx::DropVerifier () const
|
void IdentityEx::DropVerifier () const
|
||||||
{
|
{
|
||||||
// TODO: potential race condition with Verify
|
i2p::crypto::Verifier * verifier;
|
||||||
m_IsVerifierCreated = false;
|
{
|
||||||
m_Verifier = nullptr;
|
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||||
|
verifier = m_Verifier;
|
||||||
|
m_Verifier = nullptr;
|
||||||
|
}
|
||||||
|
delete verifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)
|
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)
|
||||||
@@ -417,6 +412,9 @@ namespace data
|
|||||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||||
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET:
|
||||||
|
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetEncryptor>(key);
|
||||||
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
||||||
return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key);
|
||||||
@@ -674,6 +672,9 @@ namespace data
|
|||||||
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
||||||
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET:
|
||||||
|
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
||||||
};
|
};
|
||||||
@@ -717,7 +718,10 @@ namespace data
|
|||||||
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
case SIGNING_KEY_TYPE_RSA_SHA384_3072:
|
||||||
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
case SIGNING_KEY_TYPE_RSA_SHA512_4096:
|
||||||
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
|
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
|
||||||
// no break here
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
[[fallthrough]];
|
||||||
|
#endif
|
||||||
|
// no break here
|
||||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||||
i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub);
|
i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub);
|
||||||
break;
|
break;
|
||||||
@@ -750,6 +754,9 @@ namespace data
|
|||||||
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
||||||
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
|
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET:
|
||||||
|
i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
|
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
#include "Base.h"
|
#include "Base.h"
|
||||||
#include "Signature.h"
|
#include "Signature.h"
|
||||||
#include "CryptoKey.h"
|
#include "CryptoKey.h"
|
||||||
@@ -55,6 +56,7 @@ namespace data
|
|||||||
|
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
||||||
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET = 4;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES
|
||||||
|
|
||||||
@@ -124,8 +126,8 @@ namespace data
|
|||||||
|
|
||||||
Identity m_StandardIdentity;
|
Identity m_StandardIdentity;
|
||||||
IdentHash m_IdentHash;
|
IdentHash m_IdentHash;
|
||||||
mutable std::unique_ptr<i2p::crypto::Verifier> m_Verifier;
|
mutable i2p::crypto::Verifier * m_Verifier = nullptr;
|
||||||
mutable std::atomic_bool m_IsVerifierCreated; // make sure we don't create twice
|
mutable std::mutex m_VerifierMutex;
|
||||||
size_t m_ExtendedLen;
|
size_t m_ExtendedLen;
|
||||||
uint8_t * m_ExtendedBuffer;
|
uint8_t * m_ExtendedBuffer;
|
||||||
};
|
};
|
||||||
@@ -215,6 +217,7 @@ namespace data
|
|||||||
virtual bool IsDestination () const = 0; // for garlic
|
virtual bool IsDestination () const = 0; // for garlic
|
||||||
|
|
||||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||||
|
virtual CryptoKeyType GetEncryptionType () const { return GetIdentity ()->GetCryptoKeyType (); }; // override in LeaseSet2
|
||||||
};
|
};
|
||||||
|
|
||||||
class LocalDestination
|
class LocalDestination
|
||||||
@@ -222,10 +225,12 @@ namespace data
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~LocalDestination() {};
|
virtual ~LocalDestination() {};
|
||||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const = 0;
|
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL) const = 0;
|
||||||
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
||||||
|
|
||||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||||
|
virtual bool SupportsEncryptionType (CryptoKeyType keyType) const { return GetIdentity ()->GetCryptoKeyType () == keyType; }; // override for LeaseSet
|
||||||
|
virtual const uint8_t * GetEncryptionPublicKey (CryptoKeyType keyType) const { return GetIdentity ()->GetEncryptionPublicKey (); }; // override for LeaseSet
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
|
LogPrint (eLogWarning, "LeaseSet: Lease is expired already");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
|
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
|
||||||
@@ -251,18 +251,26 @@ namespace data
|
|||||||
memcpy (m_Buffer, buf, len);
|
memcpy (m_Buffer, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases):
|
void LeaseSet::SetBufferLen (size_t len)
|
||||||
LeaseSet (storeLeases), m_StoreType (storeType), m_OrigStoreType (storeType)
|
{
|
||||||
|
if (len <= m_BufferLen) m_BufferLen = len;
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: actual buffer size ", len , " exceeds full buffer size ", m_BufferLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
|
||||||
|
LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto)
|
||||||
{
|
{
|
||||||
SetBuffer (buf, len);
|
SetBuffer (buf, len);
|
||||||
if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||||
ReadFromBufferEncrypted (buf, len, nullptr, nullptr);
|
ReadFromBufferEncrypted (buf, len, nullptr, nullptr);
|
||||||
else
|
else
|
||||||
ReadFromBuffer (buf, len);
|
ReadFromBuffer (buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret):
|
LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
|
||||||
LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_OrigStoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
const uint8_t * secret, CryptoKeyType preferredCrypto):
|
||||||
|
LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto)
|
||||||
{
|
{
|
||||||
ReadFromBufferEncrypted (buf, len, key, secret);
|
ReadFromBufferEncrypted (buf, len, key, secret);
|
||||||
}
|
}
|
||||||
@@ -302,6 +310,12 @@ namespace data
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (flags & LEASESET2_FLAG_UNPUBLISHED_LEASESET) m_IsPublic = false;
|
||||||
|
if (flags & LEASESET2_FLAG_PUBLISHED_ENCRYPTED)
|
||||||
|
{
|
||||||
|
m_IsPublishedEncrypted = true;
|
||||||
|
m_IsPublic = true;
|
||||||
|
}
|
||||||
// type specific part
|
// type specific part
|
||||||
size_t s = 0;
|
size_t s = 0;
|
||||||
switch (m_StoreType)
|
switch (m_StoreType)
|
||||||
@@ -324,6 +338,8 @@ namespace data
|
|||||||
VerifySignature (identity, buf, len, offset);
|
VerifySignature (identity, buf, len, offset);
|
||||||
SetIsValid (verified);
|
SetIsValid (verified);
|
||||||
}
|
}
|
||||||
|
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
|
||||||
|
SetBufferLen (offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Verifier>
|
template<typename Verifier>
|
||||||
@@ -349,7 +365,8 @@ namespace data
|
|||||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||||
if (offset + 1 >= len) return 0;
|
if (offset + 1 >= len) return 0;
|
||||||
// key sections
|
// key sections
|
||||||
uint16_t currentKeyType = 0;
|
CryptoKeyType preferredKeyType = m_EncryptionType;
|
||||||
|
bool preferredKeyFound = false;
|
||||||
int numKeySections = buf[offset]; offset++;
|
int numKeySections = buf[offset]; offset++;
|
||||||
for (int i = 0; i < numKeySections; i++)
|
for (int i = 0; i < numKeySections; i++)
|
||||||
{
|
{
|
||||||
@@ -357,15 +374,15 @@ namespace data
|
|||||||
if (offset + 2 >= len) return 0;
|
if (offset + 2 >= len) return 0;
|
||||||
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
|
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
|
||||||
if (offset + encryptionKeyLen >= len) return 0;
|
if (offset + encryptionKeyLen >= len) return 0;
|
||||||
if (IsStoreLeases ()) // create encryptor with leases only
|
if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only
|
||||||
{
|
{
|
||||||
// we pick first valid key, higher key type has higher priority 4-1-0
|
// we pick first valid key if preferred not found
|
||||||
// if two keys with of the same type, pick first
|
|
||||||
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
||||||
if (encryptor && (!m_Encryptor || keyType > currentKeyType))
|
if (encryptor && (!m_Encryptor || keyType == preferredKeyType))
|
||||||
{
|
{
|
||||||
m_Encryptor = encryptor; // TODO: atomic
|
m_Encryptor = encryptor; // TODO: atomic
|
||||||
currentKeyType = keyType;
|
m_EncryptionType = keyType;
|
||||||
|
if (keyType == preferredKeyType) preferredKeyFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += encryptionKeyLen;
|
offset += encryptionKeyLen;
|
||||||
@@ -479,7 +496,7 @@ namespace data
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instread ", key->GetBlindedSigType ());
|
LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instead ", key->GetBlindedSigType ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// outer key
|
// outer key
|
||||||
@@ -506,7 +523,7 @@ namespace data
|
|||||||
if (authDataLen > 0)
|
if (authDataLen > 0)
|
||||||
{
|
{
|
||||||
memcpy (innerInput + 32, subcredential, 36);
|
memcpy (innerInput + 32, subcredential, 36);
|
||||||
i2p::crypto::HKDF (outerPlainText.data () + 1, innerInput, 68, "ELS2_L2K", keys);
|
i2p::crypto::HKDF (outerPlainText.data () + 1 + authDataLen, innerInput, 68, "ELS2_L2K", keys);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// no authData presented, innerInput = subcredential || publishedTimestamp
|
// no authData presented, innerInput = subcredential || publishedTimestamp
|
||||||
@@ -529,42 +546,83 @@ namespace data
|
|||||||
else
|
else
|
||||||
LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
|
LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we set actual length of encrypted buffer
|
||||||
|
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : blindedVerifier->GetSignatureLen ();
|
||||||
|
SetBufferLen (offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper for ExtractClientAuthData
|
||||||
|
static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie)
|
||||||
|
{
|
||||||
|
// try to find clientCookie_i for clientID_i = okm[44:51]
|
||||||
|
for (int i = 0; i < numClients; i++)
|
||||||
|
{
|
||||||
|
if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
|
||||||
|
{
|
||||||
|
// clientKey_i = okm[0:31]
|
||||||
|
// clientIV_i = okm[32:43]
|
||||||
|
i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const
|
size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
uint8_t flag = buf[offset]; offset++; // flag
|
uint8_t flag = buf[offset]; offset++; // flag
|
||||||
if (flag & 0x01) // client auth
|
if (flag & 0x01) // client auth
|
||||||
{
|
{
|
||||||
if (flag & 0x02) // PSK, bit 1 is set to 1
|
if (!(flag & 0x0E)) // DH, bit 1-3 all zeroes
|
||||||
|
{
|
||||||
|
const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey
|
||||||
|
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
|
||||||
|
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
|
||||||
|
if (offset > len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// calculate authCookie
|
||||||
|
if (secret)
|
||||||
|
{
|
||||||
|
i2p::crypto::X25519Keys ck (secret, nullptr); // derive cpk_i from csk_i
|
||||||
|
uint8_t authInput[100];
|
||||||
|
ck.Agree (ephemeralPublicKey, authInput); // sharedSecret is first 32 bytes of authInput
|
||||||
|
memcpy (authInput + 32, ck.GetPublicKey (), 32); // cpk_i
|
||||||
|
memcpy (authInput + 64, subcredential, 36);
|
||||||
|
uint8_t okm[64]; // 52 actual data
|
||||||
|
i2p::crypto::HKDF (ephemeralPublicKey, authInput, 100, "ELS2_XCA", okm);
|
||||||
|
if (!GetAuthCookie (authClients, numClients, okm, authCookie))
|
||||||
|
LogPrint (eLogError, "LeaseSet2: Client cookie DH not found");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: csk_i is not provided");
|
||||||
|
}
|
||||||
|
else if (flag & 0x02) // PSK, bit 1 is set to 1
|
||||||
{
|
{
|
||||||
const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
|
const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
|
||||||
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
|
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
|
||||||
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
|
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
|
||||||
|
if (offset > len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
// calculate authCookie
|
// calculate authCookie
|
||||||
if (secret)
|
if (secret)
|
||||||
{
|
{
|
||||||
uint8_t authInput[68];
|
uint8_t authInput[68];
|
||||||
memcpy (authInput, secret, 32);
|
memcpy (authInput, secret, 32);
|
||||||
memcpy (authInput, subcredential, 36);
|
memcpy (authInput + 32, subcredential, 36);
|
||||||
uint8_t okm[64]; // 52 actual data
|
uint8_t okm[64]; // 52 actual data
|
||||||
i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
|
i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
|
||||||
// try to find clientCookie_i for clientID_i = okm[44:51]
|
if (!GetAuthCookie (authClients, numClients, okm, authCookie))
|
||||||
bool found = false;
|
LogPrint (eLogError, "LeaseSet2: Client cookie PSK not found");
|
||||||
for (int i = 0; i < numClients; i++)
|
|
||||||
{
|
|
||||||
if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
|
|
||||||
{
|
|
||||||
// clientKey_i = okm[0:31]
|
|
||||||
// clientIV_i = okm[32:43]
|
|
||||||
i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
LogPrint (eLogError, "LeaseSet2: Client cookie not found");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");
|
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");
|
||||||
@@ -705,22 +763,32 @@ namespace data
|
|||||||
}
|
}
|
||||||
|
|
||||||
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||||
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
const KeySections& encryptionKeys,
|
||||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
|
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
|
||||||
|
bool isPublic, bool isPublishedEncrypted):
|
||||||
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
LocalLeaseSet (keys.GetPublic (), nullptr, 0)
|
||||||
{
|
{
|
||||||
auto identity = keys.GetPublic ();
|
auto identity = keys.GetPublic ();
|
||||||
// assume standard LS2
|
// assume standard LS2
|
||||||
int num = tunnels.size ();
|
int num = tunnels.size ();
|
||||||
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
|
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
|
||||||
|
size_t keySectionsLen = 0;
|
||||||
|
for (const auto& it: encryptionKeys)
|
||||||
|
keySectionsLen += 2/*key type*/ + 2/*key len*/ + it.keyLen/*key*/;
|
||||||
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
|
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
|
||||||
1/*num keys*/ + 2/*key type*/ + 2/*key len*/ + keyLen/*key*/ + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
|
1/*num keys*/ + keySectionsLen + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
|
||||||
uint16_t flags = 0;
|
uint16_t flags = 0;
|
||||||
if (keys.IsOfflineSignature ())
|
if (keys.IsOfflineSignature ())
|
||||||
{
|
{
|
||||||
flags |= LEASESET2_FLAG_OFFLINE_KEYS;
|
flags |= LEASESET2_FLAG_OFFLINE_KEYS;
|
||||||
m_BufferLen += keys.GetOfflineSignature ().size ();
|
m_BufferLen += keys.GetOfflineSignature ().size ();
|
||||||
}
|
}
|
||||||
|
if (isPublishedEncrypted)
|
||||||
|
{
|
||||||
|
flags |= LEASESET2_FLAG_PUBLISHED_ENCRYPTED;
|
||||||
|
isPublic = true;
|
||||||
|
}
|
||||||
|
if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET;
|
||||||
|
|
||||||
m_Buffer = new uint8_t[m_BufferLen + 1];
|
m_Buffer = new uint8_t[m_BufferLen + 1];
|
||||||
m_Buffer[0] = storeType;
|
m_Buffer[0] = storeType;
|
||||||
@@ -739,10 +807,13 @@ namespace data
|
|||||||
}
|
}
|
||||||
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
|
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
|
||||||
// keys
|
// keys
|
||||||
m_Buffer[offset] = 1; offset++; // 1 key
|
m_Buffer[offset] = encryptionKeys.size (); offset++; // 1 key
|
||||||
htobe16buf (m_Buffer + offset, keyType); offset += 2; // key type
|
for (const auto& it: encryptionKeys)
|
||||||
htobe16buf (m_Buffer + offset, keyLen); offset += 2; // key len
|
{
|
||||||
memcpy (m_Buffer + offset, encryptionPublicKey, keyLen); offset += keyLen; // key
|
htobe16buf (m_Buffer + offset, it.keyType); offset += 2; // key type
|
||||||
|
htobe16buf (m_Buffer + offset, it.keyLen); offset += 2; // key len
|
||||||
|
memcpy (m_Buffer + offset, it.encryptionPublicKey, it.keyLen); offset += it.keyLen; // key
|
||||||
|
}
|
||||||
// leases
|
// leases
|
||||||
uint32_t expirationTime = 0; // in seconds
|
uint32_t expirationTime = 0; // in seconds
|
||||||
m_Buffer[offset] = num; offset++; // num leases
|
m_Buffer[offset] = num; offset++; // num leases
|
||||||
@@ -774,12 +845,22 @@ namespace data
|
|||||||
m_Buffer[0] = storeType;
|
m_Buffer[0] = storeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, i2p::data::SigningKeyType blindedKeyType):
|
LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys,
|
||||||
|
int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys):
|
||||||
LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls)
|
LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls)
|
||||||
{
|
{
|
||||||
size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1,
|
size_t lenInnerPlaintext = ls->GetBufferLen () + 1, lenOuterPlaintext = lenInnerPlaintext + 32 + 1;
|
||||||
lenOuterCiphertext = lenOuterPlaintext + 32;
|
uint8_t layer1Flags = 0;
|
||||||
m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/;
|
if (authKeys)
|
||||||
|
{
|
||||||
|
if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1
|
||||||
|
else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1
|
||||||
|
if (layer1Flags)
|
||||||
|
lenOuterPlaintext += 32 + 2 + authKeys->size ()*40; // auth data len
|
||||||
|
}
|
||||||
|
size_t lenOuterCiphertext = lenOuterPlaintext + 32;
|
||||||
|
|
||||||
|
m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/;
|
||||||
m_Buffer = new uint8_t[m_BufferLen + 1];
|
m_Buffer = new uint8_t[m_BufferLen + 1];
|
||||||
m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
|
||||||
BlindedPublicKey blindedKey (ls->GetIdentity ());
|
BlindedPublicKey blindedKey (ls->GetIdentity ());
|
||||||
@@ -788,9 +869,9 @@ namespace data
|
|||||||
i2p::util::GetDateString (timestamp, date);
|
i2p::util::GetDateString (timestamp, date);
|
||||||
uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max
|
uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max
|
||||||
size_t publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
|
size_t publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
|
||||||
std::unique_ptr<i2p::crypto::Signer> blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKeyType, blindedPriv));
|
std::unique_ptr<i2p::crypto::Signer> blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv));
|
||||||
auto offset = 1;
|
auto offset = 1;
|
||||||
htobe16buf (m_Buffer + offset, blindedKeyType); offset += 2; // Blinded Public Key Sig Type
|
htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type
|
||||||
memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key
|
memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key
|
||||||
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
|
||||||
auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds
|
auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds
|
||||||
@@ -812,12 +893,26 @@ namespace data
|
|||||||
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1);
|
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1);
|
||||||
offset += 32; // outerSalt
|
offset += 32; // outerSalt
|
||||||
uint8_t * outerPlainText = m_Buffer + offset;
|
uint8_t * outerPlainText = m_Buffer + offset;
|
||||||
m_Buffer[offset] = 0; offset++; // flag
|
m_Buffer[offset] = layer1Flags; offset++; // layer 1 flags
|
||||||
|
// auth data
|
||||||
|
uint8_t innerInput[68]; // authCookie || subcredential || publishedTimestamp
|
||||||
|
if (layer1Flags)
|
||||||
|
{
|
||||||
|
RAND_bytes (innerInput, 32); // authCookie
|
||||||
|
CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer + offset);
|
||||||
|
offset += 32 + 2 + authKeys->size ()*40; // auth clients
|
||||||
|
}
|
||||||
// Layer 2
|
// Layer 2
|
||||||
// keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44)
|
// keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44)
|
||||||
uint8_t keys2[64]; // 44 bytes actual data
|
uint8_t keys2[64]; // 44 bytes actual data
|
||||||
RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32)
|
RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32)
|
||||||
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2);
|
if (layer1Flags)
|
||||||
|
{
|
||||||
|
memcpy (innerInput + 32, subcredential, 36); // + subcredential || publishedTimestamp
|
||||||
|
i2p::crypto::HKDF (m_Buffer + offset, innerInput, 68, "ELS2_L2K", keys2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); // no authCookie
|
||||||
offset += 32; // innerSalt
|
offset += 32; // innerSalt
|
||||||
m_Buffer[offset] = ls->GetStoreType ();
|
m_Buffer[offset] = ls->GetStoreType ();
|
||||||
memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ());
|
memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ());
|
||||||
@@ -844,6 +939,44 @@ namespace data
|
|||||||
else
|
else
|
||||||
LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer");
|
LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const
|
||||||
|
{
|
||||||
|
if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH)
|
||||||
|
{
|
||||||
|
i2p::crypto::X25519Keys ek;
|
||||||
|
ek.GenerateKeys (); // esk and epk
|
||||||
|
memcpy (authData, ek.GetPublicKey (), 32); authData += 32; // epk
|
||||||
|
htobe16buf (authData, authKeys->size ()); authData += 2; // num clients
|
||||||
|
uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp
|
||||||
|
memcpy (authInput + 64, subcredential, 36);
|
||||||
|
for (auto& it: *authKeys)
|
||||||
|
{
|
||||||
|
ek.Agree (it, authInput); // sharedSecret = DH(esk, cpk_i)
|
||||||
|
memcpy (authInput + 32, it, 32);
|
||||||
|
uint8_t okm[64]; // 52 actual data
|
||||||
|
i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm);
|
||||||
|
memcpy (authData, okm + 44, 8); authData += 8; // clientID_i
|
||||||
|
i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // assume PSK
|
||||||
|
{
|
||||||
|
uint8_t authSalt[32];
|
||||||
|
RAND_bytes (authSalt, 32);
|
||||||
|
memcpy (authData, authSalt, 32); authData += 32; // authSalt
|
||||||
|
htobe16buf (authData, authKeys->size ()); authData += 2; // num clients
|
||||||
|
uint8_t authInput[68]; // authInput = psk_i || subcredential || publishedTimestamp
|
||||||
|
memcpy (authInput + 32, subcredential, 36);
|
||||||
|
for (auto& it: *authKeys)
|
||||||
|
{
|
||||||
|
memcpy (authInput, it, 32);
|
||||||
|
uint8_t okm[64]; // 52 actual data
|
||||||
|
i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
|
||||||
|
memcpy (authData, okm + 44, 8); authData += 8; // clientID_i
|
||||||
|
i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,9 +79,9 @@ namespace data
|
|||||||
bool operator== (const LeaseSet& other) const
|
bool operator== (const LeaseSet& other) const
|
||||||
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
||||||
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
||||||
virtual uint8_t GetOrigStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
|
|
||||||
virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only
|
virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only
|
||||||
virtual std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return nullptr; };
|
virtual std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return nullptr; };
|
||||||
|
virtual bool IsPublishedEncrypted () const { return false; };
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||||
@@ -97,6 +97,7 @@ namespace data
|
|||||||
// called from LeaseSet2
|
// called from LeaseSet2
|
||||||
LeaseSet (bool storeLeases);
|
LeaseSet (bool storeLeases);
|
||||||
void SetBuffer (const uint8_t * buf, size_t len);
|
void SetBuffer (const uint8_t * buf, size_t len);
|
||||||
|
void SetBufferLen (size_t len);
|
||||||
void SetIdentity (std::shared_ptr<const IdentityEx> identity) { m_Identity = identity; };
|
void SetIdentity (std::shared_ptr<const IdentityEx> identity) { m_Identity = identity; };
|
||||||
void SetExpirationTime (uint64_t t) { m_ExpirationTime = t; };
|
void SetExpirationTime (uint64_t t) { m_ExpirationTime = t; };
|
||||||
void SetIsValid (bool isValid) { m_IsValid = isValid; };
|
void SetIsValid (bool isValid) { m_IsValid = isValid; };
|
||||||
@@ -129,21 +130,25 @@ namespace data
|
|||||||
const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7;
|
const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7;
|
||||||
|
|
||||||
const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001;
|
const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001;
|
||||||
|
const uint16_t LEASESET2_FLAG_UNPUBLISHED_LEASESET = 0x0002;
|
||||||
|
const uint16_t LEASESET2_FLAG_PUBLISHED_ENCRYPTED = 0x0004;
|
||||||
|
|
||||||
class LeaseSet2: public LeaseSet
|
class LeaseSet2: public LeaseSet
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true);
|
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL);
|
||||||
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr); // store type 5, called from local netdb only
|
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only
|
||||||
uint8_t GetStoreType () const { return m_StoreType; };
|
uint8_t GetStoreType () const { return m_StoreType; };
|
||||||
uint8_t GetOrigStoreType () const { return m_OrigStoreType; };
|
|
||||||
uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; };
|
uint32_t GetPublishedTimestamp () const { return m_PublishedTimestamp; };
|
||||||
|
bool IsPublic () const { return m_IsPublic; };
|
||||||
|
bool IsPublishedEncrypted () const { return m_IsPublishedEncrypted; };
|
||||||
std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return m_TransientVerifier; };
|
std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return m_TransientVerifier; };
|
||||||
void Update (const uint8_t * buf, size_t len, bool verifySignature);
|
void Update (const uint8_t * buf, size_t len, bool verifySignature);
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
||||||
|
CryptoKeyType GetEncryptionType () const { return m_EncryptionType; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -160,9 +165,11 @@ namespace data
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_StoreType, m_OrigStoreType;
|
uint8_t m_StoreType;
|
||||||
uint32_t m_PublishedTimestamp = 0;
|
uint32_t m_PublishedTimestamp = 0;
|
||||||
|
bool m_IsPublic = true, m_IsPublishedEncrypted = false;
|
||||||
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
||||||
|
CryptoKeyType m_EncryptionType;
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
|
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -225,9 +232,17 @@ namespace data
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
struct KeySection
|
||||||
|
{
|
||||||
|
uint16_t keyType, keyLen;
|
||||||
|
const uint8_t * encryptionPublicKey;
|
||||||
|
};
|
||||||
|
typedef std::vector<KeySection> KeySections;
|
||||||
|
|
||||||
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||||
uint16_t keyType, uint16_t keyLen, const uint8_t * encryptionPublicKey,
|
const KeySections& encryptionKeys,
|
||||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
|
||||||
|
bool isPublic, bool isPublishedEncrypted = false);
|
||||||
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||||
|
|
||||||
virtual ~LocalLeaseSet2 () { delete[] m_Buffer; };
|
virtual ~LocalLeaseSet2 () { delete[] m_Buffer; };
|
||||||
@@ -247,17 +262,28 @@ namespace data
|
|||||||
size_t m_BufferLen;
|
size_t m_BufferLen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const int ENCRYPTED_LEASESET_AUTH_TYPE_NONE = 0;
|
||||||
|
const int ENCRYPTED_LEASESET_AUTH_TYPE_DH = 1;
|
||||||
|
const int ENCRYPTED_LEASESET_AUTH_TYPE_PSK = 2;
|
||||||
|
|
||||||
|
typedef i2p::data::Tag<32> AuthPublicKey;
|
||||||
|
|
||||||
class LocalEncryptedLeaseSet2: public LocalLeaseSet2
|
class LocalEncryptedLeaseSet2: public LocalLeaseSet2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, i2p::data::SigningKeyType blindedKeyType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519);
|
LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, int authType = ENCRYPTED_LEASESET_AUTH_TYPE_NONE, std::shared_ptr<std::vector<AuthPublicKey> > authKeys = nullptr);
|
||||||
|
|
||||||
LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
|
||||||
|
|
||||||
const IdentHash& GetStoreHash () const { return m_StoreHash; };
|
const IdentHash& GetStoreHash () const { return m_StoreHash; };
|
||||||
std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet () const { return m_InnerLeaseSet; };
|
std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet () const { return m_InnerLeaseSet; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
IdentHash m_StoreHash;
|
IdentHash m_StoreHash;
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ void LogPrint (std::stringstream& s, TValue&& arg) noexcept
|
|||||||
s << std::forward<TValue>(arg);
|
s << std::forward<TValue>(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (__cplusplus < 201703L) // below C++ 17
|
||||||
/** internal usage only -- folding args array to single string */
|
/** internal usage only -- folding args array to single string */
|
||||||
template<typename TValue, typename... TArgs>
|
template<typename TValue, typename... TArgs>
|
||||||
void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
||||||
@@ -168,6 +169,7 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
|||||||
LogPrint (s, std::forward<TValue>(arg));
|
LogPrint (s, std::forward<TValue>(arg));
|
||||||
LogPrint (s, std::forward<TArgs>(args)...);
|
LogPrint (s, std::forward<TArgs>(args)...);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create log message and send it to queue
|
* @brief Create log message and send it to queue
|
||||||
@@ -184,7 +186,11 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
|||||||
// fold message to single string
|
// fold message to single string
|
||||||
std::stringstream ss("");
|
std::stringstream ss("");
|
||||||
|
|
||||||
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||||
|
#else
|
||||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||||
|
#endif
|
||||||
|
|
||||||
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
|
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
|
||||||
msg->tid = std::this_thread::get_id();
|
msg->tid = std::this_thread::get_id();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2018, The PurpleI2P Project
|
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*
|
*
|
||||||
* Kovri go write your own code
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
#ifndef NTCP2_H__
|
#ifndef NTCP2_H__
|
||||||
#define NTCP2_H__
|
#define NTCP2_H__
|
||||||
@@ -30,7 +28,7 @@ namespace i2p
|
|||||||
namespace transport
|
namespace transport
|
||||||
{
|
{
|
||||||
|
|
||||||
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
|
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
|
||||||
const int NTCP2_MAX_PADDING_RATIO = 6; // in %
|
const int NTCP2_MAX_PADDING_RATIO = 6; // in %
|
||||||
|
|
||||||
const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds
|
const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||||
@@ -38,7 +36,7 @@ namespace transport
|
|||||||
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
|
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||||
|
|
||||||
const int NTCP2_CLOCK_SKEW = 60; // in seconds
|
const int NTCP2_CLOCK_SKEW = 60; // in seconds
|
||||||
const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
|
const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
|
||||||
|
|
||||||
enum NTCP2BlockType
|
enum NTCP2BlockType
|
||||||
@@ -48,8 +46,8 @@ namespace transport
|
|||||||
eNTCP2BlkRouterInfo, // 2
|
eNTCP2BlkRouterInfo, // 2
|
||||||
eNTCP2BlkI2NPMessage, // 3
|
eNTCP2BlkI2NPMessage, // 3
|
||||||
eNTCP2BlkTermination, // 4
|
eNTCP2BlkTermination, // 4
|
||||||
eNTCP2BlkPadding = 254
|
eNTCP2BlkPadding = 254
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NTCP2TerminationReason
|
enum NTCP2TerminationReason
|
||||||
{
|
{
|
||||||
@@ -71,21 +69,21 @@ namespace transport
|
|||||||
eNTCP2RouterInfoSignatureVerificationFail, // 15
|
eNTCP2RouterInfoSignatureVerificationFail, // 15
|
||||||
eNTCP2IncorrectSParameter, // 16
|
eNTCP2IncorrectSParameter, // 16
|
||||||
eNTCP2Banned, // 17
|
eNTCP2Banned, // 17
|
||||||
};
|
};
|
||||||
|
|
||||||
// RouterInfo flags
|
// RouterInfo flags
|
||||||
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
||||||
|
|
||||||
struct NTCP2Establisher
|
struct NTCP2Establisher
|
||||||
{
|
{
|
||||||
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
|
||||||
|
|
||||||
const uint8_t * GetK () const { return m_K; };
|
const uint8_t * GetK () const { return m_CK + 32; };
|
||||||
const uint8_t * GetCK () const { return m_CK; };
|
const uint8_t * GetCK () const { return m_CK; };
|
||||||
const uint8_t * GetH () const { return m_H; };
|
const uint8_t * GetH () const { return m_H; };
|
||||||
|
|
||||||
@@ -114,34 +112,36 @@ namespace transport
|
|||||||
|
|
||||||
i2p::crypto::X25519Keys m_EphemeralKeys;
|
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[33] /*ck*/, m_K[32] /*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;
|
||||||
uint16_t m3p2Len;
|
uint16_t m3p2Len;
|
||||||
|
|
||||||
uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer;
|
uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer;
|
||||||
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
|
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NTCP2Server;
|
class NTCP2Server;
|
||||||
class NTCP2Session: public TransportSession, public std::enable_shared_from_this<NTCP2Session>
|
class NTCP2Session: public TransportSession, public std::enable_shared_from_this<NTCP2Session>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
|
|
||||||
|
NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
|
||||||
~NTCP2Session ();
|
~NTCP2Session ();
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void TerminateByTimeout ();
|
void TerminateByTimeout ();
|
||||||
void Done ();
|
void Done ();
|
||||||
|
void Close () { m_Socket.close (); }; // for accept
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
|
|
||||||
bool IsEstablished () const { return m_IsEstablished; };
|
bool IsEstablished () const { return m_IsEstablished; };
|
||||||
bool IsTerminated () const { return m_IsTerminated; };
|
bool IsTerminated () const { return m_IsTerminated; };
|
||||||
|
|
||||||
void ClientLogin (); // Alice
|
void ClientLogin (); // Alice
|
||||||
void ServerLogin (); // Bob
|
void ServerLogin (); // Bob
|
||||||
|
|
||||||
void SendLocalRouterInfo (); // after handshake
|
void SendLocalRouterInfo (); // after handshake
|
||||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||||
|
|
||||||
@@ -194,15 +194,15 @@ namespace transport
|
|||||||
|
|
||||||
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
||||||
// data phase
|
// data phase
|
||||||
uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32];
|
uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32];
|
||||||
const uint8_t * m_SendKey, * m_ReceiveKey;
|
const uint8_t * m_SendKey, * m_ReceiveKey;
|
||||||
#if OPENSSL_SIPHASH
|
#if OPENSSL_SIPHASH
|
||||||
EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey;
|
EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey;
|
||||||
EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx;
|
EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx;
|
||||||
#else
|
#else
|
||||||
const uint8_t * m_SendSipKey, * m_ReceiveSipKey;
|
const uint8_t * m_SendSipKey, * m_ReceiveSipKey;
|
||||||
#endif
|
#endif
|
||||||
uint16_t m_NextReceivedLen;
|
uint16_t m_NextReceivedLen;
|
||||||
uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer;
|
uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer;
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@@ -217,31 +217,51 @@ namespace transport
|
|||||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NTCP2Server
|
class NTCP2Server: private i2p::util::RunnableServiceWithWork
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum RemoteAddressType
|
||||||
|
{
|
||||||
|
eIP4Address,
|
||||||
|
eIP6Address,
|
||||||
|
eHostname
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ProxyType
|
||||||
|
{
|
||||||
|
eNoProxy,
|
||||||
|
eSocksProxy,
|
||||||
|
eHTTPProxy
|
||||||
|
};
|
||||||
|
|
||||||
NTCP2Server ();
|
NTCP2Server ();
|
||||||
~NTCP2Server ();
|
~NTCP2Server ();
|
||||||
|
|
||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||||
|
|
||||||
bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming = false);
|
||||||
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
|
||||||
std::shared_ptr<NTCP2Session> FindNTCP2Session (const i2p::data::IdentHash& ident);
|
std::shared_ptr<NTCP2Session> FindNTCP2Session (const i2p::data::IdentHash& ident);
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
void ConnectWithProxy (const std::string& addr, uint16_t port, RemoteAddressType addrtype, std::shared_ptr<NTCP2Session> conn);
|
||||||
|
|
||||||
void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCP2Session> conn);
|
void Connect(const boost::asio::ip::address & address, uint16_t port, std::shared_ptr<NTCP2Session> conn);
|
||||||
|
|
||||||
|
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType addrtype);
|
||||||
|
|
||||||
|
|
||||||
|
bool UsingProxy() const { return m_ProxyType != eNoProxy; };
|
||||||
|
void UseProxy(ProxyType proxy, const std::string & address, uint16_t port);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
|
||||||
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||||
void HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
void HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||||
|
|
||||||
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||||
|
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer, const std::string & host, uint16_t port, RemoteAddressType adddrtype);
|
||||||
|
|
||||||
// timer
|
// timer
|
||||||
void ScheduleTermination ();
|
void ScheduleTermination ();
|
||||||
@@ -249,15 +269,17 @@ namespace transport
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
|
||||||
std::thread * m_Thread;
|
|
||||||
boost::asio::io_service m_Service;
|
|
||||||
boost::asio::io_service::work m_Work;
|
|
||||||
boost::asio::deadline_timer m_TerminationTimer;
|
boost::asio::deadline_timer m_TerminationTimer;
|
||||||
std::unique_ptr<boost::asio::ip::tcp::acceptor> m_NTCP2Acceptor, m_NTCP2V6Acceptor;
|
std::unique_ptr<boost::asio::ip::tcp::acceptor> m_NTCP2Acceptor, m_NTCP2V6Acceptor;
|
||||||
std::map<i2p::data::IdentHash, std::shared_ptr<NTCP2Session> > m_NTCP2Sessions;
|
std::map<i2p::data::IdentHash, std::shared_ptr<NTCP2Session> > m_NTCP2Sessions;
|
||||||
std::list<std::shared_ptr<NTCP2Session> > m_PendingIncomingSessions;
|
std::list<std::shared_ptr<NTCP2Session> > m_PendingIncomingSessions;
|
||||||
|
|
||||||
|
ProxyType m_ProxyType =eNoProxy;
|
||||||
|
std::string m_ProxyAddress;
|
||||||
|
uint16_t m_ProxyPort;
|
||||||
|
boost::asio::ip::tcp::resolver m_Resolver;
|
||||||
|
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// for HTTP/I2PControl
|
// for HTTP/I2PControl
|
||||||
|
|||||||
@@ -14,9 +14,6 @@
|
|||||||
#include "NTCPSession.h"
|
#include "NTCPSession.h"
|
||||||
#include "HTTP.h"
|
#include "HTTP.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
#include "Event.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace i2p::crypto;
|
using namespace i2p::crypto;
|
||||||
|
|
||||||
@@ -649,9 +646,6 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (!m_NextMessage->IsExpired ())
|
if (!m_NextMessage->IsExpired ())
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
QueueIntEvent("transport.recvmsg", GetIdentHashBase64(), 1);
|
|
||||||
#endif
|
|
||||||
m_Handler.PutNextMessage (m_NextMessage);
|
m_Handler.PutNextMessage (m_NextMessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
#include "NTCP2.h"
|
#include "NTCP2.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
#include "Garlic.h"
|
#include "Garlic.h"
|
||||||
#include "NetDb.hpp"
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "NetDb.hpp"
|
||||||
|
|
||||||
using namespace i2p::transport;
|
using namespace i2p::transport;
|
||||||
|
|
||||||
@@ -307,10 +308,18 @@ namespace data
|
|||||||
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
|
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
|
||||||
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
|
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
|
||||||
{
|
{
|
||||||
// TODO: implement actual update
|
if (leaseSet->IsPublic ())
|
||||||
LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
|
{
|
||||||
m_LeaseSets[ident] = leaseSet;
|
// TODO: implement actual update
|
||||||
return true;
|
LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
|
||||||
|
m_LeaseSets[ident] = leaseSet;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "NetDb: Unpublished LeaseSet2 received: ", ident.ToBase32());
|
||||||
|
m_LeaseSets.erase (ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -523,9 +532,10 @@ namespace data
|
|||||||
auto total = m_RouterInfos.size ();
|
auto total = m_RouterInfos.size ();
|
||||||
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||||
|
auto uptime = i2p::context.GetUptime ();
|
||||||
// routers don't expire if less than 90 or uptime is less than 1 hour
|
// routers don't expire if less than 90 or uptime is less than 1 hour
|
||||||
bool checkForExpiration = total > NETDB_MIN_ROUTERS && ts > (i2p::context.GetStartupTime () + 600)*1000LL; // 10 minutes
|
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
|
||||||
if (checkForExpiration && ts > (i2p::context.GetStartupTime () + 3600)*1000LL) // 1 hour
|
if (checkForExpiration && uptime > 3600) // 1 hour
|
||||||
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
|
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
|
||||||
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
|
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
|
||||||
|
|
||||||
@@ -909,7 +919,7 @@ namespace data
|
|||||||
else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
|
else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
|
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found");
|
||||||
replyMsg = CreateDatabaseStoreMsg (leaseSet);
|
replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -940,10 +950,20 @@ namespace data
|
|||||||
const uint8_t numTags = excluded[32];
|
const uint8_t numTags = excluded[32];
|
||||||
if (numTags)
|
if (numTags)
|
||||||
{
|
{
|
||||||
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
|
if (flag & DATABASE_LOOKUP_ECIES_FLAG)
|
||||||
i2p::garlic::GarlicRoutingSession garlic (sessionKey, sessionTag);
|
{
|
||||||
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
uint64_t tag;
|
||||||
if(replyMsg == nullptr) LogPrint(eLogError, "NetDb: failed to wrap message");
|
memcpy (&tag, excluded + 33, 8);
|
||||||
|
replyMsg = i2p::garlic::WrapECIESX25519AEADRatchetMessage (replyMsg, sessionKey, tag);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
|
||||||
|
i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag);
|
||||||
|
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
||||||
|
}
|
||||||
|
if (!replyMsg)
|
||||||
|
LogPrint (eLogError, "NetDb: failed to wrap message");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint(eLogWarning, "NetDb: encrypted reply requested but no tags provided");
|
LogPrint(eLogWarning, "NetDb: encrypted reply requested but no tags provided");
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace i2p
|
|||||||
|
|
||||||
RouterContext::RouterContext ():
|
RouterContext::RouterContext ():
|
||||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||||
m_StartupTime (0), m_ShareRatio (100), m_Status (eRouterStatusOK),
|
m_ShareRatio (100), m_Status (eRouterStatusOK),
|
||||||
m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID)
|
m_Error (eRouterErrorNone), m_NetID (I2PD_NET_ID)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,8 @@ namespace i2p
|
|||||||
void RouterContext::Init ()
|
void RouterContext::Init ()
|
||||||
{
|
{
|
||||||
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
|
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
|
||||||
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
|
m_StartupTime = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
if (!Load ())
|
if (!Load ())
|
||||||
CreateNewRouter ();
|
CreateNewRouter ();
|
||||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||||
@@ -183,17 +184,18 @@ namespace i2p
|
|||||||
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4only)
|
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4only)
|
||||||
{
|
{
|
||||||
if (!m_NTCP2Keys) return;
|
if (!m_NTCP2Keys) return;
|
||||||
if (!port)
|
|
||||||
{
|
|
||||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
|
||||||
if (port == 9150) port = 9151; // Tor browser
|
|
||||||
}
|
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||||
{
|
{
|
||||||
if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) && (!v4only || address->host.is_v4 ()))
|
if (address->IsNTCP2 () && (address->port != port || address->ntcp2->isPublished != publish) && (!v4only || address->host.is_v4 ()))
|
||||||
{
|
{
|
||||||
address->port = port;
|
if (!port && !address->port)
|
||||||
|
{
|
||||||
|
// select random port only if address's port is not set
|
||||||
|
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||||
|
if (port == 9150) port = 9151; // Tor browser
|
||||||
|
}
|
||||||
|
if (port) address->port = port;
|
||||||
address->cost = publish ? 3 : 14;
|
address->cost = publish ? 3 : 14;
|
||||||
address->ntcp2->isPublished = publish;
|
address->ntcp2->isPublished = publish;
|
||||||
address->ntcp2->iv = m_NTCP2Keys->iv;
|
address->ntcp2->iv = m_NTCP2Keys->iv;
|
||||||
@@ -336,7 +338,11 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
case low : /* not set */; break;
|
case low : /* not set */; break;
|
||||||
case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P'
|
case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P'
|
||||||
case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; // no break here, extra + high means 'X'
|
case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth;
|
||||||
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
[[fallthrough]];
|
||||||
|
#endif
|
||||||
|
// no break here, extra + high means 'X'
|
||||||
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
|
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
|
||||||
}
|
}
|
||||||
m_RouterInfo.SetCaps (caps);
|
m_RouterInfo.SetCaps (caps);
|
||||||
@@ -432,14 +438,14 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
// remove NTCP or NTCP2 v4 address
|
// remove NTCP or NTCP2 v4 address
|
||||||
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
||||||
if (ntcp)
|
if (ntcp)
|
||||||
PublishNTCPAddress (false);
|
PublishNTCPAddress (false);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
if (ntcp2)
|
if (ntcp2)
|
||||||
PublishNTCP2Address (port, false, true);
|
PublishNTCP2Address (port, false, true);
|
||||||
}
|
}
|
||||||
// update
|
// update
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
}
|
}
|
||||||
@@ -489,7 +495,7 @@ namespace i2p
|
|||||||
void RouterContext::SetSupportsV6 (bool supportsV6)
|
void RouterContext::SetSupportsV6 (bool supportsV6)
|
||||||
{
|
{
|
||||||
if (supportsV6)
|
if (supportsV6)
|
||||||
{
|
{
|
||||||
m_RouterInfo.EnableV6 ();
|
m_RouterInfo.EnableV6 ();
|
||||||
// insert v6 addresses if necessary
|
// insert v6 addresses if necessary
|
||||||
bool foundSSU = false, foundNTCP = false, foundNTCP2 = false;
|
bool foundSSU = false, foundNTCP = false, foundNTCP2 = false;
|
||||||
@@ -507,7 +513,7 @@ namespace i2p
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
foundNTCP = true;
|
foundNTCP = true;
|
||||||
}
|
}
|
||||||
port = addr->port;
|
port = addr->port;
|
||||||
}
|
}
|
||||||
if (!port) i2p::config::GetOption("port", port);
|
if (!port) i2p::config::GetOption("port", port);
|
||||||
@@ -519,7 +525,7 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
std::string host = "::1"; // TODO: read host
|
std::string host = "::1"; // TODO: read host
|
||||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, GetIdentHash ());
|
m_RouterInfo.AddSSUAddress (host.c_str (), port, GetIdentHash ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NTCP2
|
// NTCP2
|
||||||
if (!foundNTCP2)
|
if (!foundNTCP2)
|
||||||
@@ -528,11 +534,11 @@ namespace i2p
|
|||||||
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
||||||
if (ntcp2 && ntcp2Published)
|
if (ntcp2 && ntcp2Published)
|
||||||
{
|
{
|
||||||
std::string ntcp2Host;
|
std::string ntcp2Host;
|
||||||
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
||||||
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
|
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
|
||||||
else
|
else
|
||||||
ntcp2Host = "::1";
|
ntcp2Host = "::1";
|
||||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||||
if (!ntcp2Port) ntcp2Port = port;
|
if (!ntcp2Port) ntcp2Port = port;
|
||||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
|
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
|
||||||
@@ -544,10 +550,10 @@ namespace i2p
|
|||||||
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
bool ntcp; i2p::config::GetOption("ntcp", ntcp);
|
||||||
if (ntcp)
|
if (ntcp)
|
||||||
{
|
{
|
||||||
std::string host = "::1";
|
std::string host = "::1";
|
||||||
m_RouterInfo.AddNTCPAddress (host.c_str (), port);
|
m_RouterInfo.AddNTCPAddress (host.c_str (), port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_RouterInfo.DisableV6 ();
|
m_RouterInfo.DisableV6 ();
|
||||||
@@ -690,9 +696,9 @@ namespace i2p
|
|||||||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
@@ -715,10 +721,10 @@ namespace i2p
|
|||||||
|
|
||||||
uint32_t RouterContext::GetUptime () const
|
uint32_t RouterContext::GetUptime () const
|
||||||
{
|
{
|
||||||
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;
|
return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now() - m_StartupTime).count ();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||||
{
|
{
|
||||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
@@ -64,8 +65,7 @@ namespace i2p
|
|||||||
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
||||||
i2p::crypto::X25519Keys& GetStaticKeys ();
|
i2p::crypto::X25519Keys& GetStaticKeys ();
|
||||||
|
|
||||||
uint32_t GetUptime () const;
|
uint32_t GetUptime () const; // in seconds
|
||||||
uint32_t GetStartupTime () const { return m_StartupTime; };
|
|
||||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||||
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
|
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
|
||||||
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
|
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
|
||||||
@@ -108,19 +108,24 @@ namespace i2p
|
|||||||
|
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||||
void SetLeaseSetUpdated () {};
|
void SetLeaseSetUpdated () {};
|
||||||
|
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () { return nullptr; };
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () { return nullptr; };
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
|
||||||
|
|
||||||
// override GarlicDestination
|
// override GarlicDestination
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// implements GarlicDestination
|
||||||
|
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||||
|
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateNewRouter ();
|
void CreateNewRouter ();
|
||||||
@@ -136,8 +141,8 @@ namespace i2p
|
|||||||
i2p::data::PrivateKeys m_Keys;
|
i2p::data::PrivateKeys m_Keys;
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
||||||
uint64_t m_LastUpdateTime; // in seconds
|
uint64_t m_LastUpdateTime; // in seconds
|
||||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||||
uint64_t m_StartupTime; // in seconds since epoch
|
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
|
||||||
uint64_t m_BandwidthLimit; // allowed bandwidth
|
uint64_t m_BandwidthLimit; // allowed bandwidth
|
||||||
int m_ShareRatio;
|
int m_ShareRatio;
|
||||||
RouterStatus m_Status;
|
RouterStatus m_Status;
|
||||||
|
|||||||
@@ -160,6 +160,13 @@ namespace transport
|
|||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
|
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
|
||||||
|
if (m_IsRunning)
|
||||||
|
{
|
||||||
|
// restart socket
|
||||||
|
m_Socket.close ();
|
||||||
|
OpenSocket ();
|
||||||
|
Receive ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,6 +182,12 @@ namespace transport
|
|||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
|
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
|
||||||
|
if (m_IsRunning)
|
||||||
|
{
|
||||||
|
m_SocketV6.close ();
|
||||||
|
OpenSocketV6 ();
|
||||||
|
ReceiveV6 ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,6 @@
|
|||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "SSU.h"
|
#include "SSU.h"
|
||||||
#include "SSUData.h"
|
#include "SSUData.h"
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
#include "Event.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -241,9 +238,6 @@ namespace transport
|
|||||||
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
|
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
if (!msg->IsExpired ())
|
if (!msg->IsExpired ())
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
QueueIntEvent("transport.recvmsg", m_Session.GetIdentHashBase64(), 1);
|
|
||||||
#endif
|
|
||||||
m_Handler.PutNextMessage (msg);
|
m_Handler.PutNextMessage (msg);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -448,7 +442,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
catch (boost::system::system_error& ec)
|
catch (boost::system::system_error& ec)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU: Can't resend data fragment ", ec.what ());
|
LogPrint (eLogWarning, "SSU: Can't resend message ", it->first, " data fragment: ", ec.what ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,7 +452,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||||
it = m_SentMessages.erase (it);
|
it = m_SentMessages.erase (it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -494,7 +488,7 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||||
it = m_IncompleteMessages.erase (it);
|
it = m_IncompleteMessages.erase (it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
#include "version.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
@@ -729,7 +730,8 @@ namespace transport
|
|||||||
encryption.Encrypt (encrypted, encryptedLen, encrypted);
|
encryption.Encrypt (encrypted, encryptedLen, encrypted);
|
||||||
// assume actual buffer size is 18 (16 + 2) bytes more
|
// assume actual buffer size is 18 (16 + 2) bytes more
|
||||||
memcpy (buf + len, iv, 16);
|
memcpy (buf + len, iv, 16);
|
||||||
htobe16buf (buf + len + 16, encryptedLen);
|
uint16_t netid = i2p::context.GetNetID ();
|
||||||
|
htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
|
||||||
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac);
|
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -750,7 +752,8 @@ namespace transport
|
|||||||
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
|
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
|
||||||
// assume actual buffer size is 18 (16 + 2) bytes more
|
// assume actual buffer size is 18 (16 + 2) bytes more
|
||||||
memcpy (buf + len, header->iv, 16);
|
memcpy (buf + len, header->iv, 16);
|
||||||
htobe16buf (buf + len + 16, encryptedLen);
|
uint16_t netid = i2p::context.GetNetID ();
|
||||||
|
htobe16buf (buf + 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -799,7 +802,8 @@ namespace transport
|
|||||||
uint16_t encryptedLen = len - (encrypted - buf);
|
uint16_t encryptedLen = len - (encrypted - buf);
|
||||||
// assume actual buffer size is 18 (16 + 2) bytes more
|
// assume actual buffer size is 18 (16 + 2) bytes more
|
||||||
memcpy (buf + len, header->iv, 16);
|
memcpy (buf + len, header->iv, 16);
|
||||||
htobe16buf (buf + len + 16, encryptedLen);
|
uint16_t netid = i2p::context.GetNetID ();
|
||||||
|
htobe16buf (buf + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
|
||||||
uint8_t digest[16];
|
uint8_t digest[16];
|
||||||
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, digest);
|
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, digest);
|
||||||
return !memcmp (header->mac, digest, 16);
|
return !memcmp (header->mac, digest, 16);
|
||||||
|
|||||||
@@ -86,13 +86,14 @@ namespace stream
|
|||||||
LogPrint (eLogDebug, "Streaming: Stream deleted");
|
LogPrint (eLogDebug, "Streaming: Stream deleted");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::Terminate ()
|
void Stream::Terminate (bool deleteFromDestination) // shoudl be called from StreamingDestination::Stop only
|
||||||
{
|
{
|
||||||
m_AckSendTimer.cancel ();
|
m_AckSendTimer.cancel ();
|
||||||
m_ReceiveTimer.cancel ();
|
m_ReceiveTimer.cancel ();
|
||||||
m_ResendTimer.cancel ();
|
m_ResendTimer.cancel ();
|
||||||
//CleanUp (); /* Need to recheck - broke working on windows */
|
//CleanUp (); /* Need to recheck - broke working on windows */
|
||||||
m_LocalDestination.DeleteStream (shared_from_this ());
|
if (deleteFromDestination)
|
||||||
|
m_LocalDestination.DeleteStream (shared_from_this ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stream::CleanUp ()
|
void Stream::CleanUp ()
|
||||||
@@ -847,6 +848,9 @@ namespace stream
|
|||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time
|
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time
|
||||||
|
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||||
|
[[fallthrough]];
|
||||||
|
#endif
|
||||||
// no break here
|
// no break here
|
||||||
case 4:
|
case 4:
|
||||||
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
|
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||||
@@ -918,7 +922,7 @@ namespace stream
|
|||||||
{
|
{
|
||||||
expired = false;
|
expired = false;
|
||||||
// time to request
|
// time to request
|
||||||
if (m_RemoteLeaseSet->GetOrigStoreType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
if (m_RemoteLeaseSet->IsPublishedEncrypted ())
|
||||||
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
|
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
|
||||||
std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity));
|
std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity));
|
||||||
else
|
else
|
||||||
@@ -964,7 +968,6 @@ namespace stream
|
|||||||
|
|
||||||
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
|
StreamingDestination::StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort, bool gzip):
|
||||||
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
m_Owner (owner), m_LocalPort (localPort), m_Gzip (gzip),
|
||||||
m_LastIncomingReceiveStreamID (0),
|
|
||||||
m_PendingIncomingTimer (m_Owner->GetService ())
|
m_PendingIncomingTimer (m_Owner->GetService ())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -990,7 +993,10 @@ namespace stream
|
|||||||
m_PendingIncomingStreams.clear ();
|
m_PendingIncomingStreams.clear ();
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||||
|
for (auto it: m_Streams)
|
||||||
|
it.second->Terminate (false); // we delete here
|
||||||
m_Streams.clear ();
|
m_Streams.clear ();
|
||||||
|
m_IncomingStreams.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1013,18 +1019,17 @@ namespace stream
|
|||||||
if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream
|
if (packet->IsSYN () && !packet->GetSeqn ()) // new incoming stream
|
||||||
{
|
{
|
||||||
uint32_t receiveStreamID = packet->GetReceiveStreamID ();
|
uint32_t receiveStreamID = packet->GetReceiveStreamID ();
|
||||||
if (receiveStreamID == m_LastIncomingReceiveStreamID)
|
auto it1 = m_IncomingStreams.find (receiveStreamID);
|
||||||
|
if (it1 != m_IncomingStreams.end ())
|
||||||
{
|
{
|
||||||
// already pending
|
// already pending
|
||||||
LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists");
|
LogPrint(eLogWarning, "Streaming: Incoming streaming with rSID=", receiveStreamID, " already exists");
|
||||||
DeletePacket (packet); // drop it, because previous should be connected
|
DeletePacket (packet); // drop it, because previous should be connected
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto incomingStream = CreateNewIncomingStream ();
|
auto incomingStream = CreateNewIncomingStream (receiveStreamID);
|
||||||
incomingStream->HandleNextPacket (packet); // SYN
|
incomingStream->HandleNextPacket (packet); // SYN
|
||||||
auto ident = incomingStream->GetRemoteIdentity();
|
auto ident = incomingStream->GetRemoteIdentity();
|
||||||
|
|
||||||
m_LastIncomingReceiveStreamID = receiveStreamID;
|
|
||||||
|
|
||||||
// handle saved packets if any
|
// handle saved packets if any
|
||||||
{
|
{
|
||||||
@@ -1062,13 +1067,13 @@ namespace stream
|
|||||||
else // follow on packet without SYN
|
else // follow on packet without SYN
|
||||||
{
|
{
|
||||||
uint32_t receiveStreamID = packet->GetReceiveStreamID ();
|
uint32_t receiveStreamID = packet->GetReceiveStreamID ();
|
||||||
for (auto& it: m_Streams)
|
auto it1 = m_IncomingStreams.find (receiveStreamID);
|
||||||
if (it.second->GetSendStreamID () == receiveStreamID)
|
if (it1 != m_IncomingStreams.end ())
|
||||||
{
|
{
|
||||||
// found
|
// found
|
||||||
it.second->HandleNextPacket (packet);
|
it1->second->HandleNextPacket (packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// save follow on packet
|
// save follow on packet
|
||||||
auto it = m_SavedPackets.find (receiveStreamID);
|
auto it = m_SavedPackets.find (receiveStreamID);
|
||||||
if (it != m_SavedPackets.end ())
|
if (it != m_SavedPackets.end ())
|
||||||
@@ -1105,11 +1110,12 @@ namespace stream
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream ()
|
std::shared_ptr<Stream> StreamingDestination::CreateNewIncomingStream (uint32_t receiveStreamID)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this);
|
auto s = std::make_shared<Stream> (m_Owner->GetService (), *this);
|
||||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||||
m_Streams[s->GetRecvStreamID ()] = s;
|
m_Streams[s->GetRecvStreamID ()] = s;
|
||||||
|
m_IncomingStreams[receiveStreamID] = s;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1118,12 +1124,20 @@ namespace stream
|
|||||||
if (stream)
|
if (stream)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
std::unique_lock<std::mutex> l(m_StreamsMutex);
|
||||||
auto it = m_Streams.find (stream->GetRecvStreamID ());
|
m_Streams.erase (stream->GetRecvStreamID ());
|
||||||
if (it != m_Streams.end ())
|
m_IncomingStreams.erase (stream->GetSendStreamID ());
|
||||||
m_Streams.erase (it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StreamingDestination::DeleteStream (uint32_t recvStreamID)
|
||||||
|
{
|
||||||
|
auto it = m_Streams.find (recvStreamID);
|
||||||
|
if (it == m_Streams.end ())
|
||||||
|
return false;
|
||||||
|
DeleteStream (it->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void StreamingDestination::SetAcceptor (const Acceptor& acceptor)
|
void StreamingDestination::SetAcceptor (const Acceptor& acceptor)
|
||||||
{
|
{
|
||||||
m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet
|
m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet
|
||||||
|
|||||||
@@ -180,8 +180,7 @@ namespace stream
|
|||||||
int GetWindowSize () const { return m_WindowSize; };
|
int GetWindowSize () const { return m_WindowSize; };
|
||||||
int GetRTT () const { return m_RTT; };
|
int GetRTT () const { return m_RTT; };
|
||||||
|
|
||||||
/** don't call me */
|
void Terminate (bool deleteFromDestination = true);
|
||||||
void Terminate ();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -251,6 +250,7 @@ namespace stream
|
|||||||
|
|
||||||
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||||
void DeleteStream (std::shared_ptr<Stream> stream);
|
void DeleteStream (std::shared_ptr<Stream> stream);
|
||||||
|
bool DeleteStream (uint32_t recvStreamID);
|
||||||
void SetAcceptor (const Acceptor& acceptor);
|
void SetAcceptor (const Acceptor& acceptor);
|
||||||
void ResetAcceptor ();
|
void ResetAcceptor ();
|
||||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||||
@@ -269,8 +269,10 @@ namespace stream
|
|||||||
|
|
||||||
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
|
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
void HandleNextPacket (Packet * packet);
|
void HandleNextPacket (Packet * packet);
|
||||||
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
std::shared_ptr<Stream> CreateNewIncomingStream (uint32_t receiveStreamID);
|
||||||
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
|
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -280,8 +282,8 @@ namespace stream
|
|||||||
bool m_Gzip; // gzip compression of data messages
|
bool m_Gzip; // gzip compression of data messages
|
||||||
std::mutex m_StreamsMutex;
|
std::mutex m_StreamsMutex;
|
||||||
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams; // sendStreamID->stream
|
std::map<uint32_t, std::shared_ptr<Stream> > m_Streams; // sendStreamID->stream
|
||||||
|
std::map<uint32_t, std::shared_ptr<Stream> > m_IncomingStreams; // receiveStreamID->stream
|
||||||
Acceptor m_Acceptor;
|
Acceptor m_Acceptor;
|
||||||
uint32_t m_LastIncomingReceiveStreamID;
|
|
||||||
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
|
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
|
||||||
boost::asio::deadline_timer m_PendingIncomingTimer;
|
boost::asio::deadline_timer m_PendingIncomingTimer;
|
||||||
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
|
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
|
||||||
|
|||||||
@@ -71,14 +71,14 @@ public:
|
|||||||
return std::string (str, str + l);
|
return std::string (str, str + l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FromBase32 (const std::string& s)
|
size_t FromBase32 (const std::string& s)
|
||||||
{
|
{
|
||||||
i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
return i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FromBase64 (const std::string& s)
|
size_t FromBase64 (const std::string& s)
|
||||||
{
|
{
|
||||||
i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -93,4 +93,16 @@ private:
|
|||||||
} // data
|
} // data
|
||||||
} // i2p
|
} // i2p
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
// hash for std::unordered_map
|
||||||
|
template<size_t sz> struct hash<i2p::data::Tag<sz> >
|
||||||
|
{
|
||||||
|
size_t operator()(const i2p::data::Tag<sz>& s) const
|
||||||
|
{
|
||||||
|
return s.GetLL ()[0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* TAG_H__ */
|
#endif /* TAG_H__ */
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "RouterInfo.h"
|
#include "RouterInfo.h"
|
||||||
@@ -67,8 +68,16 @@ namespace transport
|
|||||||
|
|
||||||
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
|
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; };
|
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity ()
|
||||||
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; };
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
|
||||||
|
return m_RemoteIdentity;
|
||||||
|
}
|
||||||
|
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
|
||||||
|
m_RemoteIdentity = ident;
|
||||||
|
}
|
||||||
|
|
||||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||||
@@ -85,6 +94,7 @@ namespace transport
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||||
|
mutable std::mutex m_RemoteIdentityMutex;
|
||||||
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
|
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
|
||||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||||
bool m_IsOutgoing;
|
bool m_IsOutgoing;
|
||||||
|
|||||||
@@ -6,10 +6,6 @@
|
|||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "HTTP.h"
|
#include "HTTP.h"
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
#include "Event.h"
|
|
||||||
#include "util.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace i2p::data;
|
using namespace i2p::data;
|
||||||
|
|
||||||
@@ -157,6 +153,7 @@ namespace transport
|
|||||||
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);
|
||||||
|
std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
|
||||||
i2p::http::URL proxyurl;
|
i2p::http::URL proxyurl;
|
||||||
uint16_t softLimit, hardLimit, threads;
|
uint16_t softLimit, hardLimit, threads;
|
||||||
i2p::config::GetOption("limits.ntcpsoft", softLimit);
|
i2p::config::GetOption("limits.ntcpsoft", softLimit);
|
||||||
@@ -196,13 +193,38 @@ namespace transport
|
|||||||
LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy);
|
LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// create NTCP2. TODO: move to acceptor
|
// create NTCP2. TODO: move to acceptor
|
||||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||||
if (ntcp2)
|
if (ntcp2)
|
||||||
{
|
{
|
||||||
m_NTCP2Server = new NTCP2Server ();
|
if(!ntcp2proxy.empty())
|
||||||
m_NTCP2Server->Start ();
|
{
|
||||||
}
|
if(proxyurl.parse(ntcp2proxy))
|
||||||
|
{
|
||||||
|
if(proxyurl.schema == "socks" || proxyurl.schema == "http")
|
||||||
|
{
|
||||||
|
m_NTCP2Server = new NTCP2Server ();
|
||||||
|
NTCP2Server::ProxyType proxytype = NTCP2Server::eSocksProxy;
|
||||||
|
|
||||||
|
if (proxyurl.schema == "http")
|
||||||
|
proxytype = NTCP2Server::eHTTPProxy;
|
||||||
|
|
||||||
|
m_NTCP2Server->UseProxy(proxytype, proxyurl.host, proxyurl.port) ;
|
||||||
|
m_NTCP2Server->Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogError, "Transports: unsupported NTCP2 proxy URL ", ntcp2proxy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint(eLogError, "Transports: invalid NTCP2 proxy url ", ntcp2proxy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_NTCP2Server = new NTCP2Server ();
|
||||||
|
m_NTCP2Server->Start ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create acceptors
|
// create acceptors
|
||||||
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
auto& addresses = context.GetRouterInfo ().GetAddresses ();
|
||||||
@@ -249,11 +271,11 @@ namespace transport
|
|||||||
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
|
||||||
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
|
||||||
|
|
||||||
if (m_IsNAT)
|
if (m_IsNAT)
|
||||||
{
|
{
|
||||||
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
|
||||||
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::Stop ()
|
void Transports::Stop ()
|
||||||
@@ -346,9 +368,6 @@ namespace transport
|
|||||||
|
|
||||||
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
void Transports::SendMessages (const i2p::data::IdentHash& ident, const std::vector<std::shared_ptr<i2p::I2NPMessage> >& msgs)
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
QueueIntEvent("transport.send", ident.ToBase64(), msgs.size());
|
|
||||||
#endif
|
|
||||||
m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
m_Service->post (std::bind (&Transports::PostMessages, this, ident, msgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,24 +424,36 @@ namespace transport
|
|||||||
{
|
{
|
||||||
if (peer.router) // we have RI already
|
if (peer.router) // we have RI already
|
||||||
{
|
{
|
||||||
if (!peer.numAttempts) // NTCP2
|
if (!peer.numAttempts) // NTCP2
|
||||||
{
|
{
|
||||||
peer.numAttempts++;
|
peer.numAttempts++;
|
||||||
if (m_NTCP2Server) // we support NTCP2
|
if (m_NTCP2Server) // we support NTCP2
|
||||||
{
|
{
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
|
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
|
||||||
m_NTCP2Server->Connect (address->host, address->port, s);
|
|
||||||
return true;
|
if(m_NTCP2Server->UsingProxy())
|
||||||
}
|
{
|
||||||
}
|
NTCP2Server::RemoteAddressType remote = NTCP2Server::eIP4Address;
|
||||||
}
|
std::string addr = address->host.to_string();
|
||||||
|
|
||||||
|
if(address->host.is_v6())
|
||||||
|
remote = NTCP2Server::eIP6Address;
|
||||||
|
|
||||||
|
m_NTCP2Server->ConnectWithProxy(addr, address->port, remote, s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_NTCP2Server->Connect (address->host, address->port, s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (peer.numAttempts == 1) // NTCP1
|
if (peer.numAttempts == 1) // NTCP1
|
||||||
{
|
{
|
||||||
peer.numAttempts++;
|
peer.numAttempts++;
|
||||||
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
|
||||||
if (address && m_NTCPServer)
|
if (address && m_NTCPServer)
|
||||||
{
|
{
|
||||||
@@ -465,6 +496,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
||||||
|
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
|
||||||
peer.Done ();
|
peer.Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
@@ -503,28 +535,6 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transports::CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
|
|
||||||
{
|
|
||||||
if (!router) return;
|
|
||||||
m_Service->post (std::bind (&Transports::PostCloseSession, this, router));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transports::PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router)
|
|
||||||
{
|
|
||||||
auto ssuSession = m_SSUServer ? m_SSUServer->FindSession (router) : nullptr;
|
|
||||||
if (ssuSession) // try SSU first
|
|
||||||
{
|
|
||||||
m_SSUServer->DeleteSession (ssuSession);
|
|
||||||
LogPrint (eLogDebug, "Transports: SSU session closed");
|
|
||||||
}
|
|
||||||
auto ntcpSession = m_NTCPServer ? m_NTCPServer->FindNTCPSession(router->GetIdentHash()) : nullptr;
|
|
||||||
if (ntcpSession) // try deleting ntcp session too
|
|
||||||
{
|
|
||||||
ntcpSession->Terminate ();
|
|
||||||
LogPrint(eLogDebug, "Transports: NTCP session closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Transports::DetectExternalIP ()
|
void Transports::DetectExternalIP ()
|
||||||
{
|
{
|
||||||
@@ -562,7 +572,10 @@ namespace transport
|
|||||||
{
|
{
|
||||||
auto addr = router->GetSSUV6Address ();
|
auto addr = router->GetSSUV6Address ();
|
||||||
if (addr)
|
if (addr)
|
||||||
m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false);
|
m_SSUServer->GetServiceV6 ().post ([this, router, addr]
|
||||||
|
{
|
||||||
|
m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -576,6 +589,7 @@ namespace transport
|
|||||||
if (RoutesRestricted() || !i2p::context.SupportsV4 ()) return;
|
if (RoutesRestricted() || !i2p::context.SupportsV4 ()) return;
|
||||||
if (m_SSUServer)
|
if (m_SSUServer)
|
||||||
{
|
{
|
||||||
|
LogPrint (eLogInfo, "Transports: Started peer test");
|
||||||
bool statusChanged = false;
|
bool statusChanged = false;
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
@@ -591,7 +605,7 @@ namespace transport
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!statusChanged)
|
if (!statusChanged)
|
||||||
LogPrint (eLogWarning, "Can't find routers for peer test");
|
LogPrint (eLogWarning, "Transports: Can't find routers for peer test");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,9 +629,6 @@ namespace transport
|
|||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "false"}});
|
|
||||||
#endif
|
|
||||||
bool sendDatabaseStore = true;
|
bool sendDatabaseStore = true;
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (it->second.delayedMessages.size () > 0)
|
||||||
{
|
{
|
||||||
@@ -643,9 +654,6 @@ namespace transport
|
|||||||
session->Done();
|
session->Done();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}});
|
|
||||||
#endif
|
|
||||||
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
|
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
|
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
|
||||||
@@ -660,17 +668,19 @@ namespace transport
|
|||||||
auto remoteIdentity = session->GetRemoteIdentity ();
|
auto remoteIdentity = session->GetRemoteIdentity ();
|
||||||
if (!remoteIdentity) return;
|
if (!remoteIdentity) return;
|
||||||
auto ident = remoteIdentity->GetIdentHash ();
|
auto ident = remoteIdentity->GetIdentHash ();
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitEvent({{"type" , "transport.disconnected"}, {"ident", ident.ToBase64()}});
|
|
||||||
#endif
|
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
|
auto before = it->second.sessions.size ();
|
||||||
it->second.sessions.remove (session);
|
it->second.sessions.remove (session);
|
||||||
if (it->second.sessions.empty ()) // TODO: why?
|
if (it->second.sessions.empty ())
|
||||||
{
|
{
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (it->second.delayedMessages.size () > 0)
|
||||||
|
{
|
||||||
|
if (before > 0) // we had an active session before
|
||||||
|
it->second.numAttempts = 0; // start over
|
||||||
ConnectToPeer (ident, it->second);
|
ConnectToPeer (ident, it->second);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ namespace transport
|
|||||||
|
|
||||||
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);
|
||||||
void CloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
|
||||||
|
|
||||||
void PeerConnected (std::shared_ptr<TransportSession> session);
|
void PeerConnected (std::shared_ptr<TransportSession> session);
|
||||||
void PeerDisconnected (std::shared_ptr<TransportSession> session);
|
void PeerDisconnected (std::shared_ptr<TransportSession> session);
|
||||||
@@ -131,7 +130,6 @@ namespace transport
|
|||||||
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
void RequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, const i2p::data::IdentHash& ident);
|
||||||
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
void HandleRequestComplete (std::shared_ptr<const i2p::data::RouterInfo> r, i2p::data::IdentHash ident);
|
||||||
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
void PostMessages (i2p::data::IdentHash ident, std::vector<std::shared_ptr<i2p::I2NPMessage> > msgs);
|
||||||
void PostCloseSession (std::shared_ptr<const i2p::data::RouterInfo> router);
|
|
||||||
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
bool ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer);
|
||||||
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
void HandlePeerCleanupTimer (const boost::system::error_code& ecode);
|
||||||
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
void HandlePeerTestTimer (const boost::system::error_code& ecode);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
|
#include <random>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -13,9 +14,6 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "TunnelPool.h"
|
#include "TunnelPool.h"
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
#include "Event.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -34,9 +32,6 @@ namespace tunnel
|
|||||||
|
|
||||||
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
|
void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel)
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64();
|
|
||||||
#endif
|
|
||||||
auto numHops = m_Config->GetNumHops ();
|
auto numHops = m_Config->GetNumHops ();
|
||||||
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
|
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
|
||||||
auto msg = NewI2NPShortMessage ();
|
auto msg = NewI2NPShortMessage ();
|
||||||
@@ -45,7 +40,7 @@ namespace tunnel
|
|||||||
// shuffle records
|
// shuffle records
|
||||||
std::vector<int> recordIndicies;
|
std::vector<int> recordIndicies;
|
||||||
for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i);
|
for (int i = 0; i < numRecords; i++) recordIndicies.push_back(i);
|
||||||
std::random_shuffle (recordIndicies.begin(), recordIndicies.end());
|
std::shuffle (recordIndicies.begin(), recordIndicies.end(), std::mt19937(std::random_device()()));
|
||||||
|
|
||||||
// create real records
|
// create real records
|
||||||
uint8_t * records = msg->GetPayload () + 1;
|
uint8_t * records = msg->GetPayload () + 1;
|
||||||
@@ -63,15 +58,9 @@ namespace tunnel
|
|||||||
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx);
|
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx);
|
||||||
hop->recordIndex = idx;
|
hop->recordIndex = idx;
|
||||||
i++;
|
i++;
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
peers += ":" + hop->ident->GetIdentHash().ToBase64();
|
|
||||||
#endif
|
|
||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnel.build", this, peers);
|
|
||||||
#endif
|
|
||||||
// fill up fake records with random data
|
// fill up fake records with random data
|
||||||
for (int i = numHops; i < numRecords; i++)
|
for (int i = numHops; i < numRecords; i++)
|
||||||
{
|
{
|
||||||
@@ -206,9 +195,6 @@ namespace tunnel
|
|||||||
void Tunnel::SetState(TunnelState state)
|
void Tunnel::SetState(TunnelState state)
|
||||||
{
|
{
|
||||||
m_State = state;
|
m_State = state;
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnel.state", this, state);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -590,7 +576,6 @@ namespace tunnel
|
|||||||
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
|
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
|
||||||
{
|
{
|
||||||
auto tunnel = it->second;
|
auto tunnel = it->second;
|
||||||
auto pool = tunnel->GetTunnelPool();
|
|
||||||
switch (tunnel->GetState ())
|
switch (tunnel->GetState ())
|
||||||
{
|
{
|
||||||
case eTunnelStatePending:
|
case eTunnelStatePending:
|
||||||
@@ -613,11 +598,6 @@ namespace tunnel
|
|||||||
hop = hop->next;
|
hop = hop->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed);
|
|
||||||
#endif
|
|
||||||
// for i2lua
|
|
||||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultTimeout);
|
|
||||||
// delete
|
// delete
|
||||||
it = pendingTunnels.erase (it);
|
it = pendingTunnels.erase (it);
|
||||||
m_NumFailedTunnelCreations++;
|
m_NumFailedTunnelCreations++;
|
||||||
@@ -627,12 +607,6 @@ namespace tunnel
|
|||||||
break;
|
break;
|
||||||
case eTunnelStateBuildFailed:
|
case eTunnelStateBuildFailed:
|
||||||
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted");
|
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " failed, deleted");
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnel.state", tunnel.get(), eTunnelStateBuildFailed);
|
|
||||||
#endif
|
|
||||||
// for i2lua
|
|
||||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultRejected);
|
|
||||||
|
|
||||||
it = pendingTunnels.erase (it);
|
it = pendingTunnels.erase (it);
|
||||||
m_NumFailedTunnelCreations++;
|
m_NumFailedTunnelCreations++;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -19,49 +19,11 @@
|
|||||||
#include "TunnelGateway.h"
|
#include "TunnelGateway.h"
|
||||||
#include "TunnelBase.h"
|
#include "TunnelBase.h"
|
||||||
#include "I2NPProtocol.h"
|
#include "I2NPProtocol.h"
|
||||||
#include "Event.h"
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename TunnelT>
|
|
||||||
static void EmitTunnelEvent(const std::string & ev, const TunnelT & t)
|
|
||||||
{
|
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}});
|
|
||||||
#else
|
|
||||||
(void) ev;
|
|
||||||
(void) t;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TunnelT, typename T>
|
|
||||||
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val)
|
|
||||||
{
|
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", std::to_string(val)}, {"inbound", std::to_string(t->IsInbound())}});
|
|
||||||
#else
|
|
||||||
(void) ev;
|
|
||||||
(void) t;
|
|
||||||
(void) val;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TunnelT>
|
|
||||||
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const std::string & val)
|
|
||||||
{
|
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitEvent({{"type", ev}, {"tid", std::to_string(t->GetTunnelID())}, {"value", val}, {"inbound", std::to_string(t->IsInbound())}});
|
|
||||||
#else
|
|
||||||
(void) ev;
|
|
||||||
(void) t;
|
|
||||||
(void) val;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
||||||
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
||||||
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
@@ -10,9 +11,6 @@
|
|||||||
#include "Tunnel.h"
|
#include "Tunnel.h"
|
||||||
#include "TunnelPool.h"
|
#include "TunnelPool.h"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
#include "Event.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
@@ -85,25 +83,17 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
if (!m_IsActive) return;
|
if (!m_IsActive) return;
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnels.created", createdTunnel);
|
|
||||||
#endif
|
|
||||||
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_InboundTunnelsMutex);
|
||||||
m_InboundTunnels.insert (createdTunnel);
|
m_InboundTunnels.insert (createdTunnel);
|
||||||
}
|
}
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
m_LocalDestination->SetLeaseSetUpdated ();
|
m_LocalDestination->SetLeaseSetUpdated ();
|
||||||
|
|
||||||
OnTunnelBuildResult(createdTunnel, eBuildResultOkay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel)
|
void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel)
|
||||||
{
|
{
|
||||||
if (expiredTunnel)
|
if (expiredTunnel)
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnels.expired", expiredTunnel);
|
|
||||||
#endif
|
|
||||||
expiredTunnel->SetTunnelPool (nullptr);
|
expiredTunnel->SetTunnelPool (nullptr);
|
||||||
for (auto& it: m_Tests)
|
for (auto& it: m_Tests)
|
||||||
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
if (it.second.second == expiredTunnel) it.second.second = nullptr;
|
||||||
@@ -117,14 +107,9 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
if (!m_IsActive) return;
|
if (!m_IsActive) return;
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnels.created", createdTunnel);
|
|
||||||
#endif
|
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
m_OutboundTunnels.insert (createdTunnel);
|
m_OutboundTunnels.insert (createdTunnel);
|
||||||
}
|
}
|
||||||
OnTunnelBuildResult(createdTunnel, eBuildResultOkay);
|
|
||||||
|
|
||||||
//CreatePairedInboundTunnel (createdTunnel);
|
//CreatePairedInboundTunnel (createdTunnel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,9 +117,6 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
if (expiredTunnel)
|
if (expiredTunnel)
|
||||||
{
|
{
|
||||||
#ifdef WITH_EVENTS
|
|
||||||
EmitTunnelEvent("tunnels.expired", expiredTunnel);
|
|
||||||
#endif
|
|
||||||
expiredTunnel->SetTunnelPool (nullptr);
|
expiredTunnel->SetTunnelPool (nullptr);
|
||||||
for (auto& it: m_Tests)
|
for (auto& it: m_Tests)
|
||||||
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
if (it.second.first == expiredTunnel) it.second.first = nullptr;
|
||||||
@@ -441,7 +423,7 @@ namespace tunnel
|
|||||||
int size = m_ExplicitPeers->size ();
|
int size = m_ExplicitPeers->size ();
|
||||||
std::vector<int> peerIndicies;
|
std::vector<int> peerIndicies;
|
||||||
for (int i = 0; i < size; i++) peerIndicies.push_back(i);
|
for (int i = 0; i < size; i++) peerIndicies.push_back(i);
|
||||||
std::random_shuffle (peerIndicies.begin(), peerIndicies.end());
|
std::shuffle (peerIndicies.begin(), peerIndicies.end(), std::mt19937(std::random_device()()));
|
||||||
|
|
||||||
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops;
|
||||||
for (int i = 0; i < numHops; i++)
|
for (int i = 0; i < numHops; i++)
|
||||||
@@ -610,11 +592,5 @@ namespace tunnel
|
|||||||
}
|
}
|
||||||
return tun;
|
return tun;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result)
|
|
||||||
{
|
|
||||||
auto peers = tunnel->GetPeers();
|
|
||||||
if(m_CustomPeerSelector) m_CustomPeerSelector->OnBuildResult(peers, tunnel->IsInbound(), result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,6 @@ namespace tunnel
|
|||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
class OutboundTunnel;
|
class OutboundTunnel;
|
||||||
|
|
||||||
|
|
||||||
enum TunnelBuildResult {
|
|
||||||
eBuildResultOkay, // tunnel was built okay
|
|
||||||
eBuildResultRejected, // tunnel build was explicitly rejected
|
|
||||||
eBuildResultTimeout // tunnel build timed out
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
|
typedef std::shared_ptr<const i2p::data::IdentityEx> Peer;
|
||||||
typedef std::vector<Peer> Path;
|
typedef std::vector<Peer> Path;
|
||||||
|
|
||||||
@@ -38,7 +31,6 @@ namespace tunnel
|
|||||||
{
|
{
|
||||||
virtual ~ITunnelPeerSelector() {};
|
virtual ~ITunnelPeerSelector() {};
|
||||||
virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
|
virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
|
||||||
virtual bool OnBuildResult(const Path & peers, bool isInbound, TunnelBuildResult result) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -98,8 +90,6 @@ namespace tunnel
|
|||||||
std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude=nullptr) const;
|
std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude=nullptr) const;
|
||||||
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
|
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const;
|
||||||
|
|
||||||
void OnTunnelBuildResult(std::shared_ptr<Tunnel> tunnel, TunnelBuildResult result);
|
|
||||||
|
|
||||||
// for overriding tunnel peer selection
|
// for overriding tunnel peer selection
|
||||||
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace api
|
|||||||
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
auto localDestination = std::make_shared<i2p::client::ClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<i2p::client::RunnableClientDestination> (keys, isPublic, params);
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ namespace api
|
|||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
|
||||||
auto localDestination = std::make_shared<i2p::client::ClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<i2p::client::RunnableClientDestination> (keys, isPublic, params);
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
||||||
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
||||||
|
|
||||||
// inet_pton exists Windows since Vista, but XP haven't that function!
|
// inet_pton exists Windows since Vista, but XP doesn't have that function!
|
||||||
// This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
// This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
||||||
int inet_pton_xp(int af, const char *src, void *dst)
|
int inet_pton_xp(int af, const char *src, void *dst)
|
||||||
{
|
{
|
||||||
@@ -57,21 +57,65 @@ namespace i2p
|
|||||||
{
|
{
|
||||||
namespace util
|
namespace util
|
||||||
{
|
{
|
||||||
|
|
||||||
|
void RunnableService::StartIOService ()
|
||||||
|
{
|
||||||
|
if (!m_IsRunning)
|
||||||
|
{
|
||||||
|
m_IsRunning = true;
|
||||||
|
m_Thread.reset (new std::thread (std::bind (& RunnableService::Run, this)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunnableService::StopIOService ()
|
||||||
|
{
|
||||||
|
if (m_IsRunning)
|
||||||
|
{
|
||||||
|
m_IsRunning = false;
|
||||||
|
m_Service.stop ();
|
||||||
|
if (m_Thread)
|
||||||
|
{
|
||||||
|
m_Thread->join ();
|
||||||
|
m_Thread = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunnableService::Run ()
|
||||||
|
{
|
||||||
|
while (m_IsRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_Service.run ();
|
||||||
|
}
|
||||||
|
catch (std::exception& ex)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, m_Name, ": runtime exception: ", ex.what ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
bool IsWindowsXPorLater()
|
bool IsWindowsXPorLater()
|
||||||
{
|
{
|
||||||
OSVERSIONINFO osvi;
|
static bool isRequested = false;
|
||||||
|
static bool isXP = false;
|
||||||
|
if (!isRequested)
|
||||||
|
{
|
||||||
|
// request
|
||||||
|
OSVERSIONINFO osvi;
|
||||||
|
|
||||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
GetVersionEx(&osvi);
|
GetVersionEx(&osvi);
|
||||||
|
|
||||||
if (osvi.dwMajorVersion <= 5)
|
isXP = osvi.dwMajorVersion <= 5;
|
||||||
return true;
|
isRequested = true;
|
||||||
else
|
}
|
||||||
return false;
|
return isXP;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
|
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
|
||||||
@@ -202,21 +246,20 @@ namespace net
|
|||||||
std::string localAddressUniversal = localAddress.to_string();
|
std::string localAddressUniversal = localAddress.to_string();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (IsWindowsXPorLater())
|
typedef int (* IPN)(int af, const char *src, void *dst);
|
||||||
{
|
IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
|
||||||
#define inet_pton inet_pton_xp
|
if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found
|
||||||
}
|
|
||||||
|
|
||||||
if(localAddress.is_v4())
|
if(localAddress.is_v4())
|
||||||
{
|
{
|
||||||
sockaddr_in inputAddress;
|
sockaddr_in inputAddress;
|
||||||
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
|
inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
|
||||||
return GetMTUWindowsIpv4(inputAddress, fallback);
|
return GetMTUWindowsIpv4(inputAddress, fallback);
|
||||||
}
|
}
|
||||||
else if(localAddress.is_v6())
|
else if(localAddress.is_v6())
|
||||||
{
|
{
|
||||||
sockaddr_in6 inputAddress;
|
sockaddr_in6 inputAddress;
|
||||||
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
|
inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
|
||||||
return GetMTUWindowsIpv6(inputAddress, fallback);
|
return GetMTUWindowsIpv6(inputAddress, fallback);
|
||||||
} else {
|
} else {
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
|
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
|
||||||
@@ -281,7 +324,7 @@ namespace net
|
|||||||
|
|
||||||
int GetMTU(const boost::asio::ip::address& localAddress)
|
int GetMTU(const boost::asio::ip::address& localAddress)
|
||||||
{
|
{
|
||||||
const int fallback = 576; // fallback MTU
|
int fallback = localAddress.is_v6 () ? 1280 : 620; // fallback MTU
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
return GetMTUWindows(localAddress, fallback);
|
return GetMTUWindows(localAddress, fallback);
|
||||||
@@ -312,15 +355,14 @@ namespace net
|
|||||||
if (cur_ifname == ifname && cur->ifa_addr && cur->ifa_addr->sa_family == af)
|
if (cur_ifname == ifname && cur->ifa_addr && cur->ifa_addr->sa_family == af)
|
||||||
{
|
{
|
||||||
// match
|
// match
|
||||||
char * addr = new char[INET6_ADDRSTRLEN];
|
char addr[INET6_ADDRSTRLEN];
|
||||||
bzero(addr, INET6_ADDRSTRLEN);
|
memset (addr, 0, INET6_ADDRSTRLEN);
|
||||||
if(af == AF_INET)
|
if(af == AF_INET)
|
||||||
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
|
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
|
||||||
else
|
else
|
||||||
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
|
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
|
||||||
freeifaddrs(addrs);
|
freeifaddrs(addrs);
|
||||||
std::string cur_ifaddr(addr);
|
std::string cur_ifaddr(addr);
|
||||||
delete[] addr;
|
|
||||||
return boost::asio::ip::address::from_string(cur_ifaddr);
|
return boost::asio::ip::address::from_string(cur_ifaddr);
|
||||||
}
|
}
|
||||||
cur = cur->ifa_next;
|
cur = cur->ifa_next;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ namespace util
|
|||||||
{
|
{
|
||||||
auto tmp = m_Head;
|
auto tmp = m_Head;
|
||||||
m_Head = static_cast<T*>(*(void * *)m_Head); // next
|
m_Head = static_cast<T*>(*(void * *)m_Head); // next
|
||||||
delete tmp;
|
::operator delete ((void *)tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +123,43 @@ namespace util
|
|||||||
std::mutex m_Mutex;
|
std::mutex m_Mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RunnableService
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
RunnableService (const std::string& name): m_Name (name), m_IsRunning (false) {}
|
||||||
|
virtual ~RunnableService () {}
|
||||||
|
|
||||||
|
boost::asio::io_service& GetIOService () { return m_Service; }
|
||||||
|
bool IsRunning () const { return m_IsRunning; };
|
||||||
|
|
||||||
|
void StartIOService ();
|
||||||
|
void StopIOService ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void Run ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string m_Name;
|
||||||
|
volatile bool m_IsRunning;
|
||||||
|
std::unique_ptr<std::thread> m_Thread;
|
||||||
|
boost::asio::io_service m_Service;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RunnableServiceWithWork: public RunnableService
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
RunnableServiceWithWork (const std::string& name):
|
||||||
|
RunnableService (name), m_Work (GetIOService ()) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
boost::asio::io_service::work m_Work;
|
||||||
|
};
|
||||||
|
|
||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
int GetMTU (const boost::asio::ip::address& localAddress);
|
int GetMTU (const boost::asio::ip::address& localAddress);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 26
|
#define I2PD_VERSION_MINOR 31
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 40
|
#define I2P_VERSION_MICRO 45
|
||||||
#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)
|
||||||
|
|
||||||
|
|||||||
@@ -237,17 +237,19 @@ namespace client
|
|||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
Address::Address (const std::string& b32)
|
Address::Address (const std::string& b32):
|
||||||
|
addressType (eAddressInvalid)
|
||||||
{
|
{
|
||||||
if (b32.length () <= B33_ADDRESS_THRESHOLD)
|
if (b32.length () <= B33_ADDRESS_THRESHOLD)
|
||||||
{
|
{
|
||||||
addressType = eAddressIndentHash;
|
if (identHash.FromBase32 (b32) > 0)
|
||||||
identHash.FromBase32 (b32);
|
addressType = eAddressIndentHash;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addressType = eAddressBlindedPublicKey;
|
|
||||||
blindedPublicKey = std::make_shared<i2p::data::BlindedPublicKey>(b32);
|
blindedPublicKey = std::make_shared<i2p::data::BlindedPublicKey>(b32);
|
||||||
|
if (blindedPublicKey->IsValid ())
|
||||||
|
addressType = eAddressBlindedPublicKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +322,10 @@ namespace client
|
|||||||
{
|
{
|
||||||
auto pos = address.find(".b32.i2p");
|
auto pos = address.find(".b32.i2p");
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
return std::make_shared<const Address>(address.substr (0, pos));
|
{
|
||||||
|
auto addr = std::make_shared<const Address>(address.substr (0, pos));
|
||||||
|
return addr->IsValid () ? addr : nullptr;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos = address.find (".i2p");
|
pos = address.find (".i2p");
|
||||||
@@ -422,9 +427,9 @@ namespace client
|
|||||||
std::string name = s.substr(0, pos++);
|
std::string name = s.substr(0, pos++);
|
||||||
std::string addr = s.substr(pos);
|
std::string addr = s.substr(pos);
|
||||||
|
|
||||||
size_t pos = s.find('#');
|
size_t pos = addr.find('#');
|
||||||
if (pos != std::string::npos)
|
if (pos != std::string::npos)
|
||||||
addr = addr.substr(pos); // remove comments
|
addr = addr.substr(0, pos); // remove comments
|
||||||
|
|
||||||
auto ident = std::make_shared<i2p::data::IdentityEx> ();
|
auto ident = std::make_shared<i2p::data::IdentityEx> ();
|
||||||
if (!ident->FromBase64(addr)) {
|
if (!ident->FromBase64(addr)) {
|
||||||
|
|||||||
@@ -33,13 +33,14 @@ namespace client
|
|||||||
|
|
||||||
struct Address
|
struct Address
|
||||||
{
|
{
|
||||||
enum { eAddressIndentHash, eAddressBlindedPublicKey } addressType;
|
enum { eAddressIndentHash, eAddressBlindedPublicKey, eAddressInvalid } addressType;
|
||||||
i2p::data::IdentHash identHash;
|
i2p::data::IdentHash identHash;
|
||||||
std::shared_ptr<i2p::data::BlindedPublicKey> blindedPublicKey;
|
std::shared_ptr<i2p::data::BlindedPublicKey> blindedPublicKey;
|
||||||
|
|
||||||
Address (const std::string& b32);
|
Address (const std::string& b32);
|
||||||
Address (const i2p::data::IdentHash& hash);
|
Address (const i2p::data::IdentHash& hash);
|
||||||
bool IsIdentHash () const { return addressType == eAddressIndentHash; };
|
bool IsIdentHash () const { return addressType == eAddressIndentHash; };
|
||||||
|
bool IsValid () const { return addressType != eAddressInvalid; };
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
||||||
|
|||||||
@@ -341,17 +341,17 @@ namespace client
|
|||||||
SendReplyOK();
|
SendReplyOK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandSession::SendData (const char * data)
|
void BOBCommandSession::SendRaw (const char * data)
|
||||||
{
|
{
|
||||||
std::ostream os(&m_SendBuffer);
|
std::ostream os(&m_SendBuffer);
|
||||||
os << "DATA " << data << std::endl;
|
os << data << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out)
|
void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out)
|
||||||
{
|
{
|
||||||
// helper lambdas
|
// helper lambdas
|
||||||
const auto isset = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
|
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
|
||||||
const auto issetNum = [&isset](const int p) { return isset(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
|
const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
|
||||||
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
|
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
|
||||||
const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); };
|
const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); };
|
||||||
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
|
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
|
||||||
@@ -359,8 +359,8 @@ namespace client
|
|||||||
// tunnel info
|
// tunnel info
|
||||||
const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname();
|
const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname();
|
||||||
const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet();
|
const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet();
|
||||||
const std::string inhost = isset(currentTunnel ? m_InHost : dest->GetInHost());
|
const std::string inhost = issetStr(currentTunnel ? m_InHost : dest->GetInHost());
|
||||||
const std::string outhost = isset(currentTunnel ? m_OutHost : dest->GetOutHost());
|
const std::string outhost = issetStr(currentTunnel ? m_OutHost : dest->GetOutHost());
|
||||||
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
|
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
|
||||||
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
|
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
|
||||||
const bool keys = destExists(dest); // key must exist when destination is created
|
const bool keys = destExists(dest); // key must exist when destination is created
|
||||||
@@ -370,7 +370,8 @@ namespace client
|
|||||||
|
|
||||||
// build line
|
// build line
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "NICKNAME: " << nickname << " " << "STARTING: " << bool_str(starting) << " "
|
ss << "DATA "
|
||||||
|
<< "NICKNAME: " << nickname << " " << "STARTING: " << bool_str(starting) << " "
|
||||||
<< "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " "
|
<< "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " "
|
||||||
<< "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " "
|
<< "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " "
|
||||||
<< "INPORT: " << inport << " " << "INHOST: " << inhost << " "
|
<< "INPORT: " << inport << " " << "INHOST: " << inhost << " "
|
||||||
@@ -654,16 +655,16 @@ namespace client
|
|||||||
for (const auto& it: destinations)
|
for (const auto& it: destinations)
|
||||||
{
|
{
|
||||||
BuildStatusLine(false, it.second, statusLine);
|
BuildStatusLine(false, it.second, statusLine);
|
||||||
SendData (statusLine.c_str());
|
SendRaw(statusLine.c_str());
|
||||||
if(m_Nickname.compare(it.second->GetNickname()) == 0)
|
if(m_Nickname.compare(it.second->GetNickname()) == 0)
|
||||||
sentCurrent = true;
|
sentCurrent = true;
|
||||||
}
|
}
|
||||||
if(!sentCurrent && !m_Nickname.empty())
|
if(!sentCurrent && !m_Nickname.empty())
|
||||||
{
|
{
|
||||||
// add the current tunnel to the list
|
// add the current tunnel to the list.
|
||||||
|
// this is for the incomplete tunnel which has not been started yet.
|
||||||
BuildStatusLine(true, m_CurrentDestination, statusLine);
|
BuildStatusLine(true, m_CurrentDestination, statusLine);
|
||||||
LogPrint(eLogError, statusLine);
|
SendRaw(statusLine.c_str());
|
||||||
SendData(statusLine.c_str());
|
|
||||||
}
|
}
|
||||||
SendReplyOK ("Listing done");
|
SendReplyOK ("Listing done");
|
||||||
}
|
}
|
||||||
@@ -690,21 +691,23 @@ namespace client
|
|||||||
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
|
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "BOB: status ", operand);
|
LogPrint (eLogDebug, "BOB: status ", operand);
|
||||||
|
const std::string name = operand;
|
||||||
std::string statusLine;
|
std::string statusLine;
|
||||||
if (m_Nickname == operand)
|
|
||||||
|
// always prefer destination
|
||||||
|
auto ptr = m_Owner.FindDestination(name);
|
||||||
|
if(ptr != nullptr)
|
||||||
{
|
{
|
||||||
// check current tunnel
|
// tunnel destination exists
|
||||||
BuildStatusLine(true, nullptr, statusLine);
|
BuildStatusLine(false, ptr, statusLine);
|
||||||
SendReplyOK(statusLine.c_str());
|
SendReplyOK(statusLine.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// check other
|
if(m_Nickname == name && !name.empty())
|
||||||
std::string name = operand;
|
|
||||||
auto ptr = m_Owner.FindDestination(name);
|
|
||||||
if(ptr != nullptr)
|
|
||||||
{
|
{
|
||||||
BuildStatusLine(false, ptr, statusLine);
|
// tunnel is incomplete / has not been started yet
|
||||||
|
BuildStatusLine(true, nullptr, statusLine);
|
||||||
SendReplyOK(statusLine.c_str());
|
SendReplyOK(statusLine.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -740,8 +743,8 @@ namespace client
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
|
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
|
||||||
m_IsRunning (false), m_Thread (nullptr),
|
RunnableService ("BOB"),
|
||||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
|
m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
|
||||||
{
|
{
|
||||||
// command -> handler
|
// command -> handler
|
||||||
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
|
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
|
||||||
@@ -791,7 +794,8 @@ namespace client
|
|||||||
|
|
||||||
BOBCommandChannel::~BOBCommandChannel ()
|
BOBCommandChannel::~BOBCommandChannel ()
|
||||||
{
|
{
|
||||||
Stop ();
|
if (IsRunning ())
|
||||||
|
Stop ();
|
||||||
for (const auto& it: m_Destinations)
|
for (const auto& it: m_Destinations)
|
||||||
delete it.second;
|
delete it.second;
|
||||||
}
|
}
|
||||||
@@ -799,38 +803,15 @@ namespace client
|
|||||||
void BOBCommandChannel::Start ()
|
void BOBCommandChannel::Start ()
|
||||||
{
|
{
|
||||||
Accept ();
|
Accept ();
|
||||||
m_IsRunning = true;
|
StartIOService ();
|
||||||
m_Thread = new std::thread (std::bind (&BOBCommandChannel::Run, this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandChannel::Stop ()
|
void BOBCommandChannel::Stop ()
|
||||||
{
|
{
|
||||||
m_IsRunning = false;
|
|
||||||
for (auto& it: m_Destinations)
|
for (auto& it: m_Destinations)
|
||||||
it.second->Stop ();
|
it.second->Stop ();
|
||||||
m_Acceptor.cancel ();
|
m_Acceptor.cancel ();
|
||||||
m_Service.stop ();
|
StopIOService ();
|
||||||
if (m_Thread)
|
|
||||||
{
|
|
||||||
m_Thread->join ();
|
|
||||||
delete m_Thread;
|
|
||||||
m_Thread = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BOBCommandChannel::Run ()
|
|
||||||
{
|
|
||||||
while (m_IsRunning)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_Service.run ();
|
|
||||||
}
|
|
||||||
catch (std::exception& ex)
|
|
||||||
{
|
|
||||||
LogPrint (eLogError, "BOB: runtime exception: ", ex.what ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
|
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include "util.h"
|
||||||
#include "I2PTunnel.h"
|
#include "I2PTunnel.h"
|
||||||
#include "I2PService.h"
|
#include "I2PService.h"
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
@@ -213,7 +214,7 @@ namespace client
|
|||||||
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void SendReplyOK (const char * msg = nullptr);
|
void SendReplyOK (const char * msg = nullptr);
|
||||||
void SendReplyError (const char * msg);
|
void SendReplyError (const char * msg);
|
||||||
void SendData (const char * data);
|
void SendRaw (const char * data);
|
||||||
|
|
||||||
void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out);
|
void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out);
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ namespace client
|
|||||||
};
|
};
|
||||||
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
|
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
|
||||||
|
|
||||||
class BOBCommandChannel
|
class BOBCommandChannel: private i2p::util::RunnableService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -241,22 +242,18 @@ namespace client
|
|||||||
void Start ();
|
void Start ();
|
||||||
void Stop ();
|
void Stop ();
|
||||||
|
|
||||||
boost::asio::io_service& GetService () { return m_Service; };
|
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||||
void AddDestination (const std::string& name, BOBDestination * dest);
|
void AddDestination (const std::string& name, BOBDestination * dest);
|
||||||
void DeleteDestination (const std::string& name);
|
void DeleteDestination (const std::string& name);
|
||||||
BOBDestination * FindDestination (const std::string& name);
|
BOBDestination * FindDestination (const std::string& name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Run ();
|
|
||||||
void Accept ();
|
void Accept ();
|
||||||
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session);
|
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool m_IsRunning;
|
|
||||||
std::thread * m_Thread;
|
|
||||||
boost::asio::io_service m_Service;
|
|
||||||
boost::asio::ip::tcp::acceptor m_Acceptor;
|
boost::asio::ip::tcp::acceptor m_Acceptor;
|
||||||
std::map<std::string, BOBDestination *> m_Destinations;
|
std::map<std::string, BOBDestination *> m_Destinations;
|
||||||
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
|
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ClientContext.h"
|
#include "ClientContext.h"
|
||||||
#include "SOCKS.h"
|
#include "SOCKS.h"
|
||||||
#include "WebSocks.h"
|
|
||||||
#include "MatchedDestination.h"
|
#include "MatchedDestination.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
@@ -53,14 +52,19 @@ namespace client
|
|||||||
|
|
||||||
// SAM
|
// SAM
|
||||||
bool sam; i2p::config::GetOption("sam.enabled", sam);
|
bool sam; i2p::config::GetOption("sam.enabled", sam);
|
||||||
if (sam) {
|
if (sam)
|
||||||
|
{
|
||||||
std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
|
std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
|
||||||
uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
|
uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
|
||||||
|
bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread);
|
||||||
LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
|
LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
|
||||||
try {
|
try
|
||||||
m_SamBridge = new SAMBridge (samAddr, samPort);
|
{
|
||||||
m_SamBridge->Start ();
|
m_SamBridge = new SAMBridge (samAddr, samPort, singleThread);
|
||||||
} catch (std::exception& e) {
|
m_SamBridge->Start ();
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
|
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,21 +309,34 @@ namespace client
|
|||||||
const std::map<std::string, std::string> * params)
|
const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
||||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params);
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
AddLocalDestination (localDestination);
|
||||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
return localDestination;
|
||||||
localDestination->Start ();
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (
|
||||||
|
boost::asio::io_service& service, bool isPublic,
|
||||||
|
i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType,
|
||||||
|
const std::map<std::string, std::string> * params)
|
||||||
|
{
|
||||||
|
i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType);
|
||||||
|
auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params);
|
||||||
|
AddLocalDestination (localDestination);
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params)
|
std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params)
|
||||||
{
|
{
|
||||||
MatchedTunnelDestination * cl = new MatchedTunnelDestination(keys, name, params);
|
auto localDestination = std::make_shared<MatchedTunnelDestination>(keys, name, params);
|
||||||
auto localDestination = std::shared_ptr<ClientDestination>(cl);
|
AddLocalDestination (localDestination);
|
||||||
|
return localDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientContext::AddLocalDestination (std::shared_ptr<ClientDestination> localDestination)
|
||||||
|
{
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
||||||
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
m_Destinations[localDestination->GetIdentHash ()] = localDestination;
|
||||||
localDestination->Start ();
|
localDestination->Start ();
|
||||||
return localDestination;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
|
void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination)
|
||||||
@@ -344,14 +361,26 @@ namespace client
|
|||||||
if (it != m_Destinations.end ())
|
if (it != m_Destinations.end ())
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
||||||
if (!it->second->IsRunning ())
|
it->second->Start (); // make sure to start
|
||||||
it->second->Start ();
|
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
auto localDestination = std::make_shared<ClientDestination> (keys, isPublic, params);
|
auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params);
|
||||||
std::unique_lock<std::mutex> l(m_DestinationsMutex);
|
AddLocalDestination (localDestination);
|
||||||
m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination;
|
return localDestination;
|
||||||
localDestination->Start ();
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (boost::asio::io_service& service,
|
||||||
|
const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params)
|
||||||
|
{
|
||||||
|
auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ());
|
||||||
|
if (it != m_Destinations.end ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists");
|
||||||
|
it->second->Start (); // make sure to start
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params);
|
||||||
|
AddLocalDestination (localDestination);
|
||||||
return localDestination;
|
return localDestination;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,6 +410,16 @@ namespace client
|
|||||||
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value);
|
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Section>
|
||||||
|
void ClientContext::ReadI2CPOptionsGroup (const Section& section, const std::string& group, std::map<std::string, std::string>& options) const
|
||||||
|
{
|
||||||
|
for (auto it: section.second)
|
||||||
|
{
|
||||||
|
if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group))
|
||||||
|
options[it.first] = it.second.get_value ("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Section>
|
template<typename Section>
|
||||||
void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const
|
void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const
|
||||||
{
|
{
|
||||||
@@ -395,6 +434,17 @@ namespace client
|
|||||||
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
options[I2CP_PARAM_LEASESET_TYPE] = GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE);
|
||||||
std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "");
|
std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, "");
|
||||||
if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType;
|
if (encType.length () > 0) options[I2CP_PARAM_LEASESET_ENCRYPTION_TYPE] = encType;
|
||||||
|
std::string privKey = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_PRIV_KEY, "");
|
||||||
|
if (privKey.length () > 0) options[I2CP_PARAM_LEASESET_PRIV_KEY] = privKey;
|
||||||
|
auto authType = GetI2CPOption(section, I2CP_PARAM_LEASESET_AUTH_TYPE, 0);
|
||||||
|
if (authType != "0") // auth is set
|
||||||
|
{
|
||||||
|
options[I2CP_PARAM_LEASESET_AUTH_TYPE] = authType;
|
||||||
|
if (authType == "1") // DH
|
||||||
|
ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_DH, options);
|
||||||
|
else if (authType == "2") // PSK
|
||||||
|
ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_PSK, options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -547,10 +597,8 @@ namespace client
|
|||||||
}
|
}
|
||||||
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
|
else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS)
|
||||||
{
|
{
|
||||||
// websocks proxy
|
LogPrint(eLogError, "Clients: I2P Client tunnel websocks is deprecated");
|
||||||
auto tun = std::make_shared<WebSocks>(address, port, localDestination);
|
continue;
|
||||||
clientTunnel = tun;
|
|
||||||
clientEndpoint = tun->GetLocalEndpoint();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -608,8 +656,8 @@ namespace client
|
|||||||
|
|
||||||
// I2CP
|
// I2CP
|
||||||
std::map<std::string, std::string> options;
|
std::map<std::string, std::string> options;
|
||||||
ReadI2CPOptions (section, options);
|
ReadI2CPOptions (section, options);
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
std::shared_ptr<ClientDestination> localDestination = nullptr;
|
||||||
i2p::data::PrivateKeys k;
|
i2p::data::PrivateKeys k;
|
||||||
if(!LoadPrivateKeys (k, keys, sigType, cryptoType))
|
if(!LoadPrivateKeys (k, keys, sigType, cryptoType))
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace client
|
|||||||
const char I2P_CLIENT_TUNNEL_CRYPTO_TYPE[] = "cryptotype";
|
const char I2P_CLIENT_TUNNEL_CRYPTO_TYPE[] = "cryptotype";
|
||||||
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport";
|
||||||
const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
|
const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels";
|
||||||
const char I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT[] = "connecttimeout";
|
const char I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT[] = "connecttimeout";
|
||||||
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
const char I2P_SERVER_TUNNEL_HOST[] = "host";
|
||||||
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
|
const char I2P_SERVER_TUNNEL_HOST_OVERRIDE[] = "hostoverride";
|
||||||
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
const char I2P_SERVER_TUNNEL_PORT[] = "port";
|
||||||
@@ -68,8 +68,15 @@ namespace client
|
|||||||
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
||||||
const std::map<std::string, std::string> * params = nullptr); // used by SAM only
|
const std::map<std::string, std::string> * params = nullptr); // used by SAM only
|
||||||
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (boost::asio::io_service& service,
|
||||||
|
bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
|
||||||
|
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL,
|
||||||
|
const std::map<std::string, std::string> * params = nullptr); // same as previous but on external io_service
|
||||||
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||||
const std::map<std::string, std::string> * params = nullptr);
|
const std::map<std::string, std::string> * params = nullptr);
|
||||||
|
std::shared_ptr<ClientDestination> CreateNewLocalDestination (boost::asio::io_service& service,
|
||||||
|
const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||||
|
const std::map<std::string, std::string> * params = nullptr); // same as previous but on external io_service
|
||||||
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr);
|
std::shared_ptr<ClientDestination> CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map<std::string, std::string> * params = nullptr);
|
||||||
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
void DeleteLocalDestination (std::shared_ptr<ClientDestination> destination);
|
||||||
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
std::shared_ptr<ClientDestination> FindLocalDestination (const i2p::data::IdentHash& destination) const;
|
||||||
@@ -95,6 +102,8 @@ namespace client
|
|||||||
template<typename Section>
|
template<typename Section>
|
||||||
std::string GetI2CPStringOption (const Section& section, const std::string& name, const std::string& value) const; // GetI2CPOption with string default value
|
std::string GetI2CPStringOption (const Section& section, const std::string& name, const std::string& value) const; // GetI2CPOption with string default value
|
||||||
template<typename Section>
|
template<typename Section>
|
||||||
|
void ReadI2CPOptionsGroup (const Section& section, const std::string& group, std::map<std::string, std::string>& options) const;
|
||||||
|
template<typename Section>
|
||||||
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const; // for tunnels
|
void ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const; // for tunnels
|
||||||
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const; // for HTTP and SOCKS proxy
|
void ReadI2CPOptionsFromConfig (const std::string& prefix, std::map<std::string, std::string>& options) const; // for HTTP and SOCKS proxy
|
||||||
|
|
||||||
@@ -105,6 +114,7 @@ namespace client
|
|||||||
void VisitTunnels (Visitor v); // Visitor: (I2PService *) -> bool, true means retain
|
void VisitTunnels (Visitor v); // Visitor: (I2PService *) -> bool, true means retain
|
||||||
|
|
||||||
void CreateNewSharedLocalDestination ();
|
void CreateNewSharedLocalDestination ();
|
||||||
|
void AddLocalDestination (std::shared_ptr<ClientDestination> localDestination);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user