mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
315 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ab5ac66b6 | ||
|
|
18cb3912e5 | ||
|
|
a818b0ba02 | ||
|
|
3716b6f988 | ||
|
|
c9e4e78f41 | ||
|
|
9b4e8bf64b | ||
|
|
5aebefe73f | ||
|
|
8f2124beab | ||
|
|
8b8b43df28 | ||
|
|
c42b991bc9 | ||
|
|
ec08333bf9 | ||
|
|
9e5b4e14c9 | ||
|
|
1f5ed89a88 | ||
|
|
2304a2bc2e | ||
|
|
dc82105226 | ||
|
|
5221f3ddc9 | ||
|
|
e970deb92b | ||
|
|
9db7ec6bb0 | ||
|
|
2e691b6655 | ||
|
|
f22e10537b | ||
|
|
6e532c494c | ||
|
|
f9ed0d4aa2 | ||
|
|
78b1afcc8c | ||
|
|
40340cf9c2 | ||
|
|
eb6437050f | ||
|
|
45ebfe378b | ||
|
|
1326597226 | ||
|
|
751da92c13 | ||
|
|
e10ca637da | ||
|
|
c5d9d71a8a | ||
|
|
3e0f5d231d | ||
|
|
6990f177ba | ||
|
|
98e713166b | ||
|
|
4c91ae0085 | ||
|
|
43f74d4d5a | ||
|
|
8c3e716c3f | ||
|
|
05946125b5 | ||
|
|
1e2a0a4549 | ||
|
|
f9f5084dd7 | ||
|
|
b7e7c6db7b | ||
|
|
f9d67b28ec | ||
|
|
46b77cc280 | ||
|
|
2f10decf56 | ||
|
|
678a1ae0fb | ||
|
|
51cbffd097 | ||
|
|
207b13dcab | ||
|
|
3052dbd1e8 | ||
|
|
5891b1ceb2 | ||
|
|
07e14ddda8 | ||
|
|
db5e90787c | ||
|
|
67e501f5c7 | ||
|
|
2160001167 | ||
|
|
f5f4150d17 | ||
|
|
887f292612 | ||
|
|
f5f282af97 | ||
|
|
82f9585b7a | ||
|
|
eb561bb0c2 | ||
|
|
81207999eb | ||
|
|
2fef595b83 | ||
|
|
2024e790ca | ||
|
|
f9925c7374 | ||
|
|
dd774b8dfd | ||
|
|
064b8042a5 | ||
|
|
7923ed9567 | ||
|
|
30b83414ef | ||
|
|
990906c57f | ||
|
|
4c323a666a | ||
|
|
a3f165d374 | ||
|
|
4977f9e6b4 | ||
|
|
7d5f51e357 | ||
|
|
371a339b18 | ||
|
|
7e7aee27b6 | ||
|
|
53148fe58f | ||
|
|
56b6de6962 | ||
|
|
44735681af | ||
|
|
ee1c4f4fdc | ||
|
|
fb6ecdde1e | ||
|
|
861166d8a9 | ||
|
|
70dca81c40 | ||
|
|
2774d72888 | ||
|
|
2440ffbfc9 | ||
|
|
77c5dde320 | ||
|
|
aa49cad279 | ||
|
|
f56ae240ab | ||
|
|
e871a30a78 | ||
|
|
30e6984889 | ||
|
|
324932c758 | ||
|
|
421800bc8f | ||
|
|
86fb47b2b4 | ||
|
|
715f83bf84 | ||
|
|
87bf5c2418 | ||
|
|
5c9af1c613 | ||
|
|
765e0e5c6b | ||
|
|
cc296e16dc | ||
|
|
ab9901525b | ||
|
|
3643a46a0c | ||
|
|
d467e6869d | ||
|
|
db36018849 | ||
|
|
3c5c375f71 | ||
|
|
7473d8c9aa | ||
|
|
33645d7f09 | ||
|
|
9f1106b14a | ||
|
|
3dd952b49b | ||
|
|
6b85bd2cb8 | ||
|
|
60b164c853 | ||
|
|
40c8a1bc1d | ||
|
|
22de695f12 | ||
|
|
e91f588cd7 | ||
|
|
7b72d91549 | ||
|
|
b3c2e86436 | ||
|
|
908bdc7624 | ||
|
|
21c1ec9c8c | ||
|
|
6d7d71bb16 | ||
|
|
6eba061c2a | ||
|
|
f184f550b9 | ||
|
|
bb7c0fef20 | ||
|
|
5c15a12116 | ||
|
|
68d015763e | ||
|
|
7faa732f38 | ||
|
|
11f9eeabf1 | ||
|
|
a152f36894 | ||
|
|
d4ede6ff01 | ||
|
|
35542d803c | ||
|
|
f6ba776c12 | ||
|
|
1511dcb309 | ||
|
|
35afa98112 | ||
|
|
df62b40ca7 | ||
|
|
9f1a125ed9 | ||
|
|
b7e20b9b86 | ||
|
|
a5d6972913 | ||
|
|
e4cb42c599 | ||
|
|
0a34f1f3ad | ||
|
|
7bdeaa9611 | ||
|
|
ab2577ce0a | ||
|
|
34544be423 | ||
|
|
6bf0fdd344 | ||
|
|
6a177cdd1c | ||
|
|
a51ef0cfc6 | ||
|
|
48374d97df | ||
|
|
bf3d7e74f5 | ||
|
|
ab3f3890e4 | ||
|
|
dceb0fb8c5 | ||
|
|
05c1856389 | ||
|
|
dc5cba60d1 | ||
|
|
70409dcdcc | ||
|
|
a92c29e04c | ||
|
|
c4b4dc79cf | ||
|
|
510fe43ec4 | ||
|
|
73e572b66b | ||
|
|
a272a2cb7e | ||
|
|
43b990afe6 | ||
|
|
90130b5492 | ||
|
|
f22faaefeb | ||
|
|
ac25649425 | ||
|
|
04388325a8 | ||
|
|
61ec873842 | ||
|
|
ea1f2d4e26 | ||
|
|
4211c733a2 | ||
|
|
450266818a | ||
|
|
1e019157bb | ||
|
|
c9a1066f02 | ||
|
|
0062f7d764 | ||
|
|
95e994e171 | ||
|
|
31242401e5 | ||
|
|
19cc1c3b3f | ||
|
|
03bcdceb9b | ||
|
|
33ca836ad0 | ||
|
|
53f19e4050 | ||
|
|
54b7d46f5a | ||
|
|
40e6d675c5 | ||
|
|
73b77c83b8 | ||
|
|
632d41e50c | ||
|
|
17acadbfb9 | ||
|
|
2ab5924ec9 | ||
|
|
ac09a4cf0f | ||
|
|
c10ee59de3 | ||
|
|
afad405ed9 | ||
|
|
5a35de8dc9 | ||
|
|
58cf26c304 | ||
|
|
a2de5564ac | ||
|
|
338b17ccf1 | ||
|
|
843a968959 | ||
|
|
dc45c13eef | ||
|
|
0d6e801595 | ||
|
|
2cd50ebaee | ||
|
|
cb6f6a6596 | ||
|
|
e4ab0acc92 | ||
|
|
10237c41d3 | ||
|
|
ac2c6c6010 | ||
|
|
c6b2ce93c4 | ||
|
|
401b7fe883 | ||
|
|
f567417bb3 | ||
|
|
ae5cb3bbe7 | ||
|
|
0eb8e15796 | ||
|
|
1c95c7856f | ||
|
|
daf7551e59 | ||
|
|
5b63d3692e | ||
|
|
5f9972af78 | ||
|
|
1be4cce074 | ||
|
|
935e93eb36 | ||
|
|
5d924cd35a | ||
|
|
27116b9f30 | ||
|
|
8ac2ee49a8 | ||
|
|
8a8e328fcf | ||
|
|
c4207e7672 | ||
|
|
73642703bd | ||
|
|
b3bd175e64 | ||
|
|
742032907a | ||
|
|
edc0162163 | ||
|
|
94661f697b | ||
|
|
4ecf36fab6 | ||
|
|
96cdb3bca3 | ||
|
|
6c57ba36f7 | ||
|
|
cb61897236 | ||
|
|
8b931dd40b | ||
|
|
6b81478bd2 | ||
|
|
9d94eb83c1 | ||
|
|
13374f8b7b | ||
|
|
7bf7aae3d1 | ||
|
|
e5f39d0caf | ||
|
|
174983548d | ||
|
|
a9ec4d916b | ||
|
|
a55c346af5 | ||
|
|
8e0d8c96bb | ||
|
|
9abd383014 | ||
|
|
8ee9c437e1 | ||
|
|
4052b1ea6d | ||
|
|
fdde197c58 | ||
|
|
49883dc3ac | ||
|
|
d798faa1ca | ||
|
|
3f63f15b16 | ||
|
|
f8c390cdd3 | ||
|
|
8f0978cfd6 | ||
|
|
1a8a32a773 | ||
|
|
c0400bfd07 | ||
|
|
c6e4758187 | ||
|
|
56ec8fe95b | ||
|
|
67863cfcf9 | ||
|
|
4c5ec68ff1 | ||
|
|
58b7b7d731 | ||
|
|
1de1c79d4f | ||
|
|
7073a6bf38 | ||
|
|
26db88d89b | ||
|
|
876e98d91e | ||
|
|
8566f6c127 | ||
|
|
bb8dc67942 | ||
|
|
9965d72990 | ||
|
|
921ec9ec12 | ||
|
|
f1990bc2ab | ||
|
|
cdc8e463b7 | ||
|
|
0a62a962d7 | ||
|
|
b0f043ec86 | ||
|
|
ae0cf2e831 | ||
|
|
4ce7e192d6 | ||
|
|
04ca916aac | ||
|
|
a348e10620 | ||
|
|
af794f901f | ||
|
|
8a58572b34 | ||
|
|
0c25e8f1eb | ||
|
|
ff3d2db85e | ||
|
|
efd84a2404 | ||
|
|
278fd2d8d5 | ||
|
|
197882a4c9 | ||
|
|
d310efcb5c | ||
|
|
1af9117b80 | ||
|
|
44e01b41f8 | ||
|
|
7def2fa6a3 | ||
|
|
48131f4597 | ||
|
|
49e8cf89d8 | ||
|
|
e6bcd04a36 | ||
|
|
af133f4968 | ||
|
|
d723faaaa3 | ||
|
|
cc75efcbca | ||
|
|
2eded7cdd7 | ||
|
|
b10e5ce358 | ||
|
|
1bb1d89fab | ||
|
|
b9dd4aee8d | ||
|
|
518e53a61c | ||
|
|
18b6ba80f2 | ||
|
|
8debdc264c | ||
|
|
31bdce1f1f | ||
|
|
317d8cdc48 | ||
|
|
5b2b9e00a2 | ||
|
|
3dd9e81296 | ||
|
|
d2faec70be | ||
|
|
e5c773a3eb | ||
|
|
ec86c4611d | ||
|
|
247b6a0ed2 | ||
|
|
f7f36568ef | ||
|
|
e054c6e82c | ||
|
|
5e2e1a1e3d | ||
|
|
ad036de69d | ||
|
|
20652f7995 | ||
|
|
2f88a75325 | ||
|
|
292fe94352 | ||
|
|
76dca1b46b | ||
|
|
a54b5c18c6 | ||
|
|
c763472914 | ||
|
|
3a77e7ba2d | ||
|
|
41d6c117ee | ||
|
|
e8f4c42bfb | ||
|
|
bce8469e59 | ||
|
|
3f46ca41ca | ||
|
|
6b1ef6e1b9 | ||
|
|
349022ae42 | ||
|
|
bb518d3d51 | ||
|
|
c45e202fab | ||
|
|
541464b705 | ||
|
|
c762acd780 | ||
|
|
ec98ff297c | ||
|
|
af2c6c5575 | ||
|
|
7d220fb2eb | ||
|
|
f0c49b58fb | ||
|
|
d599502b1a | ||
|
|
48d9a03aa8 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build/build_mingw.cmd eol=crlf
|
||||
5
.github/workflows/build-freebsd.yml
vendored
5
.github/workflows/build-freebsd.yml
vendored
@@ -4,15 +4,16 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-10.15
|
||||
name: with UPnP
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0.1.4
|
||||
uses: vmactions/freebsd-vm@v0.1.5
|
||||
with:
|
||||
usesh: true
|
||||
mem: 2048
|
||||
prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc
|
||||
run: |
|
||||
cd build
|
||||
|
||||
50
.github/workflows/build-windows.yml
vendored
50
.github/workflows/build-windows.yml
vendored
@@ -8,14 +8,15 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Building for ${{ matrix.arch }}
|
||||
name: Building using ${{ matrix.arch }} toolchain
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
include: [
|
||||
{ msystem: MINGW64, arch: x86_64 },
|
||||
{ msystem: MINGW32, arch: i686 }
|
||||
{ msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt },
|
||||
{ msystem: MINGW64, arch: x86_64, arch_short: x64 },
|
||||
{ msystem: MINGW32, arch: i686, arch_short: x86 }
|
||||
]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -25,11 +26,50 @@ jobs:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
|
||||
update: true
|
||||
- name: build application
|
||||
- name: Build application
|
||||
run: |
|
||||
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
||||
make USE_UPNP=yes DEBUG=no -j3
|
||||
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: i2pd-${{ matrix.arch_short }}.exe
|
||||
path: i2pd.exe
|
||||
build-xp:
|
||||
name: Building for Windows XP
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW32
|
||||
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
|
||||
update: true
|
||||
- name: Build WinXP-capable CRT packages
|
||||
run: |
|
||||
git clone https://github.com/msys2/MINGW-packages
|
||||
pushd MINGW-packages
|
||||
pushd mingw-w64-headers-git
|
||||
sed -i 's/0x601/0x501/' PKGBUILD
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
|
||||
pacman --noconfirm -U mingw-w64-i686-headers-git-*-any.pkg.tar.zst
|
||||
popd
|
||||
pushd mingw-w64-crt-git
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
|
||||
pacman --noconfirm -U mingw-w64-i686-crt-git-*-any.pkg.tar.zst
|
||||
popd
|
||||
pushd mingw-w64-winpthreads-git
|
||||
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
|
||||
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
|
||||
popd
|
||||
popd
|
||||
- name: Build application
|
||||
run: |
|
||||
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
||||
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: i2pd-xp.exe
|
||||
path: i2pd.exe
|
||||
|
||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install devscripts
|
||||
debchange -v "`git describe --tags`-stretch" -M --distribution stretch "trunk build"
|
||||
debchange -v "`git describe --tags`-stretch" -b -M --distribution stretch "trunk build"
|
||||
- uses: singingwolfboy/build-dpkg-stretch@v1
|
||||
id: build
|
||||
with:
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install devscripts
|
||||
debchange -v "`git describe --tags`-buster" -M --distribution buster "trunk build"
|
||||
debchange -v "`git describe --tags`-buster" -b -M --distribution buster "trunk build"
|
||||
- uses: singingwolfboy/build-dpkg-buster@v1
|
||||
id: build
|
||||
with:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -260,6 +260,7 @@ docs/generated
|
||||
build/Makefile
|
||||
|
||||
# debian stuff
|
||||
debian/i2pd.1.gz
|
||||
.pc/
|
||||
|
||||
# qt
|
||||
|
||||
87
ChangeLog
87
ChangeLog
@@ -1,6 +1,61 @@
|
||||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.41.0] - 2022-02-20
|
||||
### Added
|
||||
- Clock syncronization through SSU
|
||||
- Drop routers older than 6 months on start
|
||||
- Localization to German
|
||||
- Don't send streaming ack too frequently
|
||||
- Select compatible outbound tunnel for I2CP messages
|
||||
- Restart webconsole's acceptor in case of exception
|
||||
### Changed
|
||||
- Use builtin bitswap for endian on windows
|
||||
- Send SessionCreated before connection close if clock skew
|
||||
- Try another floodfill for publishing if no compatible tunnels found
|
||||
- Reduce memory usage for RouterInfo structures
|
||||
- Avoid duplicated addresses in RouterInfo. Check presence of netId and version
|
||||
- Use TCP/IP sockets for I2CP on Android instead local sockets
|
||||
- Return uptime as integer in I2PControl
|
||||
- Reseed servers list/cerificates
|
||||
- Webconsole's dark style colors
|
||||
### Fixed
|
||||
- Attempt to use Yggdrasil on start on Android
|
||||
- Attempts to send peer tests to itself
|
||||
- Severe packets drop in SSU
|
||||
- Crash on tunnel tests
|
||||
- Loading addressbook subscriptions from config
|
||||
- Multiple I2CP session to the same destination
|
||||
- Build on Apple Silicon
|
||||
|
||||
## [2.40.0] - 2021-11-29
|
||||
### Added
|
||||
- Keep alive parameter for client tunnels
|
||||
- Support openssl 3.0.0
|
||||
- Localization to Armenian
|
||||
- Show git commit info in version
|
||||
- Windows menu item for opening datadir
|
||||
- Reseed if too few floodfills
|
||||
- Don't publish old and replacing tunnel in LeaseSet
|
||||
- Webconsole light/dark theme depending on system settings (via CSS)
|
||||
### Changed
|
||||
- Set gzip compression to false by default
|
||||
- Build tunnel through ECIES routers only
|
||||
- Removed ElGamal support for tunnels
|
||||
- Moved webconsole resources to separate file
|
||||
- Pick tunnels with compatible transport with another tunnel of floodfill
|
||||
- Use common cleanup timer for all SSU sessions
|
||||
- Reduced memory usage
|
||||
- Reseed servers list
|
||||
- i18n code called from ClientContext
|
||||
### Fixed
|
||||
- Tunnels reload
|
||||
- Some typos in log messages
|
||||
- Cleanup relay requests table
|
||||
- Server tunnel is not published
|
||||
- Build on GNU/Hurd. Disable pthread_setname_np
|
||||
- Crash when incorrect sigtype used with blinding
|
||||
|
||||
## [2.39.0] - 2021-08-23
|
||||
### Added
|
||||
- Short tunnel build messages
|
||||
@@ -18,11 +73,11 @@
|
||||
- Better distribution for random tunnel's peer selection
|
||||
- Yggdrasil reseed for v0.4, added two more
|
||||
- Encryption type 0,4 by default for server tunnels
|
||||
- Handle i2cp.dontPublishLeaseSet param for all destinations
|
||||
- Handle i2cp.dontPublishLeaseSet param for all destinations
|
||||
- reg.i2p for subscriptions
|
||||
- LeaseSet type 3 by default
|
||||
- Don't allocate payload buffer for every single ECIESx25519 message
|
||||
- Prefer public ipv6 instead rfc4941
|
||||
- Prefer public ipv6 instead rfc4941
|
||||
- Optimal padding for one-time ECIESx25519 message
|
||||
- Don't send datetime block for one-time ECIESx25519 message with one-time key
|
||||
- Router with expired introducer is still valid
|
||||
@@ -46,7 +101,7 @@
|
||||
## [2.38.0] - 2021-05-17
|
||||
### Added
|
||||
- Publish ipv6 introducers
|
||||
- Bind ipv6 or yggdrasil NTCP2 acceptor to specified address
|
||||
- Bind ipv6 or yggdrasil NTCP2 acceptor to specified address
|
||||
- Support .b32.i2p addresses and hostnames for SAM STREAM CREATE
|
||||
- ipv6 peer tests
|
||||
- Publish iexp param for introducers
|
||||
@@ -82,12 +137,12 @@
|
||||
- Symmetric NAT network status error
|
||||
- Bind server tunnel connection to specified address
|
||||
- lookuplocal BOB extended command
|
||||
- address4 and address6 parameters to bind outgoing connections to
|
||||
- address4 and address6 parameters to bind outgoing connections to
|
||||
- Rekey of low-bandwidth routers to ECIES
|
||||
- Popup notification windows when unable to parse config for Windows
|
||||
### Changed
|
||||
- Floodfills with "U" cap are not ignored anymore
|
||||
- Check transports reachability between tunnel peers and between router and floodfill
|
||||
- Check transports reachability between tunnel peers and between router and floodfill
|
||||
- NTCP2 and reseed HTTP proxy support authorization now
|
||||
- Show actual IP addresses for proxy connections
|
||||
- Publish and handle SSU addreses without host
|
||||
@@ -109,22 +164,22 @@
|
||||
- Dump addressbook in hosts.txt format
|
||||
- Request RouterInfo through exploratory tunnels if direct connection to fllodfill is not possible
|
||||
- Threads naming
|
||||
- Check if public x25519 key is valid
|
||||
- Check if public x25519 key is valid
|
||||
- ECIES-X25519-AEAD-Ratchet for shared local destination
|
||||
- LeaseSet creation timeout for I2CP session
|
||||
- Resend RouterInfo after some interval for longer NTCP2 sessions
|
||||
- Select reachable router of inbound tunnel gateway
|
||||
- Reseed if no compatible routers in netdb
|
||||
- Reseed if no compatible routers in netdb
|
||||
- Refresh on swipe in Android webconsole
|
||||
### Changed
|
||||
- reg.i2p for default addressbook instead inr.i2p
|
||||
- ECIES-x25519 (crypto type 4) for new routers
|
||||
- Try to connect to all compatible addresses from peer's RouterInfo
|
||||
- Replace LeaseSet completely if store type changes
|
||||
- Replace LeaseSet completely if store type changes
|
||||
- Try ECIES-X25519-AEAD-Ratchet tag before ElGamal
|
||||
- Don't detach ECIES-X25519-AEAD-Ratchet session from destination immediately
|
||||
- Viewport and styles on error in HTTP proxy
|
||||
- Don't create notification when Windows taskbar restarted
|
||||
- Don't create notification when Windows taskbar restarted
|
||||
- Cumulative SSU ACK bitfields
|
||||
- limit tunnel length to 8 hops
|
||||
- Limit tunnels quantity to 16
|
||||
@@ -157,7 +212,7 @@
|
||||
- Transient signature length, if different from identity
|
||||
- Terminate I2CP session if destroyed
|
||||
- RouterInfo publishing confirmation
|
||||
- Check if ECIES-X25519-AEAD-Ratchet session expired before generating more tags
|
||||
- Check if ECIES-X25519-AEAD-Ratchet session expired before generating more tags
|
||||
- Correct block size for delivery type local for ECIES-X25519-AEAD-Ratchet
|
||||
|
||||
## [2.34.0] - 2020-10-27
|
||||
@@ -168,7 +223,7 @@
|
||||
- Single thread for I2CP
|
||||
- Shared transient destination between proxies
|
||||
- Database lookups from ECIES destinations with ratchets response
|
||||
- Handle WebDAV HTTP methods
|
||||
- Handle WebDAV HTTP methods
|
||||
- Don't try to connect or build tunnels if offline
|
||||
- Validate IP when trying connect to remote peer
|
||||
- Handle ICMP responses and WinAPI errors for SSU
|
||||
@@ -185,7 +240,7 @@
|
||||
- Random crashes on I2CP session disconnect
|
||||
- Stream through racthets hangs if first SYN was not acked
|
||||
- Check "Last-Modified" instead "If-Modified-Since" for addressbook reponse
|
||||
- Trim behind ECIESx25519 tags
|
||||
- Trim behind ECIESx25519 tags
|
||||
- Few bugs with Android main activity
|
||||
- QT visual and layout issues
|
||||
|
||||
@@ -196,11 +251,11 @@
|
||||
- Multiple encryption keys through I2CP
|
||||
- Pre-calculated x25519 ephemeral keys
|
||||
- Change datagram routing path if nothing comes back in 10 seconds
|
||||
- Shared routing path for datagram session
|
||||
- Shared routing path for datagram session
|
||||
### Changed
|
||||
- UDP tunnels send mix of repliable and raw datagrams in bulk
|
||||
- Encrypt SSU packet again upon resend
|
||||
- Start new tunnel message if remaining buffer is too small
|
||||
- Start new tunnel message if remaining buffer is too small
|
||||
- Use LeaseSet2 for ECIES-X25519-AEAD-Ratchet automatically
|
||||
- Save new ECIES-X25519-AEAD-Ratchet session with NSR tagset
|
||||
- Generate random padding lengths for ECIES-X25519-AEAD-Ratchet in bulk
|
||||
@@ -208,11 +263,11 @@
|
||||
- Reseed servers list
|
||||
### Fixed
|
||||
- Don't connect through terminated SAM destination
|
||||
- Differentiate UDP server sessions by port
|
||||
- Differentiate UDP server sessions by port
|
||||
- ECIES-X25519-AEAD-Ratchet through I2CP
|
||||
- Don't save invalid address to AddressBook
|
||||
- ECDSA signatures names in SAM
|
||||
- AppArmor profile
|
||||
- AppArmor profile
|
||||
|
||||
## [2.32.1] - 2020-06-02
|
||||
### Added
|
||||
|
||||
43
Makefile
43
Makefile
@@ -1,3 +1,5 @@
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
SYS := $(shell $(CXX) -dumpmachine)
|
||||
|
||||
ifneq (, $(findstring darwin, $(SYS)))
|
||||
@@ -27,11 +29,22 @@ DAEMON_SRC_DIR := daemon
|
||||
# import source files lists
|
||||
include filelist.mk
|
||||
|
||||
USE_AESNI := $(or $(USE_AESNI),yes)
|
||||
USE_STATIC := $(or $(USE_STATIC),no)
|
||||
USE_MESHNET := $(or $(USE_MESHNET),no)
|
||||
USE_UPNP := $(or $(USE_UPNP),no)
|
||||
DEBUG := $(or $(DEBUG),yes)
|
||||
USE_AESNI := $(or $(USE_AESNI),yes)
|
||||
USE_STATIC := $(or $(USE_STATIC),no)
|
||||
USE_UPNP := $(or $(USE_UPNP),no)
|
||||
DEBUG := $(or $(DEBUG),yes)
|
||||
|
||||
# for debugging purposes only, when commit hash needed in trunk builds in i2pd version string
|
||||
USE_GIT_VERSION := $(or $(USE_GIT_VERSION),no)
|
||||
|
||||
# for MacOS only, waiting for "1", not "yes"
|
||||
HOMEBREW := $(or $(HOMEBREW),0)
|
||||
|
||||
# Client protocols
|
||||
USE_I2PC := $(or $(USE_I2PC),yes)
|
||||
USE_I2CP := $(or $(USE_I2CP),yes)
|
||||
USE_SAM := $(or $(USE_SAM),yes)
|
||||
USE_BOB := $(or $(USE_BOB),yes)
|
||||
|
||||
ifeq ($(DEBUG),yes)
|
||||
CXX_DEBUG = -g
|
||||
@@ -40,6 +53,19 @@ else
|
||||
LD_DEBUG = -s
|
||||
endif
|
||||
|
||||
ifeq ($(USE_I2PC),yes)
|
||||
NEEDED_CXXFLAGS += -DWITH_I2PC
|
||||
endif
|
||||
ifeq ($(USE_I2CP),yes)
|
||||
NEEDED_CXXFLAGS += -DWITH_I2CP
|
||||
endif
|
||||
ifeq ($(USE_SAM),yes)
|
||||
NEEDED_CXXFLAGS += -DWITH_SAM
|
||||
endif
|
||||
ifeq ($(USE_BOB),yes)
|
||||
NEEDED_CXXFLAGS += -DWITH_BOB
|
||||
endif
|
||||
|
||||
ifneq (, $(findstring darwin, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
ifeq ($(HOMEBREW),1)
|
||||
@@ -54,14 +80,15 @@ else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
include Makefile.bsd
|
||||
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
|
||||
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp
|
||||
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
|
||||
include Makefile.mingw
|
||||
else # not supported
|
||||
$(error Not supported platform)
|
||||
endif
|
||||
|
||||
ifeq ($(USE_MESHNET),yes)
|
||||
NEEDED_CXXFLAGS += -DMESHNET
|
||||
ifeq ($(USE_GIT_VERSION),yes)
|
||||
GIT_VERSION := $(shell git describe --tags)
|
||||
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
|
||||
endif
|
||||
|
||||
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR)
|
||||
|
||||
@@ -39,13 +39,14 @@ ifeq ($(USE_AESNI),yes)
|
||||
endif
|
||||
|
||||
install: all
|
||||
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
|
||||
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
|
||||
install -m 755 ${I2PD} ${PREFIX}/bin/
|
||||
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
||||
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
|
||||
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
|
||||
@gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
|
||||
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
|
||||
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
|
||||
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
||||
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf
|
||||
|
||||
@@ -62,3 +62,16 @@ ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64
|
||||
NEEDED_CXXFLAGS += -D__AES__ -maes
|
||||
endif
|
||||
endif
|
||||
|
||||
install: all
|
||||
install -d ${PREFIX}/bin ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/usr ${PREFIX}/usr/share ${PREFIX}/usr/share/doc/i2pd ${PREFIX}/usr/share/i2pd ${PREFIX}/usr/share/man ${PREFIX}/usr/share/man/man1 ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
|
||||
install -m 755 ${I2PD} ${PREFIX}/bin/
|
||||
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
|
||||
@cp -R contrib/certificates ${PREFIX}/usr/share/i2pd/
|
||||
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/usr/share/doc/i2pd
|
||||
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/usr/share/man/man1
|
||||
@ln -sf ${PREFIX}/usr/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
|
||||
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
|
||||
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
|
||||
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Win32Service.h"
|
||||
#ifdef WIN32_APP
|
||||
#include <windows.h>
|
||||
#include "Win32App.h"
|
||||
@@ -39,6 +40,19 @@ namespace util
|
||||
|
||||
if (!Daemon_Singleton::init(argc, argv))
|
||||
return false;
|
||||
|
||||
if (isDaemon)
|
||||
{
|
||||
LogPrint(eLogDebug, "Daemon: running as service");
|
||||
I2PService service((PSTR)SERVICE_NAME);
|
||||
if (!I2PService::Run(service))
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ BEGIN
|
||||
VALUE "FileDescription", "C++ I2P daemon"
|
||||
VALUE "FileVersion", I2PD_VERSION
|
||||
VALUE "InternalName", CODENAME
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2020, The PurpleI2P Project"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2013-2022, The PurpleI2P Project"
|
||||
VALUE "OriginalFilename", "i2pd"
|
||||
VALUE "ProductName", "Purple I2P"
|
||||
VALUE "ProductVersion", I2P_VERSION
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define ID_RELOAD 2006
|
||||
#define ID_ACCEPT_TRANSIT 2007
|
||||
#define ID_DECLINE_TRANSIT 2008
|
||||
#define ID_DATADIR 2009
|
||||
|
||||
#define ID_TRAY_ICON 2050
|
||||
#define WM_TRAYICON (WM_USER + 1)
|
||||
@@ -49,7 +50,8 @@ namespace win32
|
||||
{
|
||||
HMENU hPopup = CreatePopupMenu();
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_CONSOLE, "Open &console");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DATADIR, "Open &datadir");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "&Show app");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
|
||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
|
||||
if(!i2p::context.AcceptsTunnels())
|
||||
@@ -303,6 +305,12 @@ namespace win32
|
||||
SetTimer(hWnd, FRAME_UPDATE_TIMER, 3000, NULL);
|
||||
return 0;
|
||||
}
|
||||
case ID_DATADIR:
|
||||
{
|
||||
std::string datadir(i2p::fs::GetUTF8DataDir());
|
||||
ShellExecute(NULL, "explore", datadir.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ void SubscribeToEvents()
|
||||
Result = pNetworkListManager->IsConnectedToInternet(&IsConnect);
|
||||
if (SUCCEEDED(Result)) {
|
||||
i2p::transport::transports.SetOnline (true);
|
||||
LogPrint(eLogInfo, "NetState: current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
|
||||
LogPrint(eLogInfo, "NetState: Current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
|
||||
}
|
||||
|
||||
Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void **)&pCPContainer);
|
||||
@@ -79,7 +79,7 @@ void UnSubscribeFromEvents()
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "NetState: received exception: ", ex.what ());
|
||||
LogPrint (eLogError, "NetState: Received exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
283
Win32/Win32Service.cpp
Normal file
283
Win32/Win32Service.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include "Win32Service.h"
|
||||
#include <assert.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include "Daemon.h"
|
||||
#include "Log.h"
|
||||
|
||||
I2PService *I2PService::s_service = NULL;
|
||||
|
||||
BOOL I2PService::isService()
|
||||
{
|
||||
BOOL bIsService = FALSE;
|
||||
HWINSTA hWinStation = GetProcessWindowStation();
|
||||
if (hWinStation != NULL)
|
||||
{
|
||||
USEROBJECTFLAGS uof = { 0 };
|
||||
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
|
||||
{
|
||||
bIsService = TRUE;
|
||||
}
|
||||
}
|
||||
return bIsService;
|
||||
}
|
||||
|
||||
BOOL I2PService::Run(I2PService &service)
|
||||
{
|
||||
s_service = &service;
|
||||
SERVICE_TABLE_ENTRY serviceTable[] =
|
||||
{
|
||||
{ service.m_name, ServiceMain },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
return StartServiceCtrlDispatcher(serviceTable);
|
||||
}
|
||||
|
||||
void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
assert(s_service != NULL);
|
||||
s_service->m_statusHandle = RegisterServiceCtrlHandler(
|
||||
s_service->m_name, ServiceCtrlHandler);
|
||||
if (s_service->m_statusHandle == NULL)
|
||||
{
|
||||
throw GetLastError();
|
||||
}
|
||||
s_service->Start(dwArgc, pszArgv);
|
||||
}
|
||||
|
||||
|
||||
void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl)
|
||||
{
|
||||
switch (dwCtrl)
|
||||
{
|
||||
case SERVICE_CONTROL_STOP: s_service->Stop(); break;
|
||||
case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
|
||||
case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
|
||||
case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
|
||||
case SERVICE_CONTROL_INTERROGATE: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
I2PService::I2PService(PSTR pszServiceName,
|
||||
BOOL fCanStop,
|
||||
BOOL fCanShutdown,
|
||||
BOOL fCanPauseContinue)
|
||||
{
|
||||
m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
|
||||
m_statusHandle = NULL;
|
||||
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||
m_status.dwCurrentState = SERVICE_START_PENDING;
|
||||
|
||||
DWORD dwControlsAccepted = 0;
|
||||
if (fCanStop)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_STOP;
|
||||
if (fCanShutdown)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
|
||||
if (fCanPauseContinue)
|
||||
dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
|
||||
|
||||
m_status.dwControlsAccepted = dwControlsAccepted;
|
||||
m_status.dwWin32ExitCode = NO_ERROR;
|
||||
m_status.dwServiceSpecificExitCode = 0;
|
||||
m_status.dwCheckPoint = 0;
|
||||
m_status.dwWaitHint = 0;
|
||||
m_fStopping = FALSE;
|
||||
// Create a manual-reset event that is not signaled at first to indicate
|
||||
// the stopped signal of the service.
|
||||
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (m_hStoppedEvent == NULL)
|
||||
{
|
||||
throw GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
I2PService::~I2PService(void)
|
||||
{
|
||||
if (m_hStoppedEvent)
|
||||
{
|
||||
CloseHandle(m_hStoppedEvent);
|
||||
m_hStoppedEvent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_START_PENDING);
|
||||
OnStart(dwArgc, pszArgv);
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Start error: ", dwError);
|
||||
SetServiceStatus(SERVICE_STOPPED, dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
|
||||
{
|
||||
LogPrint(eLogInfo, "Win32Service: in OnStart (", EVENTLOG_INFORMATION_TYPE, ")");
|
||||
Daemon.start();
|
||||
_worker = new std::thread(std::bind(&I2PService::WorkerThread, this));
|
||||
}
|
||||
|
||||
void I2PService::WorkerThread()
|
||||
{
|
||||
while (!m_fStopping)
|
||||
{
|
||||
::Sleep(1000); // Simulate some lengthy operations.
|
||||
}
|
||||
// Signal the stopped event.
|
||||
SetEvent(m_hStoppedEvent);
|
||||
}
|
||||
|
||||
void I2PService::Stop()
|
||||
{
|
||||
DWORD dwOriginalState = m_status.dwCurrentState;
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_STOP_PENDING);
|
||||
OnStop();
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogInfo, "Win32Service: Stop error: ", dwError);
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(dwOriginalState);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PService::OnStop()
|
||||
{
|
||||
// Log a service stop message to the Application log.
|
||||
LogPrint(eLogInfo, "Win32Service: in OnStop (", EVENTLOG_INFORMATION_TYPE, ")");
|
||||
Daemon.stop();
|
||||
m_fStopping = TRUE;
|
||||
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
|
||||
{
|
||||
throw GetLastError();
|
||||
}
|
||||
_worker->join();
|
||||
delete _worker;
|
||||
}
|
||||
|
||||
void I2PService::Pause()
|
||||
{
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_PAUSE_PENDING);
|
||||
OnPause();
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Pause error: ", dwError);
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PService::OnPause()
|
||||
{
|
||||
}
|
||||
|
||||
void I2PService::Continue()
|
||||
{
|
||||
try
|
||||
{
|
||||
SetServiceStatus(SERVICE_CONTINUE_PENDING);
|
||||
OnContinue();
|
||||
SetServiceStatus(SERVICE_RUNNING);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Continue error: ", dwError);
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
|
||||
SetServiceStatus(SERVICE_PAUSED);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PService::OnContinue()
|
||||
{
|
||||
}
|
||||
|
||||
void I2PService::Shutdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
OnShutdown();
|
||||
SetServiceStatus(SERVICE_STOPPED);
|
||||
}
|
||||
catch (DWORD dwError)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PService::OnShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void I2PService::SetServiceStatus(DWORD dwCurrentState,
|
||||
DWORD dwWin32ExitCode,
|
||||
DWORD dwWaitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
m_status.dwCurrentState = dwCurrentState;
|
||||
m_status.dwWin32ExitCode = dwWin32ExitCode;
|
||||
m_status.dwWaitHint = dwWaitHint;
|
||||
m_status.dwCheckPoint =
|
||||
((dwCurrentState == SERVICE_RUNNING) ||
|
||||
(dwCurrentState == SERVICE_STOPPED)) ?
|
||||
0 : dwCheckPoint++;
|
||||
|
||||
::SetServiceStatus(m_statusHandle, &m_status);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
|
||||
void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService)
|
||||
{
|
||||
if (schSCManager)
|
||||
{
|
||||
CloseServiceHandle(schSCManager);
|
||||
schSCManager = NULL;
|
||||
}
|
||||
if (schService)
|
||||
{
|
||||
CloseServiceHandle(schService);
|
||||
schService = NULL;
|
||||
}
|
||||
}
|
||||
63
Win32/Win32Service.h
Normal file
63
Win32/Win32Service.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#ifndef WIN_32_SERVICE_H__
|
||||
#define WIN_32_SERVICE_H__
|
||||
|
||||
#include <thread>
|
||||
#include <windows.h>
|
||||
|
||||
#define SERVICE_NAME "i2pdService"
|
||||
|
||||
class I2PService
|
||||
{
|
||||
public:
|
||||
|
||||
I2PService(PSTR pszServiceName,
|
||||
BOOL fCanStop = TRUE,
|
||||
BOOL fCanShutdown = TRUE,
|
||||
BOOL fCanPauseContinue = FALSE);
|
||||
|
||||
virtual ~I2PService(void);
|
||||
|
||||
static BOOL isService();
|
||||
static BOOL Run(I2PService &service);
|
||||
void Stop();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
|
||||
virtual void OnStop();
|
||||
virtual void OnPause();
|
||||
virtual void OnContinue();
|
||||
virtual void OnShutdown();
|
||||
void SetServiceStatus(DWORD dwCurrentState,
|
||||
DWORD dwWin32ExitCode = NO_ERROR,
|
||||
DWORD dwWaitHint = 0);
|
||||
|
||||
private:
|
||||
|
||||
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
|
||||
static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
|
||||
void WorkerThread();
|
||||
void Start(DWORD dwArgc, PSTR *pszArgv);
|
||||
void Pause();
|
||||
void Continue();
|
||||
void Shutdown();
|
||||
static I2PService* s_service;
|
||||
PSTR m_name;
|
||||
SERVICE_STATUS m_status;
|
||||
SERVICE_STATUS_HANDLE m_statusHandle;
|
||||
|
||||
BOOL m_fStopping;
|
||||
HANDLE m_hStoppedEvent;
|
||||
|
||||
std::thread* _worker;
|
||||
};
|
||||
|
||||
#endif // WIN_32_SERVICE_H__
|
||||
@@ -1,6 +1,5 @@
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
# this addresses CMP0059 with CMake > 3.3 for PCH flags
|
||||
cmake_policy(VERSION 2.8.12)
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
cmake_policy(VERSION 3.7)
|
||||
project("i2pd")
|
||||
|
||||
# for debugging
|
||||
@@ -18,8 +17,6 @@ option(WITH_LIBRARY "Build library" ON)
|
||||
option(WITH_BINARY "Build binary" ON)
|
||||
option(WITH_STATIC "Static build" OFF)
|
||||
option(WITH_UPNP "Include support for UPnP client" OFF)
|
||||
option(WITH_PCH "Use precompiled header" OFF)
|
||||
option(WITH_MESHNET "Build for cjdns test network" OFF)
|
||||
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
|
||||
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
|
||||
|
||||
@@ -91,14 +88,14 @@ set(DAEMON_SRC
|
||||
"${DAEMON_SRC_DIR}/UPnP.cpp"
|
||||
)
|
||||
|
||||
if(WITH_MESHNET)
|
||||
add_definitions(-DMESHNET)
|
||||
endif()
|
||||
|
||||
if(WITH_UPNP)
|
||||
add_definitions(-DUSE_UPNP)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
add_definitions(-DMAC_OSX)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
|
||||
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
|
||||
@@ -200,21 +197,6 @@ else()
|
||||
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
|
||||
endif()
|
||||
|
||||
if(WITH_PCH)
|
||||
include_directories(BEFORE ${CMAKE_BINARY_DIR})
|
||||
add_library(stdafx STATIC "${LIBI2PD_SRC_DIR}/stdafx.cpp")
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} BTU)
|
||||
get_directory_property(DEFS DEFINITIONS)
|
||||
string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}")
|
||||
add_custom_command(TARGET stdafx PRE_BUILD
|
||||
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../libi2pd/stdafx.h -o ${CMAKE_BINARY_DIR}/stdafx.h.gch
|
||||
)
|
||||
target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h)
|
||||
target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h)
|
||||
target_compile_options(libi2pdlang PRIVATE -include libi2pd/stdafx.h)
|
||||
target_link_libraries(libi2pd stdafx)
|
||||
endif()
|
||||
|
||||
target_link_libraries(libi2pdclient libi2pd libi2pdlang)
|
||||
|
||||
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
|
||||
@@ -227,6 +209,10 @@ if(NOT DEFINED OPENSSL_INCLUDE_DIR)
|
||||
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
|
||||
endif()
|
||||
|
||||
if(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
|
||||
endif()
|
||||
|
||||
if(WITH_UPNP)
|
||||
find_package(MiniUPnPc REQUIRED)
|
||||
if(NOT MINIUPNPC_FOUND)
|
||||
@@ -244,15 +230,7 @@ endif()
|
||||
# load includes
|
||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
|
||||
|
||||
# warn if for meshnet
|
||||
if(WITH_MESHNET)
|
||||
message(STATUS "Building for testnet")
|
||||
message(WARNING "This build will NOT work on mainline i2p")
|
||||
endif()
|
||||
|
||||
if(NOT MSYS)
|
||||
include(CheckAtomic)
|
||||
endif()
|
||||
include(CheckAtomic)
|
||||
|
||||
# show summary
|
||||
message(STATUS "---------------------------------------")
|
||||
@@ -269,8 +247,6 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
|
||||
message(STATUS " BINARY : ${WITH_BINARY}")
|
||||
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
|
||||
message(STATUS " UPnP : ${WITH_UPNP}")
|
||||
message(STATUS " PCH : ${WITH_PCH}")
|
||||
message(STATUS " MESHNET : ${WITH_MESHNET}")
|
||||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||
message(STATUS "---------------------------------------")
|
||||
@@ -282,10 +258,6 @@ if(WITH_BINARY)
|
||||
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
|
||||
endif()
|
||||
|
||||
if(WITH_PCH)
|
||||
target_compile_options("${PROJECT_NAME}" PRIVATE -include libi2pd/stdafx.h)
|
||||
endif()
|
||||
|
||||
if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now")
|
||||
endif()
|
||||
@@ -306,7 +278,7 @@ if(WITH_BINARY)
|
||||
endif()
|
||||
|
||||
target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY})
|
||||
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
|
||||
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
|
||||
|
||||
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
|
||||
@@ -2,26 +2,25 @@
|
||||
setlocal enableextensions enabledelayedexpansion
|
||||
title Building i2pd
|
||||
|
||||
REM Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
REM Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
REM This file is part of Purple i2pd project and licensed under BSD3
|
||||
REM See full license text in LICENSE file at top of project tree
|
||||
|
||||
REM To use that script, you must have installed in your MSYS installation these packages:
|
||||
REM Base: git make zip
|
||||
REM x86_64: mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-gcc
|
||||
REM i686: mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc
|
||||
REM UCRT64: mingw-w64-ucrt-x86_64-boost mingw-w64-ucrt-x86_64-openssl mingw-w64-ucrt-x86_64-gcc
|
||||
REM MINGW32: mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc
|
||||
|
||||
REM setting up variables for MSYS
|
||||
REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\msys64 needed to edit)!
|
||||
set "WD=C:\msys64\usr\bin\"
|
||||
REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\msys64 needed to edit)
|
||||
set MSYS2_PATH_TYPE=inherit
|
||||
set CHERE_INVOKING=enabled_from_arguments
|
||||
REM set MSYSTEM=MSYS
|
||||
set MSYSTEM=MINGW32
|
||||
|
||||
set "WD=C:\msys64\usr\bin\"
|
||||
set "xSH=%WD%bash -lc"
|
||||
|
||||
set "FILELIST=i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates contrib/tunnels.d"
|
||||
set "FILELIST=i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates contrib/tunnels.d contrib/webconsole"
|
||||
|
||||
REM detecting number of processors
|
||||
set /a threads=%NUMBER_OF_PROCESSORS%
|
||||
@@ -34,38 +33,67 @@ del /S build_*.log >> nul 2>&1
|
||||
|
||||
echo Receiving latest commit and cleaning up...
|
||||
%xSH% "git checkout contrib/* && git pull && make clean" > build\build.log 2>&1
|
||||
echo.
|
||||
|
||||
REM set to variable current commit hash
|
||||
FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO (
|
||||
for /F "usebackq" %%a in (`%xSH% "git describe --tags"`) DO (
|
||||
set tag=%%a
|
||||
)
|
||||
|
||||
REM set to variable latest released tag
|
||||
for /F "usebackq" %%b in (`%xSH% "git describe --abbrev=0"`) DO (
|
||||
set reltag=%%b
|
||||
)
|
||||
|
||||
echo Preparing configuration files and README for packaging...
|
||||
|
||||
%xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul
|
||||
|
||||
REM converting configuration files to DOS format (usable in default notepad)
|
||||
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" >> build\build.log 2>&1
|
||||
REM converting configuration files to DOS format (make usable in Windows Notepad)
|
||||
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/* contrib/webconsole/style.css" >> build\build.log 2>&1
|
||||
|
||||
REM Prepare binary signing command if signing key and password provided
|
||||
if defined SIGNKEY (
|
||||
if defined SIGNPASS (
|
||||
echo Signing options found
|
||||
|
||||
for %%X in (signtool.exe) do (set xSIGNTOOL=%%~$PATH:X)
|
||||
if not defined xSIGNTOOL (
|
||||
if not defined SIGNTOOL (
|
||||
echo Error: Can't find signtool. Please provide path to binary using SIGNTOOL variable.
|
||||
exit /b 1
|
||||
) else (
|
||||
set "xSIGNTOOL=%SIGNTOOL%"
|
||||
)
|
||||
)
|
||||
|
||||
set "xSIGNOPTS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 /f ^"%SIGNKEY%^" /p ^"%SIGNPASS%^""
|
||||
)
|
||||
)
|
||||
|
||||
REM starting building
|
||||
set MSYSTEM=MINGW32
|
||||
set bitness=32
|
||||
call :BUILDING
|
||||
|
||||
set MSYSTEM=MINGW64
|
||||
set MSYSTEM=UCRT64
|
||||
set bitness=64
|
||||
call :BUILDING
|
||||
|
||||
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
|
||||
REM build for Windows XP
|
||||
if exist C:\msys64-xp\ ( call :BUILDING_XP )
|
||||
|
||||
echo.
|
||||
|
||||
REM compile installer
|
||||
C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_TextVer="%tag%" /dI2Pd_Ver="%tag%.0" build\win_installer.iss >> build\build.log 2>&1
|
||||
echo Building installer...
|
||||
C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_TextVer="%tag%" /dI2Pd_Ver="%reltag%.0" build\win_installer.iss >> build\build.log 2>&1
|
||||
|
||||
REM Sign binary
|
||||
if defined xSIGNOPTS (
|
||||
"%xSIGNTOOL%" %xSIGNOPTS% build\setup_i2pd_v%tag%.exe
|
||||
)
|
||||
|
||||
%xSH% "git checkout contrib/*" >> build\build.log 2>&1
|
||||
del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul
|
||||
|
||||
echo Build complete...
|
||||
@@ -74,13 +102,42 @@ exit /b 0
|
||||
|
||||
:BUILDING
|
||||
%xSH% "make clean" >> nul
|
||||
echo Building i2pd %tag% for win%bitness%
|
||||
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build\build_win%bitness%_%tag%.log 2>&1
|
||||
echo Building i2pd %tag% for win%bitness%...
|
||||
REM Build i2pd
|
||||
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads%" > build\build_win%bitness%_%tag%.log 2>&1
|
||||
|
||||
REM Sign binary
|
||||
if defined xSIGNOPTS (
|
||||
"%xSIGNTOOL%" %xSIGNOPTS% i2pd.exe
|
||||
)
|
||||
|
||||
REM Copy binary for installer and create distribution archive
|
||||
%xSH% "cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST%" >> build\build_win%bitness%_%tag%.log 2>&1
|
||||
|
||||
REM Clean work directory
|
||||
%xSH% "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% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build\build_winxp_%tag%.log 2>&1
|
||||
set MSYSTEM=MINGW32
|
||||
set bitness=32
|
||||
set "WD=C:\msys64-xp\usr\bin\"
|
||||
set "xSH=%WD%bash -lc"
|
||||
|
||||
:EOF
|
||||
%xSH% "make clean" >> nul
|
||||
echo Building i2pd %tag% for winxp...
|
||||
%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads%" > build\build_winxp_%tag%.log 2>&1
|
||||
|
||||
REM Sign binary
|
||||
if defined xSIGNOPTS (
|
||||
"%xSIGNTOOL%" %xSIGNOPTS% i2pd.exe
|
||||
)
|
||||
|
||||
REM Copy binary for installer and create distribution archive
|
||||
%xSH% "cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST%" >> build\build_winxp_%tag%.log 2>&1
|
||||
|
||||
REM Clean work directory
|
||||
%xSH% "make clean" >> build\build_winxp_%tag%.log 2>&1
|
||||
goto EOF
|
||||
|
||||
:EOF
|
||||
|
||||
@@ -1,16 +1,30 @@
|
||||
# Copyright (c) 2017-2022, The PurpleI2P Project
|
||||
# This file is part of Purple i2pd project and licensed under BSD3
|
||||
# See full license text in LICENSE file at top of project tree
|
||||
|
||||
# Based on the Qt 5 processor detection code, so should be very accurate
|
||||
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
|
||||
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
|
||||
# https://github.com/qt/qtbase/blob/dev/src/corelib/global/qprocessordetection.h
|
||||
# Currently handles arm (v5, v6, v7, v8), x86 (32/64), ia64, mips (32/64, mipsel, mips64el) and ppc (32/64)
|
||||
|
||||
# Regarding POWER/PowerPC, just as is noted in the Qt source,
|
||||
# "There are many more known variants/revisions that we do not handle/detect."
|
||||
|
||||
set(archdetect_c_code "
|
||||
#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
|
||||
#if defined(__arm__) || defined(__TARGET_ARCH_ARM)|| defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__)
|
||||
#if defined(__ARM64_ARCH_8__) \\
|
||||
|| defined(__aarch64__) \\
|
||||
|| defined(__ARMv8__) \\
|
||||
|| defined(__ARMv8_A__) \\
|
||||
|| defined(_M_ARM64) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8)
|
||||
#error cmake_ARCH arm64
|
||||
#if defined(__ARM_ARCH_7__) \\
|
||||
|| defined(__ARM_ARCH_7A__) \\
|
||||
|| defined(__ARM_ARCH_7R__) \\
|
||||
|| defined(__ARM_ARCH_7M__) \\
|
||||
|| defined(__ARM_ARCH_7S__) \\
|
||||
|| defined(_ARM_ARCH_7) \\
|
||||
|| defined(__CORE_CORTEXA__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
|
||||
#error cmake_ARCH armv7
|
||||
#elif defined(__ARM_ARCH_6__) \\
|
||||
@@ -23,6 +37,7 @@ set(archdetect_c_code "
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
|
||||
#error cmake_ARCH armv6
|
||||
#elif defined(__ARM_ARCH_5TEJ__) \\
|
||||
|| defined(__ARM_ARCH_5TE__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
|
||||
#error cmake_ARCH armv5
|
||||
#else
|
||||
@@ -34,6 +49,18 @@ set(archdetect_c_code "
|
||||
#error cmake_ARCH x86_64
|
||||
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||
#error cmake_ARCH ia64
|
||||
#elif defined(__mips) || defined(__mips__) || defined(_M_MRX000)
|
||||
#if defined(_MIPS_ARCH_MIPS64) || defined(__mips64)
|
||||
#if defined(__MIPSEL__)
|
||||
#error cmake_ARCH mips64el
|
||||
#else
|
||||
#error cmake_ARCH mips64
|
||||
#endif
|
||||
#elif defined(__MIPSEL__)
|
||||
#error cmake_ARCH mipsel
|
||||
#else
|
||||
#error cmake_ARCH mips
|
||||
#endif
|
||||
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|
||||
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
||||
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||
@@ -47,7 +74,7 @@ set(archdetect_c_code "
|
||||
#error cmake_ARCH unknown
|
||||
")
|
||||
|
||||
# Set ppc_support to TRUE before including this file or ppc and ppc64
|
||||
# Set ppc_support to TRUE before including this file on ppc and ppc64
|
||||
# will be treated as invalid architectures since they are no longer supported by Apple
|
||||
|
||||
function(target_architecture output_var)
|
||||
@@ -67,12 +94,14 @@ function(target_architecture output_var)
|
||||
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
|
||||
set(osx_arch_ppc TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
|
||||
set(osx_arch_ppc64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "i386")
|
||||
set(osx_arch_i386 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "x86_64")
|
||||
set(osx_arch_x86_64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
|
||||
set(osx_arch_ppc64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "arm64")
|
||||
set(osx_arch_arm64 TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
|
||||
endif()
|
||||
@@ -83,6 +112,10 @@ function(target_architecture output_var)
|
||||
list(APPEND ARCH ppc)
|
||||
endif()
|
||||
|
||||
if(osx_arch_ppc64)
|
||||
list(APPEND ARCH ppc64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_i386)
|
||||
list(APPEND ARCH i386)
|
||||
endif()
|
||||
@@ -91,8 +124,8 @@ function(target_architecture output_var)
|
||||
list(APPEND ARCH x86_64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_ppc64)
|
||||
list(APPEND ARCH ppc64)
|
||||
if(osx_arch_arm64)
|
||||
list(APPEND ARCH arm64)
|
||||
endif()
|
||||
else()
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#define I2Pd_AppName "i2pd"
|
||||
#define I2Pd_Publisher "PurpleI2P"
|
||||
; Get application version from compiled binary
|
||||
; Disabled to use definition from command line
|
||||
;#define I2Pd_ver GetFileVersionString(AddBackslash(SourcePath) + "..\i2pd_x64.exe")
|
||||
|
||||
[Setup]
|
||||
AppName={#I2Pd_AppName}
|
||||
@@ -27,7 +24,7 @@ ExtraDiskSpaceRequired=15
|
||||
|
||||
AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
|
||||
AppVerName={#I2Pd_AppName}
|
||||
AppCopyright=Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
AppCopyright=Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
AppPublisherURL=http://i2pd.website/
|
||||
AppSupportURL=https://github.com/PurpleI2P/i2pd/issues
|
||||
AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases
|
||||
@@ -47,6 +44,7 @@ Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyif
|
||||
Source: ..\contrib\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
||||
Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
|
||||
Source: ..\contrib\tunnels.d\*; DestDir: {userappdata}\i2pd\tunnels.d; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
|
||||
Source: ..\contrib\webconsole\*; DestDir: {userappdata}\i2pd\webconsole; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
|
||||
|
||||
[Icons]
|
||||
Name: {group}\I2Pd; Filename: {app}\i2pd.exe
|
||||
|
||||
18
contrib/android_binary_only/.gitignore
vendored
18
contrib/android_binary_only/.gitignore
vendored
@@ -1,18 +0,0 @@
|
||||
gen
|
||||
tests
|
||||
bin
|
||||
libs
|
||||
log*
|
||||
obj
|
||||
.gradle
|
||||
.idea
|
||||
.externalNativeBuild
|
||||
ant.properties
|
||||
local.properties
|
||||
build.sh
|
||||
android.iml
|
||||
build
|
||||
gradle
|
||||
gradlew
|
||||
gradlew.bat
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := i2pd
|
||||
LOCAL_CPP_FEATURES := rtti exceptions
|
||||
LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(DAEMON_SRC_PATH)
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
boost_system \
|
||||
boost_date_time \
|
||||
boost_filesystem \
|
||||
boost_program_options \
|
||||
crypto ssl \
|
||||
miniupnpc
|
||||
LOCAL_LDLIBS := -lz
|
||||
|
||||
LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \
|
||||
$(wildcard $(LIB_SRC_PATH)/*.cpp)\
|
||||
$(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\
|
||||
$(DAEMON_SRC_PATH)/UnixDaemon.cpp \
|
||||
$(DAEMON_SRC_PATH)/Daemon.cpp \
|
||||
$(DAEMON_SRC_PATH)/UPnP.cpp \
|
||||
$(DAEMON_SRC_PATH)/HTTPServer.cpp \
|
||||
$(DAEMON_SRC_PATH)/I2PControl.cpp \
|
||||
$(DAEMON_SRC_PATH)/i2pd.cpp
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_system
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_date_time
|
||||
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_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_filesystem
|
||||
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := boost_program_options
|
||||
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_72_0/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := crypto
|
||||
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libcrypto.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ssl
|
||||
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libssl.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
|
||||
LOCAL_STATIC_LIBRARIES := crypto
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := miniupnpc
|
||||
LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
@@ -1,40 +0,0 @@
|
||||
APP_ABI := all
|
||||
#APP_ABI += x86
|
||||
#APP_ABI += x86_64
|
||||
#APP_ABI += armeabi-v7a
|
||||
#APP_ABI += arm64-v8a
|
||||
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
|
||||
APP_PLATFORM := android-14
|
||||
|
||||
NDK_TOOLCHAIN_VERSION := clang
|
||||
APP_STL := c++_static
|
||||
|
||||
# Enable c++17 extensions in source code
|
||||
APP_CPPFLAGS += -std=c++17 -fvisibility=default -fPIE
|
||||
|
||||
APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
|
||||
APP_LDFLAGS += -rdynamic -fPIE -pie
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
APP_CPPFLAGS += -DANDROID_ARM7A
|
||||
endif
|
||||
|
||||
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
|
||||
#APP_OPTIM := debug
|
||||
|
||||
# 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/MiniUPnP-for-Android-Prebuilt.git
|
||||
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
|
||||
# change to your own
|
||||
I2PD_LIBS_PATH = /path/to/libraries
|
||||
BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt
|
||||
OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt
|
||||
MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt
|
||||
IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs
|
||||
|
||||
# don't change me
|
||||
I2PD_SRC_PATH = $(PWD)/../..
|
||||
|
||||
LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd
|
||||
LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client
|
||||
DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon
|
||||
2
contrib/android_binary_pack/.gitignore
vendored
2
contrib/android_binary_pack/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
archive
|
||||
i2pd_*_android_binary.zip
|
||||
@@ -1,48 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
#
|
||||
# This file is part of Purple i2pd project and licensed under BSD3
|
||||
#
|
||||
# See full license text in LICENSE file at top of project tree
|
||||
|
||||
GITDESC=$(git describe --tags)
|
||||
|
||||
declare -A ABILIST=(
|
||||
["armeabi-v7a"]="armv7l"
|
||||
["arm64-v8a"]="aarch64"
|
||||
["x86"]="x86"
|
||||
["x86_64"]="x86_64"
|
||||
)
|
||||
|
||||
# Remove old files and archives
|
||||
if [ -d archive ]; then
|
||||
rm -r archive
|
||||
fi
|
||||
|
||||
if [ -f ../i2pd_*_android_binary.zip ]; then
|
||||
rm i2pd_*_android_binary.zip
|
||||
fi
|
||||
|
||||
# Prepare files for package
|
||||
mkdir archive
|
||||
|
||||
for ABI in "${!ABILIST[@]}"; do
|
||||
if [ -f ../android_binary_only/libs/${ABI}/i2pd ]; then
|
||||
cp ../android_binary_only/libs/${ABI}/i2pd archive/i2pd-${ABILIST[$ABI]}
|
||||
fi
|
||||
done
|
||||
|
||||
cp i2pd archive/i2pd
|
||||
cp -rH ../android/assets/certificates archive/
|
||||
cp -rH ../android/assets/tunnels.conf.d archive/
|
||||
cp -H ../android/assets/i2pd.conf archive/
|
||||
cp -H ../android/assets/tunnels.conf archive/
|
||||
|
||||
# Compress files
|
||||
cd archive
|
||||
zip -r6 ../i2pd_${GITDESC}_android_binary.zip .
|
||||
|
||||
# Remove temporary folder
|
||||
cd ..
|
||||
rm -r archive
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
#
|
||||
# This file is part of Purple i2pd project and licensed under BSD3
|
||||
#
|
||||
# See full license text in LICENSE file at top of project tree
|
||||
#
|
||||
# That script written for use with Termux.
|
||||
|
||||
# https://stackoverflow.com/a/246128
|
||||
SOURCE="${0}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
|
||||
|
||||
arch=$(uname -m)
|
||||
|
||||
screenfind=$(which screen)
|
||||
if [ -z $screenfind ]; then
|
||||
echo "Can't find 'screen' installed. That script needs it!";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ -z i2pd-$arch ]; then
|
||||
echo "Can't find i2pd binary for your archtecture.";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR
|
||||
14
contrib/certificates/family/stormycloud.crt
Normal file
14
contrib/certificates/family/stormycloud.crt
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICKDCCAc6gAwIBAgIUcPHZXtYSqGNRCD6z8gp79WUFtI0wCgYIKoZIzj0EAwIw
|
||||
gZMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGQXVzdGlu
|
||||
MRgwFgYDVQQKDA9TdG9ybXlDbG91ZCBJbmMxIzAhBgNVBAMMGnN0b3JteWNsb3Vk
|
||||
LmZhbWlseS5pMnAubmV0MSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBzdG9ybXljbG91
|
||||
ZC5vcmcwHhcNMjIwMzE5MTU1MjU2WhcNMzIwMzE2MTU1MjU2WjCBkzELMAkGA1UE
|
||||
BhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYDVQQHDAZBdXN0aW4xGDAWBgNVBAoM
|
||||
D1N0b3JteUNsb3VkIEluYzEjMCEGA1UEAwwac3Rvcm15Y2xvdWQuZmFtaWx5Lmky
|
||||
cC5uZXQxJDAiBgkqhkiG9w0BCQEWFWFkbWluQHN0b3JteWNsb3VkLm9yZzBZMBMG
|
||||
ByqGSM49AgEGCCqGSM49AwEHA0IABFUli0hvJEmowNjJVjbKEIWBJhqe973S4VdL
|
||||
cJuA5yY3dC4Y998abWEox7/Y1BhnBbpJuiodA341bXKkLMXQy/kwCgYIKoZIzj0E
|
||||
AwIDSAAwRQIgD12F/TfY3iV1/WDF7BSKgbD5g2MfELUIy1dtUlJQuJUCIQD69mZw
|
||||
V1Z9j2x0ZsuirS3i6AMfVyTDj0RFS3U1jeHzIQ==
|
||||
-----END CERTIFICATE-----
|
||||
33
contrib/certificates/reseed/echelon3_at_mail.i2p.crt
Normal file
33
contrib/certificates/reseed/echelon3_at_mail.i2p.crt
Normal file
@@ -0,0 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFyzCCA7OgAwIBAgIRALWNWsnQ0Vmn/99iCNT7cdQwDQYJKoZIhvcNAQELBQAw
|
||||
cTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
|
||||
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGjAYBgNVBAMM
|
||||
EWVjaGVsb24zQG1haWwuaTJwMB4XDTIxMTEyOTE5MzU1OVoXDTMxMTEyOTE5MzU1
|
||||
OVowcTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwG
|
||||
A1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGjAYBgNV
|
||||
BAMMEWVjaGVsb24zQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||
CgKCAgEA3pccNiQWJUS1t3QHK7rBCNKAsM2dz4szN3+3SrDy1w+rOrK8Vt5aypPU
|
||||
QYUQwG+odjEPacuoRtO/W14KJl5yAI3eQS+X/cYDXmxvfm4zx5JRumYptXwJD57G
|
||||
rlPHnFvk8R+Hvh+/UyqgSAZ9ZaKjEzYK4AtbYEXtopaM4U2VYN8xKjvKyWlhPdxo
|
||||
kI3//qcTlSqGHHeHrkItLG1LubM1EnPu+9zI2WN2zBBRcm8ZtWqHoqFJ1zgJr/49
|
||||
nMK8Lnb3I54ctva8x5+gsSk4dbG/mMsOIZekFqYJJs3+u9w5fmOYI7v9GlQr7UhE
|
||||
G3MwjJ5Cj1LmLVlz/4LApZrDSd2JvwIUdGL3UW8+blaTeCPKIRvmsTeRxo1gORMF
|
||||
ZH0dg39722lK7ScwOlOUX9ggzRUlYCmvnjQJZGJEUoP68QxjlQfkXZyffmMfvm6K
|
||||
V6mcZ5aHMGO1lYAl40kWNJ0jGpmxJqTDhNFDEKr0TlRGVxXGWzObEOrcJ8ysRMc1
|
||||
x6oXQhh79HXZcKwhZaXLx23ZvVoTfhRm4JH0SSP6XqQm35j4NI1SllEsDns29wU3
|
||||
Re4wOWJCCYlPG3CtY32CinwQRoVgtiJk18W8+Pxw7sBFq8sL5L0Z+5bB6nTkBfV6
|
||||
7OrZGWL0i344zQE0e3yIsLih+5Wyqw6RSSMysenl3alnUB9EvE0CAwEAAaNeMFww
|
||||
DgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAP
|
||||
BgNVHRMBAf8EBTADAQH/MBoGA1UdDgQTBBFlY2hlbG9uM0BtYWlsLmkycDANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAaUMnMYtNFBl9dFON6e4EjYo53Wknj61uIVO11dvLqjnh
|
||||
7X6guPML+GgNZsPQGLu7Bqw4hVgy/cV5AlFc7SXOhzpaYo1ycpjg3Ws1VK2wrk7+
|
||||
4bvUThNcS1KZVFDdRE62549rYNfYNfPxXvccOTW9meTCC1kLHerh65ySDr9J02O6
|
||||
o5Mf685PgBasBH6dlosOLTtee2gRLNFcAluQYKerawS1gDys5239UNHPCqTgO+Od
|
||||
FiKfl48OIOzPGLKEf4lXC+lkwZElewShrHhzd8aGueedTi0UHOtQuY7ocsofqXc8
|
||||
OnyT/y2X6wn/YkzviKgfxYDSI7FJiUgXCPcT0jUNmuwR168yL5BfzoQmrCvlOOQg
|
||||
P7ibdBJ6UkL8pRpv/SYpvaX/kf4agYtwh5IL9FzNCwNu54ZC6JilLUhYAU38Eolq
|
||||
OZ/cGiMoSFQIeBPvB3cdsqEud9W4P+MqN5A76fMzdVV77lGsIS1eCGMceR3CjOiF
|
||||
6SdAskcBZWhFiRNQweC0iv57/nPCeTCuNAqbZSHd7zC1AKhNmmsKSJUJQCGijcce
|
||||
P8Gl0AFfZneN2bVEFvJ/zd71pD8ll1Gkju16bfdWn0V4NRaxFiXNr2bL+ah9blud
|
||||
EXOomE3R6ow1QZk+Gnpy3wh9jfwlrJuFoANvHnv4WREbdjwr//71XjBri5p1wPE=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,32 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFfzCCA2egAwIBAgIESg3kkzANBgkqhkiG9w0BAQ0FADBwMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQZWNoZWxvbkBtYWls
|
||||
LmkycDAeFw0xNDA3MzExNjQ3MDJaFw0yNDA3MzAxNjQ3MDJaMHAxCzAJBgNVBAYT
|
||||
AlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9u
|
||||
eW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQDDBBlY2hlbG9uQG1h
|
||||
aWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmcEgLwwhzLNe
|
||||
XLOMSrhwB8hWpOhfjo4s6S/wjBtjjUc8nI3D0hSn3HY26p0rvcvNEWexPUpPULmC
|
||||
exGkU463nu7PiFONiORI1eJAiUFHibRiaA7Wboyo38pO73KirwjG07Y+Ua0jp+HS
|
||||
+4FQ/I/9H/bPplReTOU/6hmRbgQ69U8nE68HzZHQxP68yVJ2rPHSXMPhF4R1h0G1
|
||||
1mCAT+TgTsnwHNGF77XHJnY4/M4e2cgycEZjZow36C3t2mNDVkMgF19QQeb9WmLR
|
||||
zREn3nq9BJqHpUkn9yWw0kKXTZSds+7UxESfzf3BzK0+hky2fh5H+qbYAo2lz4yj
|
||||
81MXTAu+4RRkg4DBLlF+2dkclhwQLxxzvkRC6tPkn5i33Yltg7EfzA9IoQ05potJ
|
||||
I+iOcF+aStfFgFj9u3B5UkcF4P0cH1QD3c6BK4hIezQYqRoPly1gHqg+XdwjG/dr
|
||||
4as7HA9FTz3p2E8nClpIC1x3hfgwAdfd29aeBxO1WW/z99iMF7TBAF+u5T86XEW1
|
||||
WpknqCbTli36yJ8a5fPWxZHrryBRJT5yLxejjFeadtutBSwljiVFq+Y38VqwFivq
|
||||
VLiBt7IxAsZ8iilgfnnnAvBH6chWfSKb4H7kB4TJvDiV96QmmvoEaWYNHZozMhyK
|
||||
tO3b5w+xqbJXyCLA3Q75jD0km76hjcECAwEAAaMhMB8wHQYDVR0OBBYEFAHQcAam
|
||||
QRS/EUhuCSr9pB4Ux0rYMA0GCSqGSIb3DQEBDQUAA4ICAQBq1+1QLmgLAjrTg3tb
|
||||
4XKgAVICQRoBDNUEobQg3pYeUX9eFNya2RxNljuvYpwT80ilGMPOXcjddmr5ngiK
|
||||
dbGRcuuJk9MPEHtPaPT3+JJlvKQ3B3g2wva2Wz2OAyLZUGQs389K4nTbwh4QF0n2
|
||||
aHFL8BHiD62hiKnCoNaW4ZovUNNvOxo9lMyAiaFU2gqQNcdad8hP9EAllbvbxDx9
|
||||
Tjww2UbwQUIHS9rna4Tlu+f0hDXTWIutc2A51W2fJCb7L3+lYO7Wv55ND/WtryLZ
|
||||
XpMp27+MpuEnN3kQmz/l9R0hIJsWc/x9GQkjm5wEaIZEyTtenqwRKGmVCtAj0Pgv
|
||||
jn1L3/lWmrNq+OZHb/QeyfKtA3nXfQKVmT98ewQiK/S5i1xIAXCJPytOD887b/o1
|
||||
cdurTmCiZMwgiQ+HLJqCg3MDa5mvKqRkRdZXfE6aQWEcSbpAhpV15R17q7L+Fg0W
|
||||
shLSNucxyGNU8PjiC/nOmqfqUiPiMltJjPmscxBLim8foyxjakC4+6N6m+Jzgznj
|
||||
PocBehFAfKYj66XEwzIBN7Z2uuXoYH9YptkocFjTzvchcryVulDWZ4FWxreUMhpM
|
||||
4oyjjhSB4tB9clXlwMqg577q3D6Ms0zLTqsztyPN3zr6jGev3jpVq7Q1GOlciHPv
|
||||
JNJOWTH/Vas1W6XlwGcOOAARTQ==
|
||||
-----END CERTIFICATE-----
|
||||
32
contrib/certificates/reseed/hiduser0_at_mail.i2p.crt
Normal file
32
contrib/certificates/reseed/hiduser0_at_mail.i2p.crt
Normal file
@@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFgTCCA2mgAwIBAgIETWAY1DANBgkqhkiG9w0BAQ0FADBxMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBAbWFp
|
||||
bC5pMnAwHhcNMjExMjEzMTU0MDI3WhcNMzExMjExMTU0MDI3WjBxMQswCQYDVQQG
|
||||
EwJYWDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5v
|
||||
bnltb3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBA
|
||||
bWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXnjJ8UQ0f
|
||||
lHHpfPMiHofBPSuL4sbOJY6fOXwPhSg/h6THh9DS/ZWmJXQ3qRD0glDVtv4/Dr/9
|
||||
ldGQ5eltF9iCFXCQlMEy2HjQrBKq0nsl7RpYK12cyMaod0kkzCUk9ITLi9CmHM3Z
|
||||
gQZcmG8TWjFEpDR+idx/QkQt2pcO4vzWlDit3Vh4ivnbX5jGQHbsVjQEMQWxr+pX
|
||||
dsS+YQpjZ6RBmrooGTPO8QDOOeYLAn0lCjmffc/kzIH9E/p4/O0rOpyhVYbdxUD1
|
||||
5wkqN9l4yrtxmORG/PudnRQQ0r4TUq8vsxfGY0Euo9IbhgXF2Parel1ZhDxB1WZV
|
||||
VwWtgLIh9jGA1UMa8SYKnEfp8LWNZ3b3mUUnZb3kMrLk6jGYRWNsHmamhd4mC7AZ
|
||||
qf/8lOkEIw3bPd3YguCDRVcLui5BwIEZmqXg8uoESxfO/sW3pBrN/8M7MkTex9kN
|
||||
vjitGDDXvenK27qmNgZxbBlX72yTSfys7XTYTLnxZC8AwdAo2Wz9Z6HhGiPonf2h
|
||||
vZkc9ZxuE0jFIrsbJra4X7iyjXgi4vV4ARNg/9Ft6F4/OIbECgeDcBQqq4TlT2bZ
|
||||
EfWVrBbqXoj5vNsLigIkd+AyUNwPYEcB5IFSiiOh98pC7BH3pg0m8U5YBjxe1i+9
|
||||
EQOOG0Qtx+JigXZHu6bGE0Twy9zy+UzoKQIDAQABoyEwHzAdBgNVHQ4EFgQUGK1b
|
||||
0DkL6aLalcfBc/Uj/SF08C0wDQYJKoZIhvcNAQENBQADggIBAMpXM82bJDpH1TlH
|
||||
TvhU3Z7nfZdvEhOQfujaFUYiuNripuEKcFGn948+DvAG0FUN+uNlJoqOVs8D7InD
|
||||
gWlA9zpqw5Cl5Hij/Wns9QbXuAHJeA23fVUoaM2A6v9ifcIQ1A+rDuRQAo6/64KW
|
||||
ChTg2e99RBpfGOyqgeh7tLLe0lPPekVpKHFuXabokaKRDuBcVHcUL4tWXe3dcyqa
|
||||
Ej/PJrrS+nWL0EGZ4q80CEd2LPuDzPxNGCJt/R7ZfadENWajcgcXGceh1QBzozrB
|
||||
SL/Ya6wF9SrsB7V/r5wX0LM4ZdDaLWbtmUe5Op0h/ZMH25Sa8xAXVz+O9L6sWSoO
|
||||
FaiYTOvAiyyPz+nsxKa3xYryDHno7eKSt+hGOcaurhxbdZaEFY/CegEc73tCt9xK
|
||||
e9qF8O/WkDLmixuErw3f5en4IfzGR7p3lJAwW/8WD8C6HS39h/eE7dVZNaWgtQnZ
|
||||
SgGjgZMTJqTcQ3aZmfuCZefxGFok8w6AIkdbnd1pdMBRjYu8aXgl2hQSB9ZADDE9
|
||||
R5d3rXi0PkSFLIvsNjVa5KXrZk/tB0Hpfmepq7CufBqjP/LG9TieRoXzLYUKFF74
|
||||
QRwjP+y7AJ+VDUTpY1NV1P+k+2raubU2bOnLF3zL5DtyoyieGPhyeMMvp0fRIxdg
|
||||
bSl5VHgPXHNM8mcnndMAuzvl7jEK
|
||||
-----END CERTIFICATE-----
|
||||
34
contrib/certificates/reseed/i2p-reseed_at_mk16.de.crt
Normal file
34
contrib/certificates/reseed/i2p-reseed_at_mk16.de.crt
Normal file
@@ -0,0 +1,34 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFzTCCA7WgAwIBAgIQeUqFi0fHNQopg6BZlBLhVzANBgkqhkiG9w0BAQsFADBy
|
||||
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
||||
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEbMBkGA1UEAwwS
|
||||
aTJwLXJlc2VlZEBtazE2LmRlMB4XDTIyMDIwNTE3MzkzM1oXDTMyMDIwNTE3Mzkz
|
||||
M1owcjELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwG
|
||||
A1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGzAZBgNV
|
||||
BAMMEmkycC1yZXNlZWRAbWsxNi5kZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
|
||||
AgoCggIBAMYxs2D2xpN/8blGawvAlU9DemHIxApOEwaLNfh8aAvqEdB41NTqcx4U
|
||||
H8VchSormCfkCvezuMHO+K2HX7ihEZ1v6tbr6aX6hY9UZUyDDYsKmJoB1oKEhddv
|
||||
5UYfcWPE2eSykdFsWgTQD6Z+cRQWHEoCzb7qc+Jrw6KcnHMD0VrmBrEQPzTBxMHW
|
||||
4HC97PVkSLJTDArnS6ZiX4IbWRPw/mbpJT6EoVZo8J/it0pdn/X4KodEXDcnEMSe
|
||||
VRulfZH/nSmOOvKhoHPckmgz/u66BlnuSYXEIB0KfDIcAlSYiPDxGnAemTozJYXA
|
||||
UVMeFMs+YE5wiPgzzu+vpC31xtZLq0gyaCfgEi1P9j2ES/8pH3Gw6W2OH4kBx+jO
|
||||
TBsfI+ph6qFZ3WWT23MRVyl3ATuI/GHdczTxD9JaOn74lLI+Hnu8wXnyztVWkTMB
|
||||
4sAnzjdeHkvNDyQ10vSaN0HnGfg6zuAuUSqFQujFF8Vg8ZCcsh8GouWfzYDvi9mj
|
||||
9pfxx8v6UCC719I4J9CgFjWnn2Hqez3fO8fFulY61VPyCCZp4gKWbI2SIQP/n5gz
|
||||
ecYJRrJoem+rYfEQ/fwxROsvm3fCO4D6dt7ILRuX286GDIw2qSvP1zZVAioMwSj3
|
||||
9CAjKLwD/BhTRiMOlpaVv6IWqjtevbiaIKvbHTnoxvkGsDqe3gJhAgMBAAGjXzBd
|
||||
MA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw
|
||||
DwYDVR0TAQH/BAUwAwEB/zAbBgNVHQ4EFAQSaTJwLXJlc2VlZEBtazE2LmRlMA0G
|
||||
CSqGSIb3DQEBCwUAA4ICAQAb+x6XpJdjpVYw2bvWIUbatQJwq0YaEW5W61xGLgIG
|
||||
a37oll3YZbSY9Vk+N1cE0f61L3ya4Ioz6zlH/MO2zUG/dEk8vqdgIPUYJvyF7wwF
|
||||
w3/G4VMaDKOJx4bAZNmaiRFGYNhCOhCnZx6uZGrLNIJ2Dc+mflrGmGwYphtXVV3e
|
||||
Iv+ki3gSRgfXuMfKi4B5bLPnz7XDe4TSmwZZSRac4ly4KqmZUyntqbilRxaGTej3
|
||||
VYJ1tac8yppyk5N3VopMQNmBarNZG16wSOTD7CtKgn382jgRW8cR7BMeqhORivp0
|
||||
ZnPJFhzh4uthdlPdXXo6lxfvZjfiwlDPytvEu2QBz3urTgopGqRLcTBnLucWg9li
|
||||
OSy9z7hNEnIN3iIJJAwI1wBdDa7K0h3PFBbIUa7X2ybn81VeNSfO25Lo8YTZEKsc
|
||||
wcThJrNV6qOQv8rM/7aXugi6+VzPlCR+18iKRbebCnlqGR2dT1zFtj3negtOkrjo
|
||||
LH4H6VUr3q2Ie56IubS2hUKiUkDm0ckP3Vum35GGntyEAzl6uyog0hJFOJb3aq30
|
||||
YQLzyVEOz8NnA+32oMRzJJdDxQ7pqG5fgq7EF4d++YSgEfdVXxvfgXQ6m3jAyC7Z
|
||||
p/gX4rlxNsjeGU3Ds51wkmhH4IB1aSQr52PE6RaBhhh3SmADEv6S/3eGvE4F4MN5
|
||||
2Q==
|
||||
-----END CERTIFICATE-----
|
||||
33
contrib/certificates/reseed/rambler_at_mail.i2p.crt
Normal file
33
contrib/certificates/reseed/rambler_at_mail.i2p.crt
Normal file
@@ -0,0 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFxzCCA6+gAwIBAgIQfKAV7rmoWA8jWpLfMtDQqzANBgkqhkiG9w0BAQsFADBw
|
||||
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
||||
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQ
|
||||
cmFtYmxlckBtYWlsLmkycDAeFw0yMTExMDYwNzEwMzJaFw0zMTExMDYwNzEwMzJa
|
||||
MHAxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNV
|
||||
BAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQD
|
||||
DBByYW1ibGVyQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
|
||||
AgEAz4vQlIdjY56uqkFKWld9Oy3E8+06Ag9fUzBVleS2bdJfaFtmEa8xz6Pep7Bb
|
||||
zJK0Q9t2CW7/xqIWuspWlYn5EYAS7BFiNOX70KX4PMpltj3C4Dpxpjll9LdydU2k
|
||||
FquCflXNJESnBDdd0qDRMboMf4c9lTz0mTLwAtzInLwHGDrbxEiQ/YqPgPJreOXQ
|
||||
anhjkpxJcgpLR+9od8EdLNKbShVWEeSBnYp0FcjnZKOb9KC2gjqP0sWdzlw3i1hh
|
||||
CB38A7a03Q4yUcmxCw4ktM60d/2jCZ+G7KHwcbkfxDjl85r0UgEzgfF7LuIuxxmA
|
||||
MNLH1eAACnLTl42O72EHdtD9VWWwZF2NuFgAzT3MEFnMKDk+OqZOeZQOEgkIfrNP
|
||||
O5XYMYxHSWCf/dmSq36ZJwhC40k2S9ArS8BQNY8NvwZG5CSGDU52FKaHzFn6EwLE
|
||||
4CpsrptUX2itXLaFUiNMw6I+eSgTO7x+gpahZVqpdRSQXmpE0xA5jP/DwPyt3ZVe
|
||||
/4q4kn3imcSCxBP5NQHWfVszsruRkh9np4R0xVlT8UCwJmY8Yg8zwJG5UddTAck5
|
||||
JavDsaXgWMwcZ/qQboZKlH/iAdQnbkte8Yd5GL5nmTeS+vwuluwmA/y9kUzSUhk+
|
||||
86kA0eRJ1+e2HdA1/UOTRmyIoIeQ5/fhELMXzhksLcpMGTUCAwEAAaNdMFswDgYD
|
||||
VR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNV
|
||||
HRMBAf8EBTADAQH/MBkGA1UdDgQSBBByYW1ibGVyQG1haWwuaTJwMA0GCSqGSIb3
|
||||
DQEBCwUAA4ICAQAxRdSTZGEblnNeVuRoEQq/a/6q4egFaOkzXCPKEnDzB5yvm83g
|
||||
35ImquGFZkgaoc5qUAHVeBwOQrWgUI4xHPofnbM2VsgEUMz6h3ovobPNkN3+lRT5
|
||||
30krd0y+A/Q895EHDu0lyf3BHMmtCWiKWQBttuc0dnmoLCRsQxgy+kYJCS/81jCM
|
||||
4KNnyrtc6a/czqSq758CncjP2nErVucendsguQoA5JUw53YJ4FYHG/f9tYEkhm9C
|
||||
D6u7L3vTUcMRUrRxSiJyNixH36nEwpM6DNHiPNc+CFKZ/Zx449R1GjcpDhTrXnWP
|
||||
2H1r3cyKEM8a76VUEs2GQCaaglOR4N1goyqgYEjScf+/4VmARL3VUzfP8Oub70rM
|
||||
t1fip5QD/4VDQuA/9C9g5Rr2nJ3K2jVnpSSKnBYFYf5z9RZdTOVXjXaEi72lWxpk
|
||||
mjgK6c5EFOJxYoCaTbKX9Kz9ZIWVOVMrgHWwA/wDW+Qk5zgP9Ysau65xIp9P1RdB
|
||||
qHgR5BcIrNky9RD8cIzxzMPCSMVgnf0eLFuHmG8uUl/xHHVRprf0pd7DYkQ44HWN
|
||||
Z/g/gg3DaJdH7vvkShzgjt4iZrmOCHQIKkSGFRYZf0/Mpn6mgK9+grtO9osVgAQr
|
||||
LBO+5LIxV/S5bcrzWQLOiMABTd2X/0PTOjuXpfinZ3rDSUiNFPq5kLLSlA==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -81,7 +81,9 @@ ipv6 = false
|
||||
## Bandwidth configuration
|
||||
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
|
||||
## X - unlimited
|
||||
## Default is X for floodfill, L for regular node
|
||||
## Default is L (regular node) and X if floodfill mode enabled. If you want to
|
||||
## share more bandwidth without floodfill mode, uncomment that line and adjust
|
||||
## value to your possibilities
|
||||
# bandwidth = L
|
||||
## Max % of bandwidth limit for transit. 0-100. 100 by default
|
||||
# share = 100
|
||||
@@ -108,7 +110,8 @@ port = 7070
|
||||
# user = i2pd
|
||||
# pass = changeme
|
||||
## Select webconsole language
|
||||
## Currently supported english (default), afrikaans, russian, turkmen, ukrainian and uzbek languages
|
||||
## Currently supported english (default), afrikaans, armenian, german, russian,
|
||||
## turkmen, ukrainian and uzbek languages
|
||||
# lang = english
|
||||
|
||||
[httpproxy]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||
|
||||
Name: i2pd-git
|
||||
Version: 2.39.0
|
||||
Version: 2.41.0
|
||||
Release: git%{git_hash}%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd
|
||||
@@ -32,7 +32,7 @@ Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||
C++ implementation of I2P.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
%setup -q -n i2pd-openssl
|
||||
|
||||
|
||||
%build
|
||||
@@ -57,8 +57,14 @@ cd build
|
||||
%endif
|
||||
|
||||
|
||||
%if 0%{?fedora} >= 36
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -71,10 +77,16 @@ pushd build
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
%if 0%{?rhel} == 9
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
%if 0%{?fedora} < 37
|
||||
popd
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
@@ -82,8 +94,14 @@ popd
|
||||
%install
|
||||
pushd build
|
||||
|
||||
%if 0%{?fedora} >= 36
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -99,14 +117,14 @@ chrpath -d i2pd
|
||||
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
|
||||
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
|
||||
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
|
||||
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
||||
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
|
||||
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
|
||||
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/i2pd
|
||||
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
|
||||
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
|
||||
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
|
||||
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
|
||||
%{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
|
||||
%{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
|
||||
%{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
|
||||
%{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/i2pd.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/i2pd
|
||||
%{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
|
||||
%{__install} -D -m 644 %{_builddir}/i2pd-openssl/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
|
||||
%{__cp} -r %{_builddir}/i2pd-openssl/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
|
||||
%{__cp} -r %{_builddir}/i2pd-openssl/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
|
||||
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
|
||||
|
||||
|
||||
@@ -146,6 +164,16 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
|
||||
- update to 2.41.0
|
||||
- fixed build on Fedora Copr over openssl trunk code
|
||||
|
||||
* Mon Nov 29 2021 orignal <i2porignal@yandex.ru> - 2.40.0
|
||||
- update to 2.40.0
|
||||
|
||||
* Tue Aug 24 2021 r4sas <r4sas@i2pmail.org> - 2.39.0-2
|
||||
- changed if statements to cover fedora 35
|
||||
|
||||
* Mon Aug 23 2021 orignal <i2porignal@yandex.ru> - 2.39.0
|
||||
- update to 2.39.0
|
||||
- fixed build on fedora 36
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: i2pd
|
||||
Version: 2.39.0
|
||||
Version: 2.41.0
|
||||
Release: 1%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd-git
|
||||
@@ -54,8 +54,14 @@ cd build
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 36
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -68,10 +74,16 @@ pushd build
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
%if 0%{?rhel} == 9
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
%if 0%{?fedora} < 37
|
||||
popd
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
@@ -79,8 +91,14 @@ popd
|
||||
%install
|
||||
pushd build
|
||||
|
||||
%if 0%{?fedora} >= 36
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
%if 0%{?fedora} < 37
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
@@ -143,6 +161,15 @@ getent passwd i2pd >/dev/null || \
|
||||
|
||||
|
||||
%changelog
|
||||
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
|
||||
- update to 2.41.0
|
||||
|
||||
* Mon Nov 29 2021 orignal <i2porignal@yandex.ru> - 2.40.0
|
||||
- update to 2.40.0
|
||||
|
||||
* Tue Aug 24 2021 r4sas <r4sas@i2pmail.org> - 2.39.0-2
|
||||
- changed if statements to cover fedora 35
|
||||
|
||||
* Mon Aug 23 2021 orignal <i2porignal@yandex.ru> - 2.39.0
|
||||
- update to 2.39.0
|
||||
- fixed build on fedora 36
|
||||
|
||||
@@ -1,35 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*
|
||||
******************************************************************
|
||||
*
|
||||
* This is style sheet for webconsole, with @media selectors for adaptive
|
||||
* view on desktop and mobile devices, respecting preferred user's color
|
||||
* scheme used in system/browser.
|
||||
*
|
||||
* Minified copy of that style sheet is bundled inside i2pd sources.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--main-bg-color: #fafafa;
|
||||
--main-text-color: #103456;
|
||||
--main-link-color: #894c84;
|
||||
--main-link-hover-color: #fafafa;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--main-bg-color: #242424;
|
||||
--main-text-color: #17ab5c;
|
||||
--main-link-color: #bf64b7;
|
||||
--main-link-hover-color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font: 100%/1.5em sans-serif;
|
||||
margin: 0;
|
||||
padding: 1.5em;
|
||||
background: #FAFAFA;
|
||||
color: #103456;
|
||||
background: var(--main-bg-color);
|
||||
color: var(--main-text-color);
|
||||
}
|
||||
|
||||
a, .slide label {
|
||||
text-decoration: none;
|
||||
color: #894C84;
|
||||
color: var(--main-link-color);
|
||||
}
|
||||
|
||||
a:hover, .slide label:hover {
|
||||
color: #FAFAFA;
|
||||
background: #894C84;
|
||||
a:hover, .slide label:hover, button[type=submit]:hover {
|
||||
color: var(--main-link-hover-color);
|
||||
background: var(--main-link-color);
|
||||
}
|
||||
|
||||
a.button {
|
||||
-webkit-appearance: button;
|
||||
-moz-appearance: button;
|
||||
appearance: button;
|
||||
text-decoration: none;
|
||||
padding: 0 5px;
|
||||
border: 1px solid #894C84;
|
||||
border: 1px solid var(--main-link-color);
|
||||
}
|
||||
|
||||
.header {
|
||||
font-size: 2.5em;
|
||||
text-align: center;
|
||||
margin: 1em 0;
|
||||
color: #894C84;
|
||||
color: var(--main-link-color);
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
@@ -42,6 +72,7 @@ a.button {
|
||||
display: block;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
padding: 4px;
|
||||
max-width: 12em;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
@@ -63,8 +94,9 @@ a.button {
|
||||
.content {
|
||||
float: left;
|
||||
font-size: 1em;
|
||||
margin-left: 4em;
|
||||
max-width: 48em;
|
||||
margin-left: 2em;
|
||||
padding: 4px;
|
||||
max-width: 50em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -87,7 +119,7 @@ a.button {
|
||||
caption {
|
||||
font-size: 1.5em;
|
||||
text-align: center;
|
||||
color: #894C84;
|
||||
color: var(--main-link-color);
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -105,6 +137,8 @@ table.services {
|
||||
}
|
||||
|
||||
textarea {
|
||||
background-color: var(--main-bg-color);
|
||||
color: var(--main-text-color);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@@ -133,24 +167,45 @@ textarea {
|
||||
color: #56B734;
|
||||
}
|
||||
|
||||
button[type=submit] {
|
||||
background-color: transparent;
|
||||
color: var(--main-link-color);
|
||||
text-decoration: none;
|
||||
padding: 5px;
|
||||
border: 1px solid var(--main-link-color);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
input, select, select option {
|
||||
background-color: var(--main-bg-color);
|
||||
color: var(--main-link-color);
|
||||
padding: 5px;
|
||||
border: 1px solid var(--main-link-color);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
input:focus, select:focus, select option:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input[type=number]::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1150px) { /* adaptive style */
|
||||
.wrapper {
|
||||
max-width: 58em;
|
||||
}
|
||||
|
||||
.menu {
|
||||
max-width: 10em;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 2em;
|
||||
max-width: 42em;
|
||||
max-width: 40em;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 980px) {
|
||||
body {
|
||||
padding: 1.5em 0 0 0;
|
||||
font: 100%/1.2em sans-serif;
|
||||
padding: 1.2em 0 0 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
@@ -178,9 +233,7 @@ textarea {
|
||||
}
|
||||
|
||||
a, .slide label {
|
||||
/* margin-right: 10px; */
|
||||
display: block;
|
||||
/* font-size: 18px; */
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -193,13 +246,12 @@ textarea {
|
||||
}
|
||||
|
||||
a.button {
|
||||
-webkit-appearance: button;
|
||||
-moz-appearance: button;
|
||||
appearance: button;
|
||||
text-decoration: none;
|
||||
margin-top: 10px;
|
||||
padding: 6px;
|
||||
border: 1px solid #894c84;
|
||||
border: 2px solid var(--main-link-color);
|
||||
border-radius: 5px;
|
||||
width: -webkit-fill-available;
|
||||
}
|
||||
|
||||
@@ -207,8 +259,7 @@ textarea {
|
||||
width: 35%;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
border: 2px solid #ccc;
|
||||
-webkit-border-radius: 5px;
|
||||
border: 2px solid var(--main-link-color);
|
||||
border-radius: 5px;
|
||||
font-size: 18px;
|
||||
}
|
||||
@@ -221,17 +272,16 @@ textarea {
|
||||
textarea {
|
||||
width: -webkit-fill-available;
|
||||
height: auto;
|
||||
padding:5px;
|
||||
border:2px solid #ccc;
|
||||
-webkit-border-radius: 5px;
|
||||
padding: 5px;
|
||||
border: 2px solid var(--main-link-color);
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
button[type=submit] {
|
||||
padding: 5px 15px;
|
||||
background: #ccc;
|
||||
border: 0 none;
|
||||
background: transparent;
|
||||
border: 2px solid var(--main-link-color);
|
||||
cursor: pointer;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -26,7 +26,9 @@
|
||||
#include "Streaming.h"
|
||||
#include "Destination.h"
|
||||
#include "HTTPServer.h"
|
||||
#ifdef WITH_I2PC
|
||||
#include "I2PControl.h"
|
||||
#endif
|
||||
#include "ClientContext.h"
|
||||
#include "Crypto.h"
|
||||
#include "UPnP.h"
|
||||
@@ -45,7 +47,9 @@ namespace util
|
||||
~Daemon_Singleton_Private() {};
|
||||
|
||||
std::unique_ptr<i2p::http::HTTPServer> httpServer;
|
||||
#ifdef WITH_I2PC
|
||||
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
|
||||
#endif
|
||||
std::unique_ptr<i2p::transport::UPnP> UPnP;
|
||||
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
|
||||
};
|
||||
@@ -64,6 +68,12 @@ namespace util
|
||||
return service;
|
||||
}
|
||||
|
||||
void Daemon_Singleton::setDataDir(std::string path)
|
||||
{
|
||||
if (path != "")
|
||||
DaemonDataDir = path;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::init(int argc, char* argv[]) {
|
||||
return init(argc, argv, nullptr);
|
||||
}
|
||||
@@ -73,8 +83,14 @@ namespace util
|
||||
i2p::config::Init();
|
||||
i2p::config::ParseCmdline(argc, argv);
|
||||
|
||||
std::string config; i2p::config::GetOption("conf", config);
|
||||
std::string datadir; i2p::config::GetOption("datadir", datadir);
|
||||
std::string config; i2p::config::GetOption("conf", config);
|
||||
std::string datadir;
|
||||
if(DaemonDataDir != "") {
|
||||
datadir = DaemonDataDir;
|
||||
} else {
|
||||
i2p::config::GetOption("datadir", datadir);
|
||||
}
|
||||
|
||||
i2p::fs::DetectDataDir(datadir, IsService());
|
||||
i2p::fs::Init();
|
||||
|
||||
@@ -118,26 +134,26 @@ namespace util
|
||||
|
||||
i2p::log::Logger().SetLogLevel(loglevel);
|
||||
if (logstream) {
|
||||
LogPrint(eLogInfo, "Log: will send messages to std::ostream");
|
||||
LogPrint(eLogInfo, "Log: Sending messages to std::ostream");
|
||||
i2p::log::Logger().SendTo (logstream);
|
||||
} else if (logs == "file") {
|
||||
if (logfile == "")
|
||||
logfile = i2p::fs::DataDirPath("i2pd.log");
|
||||
LogPrint(eLogInfo, "Log: will send messages to ", logfile);
|
||||
LogPrint(eLogInfo, "Log: Sending messages to ", logfile);
|
||||
i2p::log::Logger().SendTo (logfile);
|
||||
#ifndef _WIN32
|
||||
} else if (logs == "syslog") {
|
||||
LogPrint(eLogInfo, "Log: will send messages to syslog");
|
||||
LogPrint(eLogInfo, "Log: Sending messages to syslog");
|
||||
i2p::log::Logger().SendTo("i2pd", LOG_DAEMON);
|
||||
#endif
|
||||
} else {
|
||||
// use stdout -- default
|
||||
}
|
||||
|
||||
LogPrint(eLogNone, "i2pd v", VERSION, " starting");
|
||||
LogPrint(eLogDebug, "FS: main config file: ", config);
|
||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||
LogPrint(eLogDebug, "FS: certificates directory: ", certsdir);
|
||||
LogPrint(eLogNone, "i2pd v", VERSION, " (", I2P_VERSION, ") starting...");
|
||||
LogPrint(eLogDebug, "FS: Main config file: ", config);
|
||||
LogPrint(eLogDebug, "FS: Data directory: ", datadir);
|
||||
LogPrint(eLogDebug, "FS: Certificates directory: ", certsdir);
|
||||
|
||||
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
|
||||
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
||||
@@ -151,11 +167,7 @@ namespace util
|
||||
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
#ifdef MESHNET
|
||||
// manual override for meshnet
|
||||
ipv4 = false;
|
||||
ipv6 = true;
|
||||
#endif
|
||||
|
||||
// ifname -> address
|
||||
std::string ifname; i2p::config::GetOption("ifname", ifname);
|
||||
if (ipv4 && i2p::config::IsDefault ("address4"))
|
||||
@@ -204,7 +216,7 @@ namespace util
|
||||
uint16_t port; i2p::config::GetOption("port", port);
|
||||
if (!i2p::config::IsDefault("port"))
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
|
||||
LogPrint(eLogInfo, "Daemon: Accepting incoming connections at port ", port);
|
||||
i2p::context.UpdatePort (port);
|
||||
}
|
||||
i2p::context.SetSupportsV6 (ipv6);
|
||||
@@ -244,7 +256,19 @@ namespace util
|
||||
if (!ipv4 && !ipv6)
|
||||
i2p::context.SetStatus (eRouterStatusMesh);
|
||||
}
|
||||
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
bool published; i2p::config::GetOption("ssu2.published", published);
|
||||
if (published)
|
||||
{
|
||||
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
|
||||
i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
|
||||
}
|
||||
else
|
||||
i2p::context.PublishSSU2Address (0, false, ipv4, ipv6); // unpublish
|
||||
}
|
||||
|
||||
bool transit; i2p::config::GetOption("notransit", transit);
|
||||
i2p::context.SetAcceptsTunnels (!transit);
|
||||
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
|
||||
@@ -252,7 +276,7 @@ namespace util
|
||||
|
||||
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
|
||||
if (isFloodfill) {
|
||||
LogPrint(eLogInfo, "Daemon: router will be floodfill");
|
||||
LogPrint(eLogInfo, "Daemon: Router configured as floodfill");
|
||||
i2p::context.SetFloodfill (true);
|
||||
}
|
||||
else
|
||||
@@ -267,7 +291,7 @@ namespace util
|
||||
if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
|
||||
{
|
||||
i2p::context.SetBandwidth (bandwidth[0]);
|
||||
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
|
||||
LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -275,18 +299,18 @@ namespace util
|
||||
if (value > 0)
|
||||
{
|
||||
i2p::context.SetBandwidth (value);
|
||||
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps");
|
||||
LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: unexpected bandwidth ", bandwidth, ". Set to 'low'");
|
||||
LogPrint(eLogInfo, "Daemon: Unexpected bandwidth ", bandwidth, ". Set to 'low'");
|
||||
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isFloodfill)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
|
||||
LogPrint(eLogInfo, "Daemon: Floodfill bandwidth set to 'extra'");
|
||||
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2);
|
||||
}
|
||||
else
|
||||
@@ -301,12 +325,12 @@ namespace util
|
||||
std::string family; i2p::config::GetOption("family", family);
|
||||
i2p::context.SetFamily (family);
|
||||
if (family.length () > 0)
|
||||
LogPrint(eLogInfo, "Daemon: family set to ", family);
|
||||
LogPrint(eLogInfo, "Daemon: Router family set to ", family);
|
||||
|
||||
bool trust; i2p::config::GetOption("trust.enabled", 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 routers; i2p::config::GetOption("trust.routers", routers);
|
||||
bool restricted = false;
|
||||
@@ -336,18 +360,18 @@ namespace util
|
||||
pos = comma + 1;
|
||||
}
|
||||
while (comma != std::string::npos);
|
||||
LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routers");
|
||||
LogPrint(eLogInfo, "Daemon: Setting restricted routes to use ", idents.size(), " trusted routers");
|
||||
i2p::transport::transports.RestrictRoutesToRouters(idents);
|
||||
restricted = idents.size() > 0;
|
||||
}
|
||||
if(!restricted)
|
||||
LogPrint(eLogError, "Daemon: no trusted routers of families specified");
|
||||
LogPrint(eLogError, "Daemon: No trusted routers of families specified");
|
||||
}
|
||||
|
||||
bool hidden; i2p::config::GetOption("trust.hidden", hidden);
|
||||
if (hidden)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: using hidden mode");
|
||||
LogPrint(eLogInfo, "Daemon: Hidden mode enabled");
|
||||
i2p::data::netdb.SetHidden(true);
|
||||
}
|
||||
|
||||
@@ -360,7 +384,7 @@ namespace util
|
||||
bool Daemon_Singleton::start()
|
||||
{
|
||||
i2p::log::Logger().Start();
|
||||
LogPrint(eLogInfo, "Daemon: starting NetDB");
|
||||
LogPrint(eLogInfo, "Daemon: Starting NetDB");
|
||||
i2p::data::netdb.Start();
|
||||
|
||||
bool upnp; i2p::config::GetOption("upnp.enabled", upnp);
|
||||
@@ -377,19 +401,20 @@ namespace util
|
||||
}
|
||||
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
|
||||
LogPrint(eLogInfo, "Daemon: starting Transports");
|
||||
if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled");
|
||||
if(!ntcp2) LogPrint(eLogInfo, "Daemon: ntcp2 disabled");
|
||||
LogPrint(eLogInfo, "Daemon: Starting Transports");
|
||||
if(!ssu) LogPrint(eLogInfo, "Daemon: SSU disabled");
|
||||
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
|
||||
|
||||
i2p::transport::transports.SetCheckReserved(checkInReserved);
|
||||
i2p::transport::transports.Start(ntcp2, ssu);
|
||||
i2p::transport::transports.Start(ntcp2, ssu, ssu2);
|
||||
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
|
||||
LogPrint(eLogInfo, "Daemon: Transports started");
|
||||
else
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: failed to start Transports");
|
||||
LogPrint(eLogError, "Daemon: Failed to start Transports");
|
||||
/** shut down netdb right away */
|
||||
i2p::transport::transports.Stop();
|
||||
i2p::data::netdb.Stop();
|
||||
@@ -400,7 +425,7 @@ namespace util
|
||||
if (http) {
|
||||
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
|
||||
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
|
||||
LogPrint(eLogInfo, "Daemon: starting webconsole at ", httpAddr, ":", httpPort);
|
||||
LogPrint(eLogInfo, "Daemon: Starting Webconsole at ", httpAddr, ":", httpPort);
|
||||
try
|
||||
{
|
||||
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
|
||||
@@ -408,24 +433,25 @@ namespace util
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Daemon: failed to start webconsole: ", ex.what ());
|
||||
LogPrint (eLogError, "Daemon: Failed to start Webconsole: ", ex.what ());
|
||||
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting Tunnels");
|
||||
LogPrint(eLogInfo, "Daemon: Starting Tunnels");
|
||||
i2p::tunnel::tunnels.Start();
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: starting Client");
|
||||
LogPrint(eLogInfo, "Daemon: Starting Client");
|
||||
i2p::client::context.Start ();
|
||||
|
||||
#ifdef WITH_I2PC
|
||||
// I2P Control Protocol
|
||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||
if (i2pcontrol) {
|
||||
std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
|
||||
uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort);
|
||||
LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
|
||||
LogPrint(eLogInfo, "Daemon: Starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
|
||||
try
|
||||
{
|
||||
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
|
||||
@@ -433,19 +459,20 @@ namespace util
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Daemon: failed to start I2PControl: ", ex.what ());
|
||||
LogPrint (eLogError, "Daemon: Failed to start I2PControl: ", ex.what ());
|
||||
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Daemon_Singleton::stop()
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: shutting down");
|
||||
LogPrint(eLogInfo, "Daemon: stopping Client");
|
||||
LogPrint(eLogInfo, "Daemon: Shutting down");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping Client");
|
||||
i2p::client::context.Stop();
|
||||
LogPrint(eLogInfo, "Daemon: stopping Tunnels");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping Tunnels");
|
||||
i2p::tunnel::tunnels.Stop();
|
||||
|
||||
if (d.UPnP)
|
||||
@@ -460,21 +487,23 @@ namespace util
|
||||
d.m_NTPSync = nullptr;
|
||||
}
|
||||
|
||||
LogPrint(eLogInfo, "Daemon: stopping Transports");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping Transports");
|
||||
i2p::transport::transports.Stop();
|
||||
LogPrint(eLogInfo, "Daemon: stopping NetDB");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping NetDB");
|
||||
i2p::data::netdb.Stop();
|
||||
if (d.httpServer) {
|
||||
LogPrint(eLogInfo, "Daemon: stopping HTTP Server");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping HTTP Server");
|
||||
d.httpServer->Stop();
|
||||
d.httpServer = nullptr;
|
||||
}
|
||||
#ifdef WITH_I2PC
|
||||
if (d.m_I2PControlService)
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: stopping I2PControl");
|
||||
LogPrint(eLogInfo, "Daemon: Stopping I2PControl");
|
||||
d.m_I2PControlService->Stop ();
|
||||
d.m_I2PControlService = nullptr;
|
||||
}
|
||||
#endif
|
||||
i2p::crypto::TerminateCrypto ();
|
||||
i2p::log::Logger().Stop();
|
||||
|
||||
|
||||
@@ -20,27 +20,33 @@ namespace util
|
||||
class Daemon_Singleton_Private;
|
||||
class Daemon_Singleton
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
|
||||
virtual bool init(int argc, char* argv[]);
|
||||
virtual bool start();
|
||||
virtual bool stop();
|
||||
virtual void run () {};
|
||||
virtual bool init (int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
|
||||
virtual bool init (int argc, char* argv[]);
|
||||
virtual bool start ();
|
||||
virtual bool stop ();
|
||||
virtual void run () {};
|
||||
|
||||
bool isDaemon;
|
||||
bool running;
|
||||
virtual void setDataDir (std::string path);
|
||||
|
||||
protected:
|
||||
bool isDaemon;
|
||||
bool running;
|
||||
|
||||
Daemon_Singleton();
|
||||
virtual ~Daemon_Singleton();
|
||||
protected:
|
||||
|
||||
bool IsService () const;
|
||||
Daemon_Singleton ();
|
||||
virtual ~Daemon_Singleton ();
|
||||
|
||||
// d-pointer for httpServer, httpProxy, etc.
|
||||
class Daemon_Singleton_Private;
|
||||
Daemon_Singleton_Private &d;
|
||||
bool IsService () const;
|
||||
|
||||
// d-pointer for httpServer, httpProxy, etc.
|
||||
class Daemon_Singleton_Private;
|
||||
Daemon_Singleton_Private &d;
|
||||
|
||||
private:
|
||||
|
||||
std::string DaemonDataDir;
|
||||
};
|
||||
|
||||
#if defined(QT_GUI_LIB) // check if QT
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -36,81 +36,12 @@
|
||||
#include "Win32App.h"
|
||||
#endif
|
||||
|
||||
// For image and info
|
||||
// For image, style and info
|
||||
#include "version.h"
|
||||
#include "HTTPServerResources.h"
|
||||
|
||||
namespace i2p {
|
||||
namespace http {
|
||||
const std::string itoopieFavicon =
|
||||
"data:image/png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
|
||||
"jwv8YQUAAAAJcEhZcwAALiIAAC4iAari3ZIAAAAHdElNRQfgCQsUNSZrkhi1AAAAGXRFWHRTb2Z0"
|
||||
"d2FyZQBwYWludC5uZXQgNC4wLjEyQwRr7AAAAoJJREFUOE9jwAUqi4Q1oEwwcDTV1+5sETaBclGB"
|
||||
"vb09C5QJB6kWpvFQJoOCeLC5kmjEHCgXE2SlyETLi3h6QrkM4VL+ssWSCZUgtopITLKqaOotRTEn"
|
||||
"cbAkLqAkGtOqLBLVAWLXyWSVFkkmRiqLxuaqiWb/VBYJMAYrwgckJY25VEUzniqKhjU2y+RtCRSP"
|
||||
"6lUXy/1jIBV5tlYxZUaFVMq2NInwIi9hO8fSfOEAqDZUoCwal6MulvOvyS7gi69K4j9zxZT/m0ps"
|
||||
"/28ptvvvquXXryIa7QYMMdTwqi0WNtVi0GIDseXl7TnUxFKfnGlxAGp0+D8j2eH/8Ub7/9e7nf7X"
|
||||
"+Af/B7rwt6pI0h0l0WhQADOC9DBkhSirpImHNVZKp24ukkyoshGLnN8d5fA/y13t/44Kq/8hlnL/"
|
||||
"z7fZ/58f6vcxSNpbVUVFhV1RLNBVTsQzVYZPSwhsCAhkiIfpNMrkbO6TLf071Sfk/5ZSi/+7q6z/"
|
||||
"P5ns+v9mj/P/CpuI/20y+aeNGYxZoVoYGmsF3aFMBAAZlCwftnF9ke3//bU2//fXWP8/UGv731Am"
|
||||
"+V+DdNblSqnUYqhSTKAiYSOqJBrVqiaa+S3UNPr/gmyH/xuKXf63hnn/B8bIP0UxHfEyyeSNQKVM"
|
||||
"EB1AEB2twhcTLp+gIBJUoyKasEpVJHmqskh8qryovUG/ffCHHRU2q/Tk/YuB6eGPsbExa7ZkpLu1"
|
||||
"oLEcVDtuUCgV1w60rQzElpRUE1EVSX0BYidHiInXF4nagNhYQW60EF+ApH1ktni0A1SIITSUgVlZ"
|
||||
"JHYnlIsfzJjIp9xZKswL5YKBHL+coKJoRDaUSzoozxHVrygQU4JykQADAwAT5b1NHtwZugAAAABJ"
|
||||
"RU5ErkJggg==";
|
||||
|
||||
// Bundled style
|
||||
const std::string internalCSS =
|
||||
"<style>\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:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n"
|
||||
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
|
||||
" padding: 0 5px; border: 1px solid #894C84; }\r\n"
|
||||
" .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n"
|
||||
" .wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n"
|
||||
" .menu { display: block; float: left; overflow: hidden; max-width: 12em; white-space: nowrap; text-overflow: ellipsis; }\r\n"
|
||||
" .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||
" .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||
" .content { float: left; font-size: 1em; margin-left: 4em; max-width: 48em; overflow: auto; }\r\n"
|
||||
" .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n"
|
||||
" .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n"
|
||||
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
|
||||
" table { display: table; border-collapse: collapse; text-align: center; }\r\n"
|
||||
" table.extaddr { text-align: left; } table.services { width: 100%; }\r\n"
|
||||
" textarea { word-break: break-all; }\r\n"
|
||||
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n"
|
||||
" .slide div.slidecontent, .slide [type=\"checkbox\"] { display: none; }\r\n"
|
||||
" .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n"
|
||||
" .disabled { color: #D33F3F; } .enabled { color: #56B734; }\r\n"
|
||||
" @media screen and (max-width: 1150px) {\r\n" /* adaptive style */
|
||||
" .wrapper { max-width: 58em; } .menu { max-width: 10em; }\r\n"
|
||||
" .content { margin-left: 2em; max-width: 42em; }\r\n"
|
||||
" }\r\n"
|
||||
" @media screen and (max-width: 980px) {\r\n"
|
||||
" body { padding: 1.5em 0 0 0; }\r\n"
|
||||
" .menu { width: 100%; max-width: unset; display: block; float: none; position: unset; font-size: 16px;\r\n"
|
||||
" text-align: center; }\r\n"
|
||||
" .menu a, .commands a { display: inline-block; padding: 4px; }\r\n"
|
||||
" .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n"
|
||||
" text-align: center; }\r\n"
|
||||
" a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n"
|
||||
" .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n"
|
||||
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n"
|
||||
" margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n"
|
||||
" input, select { width: 35%; text-align: center; padding: 5px;\r\n"
|
||||
" border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n"
|
||||
" table.extaddr { margin: auto; text-align: unset; }\r\n"
|
||||
" textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n"
|
||||
" -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n"
|
||||
" button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n"
|
||||
" -webkit-border-radius: 5px; border-radius: 5px; position: relative; height: 36px; display: -webkit-inline-box; margin-top: 10px; }\r\n"
|
||||
" }\r\n"
|
||||
"</style>\r\n";
|
||||
|
||||
// for external style sheet
|
||||
std::string externalCSS;
|
||||
|
||||
static void LoadExtCSS ()
|
||||
{
|
||||
std::stringstream s;
|
||||
@@ -137,9 +68,13 @@ namespace http {
|
||||
const char HTTP_PAGE_TRANSPORTS[] = "transports";
|
||||
const char HTTP_PAGE_LOCAL_DESTINATIONS[] = "local_destinations";
|
||||
const char HTTP_PAGE_LOCAL_DESTINATION[] = "local_destination";
|
||||
#ifdef WITH_I2CP
|
||||
const char HTTP_PAGE_I2CP_LOCAL_DESTINATION[] = "i2cp_local_destination";
|
||||
#endif
|
||||
#ifdef WITH_SAM
|
||||
const char HTTP_PAGE_SAM_SESSIONS[] = "sam_sessions";
|
||||
const char HTTP_PAGE_SAM_SESSION[] = "sam_session";
|
||||
#endif
|
||||
const char HTTP_PAGE_I2P_TUNNELS[] = "i2p_tunnels";
|
||||
const char HTTP_PAGE_COMMANDS[] = "commands";
|
||||
const char HTTP_PAGE_LEASESETS[] = "leasesets";
|
||||
@@ -156,7 +91,9 @@ namespace http {
|
||||
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
|
||||
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
|
||||
const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css";
|
||||
#ifdef WITH_SAM
|
||||
const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
|
||||
#endif
|
||||
const char HTTP_PARAM_ADDRESS[] = "address";
|
||||
|
||||
static std::string ConvertTime (uint64_t time)
|
||||
@@ -229,7 +166,7 @@ namespace http {
|
||||
if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug")
|
||||
i2p::log::Logger().SetLogLevel(level);
|
||||
else {
|
||||
LogPrint(eLogError, "HTTPServer: unknown loglevel set attempted");
|
||||
LogPrint(eLogError, "HTTPServer: Unknown loglevel set attempted");
|
||||
return;
|
||||
}
|
||||
i2p::log::Logger().Reopen ();
|
||||
@@ -240,7 +177,7 @@ namespace http {
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
|
||||
// Page language
|
||||
std::string currLang = i2p::context.GetLanguage ()->GetLanguage(); // get current used language
|
||||
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage(); // get current used language
|
||||
auto it = i2p::i18n::languages.find(currLang);
|
||||
std::string langCode = it->second.ShortCode;
|
||||
|
||||
@@ -251,7 +188,7 @@ namespace http {
|
||||
" <meta charset=\"UTF-8\">\r\n"
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"
|
||||
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
|
||||
" <title>Purple I2P " VERSION " Webconsole</title>\r\n";
|
||||
" <title>Purple I2P Webconsole</title>\r\n";
|
||||
GetStyles(s);
|
||||
s <<
|
||||
"</head>\r\n"
|
||||
@@ -265,12 +202,16 @@ namespace http {
|
||||
if (i2p::context.IsFloodfill ())
|
||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a><br>\r\n";
|
||||
s <<
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit Tunnels") << "</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a><br>\r\n";
|
||||
if (i2p::context.AcceptsTunnels () || i2p::tunnel::tunnels.CountTransitTunnels())
|
||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit Tunnels") << "</a><br>\r\n";
|
||||
s <<
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
|
||||
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
|
||||
#ifdef WITH_SAM
|
||||
if (i2p::client::context.GetSAMBridge ())
|
||||
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">" << tr("SAM sessions") << "</a><br>\r\n";
|
||||
#endif
|
||||
s <<
|
||||
"</div>\r\n"
|
||||
"<div class=\"content\">";
|
||||
@@ -364,10 +305,10 @@ namespace http {
|
||||
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
|
||||
s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n";
|
||||
s << "<div class='slide'>";
|
||||
if((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
|
||||
if ((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
|
||||
s << "<label for=\"slide-info\">" << tr("Hidden content. Press on text to see.") << "</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n";
|
||||
}
|
||||
if(includeHiddenContent) {
|
||||
if (includeHiddenContent) {
|
||||
s << "<b>" << tr("Router Ident") << ":</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
|
||||
if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
|
||||
s << "<b>" << tr("Router Family") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
|
||||
@@ -376,41 +317,42 @@ namespace http {
|
||||
s << "<b>"<< tr("Our external address") << ":</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
|
||||
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
|
||||
{
|
||||
s << "<tr>\r\n";
|
||||
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ())
|
||||
{
|
||||
s << "<td>NTCP2";
|
||||
if (address->host.is_v6 ()) s << "v6";
|
||||
s << "</td><td>" << tr("supported") << "</td>\r\n</tr>\r\n";
|
||||
continue;
|
||||
}
|
||||
s << "<tr>\r\n<td>";
|
||||
switch (address->transportStyle)
|
||||
{
|
||||
case i2p::data::RouterInfo::eTransportNTCP:
|
||||
{
|
||||
s << "<td>NTCP";
|
||||
if (address->IsPublishedNTCP2 ()) s << "2";
|
||||
if (address->host.is_v6 ()) s << "v6";
|
||||
s << "</td>\r\n";
|
||||
break;
|
||||
}
|
||||
s << "NTCP2";
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportSSU:
|
||||
{
|
||||
s << "<td>SSU";
|
||||
if (address->host.is_v6 ())
|
||||
s << "v6";
|
||||
s << "</td>\r\n";
|
||||
break;
|
||||
}
|
||||
s << "SSU";
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportSSU2:
|
||||
s << "SSU2";
|
||||
break;
|
||||
default:
|
||||
s << "<td>" << tr("Unknown") << "</td>\r\n";
|
||||
s << tr("Unknown");
|
||||
}
|
||||
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n</tr>\r\n";
|
||||
if (address->IsV6 ())
|
||||
{
|
||||
if (address->IsV4 ()) s << "v4";
|
||||
s << "v6";
|
||||
}
|
||||
s << "</td>\r\n";
|
||||
if (address->published)
|
||||
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n";
|
||||
else
|
||||
{
|
||||
s << "<td>" << tr("supported");
|
||||
if (address->port)
|
||||
s << " :" << address->port;
|
||||
s << "</td>\r\n";
|
||||
}
|
||||
s << "</tr>\r\n";
|
||||
}
|
||||
s << "</tbody></table>\r\n";
|
||||
}
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
if(outputFormat == OutputFormatEnum::forQtUi) {
|
||||
if (outputFormat == OutputFormatEnum::forQtUi) {
|
||||
s << "<br>";
|
||||
}
|
||||
s << "<b>" << tr("Routers") << ":</b> " << i2p::data::netdb.GetNumRouters () << " ";
|
||||
@@ -424,20 +366,28 @@ namespace http {
|
||||
s << "<b>" << tr("Client Tunnels") << ":</b> " << std::to_string(clientTunnelCount) << " ";
|
||||
s << "<b>" << tr("Transit Tunnels") << ":</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
|
||||
|
||||
if(outputFormat==OutputFormatEnum::forWebConsole) {
|
||||
if (outputFormat==OutputFormatEnum::forWebConsole) {
|
||||
bool httpproxy = i2p::client::context.GetHttpProxy () ? true : false;
|
||||
bool socksproxy = i2p::client::context.GetSocksProxy () ? true : false;
|
||||
bool bob = i2p::client::context.GetBOBCommandChannel () ? true : false;
|
||||
bool sam = i2p::client::context.GetSAMBridge () ? true : false;
|
||||
bool i2cp = i2p::client::context.GetI2CPServer () ? true : false;
|
||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||
s << "<table class=\"services\"><caption>" << tr("Services") << "</caption><tbody>\r\n";
|
||||
s << "<tr><td>" << "HTTP " << tr("Proxy") << "</td><td class='" << (httpproxy ? "enabled" : "disabled") << "'>" << (httpproxy ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||
s << "<tr><td>" << "SOCKS " << tr("Proxy") << "</td><td class='" << (socksproxy ? "enabled" : "disabled") << "'>" << (socksproxy ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||
#ifdef WITH_BOB
|
||||
bool bob = i2p::client::context.GetBOBCommandChannel () ? true : false;
|
||||
s << "<tr><td>" << "BOB" << "</td><td class='" << (bob ? "enabled" : "disabled") << "'>" << (bob ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||
#endif
|
||||
#ifdef WITH_SAM
|
||||
bool sam = i2p::client::context.GetSAMBridge () ? true : false;
|
||||
s << "<tr><td>" << "SAM" << "</td><td class='" << (sam ? "enabled" : "disabled") << "'>" << (sam ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||
#endif
|
||||
#ifdef WITH_I2CP
|
||||
bool i2cp = i2p::client::context.GetI2CPServer () ? true : false;
|
||||
s << "<tr><td>" << "I2CP" << "</td><td class='" << (i2cp ? "enabled" : "disabled") << "'>" << (i2cp ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||
#endif
|
||||
#ifdef WITH_I2PC
|
||||
bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
|
||||
s << "<tr><td>" << "I2PControl" << "</td><td class='" << (i2pcontrol ? "enabled" : "disabled") << "'>" << (i2pcontrol ? tr("Enabled") : tr("Disabled")) << "</td></tr>\r\n";
|
||||
#endif
|
||||
s << "</tbody></table>\r\n";
|
||||
}
|
||||
}
|
||||
@@ -454,6 +404,7 @@ namespace http {
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
|
||||
#ifdef WITH_I2CP
|
||||
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
||||
if (i2cpServer && !(i2cpServer->GetSessions ().empty ()))
|
||||
{
|
||||
@@ -471,6 +422,7 @@ namespace http {
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
||||
@@ -485,7 +437,7 @@ namespace http {
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
|
||||
if(dest->IsPublic())
|
||||
if (dest->IsPublic() && token)
|
||||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
auto base32 = dest->GetIdentHash ().ToBase32 ();
|
||||
@@ -499,7 +451,7 @@ namespace http {
|
||||
"</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
||||
}
|
||||
|
||||
if(dest->GetNumRemoteLeaseSets())
|
||||
if (dest->GetNumRemoteLeaseSets())
|
||||
{
|
||||
s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets ()
|
||||
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>"<< tr("Address") << "</th><th>" << tr("Type") << "</th><th>" << tr("EncType") << "</th></thead><tbody class=\"tableitem\">";
|
||||
@@ -515,8 +467,18 @@ namespace http {
|
||||
s << "<b>" << tr("Inbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto & it : pool->GetInboundTunnels ()) {
|
||||
s << "<div class=\"listitem\">";
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
// for each tunnel hop if not zero-hop
|
||||
if (it->GetNumHops ())
|
||||
{
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << "⇒ " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
|
||||
}
|
||||
);
|
||||
}
|
||||
s << "⇒ " << it->GetTunnelID () << ":me";
|
||||
if (it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << tr(/* tr: Milliseconds */ "ms") << " )";
|
||||
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
|
||||
s << "</div>\r\n";
|
||||
@@ -525,8 +487,18 @@ namespace http {
|
||||
s << "<b>" << tr("Outbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto & it : pool->GetOutboundTunnels ()) {
|
||||
s << "<div class=\"listitem\">";
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
s << it->GetTunnelID () << ":me ⇒";
|
||||
// for each tunnel hop if not zero-hop
|
||||
if (it->GetNumHops ())
|
||||
{
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ⇒";
|
||||
}
|
||||
);
|
||||
}
|
||||
if (it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
|
||||
ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ());
|
||||
s << "</div>\r\n";
|
||||
@@ -618,6 +590,7 @@ namespace http {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_I2CP
|
||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
|
||||
{
|
||||
auto i2cpServer = i2p::client::context.GetI2CPServer ();
|
||||
@@ -633,6 +606,7 @@ namespace http {
|
||||
else
|
||||
ShowError(s, tr("I2CP is not enabled"));
|
||||
}
|
||||
#endif
|
||||
|
||||
void ShowLeasesSets(std::stringstream& s)
|
||||
{
|
||||
@@ -699,8 +673,17 @@ namespace http {
|
||||
s << "<b>" << tr("Inbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) {
|
||||
s << "<div class=\"listitem\">";
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
if (it->GetNumHops ())
|
||||
{
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << "⇒ " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
|
||||
}
|
||||
);
|
||||
}
|
||||
s << "⇒ " << it->GetTunnelID () << ":me";
|
||||
if (it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
|
||||
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ());
|
||||
s << "</div>\r\n";
|
||||
@@ -709,8 +692,18 @@ namespace http {
|
||||
s << "<b>" << tr("Outbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) {
|
||||
s << "<div class=\"listitem\">";
|
||||
it->Print(s);
|
||||
if(it->LatencyIsKnown())
|
||||
s << it->GetTunnelID () << ":me ⇒";
|
||||
// for each tunnel hop if not zero-hop
|
||||
if (it->GetNumHops ())
|
||||
{
|
||||
it->VisitTunnelHops(
|
||||
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
|
||||
{
|
||||
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ⇒";
|
||||
}
|
||||
);
|
||||
}
|
||||
if (it->LatencyIsKnown())
|
||||
s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
|
||||
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ());
|
||||
s << "</div>\r\n";
|
||||
@@ -766,7 +759,7 @@ namespace http {
|
||||
s << " <button type=\"submit\">" << tr("Change") << "</button>\r\n";
|
||||
s << "</form>\r\n<br>\r\n";
|
||||
|
||||
std::string currLang = i2p::context.GetLanguage ()->GetLanguage(); // get current used language
|
||||
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage(); // get current used language
|
||||
s << "<b>" << tr("Change language") << "</b><br>\r\n";
|
||||
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
|
||||
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_SETLANGUAGE << "\">\r\n";
|
||||
@@ -782,7 +775,7 @@ namespace http {
|
||||
|
||||
void ShowTransitTunnels (std::stringstream& s)
|
||||
{
|
||||
if(i2p::tunnel::tunnels.CountTransitTunnels())
|
||||
if (i2p::tunnel::tunnels.CountTransitTunnels())
|
||||
{
|
||||
s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
|
||||
@@ -805,7 +798,7 @@ namespace http {
|
||||
}
|
||||
|
||||
template<typename Sessions>
|
||||
static void ShowNTCPTransports (std::stringstream& s, const Sessions& sessions, const std::string name)
|
||||
static void ShowTransportSessions (std::stringstream& s, const Sessions& sessions, const std::string name)
|
||||
{
|
||||
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
|
||||
for (const auto& it: sessions )
|
||||
@@ -855,7 +848,7 @@ namespace http {
|
||||
{
|
||||
auto sessions = ntcp2Server->GetNTCP2Sessions ();
|
||||
if (!sessions.empty ())
|
||||
ShowNTCPTransports (s, sessions, "NTCP2");
|
||||
ShowTransportSessions (s, sessions, "NTCP2");
|
||||
}
|
||||
auto ssuServer = i2p::transport::transports.GetSSUServer ();
|
||||
if (ssuServer)
|
||||
@@ -897,8 +890,16 @@ namespace http {
|
||||
s << "</div>\r\n</div>\r\n";
|
||||
}
|
||||
}
|
||||
auto ssu2Server = i2p::transport::transports.GetSSU2Server ();
|
||||
if (ssu2Server)
|
||||
{
|
||||
auto sessions = ssu2Server->GetSSU2Sessions ();
|
||||
if (!sessions.empty ())
|
||||
ShowTransportSessions (s, sessions, "SSU2");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_SAM
|
||||
void ShowSAMSessions (std::stringstream& s)
|
||||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
@@ -909,7 +910,7 @@ namespace http {
|
||||
return;
|
||||
}
|
||||
|
||||
if(sam->GetSessions ().size ())
|
||||
if (sam->GetSessions ().size ())
|
||||
{
|
||||
s << "<b>" << tr("SAM sessions") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto& it: sam->GetSessions ())
|
||||
@@ -961,6 +962,7 @@ namespace http {
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
void ShowI2PTunnels (std::stringstream& s)
|
||||
{
|
||||
@@ -1108,7 +1110,7 @@ namespace http {
|
||||
if (expected == provided) return true;
|
||||
}
|
||||
|
||||
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ());
|
||||
LogPrint(eLogWarning, "HTTPServer: Auth failure from ", m_Socket->remote_endpoint().address ());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1118,7 +1120,7 @@ namespace http {
|
||||
std::string content;
|
||||
HTTPRes res;
|
||||
|
||||
LogPrint(eLogDebug, "HTTPServer: request: ", req.uri);
|
||||
LogPrint(eLogDebug, "HTTPServer: Request: ", req.uri);
|
||||
|
||||
if (needAuth && !CheckAuth(req)) {
|
||||
res.code = 401;
|
||||
@@ -1126,6 +1128,7 @@ namespace http {
|
||||
SendReply(res, content);
|
||||
return;
|
||||
}
|
||||
|
||||
bool strictheaders;
|
||||
i2p::config::GetOption("http.strictheaders", strictheaders);
|
||||
if (strictheaders)
|
||||
@@ -1148,6 +1151,7 @@ namespace http {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// HTML head start
|
||||
ShowPageHead (s);
|
||||
if (req.uri.find("page=") != std::string::npos) {
|
||||
@@ -1212,12 +1216,16 @@ namespace http {
|
||||
uint32_t token = CreateToken ();
|
||||
ShowLocalDestination (s, params["b32"], token);
|
||||
}
|
||||
#ifdef WITH_I2CP
|
||||
else if (page == HTTP_PAGE_I2CP_LOCAL_DESTINATION)
|
||||
ShowI2CPLocalDestination (s, params["i2cp_id"]);
|
||||
#endif
|
||||
#ifdef WITH_SAM
|
||||
else if (page == HTTP_PAGE_SAM_SESSIONS)
|
||||
ShowSAMSessions (s);
|
||||
else if (page == HTTP_PAGE_SAM_SESSION)
|
||||
ShowSAMSession (s, params["sam_id"]);
|
||||
#endif
|
||||
else if (page == HTTP_PAGE_I2P_TUNNELS)
|
||||
ShowI2PTunnels (s);
|
||||
else if (page == HTTP_PAGE_LEASESETS)
|
||||
@@ -1268,7 +1276,7 @@ namespace http {
|
||||
else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL)
|
||||
{
|
||||
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;
|
||||
#elif defined(WIN32_APP)
|
||||
i2p::win32::StopGracefulShutdown ();
|
||||
@@ -1300,7 +1308,7 @@ namespace http {
|
||||
{
|
||||
if (dest)
|
||||
{
|
||||
if(dest->DeleteStream (streamID))
|
||||
if (dest->DeleteStream (streamID))
|
||||
s << "<b>" << tr("SUCCESS") << "</b>: " << tr("Stream closed") << "<br>\r\n<br>\r\n";
|
||||
else
|
||||
s << "<b>" << tr("ERROR") << "</b>: " << tr("Stream not found or already was closed") << "<br>\r\n<br>\r\n";
|
||||
@@ -1382,7 +1390,7 @@ namespace http {
|
||||
else if (cmd == HTTP_COMMAND_SETLANGUAGE)
|
||||
{
|
||||
std::string lang = params["lang"];
|
||||
std::string currLang = i2p::context.GetLanguage ()->GetLanguage();
|
||||
std::string currLang = i2p::client::context.GetLanguage ()->GetLanguage();
|
||||
|
||||
if (currLang.compare(lang) != 0)
|
||||
i2p::i18n::SetLanguage(lang);
|
||||
@@ -1446,7 +1454,7 @@ namespace http {
|
||||
pass[i] = alnum[random[i] % (sizeof(alnum) - 1)];
|
||||
}
|
||||
i2p::config::SetOption("http.pass", pass);
|
||||
LogPrint(eLogInfo, "HTTPServer: password set to ", pass);
|
||||
LogPrint(eLogInfo, "HTTPServer: Password set to ", pass);
|
||||
}
|
||||
|
||||
m_IsRunning = true;
|
||||
@@ -1460,7 +1468,13 @@ namespace http {
|
||||
void HTTPServer::Stop ()
|
||||
{
|
||||
m_IsRunning = false;
|
||||
|
||||
boost::system::error_code ec;
|
||||
m_Acceptor.cancel(ec);
|
||||
if (ec)
|
||||
LogPrint (eLogDebug, "HTTPServer: Error while cancelling operations on acceptor: ", ec.message ());
|
||||
m_Acceptor.close();
|
||||
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
{
|
||||
@@ -1481,7 +1495,7 @@ namespace http {
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "HTTPServer: runtime exception: ", ex.what ());
|
||||
LogPrint (eLogError, "HTTPServer: Runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1496,15 +1510,13 @@ namespace http {
|
||||
void HTTPServer::HandleAccept(const boost::system::error_code& ecode,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
|
||||
{
|
||||
if (ecode)
|
||||
if (!ecode)
|
||||
CreateConnection(newSocket);
|
||||
else
|
||||
{
|
||||
if(newSocket) newSocket->close();
|
||||
LogPrint(eLogError, "HTTP Server: error handling accept ", ecode.message());
|
||||
if(ecode != boost::asio::error::operation_aborted)
|
||||
Accept();
|
||||
return;
|
||||
if (newSocket) newSocket->close();
|
||||
LogPrint(eLogError, "HTTP Server: Error handling accept: ", ecode.message());
|
||||
}
|
||||
CreateConnection(newSocket);
|
||||
Accept ();
|
||||
}
|
||||
|
||||
|
||||
@@ -95,11 +95,15 @@ namespace http
|
||||
void ShowTunnels (std::stringstream& s);
|
||||
void ShowTransitTunnels (std::stringstream& s);
|
||||
void ShowTransports (std::stringstream& s);
|
||||
void ShowSAMSessions (std::stringstream& s);
|
||||
void ShowI2PTunnels (std::stringstream& s);
|
||||
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
|
||||
void ShowSAMSession (std::stringstream& s, const std::string& id);
|
||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id);
|
||||
#ifdef WITH_SAM
|
||||
void ShowSAMSessions (std::stringstream& s);
|
||||
void ShowSAMSession (std::stringstream& s, const std::string& id);
|
||||
#endif
|
||||
#ifdef WITH_I2CP
|
||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id);
|
||||
#endif
|
||||
} // http
|
||||
} // i2p
|
||||
|
||||
|
||||
97
daemon/HTTPServerResources.h
Normal file
97
daemon/HTTPServerResources.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#ifndef HTTP_SERVER_RESOURCES_H__
|
||||
#define HTTP_SERVER_RESOURCES_H__
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
const std::string itoopieFavicon =
|
||||
"data:image/png;base64,"
|
||||
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACx"
|
||||
"jwv8YQUAAAAJcEhZcwAALiIAAC4iAari3ZIAAAAHdElNRQfgCQsUNSZrkhi1AAAAGXRFWHRTb2Z0"
|
||||
"d2FyZQBwYWludC5uZXQgNC4wLjEyQwRr7AAAAoJJREFUOE9jwAUqi4Q1oEwwcDTV1+5sETaBclGB"
|
||||
"vb09C5QJB6kWpvFQJoOCeLC5kmjEHCgXE2SlyETLi3h6QrkM4VL+ssWSCZUgtopITLKqaOotRTEn"
|
||||
"cbAkLqAkGtOqLBLVAWLXyWSVFkkmRiqLxuaqiWb/VBYJMAYrwgckJY25VEUzniqKhjU2y+RtCRSP"
|
||||
"6lUXy/1jIBV5tlYxZUaFVMq2NInwIi9hO8fSfOEAqDZUoCwal6MulvOvyS7gi69K4j9zxZT/m0ps"
|
||||
"/28ptvvvquXXryIa7QYMMdTwqi0WNtVi0GIDseXl7TnUxFKfnGlxAGp0+D8j2eH/8Ub7/9e7nf7X"
|
||||
"+Af/B7rwt6pI0h0l0WhQADOC9DBkhSirpImHNVZKp24ukkyoshGLnN8d5fA/y13t/44Kq/8hlnL/"
|
||||
"z7fZ/58f6vcxSNpbVUVFhV1RLNBVTsQzVYZPSwhsCAhkiIfpNMrkbO6TLf071Sfk/5ZSi/+7q6z/"
|
||||
"P5ns+v9mj/P/CpuI/20y+aeNGYxZoVoYGmsF3aFMBAAZlCwftnF9ke3//bU2//fXWP8/UGv731Am"
|
||||
"+V+DdNblSqnUYqhSTKAiYSOqJBrVqiaa+S3UNPr/gmyH/xuKXf63hnn/B8bIP0UxHfEyyeSNQKVM"
|
||||
"EB1AEB2twhcTLp+gIBJUoyKasEpVJHmqskh8qryovUG/ffCHHRU2q/Tk/YuB6eGPsbExa7ZkpLu1"
|
||||
"oLEcVDtuUCgV1w60rQzElpRUE1EVSX0BYidHiInXF4nagNhYQW60EF+ApH1ktni0A1SIITSUgVlZ"
|
||||
"JHYnlIsfzJjIp9xZKswL5YKBHL+coKJoRDaUSzoozxHVrygQU4JykQADAwAT5b1NHtwZugAAAABJ"
|
||||
"RU5ErkJggg==";
|
||||
|
||||
// bundled style sheet
|
||||
const std::string internalCSS =
|
||||
"<style>\r\n"
|
||||
":root { --main-bg-color: #fafafa; --main-text-color: #103456; --main-link-color: #894c84; --main-link-hover-color: #fafafa; }\r\n"
|
||||
"@media (prefers-color-scheme: dark) { :root { --main-bg-color: #242424; --main-text-color: #17ab5c; --main-link-color: #bf64b7; --main-link-hover-color: #000000; } }\r\n"
|
||||
"body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: var(--main-bg-color); color: var(--main-text-color); }\r\n"
|
||||
"a, .slide label { text-decoration: none; color: var(--main-link-color); }\r\n"
|
||||
"a:hover, .slide label:hover, button[type=submit]:hover { color: var(--main-link-hover-color); background: var(--main-link-color); }\r\n"
|
||||
"a.button { appearance: button; text-decoration: none; padding: 0 5px; border: 1px solid var(--main-link-color); }\r\n"
|
||||
".header { font-size: 2.5em; text-align: center; margin: 1em 0; color: var(--main-link-color); }\r\n"
|
||||
".wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n"
|
||||
".menu { display: block; float: left; overflow: hidden; padding: 4px; max-width: 12em; white-space: nowrap; text-overflow: ellipsis ;}\r\n"
|
||||
".listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||
".tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||
".content { float: left; font-size: 1em; margin-left: 2em; padding: 4px; max-width: 50em; overflow: auto; }\r\n"
|
||||
".tunnel.established { color: #56B734; }\r\n"
|
||||
".tunnel.expiring { color: #D3AE3F; }\r\n"
|
||||
".tunnel.failed { color: #D33F3F; }\r\n"
|
||||
".tunnel.building { color: #434343; }\r\n"
|
||||
"caption { font-size: 1.5em; text-align: center; color: var(--main-link-color); }\r\n"
|
||||
"table { display: table; border-collapse: collapse; text-align: center; }\r\n"
|
||||
"table.extaddr { text-align: left; }\r\n"
|
||||
"table.services { width: 100%; }\r\n"
|
||||
"textarea { background-color: var(--main-bg-color); color: var(--main-text-color); word-break: break-all; }\r\n"
|
||||
".streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis; }\r\n"
|
||||
".slide div.slidecontent, .slide [type=\"checkbox\"] { display: none; }\r\n"
|
||||
".slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n"
|
||||
".disabled { color: #D33F3F; }\r\n"
|
||||
".enabled { color: #56B734; }\r\n"
|
||||
"button[type=submit] { background-color: transparent; color: var(--main-link-color); text-decoration: none;\r\n"
|
||||
" padding: 5px; border: 1px solid var(--main-link-color); font-size: 14px; }\r\n"
|
||||
"input, select, select option { background-color: var(--main-bg-color); color: var(--main-link-color); padding: 5px;\r\n"
|
||||
" border: 1px solid var(--main-link-color); font-size: 14px; }\r\n"
|
||||
"input:focus, select:focus, select option:focus { outline: none; }\r\n"
|
||||
"input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; }\r\n"
|
||||
"@media screen and (max-width: 1150px) { /* adaptive style */\r\n"
|
||||
" .wrapper { max-width: 58em; }\r\n"
|
||||
" .content { max-width: 40em; }\r\n"
|
||||
"}\r\n"
|
||||
"@media screen and (max-width: 980px) { body { font: 100%/1.2em sans-serif; padding: 1.2em 0 0 0; }\r\n"
|
||||
" .menu { width: 100%; max-width: unset; display: block; float: none; position: unset; font-size: 16px; text-align: center; }\r\n"
|
||||
" .menu a, .commands a { display: inline-block; padding: 4px; }\r\n"
|
||||
" .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%; text-align: center; }\r\n"
|
||||
" a, .slide label { display: block; }\r\n"
|
||||
" .header { margin: unset; font-size: 1.5em; }\r\n"
|
||||
" small { display: block; }\r\n"
|
||||
" a.button { appearance: button; text-decoration: none; margin-top: 10px; padding: 6px; border: 2px solid var(--main-link-color);\r\n"
|
||||
" border-radius: 5px; width: -webkit-fill-available; }\r\n"
|
||||
" input, select { width: 35%; text-align: center; padding: 5px; border: 2px solid var(--main-link-color); border-radius: 5px; font-size: 18px; }\r\n"
|
||||
" table.extaddr { margin: auto; text-align: unset; }\r\n"
|
||||
" textarea { width: -webkit-fill-available; height: auto; padding: 5px; border: 2px solid var(--main-link-color);\r\n"
|
||||
" border-radius: 5px; font-size: 12px; }\r\n"
|
||||
" button[type=submit] { padding: 5px 15px; background: transparent; border: 2px solid var(--main-link-color); cursor: pointer;\r\n"
|
||||
" border-radius: 5px; position: relative; height: 36px; display: -webkit-inline-box; margin-top: 10px; }\r\n"
|
||||
"}\r\n"
|
||||
"</style>\r\n";
|
||||
|
||||
// for external style sheet
|
||||
std::string externalCSS;
|
||||
|
||||
} // http
|
||||
} // i2p
|
||||
|
||||
#endif /* HTTP_SERVER_RESOURCES_H__ */
|
||||
@@ -1,3 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#ifdef WITH_I2PC
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
#include <openssl/x509.h>
|
||||
@@ -48,10 +58,10 @@ namespace client
|
||||
if (i2pcp_key.at(0) != '/')
|
||||
i2pcp_key = i2p::fs::DataDirPath(i2pcp_key);
|
||||
if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) {
|
||||
LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection");
|
||||
LogPrint (eLogInfo, "I2PControl: Creating new certificate for control connection");
|
||||
CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
|
||||
} else {
|
||||
LogPrint(eLogDebug, "I2PControl: using cert from ", i2pcp_crt);
|
||||
LogPrint(eLogDebug, "I2PControl: Using cert from ", i2pcp_crt);
|
||||
}
|
||||
m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use);
|
||||
m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem);
|
||||
@@ -79,8 +89,7 @@ namespace client
|
||||
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
|
||||
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
|
||||
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
|
||||
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] =
|
||||
&I2PControlService::TunnelsSuccessRateHandler;
|
||||
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
|
||||
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
|
||||
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
|
||||
|
||||
@@ -97,9 +106,15 @@ namespace client
|
||||
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
|
||||
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
|
||||
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
|
||||
#ifdef WITH_SAM
|
||||
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
|
||||
#endif
|
||||
#ifdef WITH_BOB
|
||||
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
|
||||
#endif
|
||||
#ifdef WITH_I2CP
|
||||
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
|
||||
#endif
|
||||
}
|
||||
|
||||
I2PControlService::~I2PControlService ()
|
||||
@@ -142,7 +157,7 @@ namespace client
|
||||
try {
|
||||
m_Service.run ();
|
||||
} catch (std::exception& ex) {
|
||||
LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ());
|
||||
LogPrint (eLogError, "I2PControl: Runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,10 +175,10 @@ namespace client
|
||||
Accept ();
|
||||
|
||||
if (ecode) {
|
||||
LogPrint (eLogError, "I2PControl: accept error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PControl: Accept error: ", ecode.message ());
|
||||
return;
|
||||
}
|
||||
LogPrint (eLogDebug, "I2PControl: new request from ", socket->lowest_layer ().remote_endpoint ());
|
||||
LogPrint (eLogDebug, "I2PControl: New request from ", socket->lowest_layer ().remote_endpoint ());
|
||||
Handshake (socket);
|
||||
}
|
||||
|
||||
@@ -176,7 +191,7 @@ namespace client
|
||||
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
|
||||
{
|
||||
if (ecode) {
|
||||
LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PControl: Handshake error: ", ecode.message ());
|
||||
return;
|
||||
}
|
||||
//std::this_thread::sleep_for (std::chrono::milliseconds(5));
|
||||
@@ -202,7 +217,7 @@ namespace client
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PControl: Read error: ", ecode.message ());
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -225,7 +240,7 @@ namespace client
|
||||
}
|
||||
if (ss.eof ())
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: malformed request, HTTP header expected");
|
||||
LogPrint (eLogError, "I2PControl: Malformed request, HTTP header expected");
|
||||
return; // TODO:
|
||||
}
|
||||
std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read
|
||||
@@ -250,7 +265,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "I2PControl: unknown method ", method);
|
||||
LogPrint (eLogWarning, "I2PControl: Unknown method ", method);
|
||||
response << "{\"id\":null,\"error\":";
|
||||
response << "{\"code\":-32601,\"message\":\"Method not found\"},";
|
||||
response << "\"jsonrpc\":\"2.0\"}";
|
||||
@@ -259,7 +274,7 @@ namespace client
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ());
|
||||
LogPrint (eLogError, "I2PControl: Exception when handle request: ", ex.what ());
|
||||
std::ostringstream response;
|
||||
response << "{\"id\":null,\"error\":";
|
||||
response << "{\"code\":-32700,\"message\":\"" << ex.what () << "\"},";
|
||||
@@ -268,7 +283,7 @@ namespace client
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: handle request unknown exception");
|
||||
LogPrint (eLogError, "I2PControl: Handle request unknown exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,11 +293,16 @@ namespace client
|
||||
ss << "\"" << name << "\":" << value;
|
||||
}
|
||||
|
||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const
|
||||
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const
|
||||
{
|
||||
ss << "\"" << name << "\":";
|
||||
if (value.length () > 0)
|
||||
ss << "\"" << value << "\"";
|
||||
{
|
||||
if (quotes)
|
||||
ss << "\"" << value << "\"";
|
||||
else
|
||||
ss << value;
|
||||
}
|
||||
else
|
||||
ss << "null";
|
||||
}
|
||||
@@ -329,12 +349,11 @@ namespace client
|
||||
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf)
|
||||
{
|
||||
if (ecode) {
|
||||
LogPrint (eLogError, "I2PControl: write error: ", ecode.message ());
|
||||
LogPrint (eLogError, "I2PControl: Write error: ", ecode.message ());
|
||||
}
|
||||
}
|
||||
|
||||
// handlers
|
||||
|
||||
// handlers
|
||||
void I2PControlService::AuthenticateHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
int api = params.get<int> ("API");
|
||||
@@ -359,8 +378,7 @@ namespace client
|
||||
}
|
||||
|
||||
|
||||
// I2PControl
|
||||
|
||||
// I2PControl
|
||||
void I2PControlService::I2PControlHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
for (auto& it: params)
|
||||
@@ -379,7 +397,7 @@ namespace client
|
||||
|
||||
void I2PControlService::PasswordHandler (const std::string& value)
|
||||
{
|
||||
LogPrint (eLogWarning, "I2PControl: new password=", value, ", to make it persistent you should update your config!");
|
||||
LogPrint (eLogWarning, "I2PControl: New password=", value, ", to make it persistent you should update your config!");
|
||||
m_Password = value;
|
||||
m_Tokens.clear ();
|
||||
}
|
||||
@@ -395,8 +413,8 @@ namespace client
|
||||
auto it1 = m_RouterInfoHandlers.find (it->first);
|
||||
if (it1 != m_RouterInfoHandlers.end ())
|
||||
{
|
||||
if (!first) results << ",";
|
||||
else first = false;
|
||||
if (!first) results << ",";
|
||||
else first = false;
|
||||
(this->*(it1->second))(results);
|
||||
}
|
||||
else
|
||||
@@ -406,7 +424,7 @@ namespace client
|
||||
|
||||
void I2PControlService::UptimeHandler (std::ostringstream& results)
|
||||
{
|
||||
InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL));
|
||||
InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false);
|
||||
}
|
||||
|
||||
void I2PControlService::VersionHandler (std::ostringstream& results)
|
||||
@@ -494,7 +512,7 @@ namespace client
|
||||
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
|
||||
m_ShutdownTimer.async_wait (
|
||||
[](const boost::system::error_code& ecode)
|
||||
{
|
||||
{
|
||||
Daemon.running = 0;
|
||||
});
|
||||
}
|
||||
@@ -508,7 +526,7 @@ namespace client
|
||||
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
|
||||
m_ShutdownTimer.async_wait (
|
||||
[](const boost::system::error_code& ecode)
|
||||
{
|
||||
{
|
||||
Daemon.running = 0;
|
||||
});
|
||||
}
|
||||
@@ -520,7 +538,7 @@ namespace client
|
||||
i2p::data::netdb.Reseed ();
|
||||
}
|
||||
|
||||
// network setting
|
||||
// network setting
|
||||
void I2PControlService::NetworkSettingHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
@@ -577,11 +595,11 @@ namespace client
|
||||
|
||||
// save cert
|
||||
if ((f = fopen (crt_path, "wb")) != NULL) {
|
||||
LogPrint (eLogInfo, "I2PControl: saving new cert to ", crt_path);
|
||||
LogPrint (eLogInfo, "I2PControl: Saving new cert to ", crt_path);
|
||||
PEM_write_X509 (f, x509);
|
||||
fclose (f);
|
||||
} else {
|
||||
LogPrint (eLogError, "I2PControl: can't write cert: ", strerror(errno));
|
||||
LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno));
|
||||
}
|
||||
|
||||
// save key
|
||||
@@ -590,18 +608,17 @@ namespace client
|
||||
PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
|
||||
fclose (f);
|
||||
} else {
|
||||
LogPrint (eLogError, "I2PControl: can't write key: ", strerror(errno));
|
||||
LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno));
|
||||
}
|
||||
|
||||
X509_free (x509);
|
||||
} else {
|
||||
LogPrint (eLogError, "I2PControl: can't create RSA key for certificate");
|
||||
LogPrint (eLogError, "I2PControl: Can't create RSA key for certificate");
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
}
|
||||
|
||||
// ClientServicesInfo
|
||||
|
||||
// ClientServicesInfo
|
||||
void I2PControlService::ClientServicesInfoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
for (auto it = params.begin (); it != params.end (); it++)
|
||||
@@ -707,6 +724,7 @@ namespace client
|
||||
InsertParam (results, "SOCKS", pt);
|
||||
}
|
||||
|
||||
#ifdef WITH_SAM
|
||||
void I2PControlService::SAMInfoHandler (std::ostringstream& results)
|
||||
{
|
||||
boost::property_tree::ptree pt;
|
||||
@@ -742,7 +760,9 @@ namespace client
|
||||
|
||||
InsertParam (results, "SAM", pt);
|
||||
}
|
||||
#endif // WITH_SAM
|
||||
|
||||
#ifdef WITH_BOB
|
||||
void I2PControlService::BOBInfoHandler (std::ostringstream& results)
|
||||
{
|
||||
boost::property_tree::ptree pt;
|
||||
@@ -757,7 +777,9 @@ namespace client
|
||||
|
||||
InsertParam (results, "BOB", pt);
|
||||
}
|
||||
#endif // WITH_BOB
|
||||
|
||||
#ifdef WITH_I2CP
|
||||
void I2PControlService::I2CPInfoHandler (std::ostringstream& results)
|
||||
{
|
||||
boost::property_tree::ptree pt;
|
||||
@@ -772,5 +794,7 @@ namespace client
|
||||
|
||||
InsertParam (results, "I2CP", pt);
|
||||
}
|
||||
#endif // WITH_I2CP
|
||||
}
|
||||
}
|
||||
#endif // WITH_I2PC
|
||||
@@ -1,11 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#ifdef WITH_I2PC
|
||||
|
||||
#ifndef I2P_CONTROL_H__
|
||||
#define I2P_CONTROL_H__
|
||||
|
||||
@@ -65,7 +67,7 @@ namespace client
|
||||
|
||||
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
|
||||
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
|
||||
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const;
|
||||
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const;
|
||||
void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
|
||||
|
||||
// methods
|
||||
@@ -114,9 +116,15 @@ namespace client
|
||||
void I2PTunnelInfoHandler (std::ostringstream& results);
|
||||
void HTTPProxyInfoHandler (std::ostringstream& results);
|
||||
void SOCKSInfoHandler (std::ostringstream& results);
|
||||
#ifdef WITH_SAM
|
||||
void SAMInfoHandler (std::ostringstream& results);
|
||||
#endif
|
||||
#ifdef WITH_BOB
|
||||
void BOBInfoHandler (std::ostringstream& results);
|
||||
#endif
|
||||
#ifdef WITH_I2CP
|
||||
void I2CPInfoHandler (std::ostringstream& results);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -141,3 +149,4 @@ namespace client
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // WITH_I2PC
|
||||
@@ -29,7 +29,7 @@ namespace transport
|
||||
{
|
||||
if (m_IsRunning)
|
||||
{
|
||||
LogPrint(eLogInfo, "UPnP: stopping");
|
||||
LogPrint(eLogInfo, "UPnP: Stopping");
|
||||
m_IsRunning = false;
|
||||
m_Timer.cancel ();
|
||||
m_Service.stop ();
|
||||
@@ -46,7 +46,7 @@ namespace transport
|
||||
void UPnP::Start()
|
||||
{
|
||||
m_IsRunning = true;
|
||||
LogPrint(eLogInfo, "UPnP: starting");
|
||||
LogPrint(eLogInfo, "UPnP: Starting");
|
||||
m_Service.post (std::bind (&UPnP::Discover, this));
|
||||
std::unique_lock<std::mutex> l(m_StartedMutex);
|
||||
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
|
||||
@@ -72,7 +72,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: runtime exception: ", ex.what ());
|
||||
LogPrint (eLogError, "UPnP: Runtime exception: ", ex.what ());
|
||||
PortMapping ();
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ namespace transport
|
||||
|
||||
if (isError)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err);
|
||||
LogPrint (eLogError, "UPnP: Unable to discover Internet Gateway Devices: error ", err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -117,22 +117,22 @@ namespace transport
|
||||
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
|
||||
if(err != UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: unable to get external address: error ", err);
|
||||
LogPrint (eLogError, "UPnP: Unable to get external address: error ", err);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL);
|
||||
LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL);
|
||||
if (!m_externalIPAddress[0])
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address");
|
||||
LogPrint (eLogError, "UPnP: Found Internet Gateway Device doesn't know our external address");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err);
|
||||
LogPrint (eLogError, "UPnP: Unable to find valid Internet Gateway Device: error ", err);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace transport
|
||||
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);
|
||||
LogPrint (eLogDebug, "UPnP: Port ", strPort, " is possibly 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);
|
||||
@@ -192,18 +192,18 @@ namespace transport
|
||||
#endif
|
||||
if (err != UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
LogPrint (eLogError, "UPnP: port forwarding to ", m_NetworkAddr, ":", strPort, " failed: return code ", err);
|
||||
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 ,")");
|
||||
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");
|
||||
LogPrint (eLogDebug, "UPnP: External forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -225,7 +225,7 @@ namespace transport
|
||||
}
|
||||
std::string strType (GetProto (address)), strPort (std::to_string (address->port));
|
||||
int err = UPNPCOMMAND_SUCCESS;
|
||||
|
||||
|
||||
err = CheckMapping (strPort.c_str (), strType.c_str ());
|
||||
if (err == UPNPCOMMAND_SUCCESS)
|
||||
{
|
||||
|
||||
@@ -72,7 +72,8 @@ namespace i2p
|
||||
|
||||
if (pid < 0) // error
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Could not fork: ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not fork: " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -81,13 +82,15 @@ namespace i2p
|
||||
int sid = setsid();
|
||||
if (sid < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not create process group.");
|
||||
LogPrint(eLogError, "Daemon: Could not create process group.");
|
||||
std::cerr << "i2pd: Could not create process group." << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::string d = i2p::fs::GetDataDir();
|
||||
if (chdir(d.c_str()) != 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Could not chdir: ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not chdir: " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,14 +105,14 @@ namespace i2p
|
||||
uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles);
|
||||
getrlimit(RLIMIT_NOFILE, &limit);
|
||||
if (nfiles == 0) {
|
||||
LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files");
|
||||
LogPrint(eLogInfo, "Daemon: Using system limit in ", limit.rlim_cur, " max open files");
|
||||
} else if (nfiles <= limit.rlim_max) {
|
||||
limit.rlim_cur = nfiles;
|
||||
if (setrlimit(RLIMIT_NOFILE, &limit) == 0) {
|
||||
LogPrint(eLogInfo, "Daemon: set max number of open files to ",
|
||||
LogPrint(eLogInfo, "Daemon: Set max number of open files to ",
|
||||
nfiles, " (system limit is ", limit.rlim_max, ")");
|
||||
} else {
|
||||
LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Can't set max number of open files: ", strerror(errno));
|
||||
}
|
||||
} else {
|
||||
LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max);
|
||||
@@ -122,11 +125,11 @@ namespace i2p
|
||||
if (cfsize <= limit.rlim_max) {
|
||||
limit.rlim_cur = cfsize;
|
||||
if (setrlimit(RLIMIT_CORE, &limit) != 0) {
|
||||
LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Can't set max size of coredump: ", strerror(errno));
|
||||
} else if (cfsize == 0) {
|
||||
LogPrint(eLogInfo, "Daemon: coredumps disabled");
|
||||
} else {
|
||||
LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb");
|
||||
LogPrint(eLogInfo, "Daemon: Set max size of core files to ", cfsize / 1024, "Kb");
|
||||
}
|
||||
} else {
|
||||
LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max);
|
||||
@@ -143,14 +146,16 @@ namespace i2p
|
||||
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
|
||||
if (pidFH < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Could not create pid file ", pidfile, ": ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not create pid file " << pidfile << ": " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef ANDROID
|
||||
if (lockf(pidFH, F_TLOCK, 0) != 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -159,7 +164,8 @@ namespace i2p
|
||||
ftruncate(pidFH, 0);
|
||||
if (write(pidFH, pid, strlen(pid)) < 0)
|
||||
{
|
||||
LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno));
|
||||
LogPrint(eLogError, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
|
||||
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
12
debian/changelog
vendored
12
debian/changelog
vendored
@@ -1,3 +1,15 @@
|
||||
i2pd (2.41.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.41.0/0.9.53
|
||||
|
||||
-- r4sas <r4sas@i2pmail.org> Sun, 20 Feb 2022 13:00:00 +0000
|
||||
|
||||
i2pd (2.40.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.40.0/0.9.52
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 29 Nov 2021 16:00:00 +0000
|
||||
|
||||
i2pd (2.39.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.39.0/0.9.51
|
||||
|
||||
18
debian/patches/02-upnp.patch
vendored
18
debian/patches/02-upnp.patch
vendored
@@ -2,16 +2,16 @@ Description: Enable UPnP usage in package
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2021-01-16
|
||||
Last-Update: 2022-03-23
|
||||
|
||||
--- i2pd.orig/Makefile
|
||||
+++ i2pd/Makefile
|
||||
@@ -21,7 +21,7 @@ include filelist.mk
|
||||
USE_AESNI := $(or $(USE_AESNI),yes)
|
||||
USE_STATIC := $(or $(USE_STATIC),no)
|
||||
USE_MESHNET := $(or $(USE_MESHNET),no)
|
||||
-USE_UPNP := $(or $(USE_UPNP),no)
|
||||
+USE_UPNP := $(or $(USE_UPNP),yes)
|
||||
DEBUG := $(or $(DEBUG),yes)
|
||||
@@ -31,7 +31,7 @@ include filelist.mk
|
||||
|
||||
ifeq ($(DEBUG),yes)
|
||||
USE_AESNI := $(or $(USE_AESNI),yes)
|
||||
USE_STATIC := $(or $(USE_STATIC),no)
|
||||
-USE_UPNP := $(or $(USE_UPNP),no)
|
||||
+USE_UPNP := $(or $(USE_UPNP),yes)
|
||||
DEBUG := $(or $(DEBUG),yes)
|
||||
|
||||
# for debugging purposes only, when commit hash needed in trunk builds in i2pd version string
|
||||
|
||||
2
debian/rules
vendored
2
debian/rules
vendored
@@ -14,3 +14,5 @@ export DEB_LDFLAGS_MAINT_APPEND =
|
||||
|
||||
%:
|
||||
dh $@ --parallel
|
||||
|
||||
override_dh_auto_install:
|
||||
|
||||
215
i18n/Armenian.cpp
Normal file
215
i18n/Armenian.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I18N.h"
|
||||
|
||||
// Armenian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace armenian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "armenian";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "ԿիԲ"},
|
||||
{"MiB", "ՄիԲ"},
|
||||
{"GiB", "ԳիԲ"},
|
||||
{"building", "կառուցվում է"},
|
||||
{"failed", "Անհաջող"},
|
||||
{"expiring", "Լրանում է"},
|
||||
{"established", "կարգավոյված է"},
|
||||
{"unknown", "անհայտ"},
|
||||
{"exploratory", "հետազոտոկան"},
|
||||
{"<b>i2pd</b> webconsole", "Վեբ-կոնսոլ <b>i2pd</b>"},
|
||||
{"Main page", "Գլխավոր էջ"},
|
||||
{"Router commands", "Երթուղիչի հրահանգներ"},
|
||||
{"Local Destinations", "Տեղական վերջնակետերը"},
|
||||
{"LeaseSets", "ԼիզՍեթեր"},
|
||||
{"Tunnels", "Թունելներ"},
|
||||
{"Transit Tunnels", "Տարանցիկ թունելներ"},
|
||||
{"Transports", "Տրանսպորտ"},
|
||||
{"I2P tunnels", "I2P թունելներ"},
|
||||
{"SAM sessions", "SAM նստաշրջաններ"},
|
||||
{"ERROR", "ՍԽԱԼ"},
|
||||
{"OK", "ԼԱՎ"},
|
||||
{"Testing", "Փորձարկում"},
|
||||
{"Firewalled", "Արգելափակված է դրսից"},
|
||||
{"Unknown", "Անհայտ"},
|
||||
{"Proxy", "Պրոկսի"},
|
||||
{"Mesh", "MESH-ցանց"},
|
||||
{"Error", "Սխալ"},
|
||||
{"Clock skew", "Ոչ ճշգրիտ ժամանակ"},
|
||||
{"Offline", "Օֆլայն"},
|
||||
{"Symmetric NAT", "Սիմետրիկ NAT"},
|
||||
{"Uptime", "Առկայություն"},
|
||||
{"Network status", "Ցանցի կարգավիճակ"},
|
||||
{"Network status v6", "Ցանցի կարգավիճակ v6"},
|
||||
{"Stopping in", "Դադարում"},
|
||||
{"Family", "Խմբատեսակ"},
|
||||
{"Tunnel creation success rate", "Հաջողությամբ կառուցված թունելներ"},
|
||||
{"Received", "Ստացվել է"},
|
||||
{"KiB/s", "ԿիԲ/վ"},
|
||||
{"Sent", "Ուղարկվել է"},
|
||||
{"Transit", "Տարանցում"},
|
||||
{"Data path", "Տվյալների ուղին"},
|
||||
{"Hidden content. Press on text to see.", "Թաքցված բովանդակություն: Տեսնելու համար սեղմեկ տեքստին:"},
|
||||
{"Router Ident", "Երթուղիչի նույնականացուցիչ"},
|
||||
{"Router Family", "Երթուղիչի խումբը"},
|
||||
{"Router Caps", "Երթուղիչի հատկություններ"},
|
||||
{"Version", "Տարբերակ"},
|
||||
{"Our external address", "Մեր արտաքին հասցեն"},
|
||||
{"supported", "համատեղելի է"},
|
||||
{"Routers", "Երթուղիչներ"},
|
||||
{"Floodfills", "Floodfills-ներ"},
|
||||
{"Client Tunnels", "Oգտատիրական թունելներ"},
|
||||
{"Services", "Ծառայություններ"},
|
||||
{"Enabled", "Միացված է"},
|
||||
{"Disabled", "Անջատված է"},
|
||||
{"Encrypted B33 address", "Գաղտնագրված B33 հասցեներ"},
|
||||
{"Address registration line", "Հասցեի գրանցման տող"},
|
||||
{"Domain", "Տիրույթ"},
|
||||
{"Generate", "Գեներացնել"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը"},
|
||||
{"Address", "Հասցե"},
|
||||
{"Type", "Տեսակը"},
|
||||
{"EncType", "Գաղտնագրի տեսակը"},
|
||||
{"Inbound tunnels", "Մուտքային թունելներ"},
|
||||
{"ms", "մլվ"},
|
||||
{"Outbound tunnels", "Ելքային թունելներ"},
|
||||
{"Tags", "Թեգեր"},
|
||||
{"Incoming", "Մուտքային"},
|
||||
{"Outgoing", "ելքային"},
|
||||
{"Destination", "Նշանակման վայր"},
|
||||
{"Amount", "Քանակ"},
|
||||
{"Incoming Tags", "Մուտքային պիտակներ"},
|
||||
{"Tags sessions", "Նստաշրջանի պիտակներ"},
|
||||
{"Status", "Կարգավիճակ"},
|
||||
{"Local Destination", "Տեղական նշանակման կետ"},
|
||||
{"Streams", "Հոսքեր"},
|
||||
{"Close stream", "Փակել հոսքը"},
|
||||
{"I2CP session not found", "I2CP նստաշրջանը գոյություն չունի"},
|
||||
{"I2CP is not enabled", "I2CP միացված է"},
|
||||
{"Invalid", "Անվավեր"},
|
||||
{"Store type", "Պահեստավորման տեսակը"},
|
||||
{"Expires", "Սպառվում է"},
|
||||
{"Non Expired Leases", "Չսպառված Lease-եր"},
|
||||
{"Gateway", "Դարպաս"},
|
||||
{"TunnelID", "Թունելի ID"},
|
||||
{"EndDate", "Ավարտ"},
|
||||
{"not floodfill", "ոչ floodfill-ներ"},
|
||||
{"Queue size", "Հերթի չափսը"},
|
||||
{"Run peer test", "Գործարկել փորձարկումը"},
|
||||
{"Decline transit tunnels", "Մերժել տարանցիկ թունելներ"},
|
||||
{"Accept transit tunnels", "Ընդունել տարանցիկ թունելներ"},
|
||||
{"Cancel graceful shutdown", "Չեղարկել սահուն անջատումը"},
|
||||
{"Start graceful shutdown", "Սկսել սահուն անջատումը"},
|
||||
{"Force shutdown", "Հարկադիր անջատում"},
|
||||
{"Reload external CSS styles", "Վերաբեռնեք CSS ոճաթերթը"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Նշում․ </b> այստեղ կատարված ցանկացած գործողություն մշտական չէ և չի փոխում ձեր կազմաձևման ֆայլերը։"},
|
||||
{"Logging level", "Գրառման աստիճանը"},
|
||||
{"Transit tunnels limit", "Տարանցիկ թունելների սահմանափակում"},
|
||||
{"Change", "Փոփոխել"},
|
||||
{"Change language", "Փոփոխել լեզուն"},
|
||||
{"no transit tunnels currently built", "ընթացիկ կառուցված տարանցիկ թունելներ գոյություն չունեն"},
|
||||
{"SAM disabled", "SAM-ն անջատված է"},
|
||||
{"no sessions currently running", "ներկայումս գործող նստաշրջաններ գոյություն չունեն"},
|
||||
{"SAM session not found", "SAM նստաշրջան գոյություն չունի"},
|
||||
{"SAM Session", "SAM նստաշրջան"},
|
||||
{"Server Tunnels", "Սերվերային թունելներ"},
|
||||
{"Client Forwards", "Օգտատիրական փոխանցումներ"},
|
||||
{"Server Forwards", "Սերվերային փոխանցումներ"},
|
||||
{"Unknown page", "Անհայտ էջ"},
|
||||
{"Invalid token", "Սխալ տոկեն"},
|
||||
{"SUCCESS", "ՀԱՋՈՂՎԱԾ"},
|
||||
{"Stream closed", "Հոսքն անջատված է"},
|
||||
{"Stream not found or already was closed", "Հոսքը գոյություն չունի կամ արդեն ավարտված է"},
|
||||
{"Destination not found", "Հասցեի վայրը չի գտնվել"},
|
||||
{"StreamID can't be null", "StreamID-ն չի կարող լինել դատարկ"},
|
||||
{"Return to destination page", "Վերադառնալ նախորդ էջի հասցե"},
|
||||
{"You will be redirected in 5 seconds", "Դուք կտեղափոխվեք 5 վայրկյանից"},
|
||||
{"Transit tunnels count must not exceed 65535", "Տարանցիկ թունելների քանակը չպետք է գերազանցի 65535-ը"},
|
||||
{"Back to commands list", "Վերադառնալ հրահանգների ցուցակ"},
|
||||
{"Register at reg.i2p", "Գրանցել reg.i2p-ում"},
|
||||
{"Description", "Նկարագրություն"},
|
||||
{"A bit information about service on domain", "Մի փոքր տեղեկատվություն տիրոիյթում գտնվող ծառայության մասին"},
|
||||
{"Submit", "Ուղարկվել"},
|
||||
{"Domain can't end with .b32.i2p", "Տիրույթը չպետք է վերջանա .b32.i2p-ով"},
|
||||
{"Domain must end with .i2p", "Տիրույթը պետք է վերջանա .i2p-ով"},
|
||||
{"Such destination is not found", "Այդիպսի հասցե գոյություն չունի"},
|
||||
{"Unknown command", "Անհայտ հրահանգ"},
|
||||
{"Command accepted", "Հրարահանգն ընդունված է"},
|
||||
{"Proxy error", "Պրոկսի սխալ"},
|
||||
{"Proxy info", "Պրոկսի տեղեկություն"},
|
||||
{"Proxy error: Host not found", "Պրոկսի սխալ՝ նման հոսթ գոյություն չունի"},
|
||||
{"Remote host not found in router's addressbook", "Դեպի հոսթ կատարված հարցումը գոյություն չունի երթուղիչի հասցեագրքում"},
|
||||
{"You may try to find this host on jump services below", "Ստորև Դուք կարող եք գտնել այս հոսթը jump ծառայությունների միջոցով"},
|
||||
{"Invalid request", "Սխալ հարցում"},
|
||||
{"Proxy unable to parse your request", "Պրոկսին չի կարող հասկանալ Ձեր հարցումը"},
|
||||
{"addresshelper is not supported", "addresshelper-ը համատեղելի չէ"},
|
||||
{"Host", "Հոսթ"},
|
||||
{"added to router's addressbook from helper", "Ավելացված է երթուղիչի հասցեագրքում helper-ի միջոցով"},
|
||||
{"Click here to proceed:", "Շարունակելու համար սեղմեք այստեղ"},
|
||||
{"Continue", "Շարունակել"},
|
||||
{"Addresshelper found", "addresshelper-ը գնտված է"},
|
||||
{"already in router's addressbook", "արդեն առկա է երթուղիչի հասցեագրքում"},
|
||||
{"Click here to update record:", "Սեղմեկ այստեղ որպեսզի թարվացնեք գրառումը"},
|
||||
{"invalid request uri", "Սխալ ձևավորված URI հարցում"},
|
||||
{"Can't detect destination host from request", "Չհաջողվեց հայնտաբերեկ վայրի հասցեն նշված հարցմամբ"},
|
||||
{"Outproxy failure", "Սխալ արտաքին պրոքսի"},
|
||||
{"bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
|
||||
{"unknown outproxy url", "արտաքին պրոքսիի անհայտ URL"},
|
||||
{"cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
|
||||
{"hostname too long", "Հոսթի անունը չափազանց երկար է"},
|
||||
{"cannot connect to upstream socks proxy", "չհաջողվեց միանալ վերադաս socks պրոկսիին"},
|
||||
{"Cannot negotiate with socks proxy", "Չհաջողվեց պայմանավորվել վերադաս socks պրոկսիի հետ"},
|
||||
{"CONNECT error", "Սխալ CONNECT հարցում"},
|
||||
{"Failed to Connect", "Միանալ չhաջողվեց"},
|
||||
{"socks proxy error", "Սխալ SOCKS պրոկսի"},
|
||||
{"failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
|
||||
{"No Reply From socks proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
|
||||
{"cannot connect", "Հնարավոր չե միանալ"},
|
||||
{"http out proxy not implemented", "Արտաքին http պրոկսին դեռ իրականացված չէ"},
|
||||
{"cannot connect to upstream http proxy", "Չհաջողվեց միանալ վերադաս http պրոկսի սերվերին"},
|
||||
{"Host is down", "Հոսթն անհասանելի է"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ"},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"օր", "օր"}},
|
||||
{"hours", {"ժամ", "ժամ"}},
|
||||
{"minutes", {"րոպե", "րոպե"}},
|
||||
{"seconds", {"վարկյան", "վարկյան"}},
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
215
i18n/German.cpp
Normal file
215
i18n/German.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "I18N.h"
|
||||
|
||||
// German localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace german // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "german";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "KiB"},
|
||||
{"MiB", "MiB"},
|
||||
{"GiB", "GiB"},
|
||||
{"building", "In Bau"},
|
||||
{"failed", "fehlgeschlagen"},
|
||||
{"expiring", "läuft ab in"},
|
||||
{"established", "hergestellt"},
|
||||
{"unknown", "Unbekannt"},
|
||||
{"exploratory", "erforschende"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> Webkonsole"},
|
||||
{"Main page", "Startseite"},
|
||||
{"Router commands", "Router Befehle"},
|
||||
{"Local Destinations", "Lokale Destination"},
|
||||
{"LeaseSets", "LeaseSets"},
|
||||
{"Tunnels", "Tunnel"},
|
||||
{"Transit Tunnels", "Transittunnel"},
|
||||
{"Transports", "Transporte"},
|
||||
{"I2P tunnels", "I2P Tunnel"},
|
||||
{"SAM sessions", "SAM Sitzungen"},
|
||||
{"ERROR", "FEHLER"},
|
||||
{"OK", "OK"},
|
||||
{"Testing", "Testen"},
|
||||
{"Firewalled", "Hinter eine Firewall"},
|
||||
{"Unknown", "Unbekannt"},
|
||||
{"Proxy", "Proxy"},
|
||||
{"Mesh", "Mesh"},
|
||||
{"Error", "Fehler"},
|
||||
{"Clock skew", "Zeitabweichung"},
|
||||
{"Offline", "Offline"},
|
||||
{"Symmetric NAT", "Symmetrisches NAT"},
|
||||
{"Uptime", "Laufzeit"},
|
||||
{"Network status", "Netzwerkstatus"},
|
||||
{"Network status v6", "Netzwerkstatus v6"},
|
||||
{"Stopping in", "Stoppt in"},
|
||||
{"Family", "Familie"},
|
||||
{"Tunnel creation success rate", "Erfolgsrate der Tunnelerstellung"},
|
||||
{"Received", "Eingegangen"},
|
||||
{"KiB/s", "KiB/s"},
|
||||
{"Sent", "Gesendet"},
|
||||
{"Transit", "Transit"},
|
||||
{"Data path", "Datenpfad"},
|
||||
{"Hidden content. Press on text to see.", "Versteckter Inhalt. Klicke hier, um ihn zu sehen."},
|
||||
{"Router Ident", "Routeridentität"},
|
||||
{"Router Family", "Routerfamilie"},
|
||||
{"Router Caps", "Routerattribute"},
|
||||
{"Version", "Version"},
|
||||
{"Our external address", "Unsere externe Adresse"},
|
||||
{"supported", "unterstützt"},
|
||||
{"Routers", "Router"},
|
||||
{"Floodfills", "Floodfills"},
|
||||
{"Client Tunnels", "Klienttunnel"},
|
||||
{"Services", "Services"},
|
||||
{"Enabled", "Aktiviert"},
|
||||
{"Disabled", "Deaktiviert"},
|
||||
{"Encrypted B33 address", "Verschlüsselte B33 Adresse"},
|
||||
{"Address registration line", "Adresseregistrierungszeile"},
|
||||
{"Domain", "Domain"},
|
||||
{"Generate", "Generieren"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Hinweis:</b> Der resultierende String kann nur für die Registrierung einer 2LD Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."},
|
||||
{"Address", "Adresse"},
|
||||
{"Type", "Typ"},
|
||||
{"EncType", "Verschlüsselungstyp"},
|
||||
{"Inbound tunnels", "Eingehende Tunnel"},
|
||||
{"ms", "ms"},
|
||||
{"Outbound tunnels", "Ausgehende Tunnel"},
|
||||
{"Tags", "Tags"},
|
||||
{"Incoming", "Eingehend"},
|
||||
{"Outgoing", "Ausgehend"},
|
||||
{"Destination", "Destination"},
|
||||
{"Amount", "Anzahl"},
|
||||
{"Incoming Tags", "Eingehende Tags"},
|
||||
{"Tags sessions", "Tags Sitzungen"},
|
||||
{"Status", "Status"},
|
||||
{"Local Destination", "Lokale Destination"},
|
||||
{"Streams", "Streams"},
|
||||
{"Close stream", "Stream schließen"},
|
||||
{"I2CP session not found", "I2CP Sitzung nicht gefunden"},
|
||||
{"I2CP is not enabled", "I2CP ist nicht aktiviert"},
|
||||
{"Invalid", "Ungültig"},
|
||||
{"Store type", "Speichertyp"},
|
||||
{"Expires", "Ablaufdatum"},
|
||||
{"Non Expired Leases", "Nicht abgelaufene Leases"},
|
||||
{"Gateway", "Gateway"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "Enddatum"},
|
||||
{"not floodfill", "kein Floodfill"},
|
||||
{"Queue size", "Warteschlangengröße"},
|
||||
{"Run peer test", "Peer-Test ausführen"},
|
||||
{"Decline transit tunnels", "Transittunnel ablehnen"},
|
||||
{"Accept transit tunnels", "Transittunnel akzeptieren"},
|
||||
{"Cancel graceful shutdown", "Beende das kontrollierte herunterfahren"},
|
||||
{"Start graceful shutdown", "Starte das kontrollierte Herunterfahren"},
|
||||
{"Force shutdown", "Herunterfahren erzwingen"},
|
||||
{"Reload external CSS styles", "Lade externe CSS-Styles neu"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Hinweis:</b> Alle hier durchgeführten Aktionen sind nicht dauerhaft und ändern die Konfigurationsdateien nicht."},
|
||||
{"Logging level", "Protokollierungslevel"},
|
||||
{"Transit tunnels limit", "Limit für Transittunnel"},
|
||||
{"Change", "Verändern"},
|
||||
{"Change language", "Sprache ändern"},
|
||||
{"no transit tunnels currently built", "derzeit keine Transittunnel aufgebaut"},
|
||||
{"SAM disabled", "SAM deaktiviert"},
|
||||
{"no sessions currently running", "Derzeit keine laufenden Sitzungen"},
|
||||
{"SAM session not found", "SAM Sitzung nicht gefunden"},
|
||||
{"SAM Session", "SAM Sitzung"},
|
||||
{"Server Tunnels", "Servertunnel"},
|
||||
{"Client Forwards", "Klient-Weiterleitungen"},
|
||||
{"Server Forwards", "Server-Weiterleitungen"},
|
||||
{"Unknown page", "Unbekannte Seite"},
|
||||
{"Invalid token", "Ungültiger Token"},
|
||||
{"SUCCESS", "ERFOLGREICH"},
|
||||
{"Stream closed", "Stream geschlossen"},
|
||||
{"Stream not found or already was closed", "Stream nicht gefunden oder bereits geschlossen"},
|
||||
{"Destination not found", "Destination nicht gefunden"},
|
||||
{"StreamID can't be null", "StreamID kann nicht null sein"},
|
||||
{"Return to destination page", "Zurück zur Destination-Seite"},
|
||||
{"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
|
||||
{"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
|
||||
{"Back to commands list", "Zurück zur Kommandoliste"},
|
||||
{"Register at reg.i2p", "Auf reg.i2p registrieren"},
|
||||
{"Description", "Beschreibung"},
|
||||
{"A bit information about service on domain", "Ein bisschen Informationen über den Service auf der Domain"},
|
||||
{"Submit", "Einreichen"},
|
||||
{"Domain can't end with .b32.i2p", "Domain kann nicht mit .b32.i2p enden"},
|
||||
{"Domain must end with .i2p", "Domain muss mit .i2p enden"},
|
||||
{"Such destination is not found", "Eine solche Destination konnte nicht gefunden werden"},
|
||||
{"Unknown command", "Unbekannter Befehl"},
|
||||
{"Command accepted", "Befehl akzeptiert"},
|
||||
{"Proxy error", "Proxy-Fehler"},
|
||||
{"Proxy info", "Proxy-Info"},
|
||||
{"Proxy error: Host not found", "Proxy-Fehler: Host nicht gefunden"},
|
||||
{"Remote host not found in router's addressbook", "Remote-Host nicht im Router Adressbuch gefunden"},
|
||||
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einen der Jump-Services unten finden"},
|
||||
{"Invalid request", "Ungültige Anfrage"},
|
||||
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht interpretieren"},
|
||||
{"addresshelper is not supported", "addresshelper wird nicht unterstützt"},
|
||||
{"Host", "Host"},
|
||||
{"added to router's addressbook from helper", "vom Helfer zum Router Adressbuch hinzugefügt"},
|
||||
{"Click here to proceed:", "Klicke hier um fortzufahren:"},
|
||||
{"Continue", "Fortsetzen"},
|
||||
{"Addresshelper found", "Adresshelfer gefunden"},
|
||||
{"already in router's addressbook", "bereits im Adressbuch des Routers"},
|
||||
{"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
|
||||
{"invalid request uri", "ungültige Anfrage-URI"},
|
||||
{"Can't detect destination host from request", "Kann Anhand der Anfrage den Destination-Host nicht erkennen"},
|
||||
{"Outproxy failure", "Outproxy-Fehler"},
|
||||
{"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "nicht innerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
|
||||
{"unknown outproxy url", "unbekannte Outproxy-URL"},
|
||||
{"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
|
||||
{"hostname too long", "Hostname zu lang"},
|
||||
{"cannot connect to upstream socks proxy", "Kann keine Verbindung zum Upstream-Socks-Proxy herstellen"},
|
||||
{"Cannot negotiate with socks proxy", "Kann nicht mit Socks-Proxy verhandeln"},
|
||||
{"CONNECT error", "CONNECT-Fehler"},
|
||||
{"Failed to Connect", "Verbindung konnte nicht hergestellt werden"},
|
||||
{"socks proxy error", "Socks-Proxy-Fehler"},
|
||||
{"failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
|
||||
{"No Reply From socks proxy", "Keine Antwort vom Socks-Proxy"},
|
||||
{"cannot connect", "kann nicht verbinden"},
|
||||
{"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
|
||||
{"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
|
||||
{"Host is down", "Host ist offline"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbaunen, vielleicht ist es offline. Versuche es später noch einmal."},
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"Tag", "Tage"}},
|
||||
{"hours", {"Stunde", "Stunden"}},
|
||||
{"minutes", {"Minute", "Minuten"}},
|
||||
{"seconds", {"Sekunde", "Sekunden"}},
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
12
i18n/I18N.h
12
i18n/I18N.h
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -9,7 +9,7 @@
|
||||
#ifndef __I18N_H__
|
||||
#define __I18N_H__
|
||||
|
||||
#include "RouterContext.h"
|
||||
#include "ClientContext.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -19,19 +19,19 @@ namespace i18n
|
||||
{
|
||||
const auto it = i2p::i18n::languages.find(lang);
|
||||
if (it == i2p::i18n::languages.end()) // fallback
|
||||
i2p::context.SetLanguage (i2p::i18n::english::GetLocale());
|
||||
i2p::client::context.SetLanguage (i2p::i18n::english::GetLocale());
|
||||
else
|
||||
i2p::context.SetLanguage (it->second.LocaleFunc());
|
||||
i2p::client::context.SetLanguage (it->second.LocaleFunc());
|
||||
}
|
||||
|
||||
inline std::string translate (const std::string& arg)
|
||||
{
|
||||
return i2p::context.GetLanguage ()->GetString (arg);
|
||||
return i2p::client::context.GetLanguage ()->GetString (arg);
|
||||
}
|
||||
|
||||
inline std::string translate (const std::string& arg, const std::string& arg2, const int& n)
|
||||
{
|
||||
return i2p::context.GetLanguage ()->GetPlural (arg, arg2, n);
|
||||
return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, n);
|
||||
}
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -72,19 +72,23 @@ namespace i18n
|
||||
|
||||
// Add localization here with language name as namespace
|
||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
|
||||
/**
|
||||
* That map contains international language name lower-case and name in it's language
|
||||
* That map contains international language name lower-case, name in it's language and it's code
|
||||
*/
|
||||
static std::map<std::string, langData> languages
|
||||
{
|
||||
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
|
||||
{ "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
|
||||
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
|
||||
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
|
||||
{ "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} },
|
||||
{ "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
|
||||
{ "ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace russian // language namespace
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
|
||||
return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -198,7 +198,6 @@ namespace turkmen // language namespace
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
// ShowUptime
|
||||
{"days", {"gün", "gün"}},
|
||||
{"hours", {"sagat", "sagat"}},
|
||||
{"minutes", {"minut", "minut"}},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The PurpleI2P Project
|
||||
* Copyright (c) 2021-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -34,20 +34,21 @@ namespace uzbek // language namespace
|
||||
{"KiB", "KiB"},
|
||||
{"MiB", "MiB"},
|
||||
{"GiB", "GiB"},
|
||||
{"building", "qurilish"},
|
||||
{"building", "yaratilmoqda"},
|
||||
{"failed", "muvaffaqiyatsiz"},
|
||||
{"expiring", "muddati tugaydi"},
|
||||
{"established", "aloqa o'rnatildi"},
|
||||
{"unknown", "noma'lum"},
|
||||
{"exploratory", "tadqiqiy"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> veb -konsoli"},
|
||||
{"<b>i2pd</b> webconsole", "<b>i2pd</b> veb-konsoli"},
|
||||
{"Main page", "Asosiy sahifa"},
|
||||
{"Router commands", "Router buyruqlari"},
|
||||
{"Local Destinations", "Mahalliy joylanishlar"},
|
||||
{"LeaseSets", "LeaseSets"},
|
||||
{"Tunnels", "Tunnellar"},
|
||||
{"Transit Tunnels", "Tranzit Tunellar"},
|
||||
{"Transit Tunnels", "Tranzit Tunellari"},
|
||||
{"Transports", "Transportlar"},
|
||||
{"I2P tunnels", "I2P tunnellar"},
|
||||
{"I2P tunnels", "I2P tunnellari"},
|
||||
{"SAM sessions", "SAM sessiyalari"},
|
||||
{"ERROR", "XATO"},
|
||||
{"OK", "OK"},
|
||||
@@ -70,25 +71,25 @@ namespace uzbek // language namespace
|
||||
{"KiB/s", "KiB/s"},
|
||||
{"Sent", "Yuborilgan"},
|
||||
{"Transit", "Tranzit"},
|
||||
{"Data path", "Ma'lumotlar yo'li"},
|
||||
{"Data path", "Ma'lumotlar joylanishi"},
|
||||
{"Hidden content. Press on text to see.", "Yashirin tarkib. Ko'rish uchun matn ustida bosing."},
|
||||
{"Router Ident", "Router identifikatori"},
|
||||
{"Router Family", "Router Oila"},
|
||||
{"Router Caps", "Router bayroqlari"},
|
||||
{"Router Family", "Router oilasi"},
|
||||
{"Router Caps", "Router Bayroqlari"},
|
||||
{"Version", "Versiya"},
|
||||
{"Our external address", "Bizning tashqi manzilimiz"},
|
||||
{"supported", "qo'llab -quvvatlanadi"},
|
||||
{"supported", "qo'llab-quvvatlanadi"},
|
||||
{"Routers", "Routerlar"},
|
||||
{"Floodfills", "Floodfills"},
|
||||
{"Client Tunnels", "Mijoz tunellari"},
|
||||
{"Client Tunnels", "Mijoz Tunellari"},
|
||||
{"Services", "Xizmatlar"},
|
||||
{"Enabled", "Yoqilgan"},
|
||||
{"Disabled", "O'chirilgan"},
|
||||
{"Encrypted B33 address", "Shifrlangan B33 manzil"},
|
||||
{"Address registration line", "Manzilni ro'yxatga olish liniyasi"},
|
||||
{"Domain", "Domen"},
|
||||
{"Generate", "Varatish"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Eslatma:</b> natija satridan faqat 2LD domenlarini ro'yxatdan o'tkazish uchun foydalanish mumkin (example.i2p). Subdomenlarni ro'yxatdan o'tkazish uchun i2pd-tools dan foydalaning."},
|
||||
{"Generate", "Yaratish"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Eslatma:</b> natija satridan faqat 2LD domenlarini ro'yxatdan o'tkazish uchun foydalanish mumkin (example.i2p). Subdomenlarni ro'yxatdan o'tkazish uchun 'i2pd-tools'dan foydalaning."},
|
||||
{"Address", "Manzil"},
|
||||
{"Type", "Turi"},
|
||||
{"EncType", "ShifrlashTuri"},
|
||||
@@ -99,10 +100,11 @@ namespace uzbek // language namespace
|
||||
{"Incoming", "Kiruvchi"},
|
||||
{"Outgoing", "Chiquvchi"},
|
||||
{"Destination", "Manzilgoh"},
|
||||
{"Amount", "Yig'indi"},
|
||||
{"Amount", "Soni"},
|
||||
{"Incoming Tags", "Kiruvchi teglar"},
|
||||
{"Tags sessions", "Teglar sessiyalari"},
|
||||
{"Status", "Holat"},
|
||||
{"Local Destination", "Mahalliy joylanish"},
|
||||
{"Streams", "Strim"},
|
||||
{"Close stream", "Strimni o'chirish"},
|
||||
{"I2CP session not found", "I2CP sessiyasi topilmadi"},
|
||||
@@ -117,14 +119,15 @@ namespace uzbek // language namespace
|
||||
{"not floodfill", "floodfill emas"},
|
||||
{"Queue size", "Navbat hajmi"},
|
||||
{"Run peer test", "Sinovni boshlang"},
|
||||
{"Decline transit tunnels", "Tranzit tunnellarni rad etish"},
|
||||
{"Decline transit tunnels", "Tranzit tunnellarini rad etish"},
|
||||
{"Accept transit tunnels", "Tranzit tunnellarni qabul qilish"},
|
||||
{"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qiling"},
|
||||
{"Start graceful shutdown", "Yumshoq to'xtashni boshlang"},
|
||||
{"Force shutdown", "Bizning tashqi manzilimiz"},
|
||||
{"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qilish"},
|
||||
{"Start graceful shutdown", "Yumshoq to'xtashni boshlash"},
|
||||
{"Force shutdown", "Majburiy to'xtatish"},
|
||||
{"Reload external CSS styles", "Tashqi CSS uslublarini qayta yuklang"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Eslatma:</b> bu erda qilingan har qanday harakat doimiy emas va konfiguratsiya fayllarini o'zgartirmaydi."},
|
||||
{"Transit tunnels limit", "Tranzit tunellar chegarasi"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Eslatma:</b> shu yerda qilingan har qanday harakat doimiy emas va konfiguratsiya fayllarini o'zgartirmaydi."},
|
||||
{"Logging level", "Jurnal darajasi"},
|
||||
{"Transit tunnels limit", "Tranzit tunellarning chegarasi"},
|
||||
{"Change", "O'zgartirish"},
|
||||
{"Change language", "Tilni o'zgartirish"},
|
||||
{"no transit tunnels currently built", "qurilgan tranzit tunnellari yo'q"},
|
||||
@@ -142,8 +145,8 @@ namespace uzbek // language namespace
|
||||
{"Stream not found or already was closed", "Strim topilmadi yoki allaqachon yopilgan"},
|
||||
{"Destination not found", "Yo'nalish topilmadi"},
|
||||
{"StreamID can't be null", "StreamID bo'sh bo'lishi mumkin emas"},
|
||||
{"Return to destination page", "Belgilangan sahifaga qaytish"},
|
||||
{"You will be redirected in 5 seconds", "Siz 5 soniyada qayta yo'naltirilasiz"},
|
||||
{"Return to destination page", "Manzilgoh sahifasiga qaytish"},
|
||||
{"You will be redirected in 5 seconds", "Siz 5 soniya ichida qayta yo'naltirilasiz"},
|
||||
{"Transit tunnels count must not exceed 65535", "Tranzit tunnellar soni 65535 dan oshmasligi kerak"},
|
||||
{"Back to commands list", "Buyruqlar ro'yxatiga qaytish"},
|
||||
{"Register at reg.i2p", "Reg.i2p-da ro'yxatdan o'ting"},
|
||||
@@ -159,29 +162,35 @@ namespace uzbek // language namespace
|
||||
{"Proxy info", "Proksi ma'lumotlari"},
|
||||
{"Proxy error: Host not found", "Proksi xatosi: Xost topilmadi"},
|
||||
{"Remote host not found in router's addressbook", "Masofaviy xost yo'riqnoma manzillar kitobida topilmadi"},
|
||||
{"You may try to find this host on jump services below", "Siz xost quyida o'tish xizmatlari orqali topishga harakat qilishingiz mumkin"},
|
||||
{"Invalid request", "Noto‘g‘ri so‘rov"},
|
||||
{"Proxy unable to parse your request", "Proksi sizning so'rovingizni tahlil qila olmaydi"},
|
||||
{"Proxy unable to parse your request", "Proksi sizning so'rovingizni aniqlab ololmayapti"},
|
||||
{"addresshelper is not supported", "addresshelper qo'llab -quvvatlanmaydi"},
|
||||
{"Host", "Xost"},
|
||||
{"added to router's addressbook from helper", "'helper'dan routerning 'addressbook'ga qo'shildi"},
|
||||
{"Click here to proceed:", "Davom etish uchun shu yerni bosing:"},
|
||||
{"Continue", "Davom etish"},
|
||||
{"Addresshelper found", "Addresshelper topildi"},
|
||||
{"already in router's addressbook", "allaqachon 'addressbook'da yozilgan"},
|
||||
{"Click here to update record:", "Yozuvni yangilash uchun shu yerni bosing:"},
|
||||
{"invalid request uri", "noto'g'ri URI so'rovi"},
|
||||
{"Can't detect destination host from request", "So‘rov orqali manzil xostini aniqlab bo'lmayapti"},
|
||||
{"Outproxy failure", "Tashqi proksi muvaffaqiyatsizligi"},
|
||||
{"bad outproxy settings", "noto'g'ri tashqi proksi -server sozlamalari"},
|
||||
{"bad outproxy settings", "noto'g'ri tashqi proksi-server sozlamalari"},
|
||||
{"not inside I2P network, but outproxy is not enabled", "I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"},
|
||||
{"unknown outproxy url", "noma'lum outproxy url"},
|
||||
{"cannot resolve upstream proxy", "yuqoridagi proksi -serverni aniqlab olib bolmaydi"},
|
||||
{"cannot resolve upstream proxy", "yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
|
||||
{"hostname too long", "xost nomi juda uzun"},
|
||||
{"cannot connect to upstream socks proxy", "yuqori soks proksi -serveriga ulanib bo'lmaydi"},
|
||||
{"Cannot negotiate with socks proxy", "Soks proksi bilan muzokara olib bo'lmaydi"},
|
||||
{"cannot connect to upstream socks proxy", "yuqori 'socks proxy'ga ulanib bo'lmayapti"},
|
||||
{"Cannot negotiate with socks proxy", "'Socks proxy' bilan muzokara olib bo'lmaydi"},
|
||||
{"CONNECT error", "CONNECT xatosi"},
|
||||
{"Failed to Connect", "Ulanmadi"},
|
||||
{"socks proxy error", "soks proksi xatosi"},
|
||||
{"failed to send request to upstream", "yuqori http proksi-serveriga ulanib bo'lmadi"},
|
||||
{"No Reply From socks proxy", "Soks-proksidan javob yo'q"},
|
||||
{"cannot connect", "ulab bo'lmaydi"},
|
||||
{"http out proxy not implemented", "tashqi HTTP proksi -serverni qo'llab -quvvatlash amalga oshirilmagan"},
|
||||
{"cannot connect to upstream http proxy", "yuqori http proksi-serveriga ulanib bo'lmadi"},
|
||||
{"Failed to Connect", "Ulanib bo'lmayapti"},
|
||||
{"socks proxy error", "'socks proxy' xatosi"},
|
||||
{"failed to send request to upstream", "yuqori http proksi-serveriga so'rovni uborib bo'lmadi"},
|
||||
{"No Reply From socks proxy", "'Socks proxy'dan javob yo'q"},
|
||||
{"cannot connect", "ulanib bo'lmaydi"},
|
||||
{"http out proxy not implemented", "tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"},
|
||||
{"cannot connect to upstream http proxy", "yuqori http 'proxy-server'iga ulanib bo'lmayapti"},
|
||||
{"Host is down", "Xost ishlamayapti"},
|
||||
{"Can't create connection to requested host, it may be down. Please try again later.", "Talab qilingan xost bilan aloqa o'rnatilmadi, u ishlamay qolishi mumkin. Iltimos keyinroq qayta urinib ko'ring."},
|
||||
{"", ""},
|
||||
@@ -189,10 +198,10 @@ namespace uzbek // language namespace
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"kun", "kunlar"}},
|
||||
{"days", {"kun", "kun"}},
|
||||
{"hours", {"soat", "soat"}},
|
||||
{"minutes", {"daqiqa", "daqiqalar"}},
|
||||
{"seconds", {"soniya", "soniyalar"}},
|
||||
{"minutes", {"daqiqa", "daqiqa"}},
|
||||
{"seconds", {"soniya", "soniya"}},
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -185,10 +185,7 @@ namespace data
|
||||
if (InCount && !m)
|
||||
outCount = 3 * n;
|
||||
else
|
||||
{
|
||||
outCount = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||
while ( *ps-- == P64 )
|
||||
@@ -196,7 +193,7 @@ namespace data
|
||||
ps = (unsigned char *)InBuffer;
|
||||
|
||||
if (outCount > len)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
pd = OutBuffer;
|
||||
auto endOfOutBuffer = OutBuffer + outCount;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -122,7 +122,7 @@ namespace data
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogError, "Blinding: signature type ", (int)sigType, " is not ECDSA");
|
||||
LogPrint (eLogError, "Blinding: Signature type ", (int)sigType, " is not ECDSA");
|
||||
}
|
||||
if (group)
|
||||
{
|
||||
@@ -146,7 +146,10 @@ namespace data
|
||||
m_PublicKey.resize (len);
|
||||
memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len);
|
||||
m_SigType = identity->GetSigningKeyType ();
|
||||
m_BlindedSigType = m_SigType;
|
||||
if (m_SigType == i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
|
||||
m_BlindedSigType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519; // 7 -> 11
|
||||
else
|
||||
m_BlindedSigType = m_SigType;
|
||||
}
|
||||
|
||||
BlindedPublicKey::BlindedPublicKey (const std::string& b33):
|
||||
@@ -156,7 +159,7 @@ namespace data
|
||||
size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40);
|
||||
if (l < 32)
|
||||
{
|
||||
LogPrint (eLogError, "Blinding: malformed b33 ", b33);
|
||||
LogPrint (eLogError, "Blinding: Malformed b33 ", b33);
|
||||
return;
|
||||
}
|
||||
uint32_t checksum = crc32 (0, addr + 3, l - 3);
|
||||
@@ -186,10 +189,10 @@ namespace data
|
||||
memcpy (m_PublicKey.data (), addr + offset, len);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Blinding: public key in b33 address is too short for signature type ", (int)m_SigType);
|
||||
LogPrint (eLogError, "Blinding: Public key in b33 address is too short for signature type ", (int)m_SigType);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Blinding: unknown signature type ", (int)m_SigType, " in b33");
|
||||
LogPrint (eLogError, "Blinding: Unknown signature type ", (int)m_SigType, " in b33");
|
||||
}
|
||||
|
||||
std::string BlindedPublicKey::ToB33 () const
|
||||
@@ -256,7 +259,7 @@ namespace data
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType);
|
||||
LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
|
||||
}
|
||||
return publicKeyLength;
|
||||
}
|
||||
@@ -272,21 +275,21 @@ namespace data
|
||||
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
|
||||
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
||||
publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub);
|
||||
break;
|
||||
break;
|
||||
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||
i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub);
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
break;
|
||||
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||
{
|
||||
uint8_t exp[64];
|
||||
i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp);
|
||||
uint8_t exp[64];
|
||||
i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp);
|
||||
i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub);
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType);
|
||||
LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
|
||||
}
|
||||
return publicKeyLength;
|
||||
}
|
||||
@@ -324,7 +327,7 @@ namespace data
|
||||
SHA256_Final ((uint8_t *)hash, &ctx);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Blinding: blinded key type ", (int)m_BlindedSigType, " is not supported");
|
||||
LogPrint (eLogError, "Blinding: Blinded key type ", (int)m_BlindedSigType, " is not supported");
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -61,7 +61,7 @@ namespace config {
|
||||
("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)")
|
||||
("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)")
|
||||
("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)")
|
||||
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
||||
("bandwidth", value<std::string>()->default_value(""), "Transit traffic bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
|
||||
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
|
||||
("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
|
||||
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
|
||||
@@ -109,6 +109,8 @@ namespace config {
|
||||
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
|
||||
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
|
||||
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
|
||||
("httpproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy inbound tunnels length variance")
|
||||
("httpproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy outbound tunnels length variance")
|
||||
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels")
|
||||
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
|
||||
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
|
||||
@@ -130,6 +132,8 @@ namespace config {
|
||||
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
|
||||
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
|
||||
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
|
||||
("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy inbound tunnels length variance")
|
||||
("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy outbound tunnels length variance")
|
||||
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels")
|
||||
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels")
|
||||
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy")
|
||||
@@ -203,19 +207,24 @@ namespace config {
|
||||
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
|
||||
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
|
||||
("reseed.urls", value<std::string>()->default_value(
|
||||
"https://reseed.i2p-projekt.de/,"
|
||||
"https://reseed2.i2p.net/,"
|
||||
"https://reseed.diva.exchange/,"
|
||||
"https://reseed-fr.i2pd.xyz/,"
|
||||
"https://reseed.memcpy.io/,"
|
||||
"https://reseed.onion.im/,"
|
||||
"https://i2pseed.creativecowpat.net:8443/,"
|
||||
"https://reseed.i2pgit.org/,"
|
||||
"https://i2p.novg.net/"
|
||||
"https://i2p.novg.net/,"
|
||||
"https://banana.incognet.io/,"
|
||||
"https://reseed-pl.i2pd.xyz/,"
|
||||
"https://www2.mk16.de/"
|
||||
), "Reseed URLs, separated by comma")
|
||||
("reseed.yggurls", value<std::string>()->default_value(
|
||||
"http://[324:71e:281a:9ed3::ace]:7070/,"
|
||||
"http://[301:65b9:c7cd:9a36::1]:18801/,"
|
||||
"http://[320:8936:ec1a:31f1::216]/"
|
||||
"http://[301:65b9:c7cd:9a36::1]:18801/,"
|
||||
"http://[320:8936:ec1a:31f1::216]/,"
|
||||
"http://[306:3834:97b9:a00a::1]/,"
|
||||
"http://[316:f9e0:f22e:a74f::216]/"
|
||||
), "Reseed URLs through the Yggdrasil, separated by comma")
|
||||
;
|
||||
|
||||
@@ -224,7 +233,9 @@ namespace config {
|
||||
("addressbook.defaulturl", value<std::string>()->default_value(
|
||||
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
|
||||
), "AddressBook subscription URL for initial setup")
|
||||
("addressbook.subscriptions", value<std::string>()->default_value("http://reg.i2p/hosts.txt"), "AddressBook subscriptions URLs, separated by comma")
|
||||
("addressbook.subscriptions", value<std::string>()->default_value(
|
||||
"http://reg.i2p/hosts.txt"
|
||||
), "AddressBook subscriptions URLs, separated by comma")
|
||||
("addressbook.hostsfile", value<std::string>()->default_value(""), "File to dump addresses in hosts.txt format");
|
||||
|
||||
options_description trust("Trust options");
|
||||
@@ -260,6 +271,13 @@ namespace config {
|
||||
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
|
||||
;
|
||||
|
||||
options_description ssu2("SSU2 Options");
|
||||
ntcp2.add_options()
|
||||
("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)")
|
||||
("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)")
|
||||
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)")
|
||||
;
|
||||
|
||||
options_description nettime("Time sync options");
|
||||
nettime.add_options()
|
||||
("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
|
||||
@@ -268,8 +286,9 @@ namespace config {
|
||||
"1.pool.ntp.org,"
|
||||
"2.pool.ntp.org,"
|
||||
"3.pool.ntp.org"
|
||||
), "Comma separated list of NTCP servers")
|
||||
), "Comma separated list of NTP servers")
|
||||
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)")
|
||||
("nettime.frompeers", value<bool>()->default_value(true), "Sync clock from transport peers (default: enabled)")
|
||||
;
|
||||
|
||||
options_description persist("Network information persisting options");
|
||||
@@ -309,6 +328,7 @@ namespace config {
|
||||
.add(websocket) // deprecated
|
||||
.add(exploratory)
|
||||
.add(ntcp2)
|
||||
.add(ssu2)
|
||||
.add(nettime)
|
||||
.add(persist)
|
||||
.add(cpuext)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -389,7 +389,7 @@ namespace crypto
|
||||
{
|
||||
size_t len = 32;
|
||||
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
|
||||
}
|
||||
}
|
||||
#else
|
||||
memcpy (m_PrivateKey, priv, 32);
|
||||
if (calculatePublic)
|
||||
@@ -398,8 +398,9 @@ namespace crypto
|
||||
}
|
||||
|
||||
// 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 = BN_CTX_new ();
|
||||
BN_CTX_start (ctx);
|
||||
// everything, but a, because a might come from table
|
||||
BIGNUM * k = BN_CTX_get (ctx);
|
||||
@@ -435,37 +436,32 @@ namespace crypto
|
||||
BN_bin2bn (m, 255, b);
|
||||
BN_mod_mul (b, b1, b, elgp, ctx);
|
||||
// copy a and b
|
||||
if (zeroPadding)
|
||||
{
|
||||
encrypted[0] = 0;
|
||||
bn2buf (a, encrypted + 1, 256);
|
||||
encrypted[257] = 0;
|
||||
bn2buf (b, encrypted + 258, 256);
|
||||
}
|
||||
else
|
||||
{
|
||||
bn2buf (a, encrypted, 256);
|
||||
bn2buf (b, encrypted + 256, 256);
|
||||
}
|
||||
encrypted[0] = 0;
|
||||
bn2buf (a, encrypted + 1, 256);
|
||||
encrypted[257] = 0;
|
||||
bn2buf (b, encrypted + 258, 256);
|
||||
|
||||
BN_free (a);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted,
|
||||
uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * x = BN_CTX_get (ctx), * a = BN_CTX_get (ctx), * b = BN_CTX_get (ctx);
|
||||
BN_bin2bn (key, 256, x);
|
||||
BN_sub (x, elgp, x); BN_sub_word (x, 1); // x = elgp - x- 1
|
||||
BN_bin2bn (zeroPadding ? encrypted + 1 : encrypted, 256, a);
|
||||
BN_bin2bn (zeroPadding ? encrypted + 258 : encrypted + 256, 256, b);
|
||||
BN_bin2bn (encrypted + 1, 256, a);
|
||||
BN_bin2bn (encrypted + 258, 256, b);
|
||||
// m = b*(a^x mod p) mod p
|
||||
BN_mod_exp (x, a, x, elgp, ctx);
|
||||
BN_mod_mul (b, b, x, elgp, ctx);
|
||||
uint8_t m[255];
|
||||
bn2buf (b, m, 255);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
uint8_t hash[32];
|
||||
SHA256 (m + 33, 222, hash);
|
||||
if (memcmp (m + 1, hash, 32))
|
||||
@@ -499,8 +495,9 @@ namespace crypto
|
||||
}
|
||||
|
||||
// ECIES
|
||||
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * q = BN_CTX_get (ctx);
|
||||
EC_GROUP_get_order(curve, q, ctx);
|
||||
@@ -512,19 +509,10 @@ namespace crypto
|
||||
EC_POINT_mul (curve, p, k, nullptr, nullptr, ctx);
|
||||
BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx);
|
||||
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
|
||||
if (zeroPadding)
|
||||
{
|
||||
encrypted[0] = 0;
|
||||
bn2buf (x, encrypted + 1, len);
|
||||
bn2buf (y, encrypted + 1 + len, len);
|
||||
RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len);
|
||||
}
|
||||
else
|
||||
{
|
||||
bn2buf (x, encrypted, len);
|
||||
bn2buf (y, encrypted + len, len);
|
||||
RAND_bytes (encrypted + 2*len, 256 - 2*len);
|
||||
}
|
||||
encrypted[0] = 0;
|
||||
bn2buf (x, encrypted + 1, len);
|
||||
bn2buf (y, encrypted + 1 + len, len);
|
||||
RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len);
|
||||
// encryption key and iv
|
||||
EC_POINT_mul (curve, p, nullptr, key, k, ctx);
|
||||
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
|
||||
@@ -541,36 +529,25 @@ namespace crypto
|
||||
CBCEncryption encryption;
|
||||
encryption.SetKey (shared);
|
||||
encryption.SetIV (iv);
|
||||
if (zeroPadding)
|
||||
{
|
||||
encrypted[257] = 0;
|
||||
encryption.Encrypt (m, 256, encrypted + 258);
|
||||
}
|
||||
else
|
||||
encryption.Encrypt (m, 256, encrypted + 256);
|
||||
encrypted[257] = 0;
|
||||
encryption.Encrypt (m, 256, encrypted + 258);
|
||||
EC_POINT_free (p);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
bool ret = true;
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * q = BN_CTX_get (ctx);
|
||||
EC_GROUP_get_order(curve, q, ctx);
|
||||
int len = BN_num_bytes (q);
|
||||
// point for shared secret
|
||||
BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx);
|
||||
if (zeroPadding)
|
||||
{
|
||||
BN_bin2bn (encrypted + 1, len, x);
|
||||
BN_bin2bn (encrypted + 1 + len, len, y);
|
||||
}
|
||||
else
|
||||
{
|
||||
BN_bin2bn (encrypted, len, x);
|
||||
BN_bin2bn (encrypted + len, len, y);
|
||||
}
|
||||
BN_bin2bn (encrypted + 1, len, x);
|
||||
BN_bin2bn (encrypted + 1 + len, len, y);
|
||||
auto p = EC_POINT_new (curve);
|
||||
if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr))
|
||||
{
|
||||
@@ -587,10 +564,7 @@ namespace crypto
|
||||
CBCDecryption decryption;
|
||||
decryption.SetKey (shared);
|
||||
decryption.SetIV (iv);
|
||||
if (zeroPadding)
|
||||
decryption.Decrypt (encrypted + 258, 256, m);
|
||||
else
|
||||
decryption.Decrypt (encrypted + 256, 256, m);
|
||||
decryption.Decrypt (encrypted + 258, 256, m);
|
||||
// verify and copy
|
||||
uint8_t hash[32];
|
||||
SHA256 (m + 33, 222, hash);
|
||||
@@ -610,6 +584,7 @@ namespace crypto
|
||||
|
||||
EC_POINT_free (p);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1302,7 +1277,7 @@ namespace crypto
|
||||
EVP_PKEY_CTX_set1_hkdf_key (pctx, tempKey, len);
|
||||
}
|
||||
if (info.length () > 0)
|
||||
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ());
|
||||
EVP_PKEY_CTX_add1_hkdf_info (pctx, (const uint8_t *)info.c_str (), info.length ());
|
||||
EVP_PKEY_derive (pctx, out, &outLen);
|
||||
EVP_PKEY_CTX_free (pctx);
|
||||
#else
|
||||
@@ -1320,7 +1295,7 @@ namespace crypto
|
||||
}
|
||||
|
||||
// Noise
|
||||
|
||||
|
||||
void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
@@ -1330,13 +1305,23 @@ namespace crypto
|
||||
SHA256_Final (m_H, &ctx);
|
||||
}
|
||||
|
||||
void NoiseSymmetricState::MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init (&ctx);
|
||||
SHA256_Update (&ctx, m_H, 32);
|
||||
for (const auto& it: bufs)
|
||||
SHA256_Update (&ctx, it.first, it.second);
|
||||
SHA256_Final (m_H, &ctx);
|
||||
}
|
||||
|
||||
void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret)
|
||||
{
|
||||
HKDF (m_CK, sharedSecret, 32, "", m_CK);
|
||||
// new ck is m_CK[0:31], key is m_CK[32:63]
|
||||
}
|
||||
|
||||
static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck,
|
||||
static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck,
|
||||
const uint8_t * hh, const uint8_t * pub)
|
||||
{
|
||||
// pub is Bob's public static key, hh = SHA256(h)
|
||||
@@ -1346,22 +1331,22 @@ namespace crypto
|
||||
SHA256_Update (&ctx, hh, 32);
|
||||
SHA256_Update (&ctx, pub, 32);
|
||||
SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub)
|
||||
{
|
||||
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
|
||||
static const uint8_t hh[32] =
|
||||
{
|
||||
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1,
|
||||
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1,
|
||||
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54
|
||||
}; // hh = SHA256(protocol_name || 0)
|
||||
InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub)
|
||||
{
|
||||
static const uint8_t protocolNameHash[] =
|
||||
static const uint8_t protocolNameHash[32] =
|
||||
{
|
||||
0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed,
|
||||
0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71
|
||||
@@ -1371,9 +1356,24 @@ namespace crypto
|
||||
0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5,
|
||||
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e
|
||||
}; // SHA256 (protocolNameHash)
|
||||
InitNoiseState (state, protocolNameHash, hh, pub);
|
||||
}
|
||||
InitNoiseState (state, protocolNameHash, hh, pub);
|
||||
}
|
||||
|
||||
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub)
|
||||
{
|
||||
static const uint8_t protocolNameHash[32] =
|
||||
{
|
||||
0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed, 0xf4,
|
||||
0x1b, 0x93, 0x07, 0x1d, 0xb1, 0xec, 0x24, 0xa3, 0x67, 0xf7, 0x84, 0xec, 0x27, 0x0d, 0x81, 0x32
|
||||
}; // SHA256 ("Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256")
|
||||
static const uint8_t hh[32] =
|
||||
{
|
||||
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53,
|
||||
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33
|
||||
}; // SHA256 (protocolNameHash)
|
||||
InitNoiseState (state, protocolNameHash, hh, pub);
|
||||
}
|
||||
|
||||
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub)
|
||||
{
|
||||
static const uint8_t protocolNameHash[32] =
|
||||
@@ -1386,9 +1386,9 @@ namespace crypto
|
||||
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32,
|
||||
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c
|
||||
}; // SHA256 (protocolNameHash)
|
||||
InitNoiseState (state, protocolNameHash, hh, pub);
|
||||
}
|
||||
|
||||
InitNoiseState (state, protocolNameHash, hh, pub);
|
||||
}
|
||||
|
||||
// init and terminate
|
||||
|
||||
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -39,7 +39,9 @@
|
||||
# define OPENSSL_HKDF 1
|
||||
# define OPENSSL_EDDSA 1
|
||||
# define OPENSSL_X25519 1
|
||||
# define OPENSSL_SIPHASH 1
|
||||
# if (OPENSSL_VERSION_NUMBER < 0x030000000) // 3.0.0, regression in SipHash
|
||||
# define OPENSSL_SIPHASH 1
|
||||
# endif
|
||||
# endif
|
||||
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
|
||||
# define OPENSSL_AEAD_CHACHA20_POLY1305 1
|
||||
@@ -93,7 +95,7 @@ namespace crypto
|
||||
|
||||
bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
|
||||
void SetElligatorIneligible () { m_IsElligatorIneligible = true; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_PublicKey[32];
|
||||
@@ -104,17 +106,17 @@ namespace crypto
|
||||
BN_CTX * m_Ctx;
|
||||
uint8_t m_PrivateKey[32];
|
||||
#endif
|
||||
bool m_IsElligatorIneligible = false; // true if definitly ineligible
|
||||
bool m_IsElligatorIneligible = false; // true if definitely ineligible
|
||||
};
|
||||
|
||||
// ElGamal
|
||||
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false);
|
||||
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
|
||||
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted
|
||||
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
|
||||
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);
|
||||
|
||||
// ECIES
|
||||
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false); // 222 bytes data, 514 bytes encrypted with zeropadding, 512 without
|
||||
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
|
||||
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted
|
||||
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
|
||||
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
|
||||
|
||||
// HMAC
|
||||
@@ -315,13 +317,15 @@ namespace crypto
|
||||
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
|
||||
|
||||
void MixHash (const uint8_t * buf, size_t len);
|
||||
void MixKey (const uint8_t * sharedSecret);
|
||||
void MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs);
|
||||
void MixKey (const uint8_t * sharedSecret);
|
||||
};
|
||||
|
||||
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router)
|
||||
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
|
||||
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2)
|
||||
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
|
||||
|
||||
|
||||
// init and terminate
|
||||
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
|
||||
void TerminateCrypto ();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -20,10 +20,9 @@ namespace crypto
|
||||
memcpy (m_PublicKey, pub, 256);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!ctx) return;
|
||||
ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||
ElGamalEncrypt (m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv)
|
||||
@@ -31,10 +30,9 @@ namespace crypto
|
||||
memcpy (m_PrivateKey, priv, 256);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!ctx) return false;
|
||||
return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||
return ElGamalDecrypt (m_PrivateKey, encrypted, data);
|
||||
}
|
||||
|
||||
ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub)
|
||||
@@ -54,10 +52,10 @@ namespace crypto
|
||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||
}
|
||||
|
||||
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted)
|
||||
{
|
||||
if (m_Curve && m_PublicKey)
|
||||
ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||
ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv)
|
||||
@@ -72,10 +70,10 @@ namespace crypto
|
||||
if (m_PrivateKey) BN_free (m_PrivateKey);
|
||||
}
|
||||
|
||||
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
if (m_Curve && m_PrivateKey)
|
||||
return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||
return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -114,10 +112,10 @@ namespace crypto
|
||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||
}
|
||||
|
||||
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted)
|
||||
{
|
||||
if (m_PublicKey)
|
||||
ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx, zeroPadding);
|
||||
ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv)
|
||||
@@ -130,10 +128,10 @@ namespace crypto
|
||||
if (m_PrivateKey) BN_free (m_PrivateKey);
|
||||
}
|
||||
|
||||
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding)
|
||||
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
if (m_PrivateKey)
|
||||
return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx, zeroPadding);
|
||||
return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -161,7 +159,7 @@ namespace crypto
|
||||
memcpy (m_PublicKey, pub, 32);
|
||||
}
|
||||
|
||||
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool)
|
||||
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub)
|
||||
{
|
||||
memcpy (pub, m_PublicKey, 32);
|
||||
}
|
||||
@@ -171,7 +169,7 @@ namespace crypto
|
||||
m_StaticKeys.SetPrivateKey (priv, calculatePublic);
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
|
||||
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret)
|
||||
{
|
||||
return m_StaticKeys.Agree (epub, sharedSecret);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -21,7 +21,7 @@ namespace crypto
|
||||
public:
|
||||
|
||||
virtual ~CryptoKeyEncryptor () {};
|
||||
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) = 0; // 222 bytes data, 512/514 bytes encrypted
|
||||
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted) = 0;
|
||||
};
|
||||
|
||||
class CryptoKeyDecryptor
|
||||
@@ -29,7 +29,7 @@ namespace crypto
|
||||
public:
|
||||
|
||||
virtual ~CryptoKeyDecryptor () {};
|
||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding) = 0; // 512/514 bytes encrypted, 222 bytes data
|
||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data) = 0;
|
||||
virtual size_t GetPublicKeyLen () const = 0; // we need it to set key in LS2
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace crypto
|
||||
public:
|
||||
|
||||
ElGamalEncryptor (const uint8_t * pub);
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) override; // 222 bytes data, 514 bytes encrypted
|
||||
|
||||
private:
|
||||
|
||||
@@ -51,8 +51,8 @@ namespace crypto
|
||||
public:
|
||||
|
||||
ElGamalDecryptor (const uint8_t * priv);
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
|
||||
size_t GetPublicKeyLen () const { return 256; };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data) override; // 514 bytes encrypted, 222 bytes data
|
||||
size_t GetPublicKeyLen () const override { return 256; };
|
||||
|
||||
private:
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace crypto
|
||||
|
||||
ECIESP256Encryptor (const uint8_t * pub);
|
||||
~ECIESP256Encryptor ();
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -82,8 +82,8 @@ namespace crypto
|
||||
|
||||
ECIESP256Decryptor (const uint8_t * priv);
|
||||
~ECIESP256Decryptor ();
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
|
||||
size_t GetPublicKeyLen () const { return 64; };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data) override;
|
||||
size_t GetPublicKeyLen () const override { return 64; };
|
||||
|
||||
private:
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace crypto
|
||||
|
||||
ECIESGOSTR3410Encryptor (const uint8_t * pub);
|
||||
~ECIESGOSTR3410Encryptor ();
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding);
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -115,8 +115,8 @@ namespace crypto
|
||||
|
||||
ECIESGOSTR3410Decryptor (const uint8_t * priv);
|
||||
~ECIESGOSTR3410Decryptor ();
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
|
||||
size_t GetPublicKeyLen () const { return 64; };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data) override;
|
||||
size_t GetPublicKeyLen () const override { return 64; };
|
||||
|
||||
private:
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace crypto
|
||||
|
||||
ECIESX25519AEADRatchetEncryptor (const uint8_t * pub);
|
||||
~ECIESX25519AEADRatchetEncryptor () {};
|
||||
void Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool);
|
||||
void Encrypt (const uint8_t *, uint8_t * pub) override;
|
||||
// copies m_PublicKey to pub
|
||||
|
||||
private:
|
||||
@@ -147,9 +147,9 @@ namespace crypto
|
||||
|
||||
ECIESX25519AEADRatchetDecryptor (const uint8_t * priv, bool calculatePublic = false);
|
||||
~ECIESX25519AEADRatchetDecryptor () {};
|
||||
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
|
||||
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret) override;
|
||||
// agree with static and return in sharedSecret (32 bytes)
|
||||
size_t GetPublicKeyLen () const { return 32; };
|
||||
size_t GetPublicKeyLen () const override { return 32; };
|
||||
const uint8_t * GetPubicKey () const { return m_StaticKeys.GetPublicKey (); };
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -21,6 +21,9 @@ namespace datagram
|
||||
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip):
|
||||
m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip)
|
||||
{
|
||||
if (m_Gzip)
|
||||
m_Deflator.reset (new i2p::data::GzipDeflator);
|
||||
|
||||
auto identityLen = m_Owner->GetIdentity ()->GetFullLen ();
|
||||
m_From.resize (identityLen);
|
||||
m_Owner->GetIdentity ()->ToBuffer (m_From.data (), identityLen);
|
||||
@@ -152,11 +155,16 @@ namespace datagram
|
||||
const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
|
||||
uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum)
|
||||
{
|
||||
size_t size;
|
||||
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
buf += 4; // reserve for length
|
||||
size_t size = m_Gzip ? m_Deflator.Deflate (payloads, buf, msg->maxLen - msg->len) :
|
||||
i2p::data::GzipNoCompression (payloads, buf, msg->maxLen - msg->len);
|
||||
|
||||
if (m_Gzip && m_Deflator)
|
||||
size = m_Deflator->Deflate (payloads, buf, msg->maxLen - msg->len);
|
||||
else
|
||||
size = i2p::data::GzipNoCompression (payloads, buf, msg->maxLen - msg->len);
|
||||
|
||||
if (size)
|
||||
{
|
||||
htobe32buf (msg->GetPayload (), size); // length
|
||||
@@ -295,7 +303,7 @@ namespace datagram
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ())
|
||||
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ())
|
||||
{
|
||||
bool found = false;
|
||||
for (auto& it: m_PendingRoutingSessions)
|
||||
@@ -363,8 +371,6 @@ namespace datagram
|
||||
{
|
||||
// no current path, make one
|
||||
path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
|
||||
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel();
|
||||
if (!path->outboundTunnel) return nullptr;
|
||||
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
@@ -378,6 +384,11 @@ namespace datagram
|
||||
}
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
auto leaseRouter = i2p::data::netdb.FindRouter (path->remoteLease->tunnelGateway);
|
||||
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr,
|
||||
leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports);
|
||||
if (!path->outboundTunnel) return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -117,12 +117,12 @@ namespace datagram
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
// TODO: implement calls from other thread from SAM
|
||||
|
||||
|
||||
std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash & ident);
|
||||
void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||
void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
|
||||
void FlushSendQueue (std::shared_ptr<DatagramSession> session);
|
||||
|
||||
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
||||
|
||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||
@@ -164,7 +164,7 @@ namespace datagram
|
||||
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
|
||||
i2p::data::GzipInflator m_Inflator;
|
||||
i2p::data::GzipDeflator m_Deflator;
|
||||
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
|
||||
std::vector<uint8_t> m_From, m_Signature;
|
||||
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -35,6 +35,8 @@ namespace client
|
||||
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY;
|
||||
int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
|
||||
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
|
||||
int inVar = DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE;
|
||||
int outVar = DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE;
|
||||
int numTags = DEFAULT_TAGS_TO_SEND;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
|
||||
try
|
||||
@@ -53,10 +55,16 @@ namespace client
|
||||
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
|
||||
if (it != params->end ())
|
||||
outQty = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE);
|
||||
if (it != params->end ())
|
||||
inVar = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE);
|
||||
if (it != params->end ())
|
||||
outVar = std::stoi(it->second);
|
||||
it = params->find (I2CP_PARAM_TAGS_TO_SEND);
|
||||
if (it != params->end ())
|
||||
numTags = std::stoi(it->second);
|
||||
LogPrint (eLogInfo, "Destination: parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags");
|
||||
LogPrint (eLogInfo, "Destination: Parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags");
|
||||
it = params->find (I2CP_PARAM_RATCHET_INBOUND_TAGS);
|
||||
if (it != params->end ())
|
||||
SetNumRatchetInboundTags (std::stoi(it->second));
|
||||
@@ -89,7 +97,7 @@ namespace client
|
||||
bool dontpublish = false;
|
||||
i2p::config::GetOption (it->second, dontpublish);
|
||||
m_IsPublic = !dontpublish;
|
||||
}
|
||||
}
|
||||
it = params->find (I2CP_PARAM_LEASESET_TYPE);
|
||||
if (it != params->end ())
|
||||
m_LeaseSetType = std::stoi(it->second);
|
||||
@@ -112,7 +120,7 @@ namespace client
|
||||
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
|
||||
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
|
||||
{
|
||||
LogPrint(eLogError, "Destination: invalid value i2cp.leaseSetPrivKey ", it->second);
|
||||
LogPrint(eLogError, "Destination: Invalid value i2cp.leaseSetPrivKey ", it->second);
|
||||
m_LeaseSetPrivKey.reset (nullptr);
|
||||
}
|
||||
}
|
||||
@@ -120,10 +128,10 @@ namespace client
|
||||
}
|
||||
catch (std::exception & ex)
|
||||
{
|
||||
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
|
||||
LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
|
||||
}
|
||||
SetNumTags (numTags);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty);
|
||||
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty, inVar, outVar);
|
||||
if (explicitPeers)
|
||||
m_Pool->SetExplicitPeers (explicitPeers);
|
||||
if(params)
|
||||
@@ -136,7 +144,7 @@ namespace client
|
||||
auto minlatency = std::stoi(itr->second);
|
||||
if ( minlatency > 0 && maxlatency > 0 ) {
|
||||
// set tunnel pool latency
|
||||
LogPrint(eLogInfo, "Destination: requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]");
|
||||
LogPrint(eLogInfo, "Destination: Requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]");
|
||||
m_Pool->RequireLatency(minlatency, maxlatency);
|
||||
}
|
||||
}
|
||||
@@ -251,7 +259,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: remote LeaseSet expired");
|
||||
LogPrint (eLogWarning, "Destination: Remote LeaseSet expired");
|
||||
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
||||
m_RemoteLeaseSets.erase (ident);
|
||||
return nullptr;
|
||||
@@ -331,6 +339,22 @@ namespace client
|
||||
return true;
|
||||
}
|
||||
|
||||
void LeaseSetDestination::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t k[32];
|
||||
uint64_t t;
|
||||
} data;
|
||||
memcpy (data.k, key, 32);
|
||||
data.t = tag;
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([s,data](void)
|
||||
{
|
||||
s->AddECIESx25519Key (data.k, data.t);
|
||||
});
|
||||
}
|
||||
|
||||
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg));
|
||||
@@ -367,8 +391,8 @@ namespace client
|
||||
HandleDatabaseSearchReplyMessage (payload, len);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply: // might come as garlic encrypted
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID));
|
||||
break;
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID));
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID);
|
||||
return false;
|
||||
@@ -395,7 +419,7 @@ namespace client
|
||||
LogPrint (eLogDebug, "Destination: Remote LeaseSet");
|
||||
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
|
||||
auto it = m_RemoteLeaseSets.find (key);
|
||||
if (it != m_RemoteLeaseSets.end () &&
|
||||
if (it != m_RemoteLeaseSets.end () &&
|
||||
it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type
|
||||
{
|
||||
leaseSet = it->second;
|
||||
@@ -487,7 +511,7 @@ namespace client
|
||||
i2p::data::IdentHash peerHash (buf + 33 + i*32);
|
||||
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
|
||||
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
|
||||
}
|
||||
}
|
||||
@@ -555,16 +579,9 @@ namespace client
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
return;
|
||||
}
|
||||
auto outbound = m_Pool->GetNextOutboundTunnel ();
|
||||
if (!outbound)
|
||||
if (!m_Pool->GetInboundTunnels ().size () || !m_Pool->GetOutboundTunnels ().size ())
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
|
||||
return;
|
||||
}
|
||||
auto inbound = m_Pool->GetNextInboundTunnel ();
|
||||
if (!inbound)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. Destination is not ready");
|
||||
return;
|
||||
}
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||
@@ -573,7 +590,34 @@ namespace client
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
m_ExcludedFloodfills.clear ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
|
||||
auto inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
|
||||
if (!outbound || !inbound)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill");
|
||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||
floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
|
||||
if (floodfill)
|
||||
{
|
||||
outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
|
||||
if (outbound)
|
||||
{
|
||||
inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
|
||||
if (!inbound)
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
|
||||
if (!floodfill || !outbound || !inbound)
|
||||
{
|
||||
m_ExcludedFloodfills.clear ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
|
||||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||
@@ -618,7 +662,7 @@ namespace client
|
||||
auto ls = GetLeaseSetMt ();
|
||||
if (!ls)
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: couldn't verify LeaseSet for ", GetIdentHash().ToBase32());
|
||||
LogPrint (eLogWarning, "Destination: Couldn't verify LeaseSet for ", GetIdentHash().ToBase32());
|
||||
return;
|
||||
}
|
||||
auto s = shared_from_this ();
|
||||
@@ -630,7 +674,7 @@ namespace client
|
||||
if (*ls == *leaseSet)
|
||||
{
|
||||
// we got latest LeasetSet
|
||||
LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", s->GetIdentHash().ToBase32());
|
||||
LogPrint (eLogDebug, "Destination: Published LeaseSet verified for ", s->GetIdentHash().ToBase32());
|
||||
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
|
||||
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
|
||||
return;
|
||||
@@ -639,7 +683,7 @@ namespace client
|
||||
LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", s->GetIdentHash().ToBase32());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", s->GetIdentHash().ToBase32());
|
||||
LogPrint (eLogWarning, "Destination: Couldn't find published LeaseSet for ", s->GetIdentHash().ToBase32());
|
||||
// we have to publish again
|
||||
s->Publish ();
|
||||
});
|
||||
@@ -751,10 +795,10 @@ namespace client
|
||||
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
|
||||
{
|
||||
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
|
||||
request->replyTunnel = m_Pool->GetNextInboundTunnel ();
|
||||
request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true));
|
||||
if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
|
||||
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
|
||||
request->outboundTunnel = m_Pool->GetNextOutboundTunnel ();
|
||||
request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false));
|
||||
if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
|
||||
|
||||
if (request->replyTunnel && request->outboundTunnel)
|
||||
@@ -767,11 +811,11 @@ namespace client
|
||||
uint8_t replyKey[32], replyTag[32];
|
||||
RAND_bytes (replyKey, 32); // random session key
|
||||
RAND_bytes (replyTag, isECIES ? 8 : 32); // random session tag
|
||||
if (isECIES)
|
||||
if (isECIES)
|
||||
AddECIESx25519Key (replyKey, replyTag);
|
||||
else
|
||||
else
|
||||
AddSessionKey (replyKey, replyTag);
|
||||
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
|
||||
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
|
||||
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
|
||||
request->outboundTunnel->SendTunnelDataMsg (
|
||||
{
|
||||
@@ -866,8 +910,8 @@ namespace client
|
||||
|
||||
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),
|
||||
LeaseSetDestination (service, isPublic, params),
|
||||
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
|
||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
||||
m_ReadyChecker(service)
|
||||
@@ -916,11 +960,11 @@ namespace client
|
||||
encryptionKey->GenerateKeys ();
|
||||
encryptionKey->CreateDecryptor ();
|
||||
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||
{
|
||||
{
|
||||
m_ECIESx25519EncryptionKey.reset (encryptionKey);
|
||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2
|
||||
}
|
||||
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2
|
||||
}
|
||||
else
|
||||
m_StandardEncryptionKey.reset (encryptionKey);
|
||||
}
|
||||
@@ -939,7 +983,7 @@ namespace client
|
||||
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
|
||||
if (it != params->end ())
|
||||
i2p::config::GetOption (it->second, m_IsStreamingAnswerPings);
|
||||
|
||||
|
||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
|
||||
{
|
||||
// authentication for encrypted LeaseSet
|
||||
@@ -966,7 +1010,7 @@ namespace client
|
||||
}
|
||||
catch (std::exception & ex)
|
||||
{
|
||||
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
|
||||
LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1042,7 +1086,7 @@ namespace client
|
||||
LogPrint (eLogError, "Destination: Missing raw datagram destination");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
|
||||
LogPrint (eLogError, "Destination: Data: Unexpected protocol ", buf[9]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,7 +1094,7 @@ namespace client
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream");
|
||||
LogPrint (eLogError, "Destination: Request callback is not specified in CreateStream");
|
||||
return;
|
||||
}
|
||||
auto leaseSet = FindLeaseSet (dest);
|
||||
@@ -1074,7 +1118,7 @@ namespace client
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream");
|
||||
LogPrint (eLogError, "Destination: Request callback is not specified in CreateStream");
|
||||
return;
|
||||
}
|
||||
auto s = GetSharedFromThis ();
|
||||
@@ -1096,6 +1140,35 @@ namespace client
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClientDestination::SendPing (const i2p::data::IdentHash& to)
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
{
|
||||
auto leaseSet = FindLeaseSet (to);
|
||||
if (leaseSet)
|
||||
m_StreamingDestination->SendPing (leaseSet);
|
||||
else
|
||||
{
|
||||
auto s = m_StreamingDestination;
|
||||
RequestDestination (to,
|
||||
[s](std::shared_ptr<const i2p::data::LeaseSet> ls)
|
||||
{
|
||||
if (ls) s->SendPing (ls);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientDestination::SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to)
|
||||
{
|
||||
auto s = m_StreamingDestination;
|
||||
RequestDestinationWithEncryptedLeaseSet (to,
|
||||
[s](std::shared_ptr<const i2p::data::LeaseSet> ls)
|
||||
{
|
||||
if (ls) s->SendPing (ls);
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
|
||||
{
|
||||
if (port)
|
||||
@@ -1153,18 +1226,18 @@ namespace client
|
||||
auto ret = it->second;
|
||||
m_StreamingDestinationsByPorts.erase (it);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip)
|
||||
{
|
||||
if (m_DatagramDestination == nullptr)
|
||||
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip);
|
||||
return m_DatagramDestination;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const
|
||||
{
|
||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > ret;
|
||||
@@ -1245,15 +1318,15 @@ namespace client
|
||||
if (m_DatagramDestination) m_DatagramDestination->CleanUp ();
|
||||
}
|
||||
|
||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
{
|
||||
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||
if (m_ECIESx25519EncryptionKey && m_ECIESx25519EncryptionKey->decryptor)
|
||||
return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true);
|
||||
return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data);
|
||||
if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor)
|
||||
return m_StandardEncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true);
|
||||
return m_StandardEncryptionKey->decryptor->Decrypt (encrypted, data);
|
||||
else
|
||||
LogPrint (eLogError, "Destinations: decryptor is not set");
|
||||
LogPrint (eLogError, "Destinations: Decryptor is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -53,6 +53,10 @@ namespace client
|
||||
const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5;
|
||||
const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity";
|
||||
const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5;
|
||||
const char I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE[] = "inbound.lengthVariance";
|
||||
const int DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE = 0;
|
||||
const char I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE[] = "outbound.lengthVariance";
|
||||
const int DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE = 0;
|
||||
const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers";
|
||||
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
|
||||
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
|
||||
@@ -68,8 +72,8 @@ namespace client
|
||||
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
|
||||
|
||||
const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn
|
||||
|
||||
// latency
|
||||
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
|
||||
const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
|
||||
@@ -80,7 +84,7 @@ namespace client
|
||||
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
|
||||
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
|
||||
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
|
||||
const int DEFAULT_ANSWER_PINGS = true;
|
||||
const int DEFAULT_ANSWER_PINGS = true;
|
||||
|
||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||
|
||||
@@ -134,11 +138,13 @@ namespace client
|
||||
|
||||
// override GarlicDestination
|
||||
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
||||
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag);
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void SetLeaseSetUpdated ();
|
||||
|
||||
bool IsPublic () const { return m_IsPublic; };
|
||||
void SetPublic (bool pub) { m_IsPublic = pub; };
|
||||
|
||||
protected:
|
||||
|
||||
@@ -242,19 +248,21 @@ namespace client
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||
void SendPing (const i2p::data::IdentHash& to);
|
||||
void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to);
|
||||
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||
void StopAcceptingStreams ();
|
||||
bool IsAcceptingStreams () const;
|
||||
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
|
||||
int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
|
||||
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
|
||||
|
||||
|
||||
// datagram
|
||||
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
|
||||
i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true);
|
||||
|
||||
// implements LocalDestination
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
|
||||
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const;
|
||||
@@ -311,5 +319,4 @@ namespace client
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -90,24 +90,24 @@ namespace garlic
|
||||
}
|
||||
|
||||
void RatchetTagSet::DeleteSymmKey (int index)
|
||||
{
|
||||
{
|
||||
m_ItermediateSymmKeys.erase (index);
|
||||
}
|
||||
|
||||
|
||||
void ReceiveRatchetTagSet::Expire ()
|
||||
{
|
||||
if (!m_ExpirationTimestamp)
|
||||
m_ExpirationTimestamp = i2p::util::GetSecondsSinceEpoch () + ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT;
|
||||
}
|
||||
|
||||
bool ReceiveRatchetTagSet::IsExpired (uint64_t ts) const
|
||||
{
|
||||
return m_ExpirationTimestamp && ts > m_ExpirationTimestamp;
|
||||
}
|
||||
|
||||
bool ReceiveRatchetTagSet::IsIndexExpired (int index) const
|
||||
{
|
||||
return index < m_TrimBehindIndex;
|
||||
bool ReceiveRatchetTagSet::IsExpired (uint64_t ts) const
|
||||
{
|
||||
return m_ExpirationTimestamp && ts > m_ExpirationTimestamp;
|
||||
}
|
||||
|
||||
bool ReceiveRatchetTagSet::IsIndexExpired (int index) const
|
||||
{
|
||||
return index < m_TrimBehindIndex;
|
||||
}
|
||||
|
||||
bool ReceiveRatchetTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index)
|
||||
@@ -115,21 +115,21 @@ namespace garlic
|
||||
auto session = GetSession ();
|
||||
if (!session) return false;
|
||||
return session->HandleNextMessage (buf, len, shared_from_this (), index);
|
||||
}
|
||||
}
|
||||
|
||||
SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
|
||||
ReceiveRatchetTagSet (nullptr), m_Destination (destination)
|
||||
{
|
||||
memcpy (m_Key, key, 32);
|
||||
Expire ();
|
||||
ReceiveRatchetTagSet (nullptr), m_Destination (destination)
|
||||
{
|
||||
memcpy (m_Key, key, 32);
|
||||
Expire ();
|
||||
}
|
||||
|
||||
|
||||
bool SymmetricKeyTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index)
|
||||
{
|
||||
if (len < 24) return false;
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12); // n = 0
|
||||
size_t offset = 8; // first 8 bytes is reply tag used as AD
|
||||
size_t offset = 8; // first 8 bytes is reply tag used as AD
|
||||
len -= 16; // poly1305
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len - offset, buf, 8, m_Key, nonce, buf + offset, len - offset, false)) // decrypt
|
||||
{
|
||||
@@ -137,33 +137,33 @@ namespace garlic
|
||||
return false;
|
||||
}
|
||||
// we assume 1 I2NP block with delivery type local
|
||||
if (offset + 3 > len)
|
||||
{
|
||||
if (offset + 3 > len)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Symmetric key tagset is too short ", len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (buf[offset] != eECIESx25519BlkGalicClove)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Symmetric key tagset unexpected block ", (int)buf[offset]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
auto size = bufbe16toh (buf + offset);
|
||||
offset += 2;
|
||||
if (offset + size > len)
|
||||
if (offset + size > len)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Symmetric key tagset block is too long ", size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_Destination)
|
||||
m_Destination->HandleECIESx25519GarlicClove (buf + offset, size);
|
||||
m_Destination->HandleECIESx25519GarlicClove (buf + offset, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS):
|
||||
GarlicRoutingSession (owner, true)
|
||||
{
|
||||
if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
|
||||
if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
|
||||
RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0;
|
||||
}
|
||||
|
||||
@@ -181,11 +181,11 @@ namespace garlic
|
||||
{
|
||||
bool ineligible = false;
|
||||
while (!ineligible)
|
||||
{
|
||||
{
|
||||
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||
ineligible = m_EphemeralKeys->IsElligatorIneligible ();
|
||||
if (!ineligible) // we haven't tried it yet
|
||||
{
|
||||
{
|
||||
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf))
|
||||
return true; // success
|
||||
// otherwise return back
|
||||
@@ -194,7 +194,7 @@ namespace garlic
|
||||
}
|
||||
else
|
||||
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
|
||||
}
|
||||
}
|
||||
// we still didn't find elligator eligible pair
|
||||
for (int i = 0; i < 25; i++)
|
||||
{
|
||||
@@ -208,7 +208,7 @@ namespace garlic
|
||||
// let NTCP2 use it
|
||||
m_EphemeralKeys->SetElligatorIneligible ();
|
||||
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (eLogError, "Garlic: Can't generate elligator eligible x25519 keys");
|
||||
return false;
|
||||
@@ -229,7 +229,7 @@ namespace garlic
|
||||
// we are Bob
|
||||
// KDF1
|
||||
i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk
|
||||
|
||||
|
||||
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: Can't decode elligator");
|
||||
@@ -239,11 +239,11 @@ namespace garlic
|
||||
MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
|
||||
|
||||
uint8_t sharedSecret[32];
|
||||
if (!GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk)
|
||||
if (!GetOwner ()->Decrypt (m_Aepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MixKey (sharedSecret);
|
||||
|
||||
// decrypt flags/static
|
||||
@@ -263,11 +263,11 @@ namespace garlic
|
||||
{
|
||||
// static key, fs is apk
|
||||
memcpy (m_RemoteStaticKey, fs, 32);
|
||||
if (!GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, apk)
|
||||
if (!GetOwner ()->Decrypt (fs, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, apk)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MixKey (sharedSecret);
|
||||
}
|
||||
else // all zeros flags
|
||||
@@ -280,13 +280,13 @@ namespace garlic
|
||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
m_State = eSessionStateNewSessionReceived;
|
||||
if (isStatic)
|
||||
{
|
||||
if (isStatic)
|
||||
{
|
||||
MixHash (buf, len); // h = SHA256(h || ciphertext)
|
||||
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
||||
}
|
||||
}
|
||||
HandlePayload (payload.data (), len - 16, nullptr, 0);
|
||||
|
||||
return true;
|
||||
@@ -314,7 +314,7 @@ namespace garlic
|
||||
GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size);
|
||||
break;
|
||||
case eECIESx25519BlkNextKey:
|
||||
LogPrint (eLogDebug, "Garlic: next key");
|
||||
LogPrint (eLogDebug, "Garlic: Next key");
|
||||
if (receiveTagset)
|
||||
HandleNextKey (buf + offset, size, receiveTagset);
|
||||
else
|
||||
@@ -322,7 +322,7 @@ namespace garlic
|
||||
break;
|
||||
case eECIESx25519BlkAck:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: ack");
|
||||
LogPrint (eLogDebug, "Garlic: Ack");
|
||||
int numAcks = size >> 2; // /4
|
||||
auto offset1 = offset;
|
||||
for (auto i = 0; i < numAcks; i++)
|
||||
@@ -334,24 +334,24 @@ namespace garlic
|
||||
}
|
||||
case eECIESx25519BlkAckRequest:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: ack request");
|
||||
LogPrint (eLogDebug, "Garlic: Ack request");
|
||||
m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
|
||||
break;
|
||||
}
|
||||
case eECIESx25519BlkTermination:
|
||||
LogPrint (eLogDebug, "Garlic: termination");
|
||||
LogPrint (eLogDebug, "Garlic: Termination");
|
||||
if (GetOwner ())
|
||||
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
|
||||
if (receiveTagset) receiveTagset->Expire ();
|
||||
break;
|
||||
case eECIESx25519BlkDateTime:
|
||||
LogPrint (eLogDebug, "Garlic: datetime");
|
||||
LogPrint (eLogDebug, "Garlic: Datetime");
|
||||
break;
|
||||
case eECIESx25519BlkOptions:
|
||||
LogPrint (eLogDebug, "Garlic: options");
|
||||
LogPrint (eLogDebug, "Garlic: Options");
|
||||
break;
|
||||
case eECIESx25519BlkPadding:
|
||||
LogPrint (eLogDebug, "Garlic: padding");
|
||||
LogPrint (eLogDebug, "Garlic: Padding");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk);
|
||||
@@ -381,7 +381,7 @@ namespace garlic
|
||||
newTagset->NextSessionTagRatchet ();
|
||||
m_SendTagset = newTagset;
|
||||
m_SendForwardKey = false;
|
||||
LogPrint (eLogDebug, "Garlic: next send tagset ", newTagset->GetTagSetID (), " created");
|
||||
LogPrint (eLogDebug, "Garlic: Next send tagset ", newTagset->GetTagSetID (), " created");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "Garlic: Unexpected next key ", keyID);
|
||||
@@ -424,7 +424,7 @@ namespace garlic
|
||||
GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
|
||||
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
||||
receiveTagset->Expire ();
|
||||
LogPrint (eLogDebug, "Garlic: next receive tagset ", tagsetID, " created");
|
||||
LogPrint (eLogDebug, "Garlic: Next receive tagset ", tagsetID, " created");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace garlic
|
||||
m_NextSendRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
|
||||
|
||||
m_SendForwardKey = true;
|
||||
LogPrint (eLogDebug, "Garlic: new send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created");
|
||||
LogPrint (eLogDebug, "Garlic: New send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created");
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic)
|
||||
@@ -468,7 +468,7 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Bob static key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MixKey (sharedSecret);
|
||||
// encrypt flags/static key section
|
||||
uint8_t nonce[12];
|
||||
@@ -478,7 +478,7 @@ namespace garlic
|
||||
fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
|
||||
else
|
||||
{
|
||||
memset (out + offset, 0, 32); // all zeros flags section
|
||||
memset (out + offset, 0, 32); // all zeros flags section
|
||||
fs = out + offset;
|
||||
}
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
|
||||
@@ -486,14 +486,14 @@ namespace garlic
|
||||
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed ");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
|
||||
offset += 48;
|
||||
// KDF2
|
||||
if (isStatic)
|
||||
{
|
||||
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk)
|
||||
MixKey (sharedSecret);
|
||||
{
|
||||
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk)
|
||||
MixKey (sharedSecret);
|
||||
}
|
||||
else
|
||||
CreateNonce (1, nonce);
|
||||
@@ -503,10 +503,10 @@ namespace garlic
|
||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
m_State = eSessionStateNewSessionSent;
|
||||
if (isStatic)
|
||||
{
|
||||
{
|
||||
MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext)
|
||||
if (GetOwner ())
|
||||
{
|
||||
@@ -514,11 +514,11 @@ namespace garlic
|
||||
InitNewSessionTagset (tagsetNsr);
|
||||
tagsetNsr->Expire (); // let non-replied session expire
|
||||
GenerateMoreReceiveTags (tagsetNsr, ECIESX25519_NSR_NUM_GENERATED_TAGS);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
|
||||
{
|
||||
// we are Bob
|
||||
@@ -534,7 +534,7 @@ namespace garlic
|
||||
LogPrint (eLogError, "Garlic: Can't encode elligator");
|
||||
return false;
|
||||
}
|
||||
memcpy (m_NSREncodedKey, out + offset, 56); // for possible next NSR
|
||||
memcpy (m_NSREncodedKey, out + offset, 32); // for possible next NSR
|
||||
memcpy (m_NSRH, m_H, 32);
|
||||
offset += 32;
|
||||
// KDF for Reply Key Section
|
||||
@@ -545,13 +545,13 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MixKey (sharedSecret);
|
||||
if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MixKey (sharedSecret);
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (0, nonce);
|
||||
@@ -584,10 +584,10 @@ namespace garlic
|
||||
}
|
||||
m_State = eSessionStateNewSessionReplySent;
|
||||
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
|
||||
|
||||
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
|
||||
@@ -618,7 +618,7 @@ namespace garlic
|
||||
bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (uint8_t * buf, size_t len)
|
||||
{
|
||||
// we are Alice
|
||||
LogPrint (eLogDebug, "Garlic: reply received");
|
||||
LogPrint (eLogDebug, "Garlic: Reply received");
|
||||
const uint8_t * tag = buf;
|
||||
buf += 8; len -= 8; // tag
|
||||
uint8_t bepk[32]; // Bob's ephemeral key
|
||||
@@ -637,9 +637,9 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Bob ephemeral key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
MixKey (sharedSecret);
|
||||
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk)
|
||||
GetOwner ()->Decrypt (bepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk)
|
||||
MixKey (sharedSecret);
|
||||
|
||||
uint8_t nonce[12];
|
||||
@@ -700,11 +700,11 @@ namespace garlic
|
||||
uint64_t tag = m_SendTagset->GetNextSessionTag ();
|
||||
if (!tag)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset");
|
||||
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset");
|
||||
if (GetOwner ())
|
||||
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
memcpy (out, &tag, 8);
|
||||
// ad = The session tag, 8 bytes
|
||||
// ciphertext = ENCRYPT(k, n, payload, ad)
|
||||
@@ -736,7 +736,7 @@ namespace garlic
|
||||
}
|
||||
HandlePayload (payload, len - 16, receiveTagset, index);
|
||||
if (GetOwner ())
|
||||
{
|
||||
{
|
||||
int moreTags = 0;
|
||||
if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings?
|
||||
{
|
||||
@@ -745,17 +745,17 @@ namespace garlic
|
||||
index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
|
||||
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
|
||||
moreTags -= (receiveTagset->GetNextIndex () - index);
|
||||
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
|
||||
}
|
||||
}
|
||||
if (moreTags > 0)
|
||||
GenerateMoreReceiveTags (receiveTagset, moreTags);
|
||||
if (index > 0)
|
||||
receiveTagset->SetTrimBehind (index);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -774,13 +774,13 @@ namespace garlic
|
||||
#endif
|
||||
case eSessionStateEstablished:
|
||||
if (receiveTagset->IsNS ())
|
||||
{
|
||||
// our of sequence NSR
|
||||
LogPrint (eLogDebug, "Garlic: check for out of order NSR with index ", index);
|
||||
{
|
||||
// our of sequence NSR
|
||||
LogPrint (eLogDebug, "Garlic: Check for out of order NSR with index ", index);
|
||||
if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2)
|
||||
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS);
|
||||
return HandleNewOutgoingSessionReply (buf, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
return HandleExistingSessionMessage (buf, len, receiveTagset, index);
|
||||
case eSessionStateNew:
|
||||
@@ -792,7 +792,7 @@ namespace garlic
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
|
||||
{
|
||||
uint8_t * payload = GetOwner ()->GetPayloadBuffer ();
|
||||
@@ -829,7 +829,7 @@ namespace garlic
|
||||
if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen, false))
|
||||
return nullptr;
|
||||
len += 96;
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
@@ -844,18 +844,18 @@ namespace garlic
|
||||
{
|
||||
m_State = eSessionStateOneTime;
|
||||
return WrapSingleMessage (msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload)
|
||||
{
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
size_t payloadLen = 0;
|
||||
if (first) payloadLen += 7;// datatime
|
||||
if (msg)
|
||||
{
|
||||
{
|
||||
payloadLen += msg->GetPayloadLength () + 13;
|
||||
if (m_Destination) payloadLen += 32;
|
||||
}
|
||||
}
|
||||
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
// resubmit non-confirmed LeaseSet
|
||||
@@ -896,9 +896,9 @@ namespace garlic
|
||||
paddingSize = m_PaddingSizes[m_NextPaddingSize++] & 0x0F; // 0 - 15
|
||||
if (m_NextPaddingSize >= 32)
|
||||
{
|
||||
RAND_bytes (m_PaddingSizes, 32);
|
||||
RAND_bytes (m_PaddingSizes, 32);
|
||||
m_NextPaddingSize = 0;
|
||||
}
|
||||
}
|
||||
if (delta > 3)
|
||||
{
|
||||
delta -= 3;
|
||||
@@ -912,9 +912,9 @@ namespace garlic
|
||||
{
|
||||
if (payloadLen > I2NP_MAX_MESSAGE_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: payload length ", payloadLen, " is too long");
|
||||
LogPrint (eLogError, "Garlic: Payload length ", payloadLen, " is too long");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
m_LastSentTimestamp = ts;
|
||||
size_t offset = 0;
|
||||
// DateTime
|
||||
@@ -993,7 +993,7 @@ namespace garlic
|
||||
htobe16buf (payload + offset, paddingSize); offset += 2;
|
||||
memset (payload + offset, 0, paddingSize); offset += paddingSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
return payloadLen;
|
||||
}
|
||||
|
||||
@@ -1050,17 +1050,17 @@ namespace garlic
|
||||
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags)
|
||||
{
|
||||
if (GetOwner ())
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < numTags; i++)
|
||||
{
|
||||
{
|
||||
auto tag = GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset);
|
||||
if (!tag)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset");
|
||||
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
||||
@@ -1073,9 +1073,9 @@ namespace garlic
|
||||
RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState):
|
||||
ECIESX25519AEADRatchetSession (&i2p::context, false)
|
||||
{
|
||||
SetLeaseSetUpdateStatus (eLeaseSetDoNotSend);
|
||||
SetLeaseSetUpdateStatus (eLeaseSetDoNotSend);
|
||||
SetNoiseState (initState);
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
@@ -1084,16 +1084,16 @@ namespace garlic
|
||||
// we are Bob
|
||||
m_CurrentNoiseState.MixHash (buf, 32);
|
||||
uint8_t sharedSecret[32];
|
||||
if (!GetOwner ()->Decrypt (buf, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk)
|
||||
if (!GetOwner ()->Decrypt (buf, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) // x25519(bsk, aepk)
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_CurrentNoiseState.MixKey (sharedSecret);
|
||||
buf += 32; len -= 32;
|
||||
buf += 32; len -= 32;
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (0, nonce);
|
||||
std::vector<uint8_t> payload (len - 16);
|
||||
std::vector<uint8_t> payload (len - 16);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_CurrentNoiseState.m_H, 32,
|
||||
m_CurrentNoiseState.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt
|
||||
{
|
||||
@@ -1102,20 +1102,20 @@ namespace garlic
|
||||
}
|
||||
HandlePayload (payload.data (), len - 16, nullptr, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t CreateGarlicPayload (std::shared_ptr<const I2NPMessage> msg, uint8_t * payload,
|
||||
static size_t CreateGarlicPayload (std::shared_ptr<const I2NPMessage> msg, uint8_t * payload,
|
||||
bool datetime, size_t optimalSize)
|
||||
{
|
||||
size_t len = 0;
|
||||
if (datetime)
|
||||
{
|
||||
{
|
||||
// DateTime
|
||||
payload[0] = eECIESx25519BlkDateTime;
|
||||
payload[0] = eECIESx25519BlkDateTime;
|
||||
htobe16buf (payload + 1, 4);
|
||||
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
|
||||
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
|
||||
len = 7;
|
||||
}
|
||||
}
|
||||
// I2NP
|
||||
payload += len;
|
||||
uint16_t cloveSize = msg->GetPayloadLength () + 10;
|
||||
@@ -1139,14 +1139,14 @@ namespace garlic
|
||||
delta -= 3;
|
||||
if (paddingSize > delta) paddingSize %= delta;
|
||||
}
|
||||
payload[0] = eECIESx25519BlkPadding;
|
||||
htobe16buf (payload + 1, paddingSize);
|
||||
payload[0] = eECIESx25519BlkPadding;
|
||||
htobe16buf (payload + 1, paddingSize);
|
||||
if (paddingSize) memset (payload + 3, 0, paddingSize);
|
||||
len += paddingSize + 3;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
auto m = NewI2NPMessage ();
|
||||
@@ -1188,8 +1188,8 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: Incorrect Bob static key");
|
||||
return nullptr;
|
||||
}
|
||||
noiseState.MixKey (sharedSecret);
|
||||
}
|
||||
noiseState.MixKey (sharedSecret);
|
||||
auto payload = buf + offset;
|
||||
size_t len = CreateGarlicPayload (msg, payload, true, 900); // 1003 - 32 eph key - 16 Poly1305 hash - 16 I2NP header - 4 garlic length - 35 router tunnel delivery
|
||||
uint8_t nonce[12];
|
||||
@@ -1205,6 +1205,6 @@ namespace garlic
|
||||
m->len += offset + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
@@ -28,7 +27,7 @@ namespace garlic
|
||||
{
|
||||
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
|
||||
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can
|
||||
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
|
||||
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
||||
@@ -46,7 +45,7 @@ namespace garlic
|
||||
|
||||
RatchetTagSet () {};
|
||||
virtual ~RatchetTagSet () {};
|
||||
|
||||
|
||||
void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
|
||||
void NextSessionTagRatchet ();
|
||||
uint64_t GetNextSessionTag ();
|
||||
@@ -57,14 +56,14 @@ namespace garlic
|
||||
|
||||
int GetTagSetID () const { return m_TagSetID; };
|
||||
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::Tag<64> m_SessionTagKeyData;
|
||||
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32];
|
||||
int m_NextIndex, m_NextSymmKeyIndex;
|
||||
std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys;
|
||||
|
||||
|
||||
int m_TagSetID = 0;
|
||||
};
|
||||
|
||||
@@ -74,27 +73,27 @@ namespace garlic
|
||||
{
|
||||
public:
|
||||
|
||||
ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false):
|
||||
ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false):
|
||||
m_Session (session), m_IsNS (isNS) {};
|
||||
|
||||
bool IsNS () const { return m_IsNS; };
|
||||
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session; };
|
||||
void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; };
|
||||
void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; };
|
||||
int GetTrimBehind () const { return m_TrimBehindIndex; };
|
||||
|
||||
|
||||
void Expire ();
|
||||
bool IsExpired (uint64_t ts) const;
|
||||
|
||||
bool IsExpired (uint64_t ts) const;
|
||||
|
||||
virtual bool IsIndexExpired (int index) const;
|
||||
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
int m_TrimBehindIndex = 0;
|
||||
std::shared_ptr<ECIESX25519AEADRatchetSession> m_Session;
|
||||
bool m_IsNS;
|
||||
uint64_t m_ExpirationTimestamp = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class SymmetricKeyTagSet: public ReceiveRatchetTagSet
|
||||
{
|
||||
@@ -104,13 +103,13 @@ namespace garlic
|
||||
|
||||
bool IsIndexExpired (int index) const { return false; };
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
GarlicDestination * m_Destination;
|
||||
uint8_t m_Key[32];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
enum ECIESx25519BlockType
|
||||
{
|
||||
eECIESx25519BlkDateTime = 0,
|
||||
@@ -128,7 +127,7 @@ namespace garlic
|
||||
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
|
||||
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
|
||||
|
||||
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
|
||||
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
|
||||
private i2p::crypto::NoiseSymmetricState,
|
||||
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
|
||||
{
|
||||
@@ -158,10 +157,10 @@ namespace garlic
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index = 0);
|
||||
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||
std::shared_ptr<I2NPMessage> WrapOneTimeMessage (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 Terminate () { m_IsTerminated = true; }
|
||||
void SetDestination (const i2p::data::IdentHash& dest) // TODO:
|
||||
{
|
||||
@@ -171,19 +170,19 @@ namespace garlic
|
||||
bool CheckExpired (uint64_t ts); // true is expired
|
||||
bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; }
|
||||
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
|
||||
|
||||
|
||||
bool IsRatchets () const { return true; };
|
||||
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
|
||||
bool IsTerminated () const { return m_IsTerminated; }
|
||||
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
||||
|
||||
protected:
|
||||
|
||||
protected:
|
||||
|
||||
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
|
||||
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
|
||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
||||
@@ -198,7 +197,7 @@ namespace garlic
|
||||
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);
|
||||
|
||||
|
||||
size_t CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload);
|
||||
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len);
|
||||
size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
|
||||
@@ -221,7 +220,7 @@ namespace garlic
|
||||
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
|
||||
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
|
||||
uint8_t m_PaddingSizes[32], m_NextPaddingSize;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP only
|
||||
@@ -240,12 +239,12 @@ namespace garlic
|
||||
RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState);
|
||||
bool HandleNextMessage (const uint8_t * buf, size_t len);
|
||||
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
i2p::crypto::NoiseSymmetricState m_CurrentNoiseState;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -88,7 +88,7 @@ namespace data
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
if (verifier && cn)
|
||||
m_SigningKeys[cn] = verifier;
|
||||
m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ namespace data
|
||||
}
|
||||
|
||||
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
|
||||
const char * signature, const char * key)
|
||||
const char * signature, const char * key) const
|
||||
{
|
||||
uint8_t buf[100], signatureBuf[64];
|
||||
size_t len = family.length (), signatureLen = strlen (signature);
|
||||
@@ -137,11 +137,19 @@ namespace data
|
||||
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
|
||||
auto it = m_SigningKeys.find (family);
|
||||
if (it != m_SigningKeys.end ())
|
||||
return it->second->Verify (buf, len, signatureBuf);
|
||||
return it->second.first->Verify (buf, len, signatureBuf);
|
||||
// TODO: process key
|
||||
return true;
|
||||
}
|
||||
|
||||
FamilyID Families::GetFamilyID (const std::string& family) const
|
||||
{
|
||||
auto it = m_SigningKeys.find (family);
|
||||
if (it != m_SigningKeys.end ())
|
||||
return it->second.second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident)
|
||||
{
|
||||
auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -19,6 +19,7 @@ namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
typedef int FamilyID;
|
||||
class Families
|
||||
{
|
||||
public:
|
||||
@@ -27,7 +28,8 @@ namespace data
|
||||
~Families ();
|
||||
void LoadCertificates ();
|
||||
bool VerifyFamily (const std::string& family, const IdentHash& ident,
|
||||
const char * signature, const char * key = nullptr);
|
||||
const char * signature, const char * key = nullptr) const;
|
||||
FamilyID GetFamilyID (const std::string& family) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -35,7 +37,7 @@ namespace data
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
|
||||
std::map<std::string, std::pair<std::shared_ptr<i2p::crypto::Verifier>, FamilyID> > m_SigningKeys; // family -> (verifier, id)
|
||||
};
|
||||
|
||||
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -164,9 +164,7 @@ namespace garlic
|
||||
RAND_bytes (elGamal.preIV, 32); // Pre-IV
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
SHA256(elGamal.preIV, 32, iv);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
m_Destination->Encrypt ((uint8_t *)&elGamal, buf);
|
||||
m_Encryption.SetIV (iv);
|
||||
buf += 514;
|
||||
len += 514;
|
||||
@@ -273,7 +271,7 @@ namespace garlic
|
||||
(*numCloves)++;
|
||||
}
|
||||
}
|
||||
if (msg) // clove message ifself if presented
|
||||
if (msg) // clove message itself if presented
|
||||
{
|
||||
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
|
||||
(*numCloves)++;
|
||||
@@ -435,12 +433,10 @@ namespace garlic
|
||||
GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
|
||||
m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard
|
||||
{
|
||||
m_Ctx = BN_CTX_new ();
|
||||
}
|
||||
|
||||
GarlicDestination::~GarlicDestination ()
|
||||
{
|
||||
BN_CTX_free (m_Ctx);
|
||||
if (m_PayloadBuffer)
|
||||
delete[] m_PayloadBuffer;
|
||||
}
|
||||
@@ -456,7 +452,7 @@ namespace garlic
|
||||
{
|
||||
it.second->Terminate ();
|
||||
it.second->SetOwner (nullptr);
|
||||
}
|
||||
}
|
||||
m_ECIESx25519Sessions.clear ();
|
||||
m_ECIESx25519Tags.clear ();
|
||||
}
|
||||
@@ -474,27 +470,32 @@ namespace garlic
|
||||
uint64_t t;
|
||||
memcpy (&t, tag, 8);
|
||||
AddECIESx25519Key (key, t);
|
||||
}
|
||||
}
|
||||
|
||||
void GarlicDestination::AddECIESx25519Key (const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key);
|
||||
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{0, tagset});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
|
||||
{
|
||||
AddSessionKey (key, tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GarlicDestination::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
AddECIESx25519Key (key, tag);
|
||||
}
|
||||
|
||||
void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
uint32_t length = bufbe32toh (buf);
|
||||
if (length > msg->GetLength ())
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
|
||||
LogPrint (eLogWarning, "Garlic: Message length ", length, " exceeds I2NP message length ", msg->GetLength ());
|
||||
return;
|
||||
}
|
||||
auto mod = length & 0x0f; // %16
|
||||
@@ -502,10 +503,10 @@ namespace garlic
|
||||
|
||||
bool found = false;
|
||||
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||
// try ECIESx25519 tag
|
||||
// try ECIESx25519 tag
|
||||
found = HandleECIESx25519TagMessage (buf, length);
|
||||
if (!found)
|
||||
{
|
||||
{
|
||||
auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16
|
||||
// AES tag might be used even if encryption type is not ElGamal/AES
|
||||
if (it != m_Tags.end ()) // try AES tag
|
||||
@@ -523,7 +524,7 @@ namespace garlic
|
||||
found = true;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
|
||||
LogPrint (eLogWarning, "Garlic: Message length ", length, " is less than 32 bytes");
|
||||
}
|
||||
if (!found) // assume new session
|
||||
{
|
||||
@@ -531,7 +532,7 @@ namespace garlic
|
||||
// try ElGamal/AES first if leading block is 514
|
||||
ElGamalBlock elGamal;
|
||||
if (mod == 2 && length >= 514 && SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) &&
|
||||
Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL))
|
||||
Decrypt (buf, (uint8_t *)&elGamal, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL))
|
||||
{
|
||||
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
@@ -546,37 +547,37 @@ namespace garlic
|
||||
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
||||
if (!session->HandleNextMessage (buf, length, nullptr, 0))
|
||||
{
|
||||
// try to gererate more tags for last tagset
|
||||
// try to generate more tags for last tagset
|
||||
if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS))
|
||||
{
|
||||
uint64_t missingTag; memcpy (&missingTag, buf, 8);
|
||||
auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS);
|
||||
LogPrint (eLogWarning, "Garlic: trying to generate more ECIES-X25519-AEAD-Ratchet tags");
|
||||
LogPrint (eLogWarning, "Garlic: Trying to generate more ECIES-X25519-AEAD-Ratchet tags");
|
||||
for (int i = 0; i < maxTags; i++)
|
||||
{
|
||||
auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset);
|
||||
if (!nextTag)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset");
|
||||
LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nextTag == missingTag)
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated");
|
||||
if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index))
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) m_LastTagset = nullptr;
|
||||
}
|
||||
if (!found)
|
||||
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
}
|
||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Failed to decrypt message");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,14 +590,14 @@ namespace garlic
|
||||
{
|
||||
if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
|
||||
m_LastTagset = it->second.tagset;
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
m_ECIESx25519Tags.erase (it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||
{
|
||||
@@ -633,7 +634,7 @@ namespace garlic
|
||||
SHA256 (buf, payloadSize, digest);
|
||||
if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: wrong payload hash");
|
||||
LogPrint (eLogError, "Garlic: Wrong payload hash");
|
||||
return;
|
||||
}
|
||||
HandleGarlicPayload (buf, payloadSize, from);
|
||||
@@ -643,7 +644,7 @@ namespace garlic
|
||||
{
|
||||
if (len < 1)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: payload is too short");
|
||||
LogPrint (eLogError, "Garlic: Payload is too short");
|
||||
return;
|
||||
}
|
||||
int numCloves = buf[0];
|
||||
@@ -658,7 +659,7 @@ namespace garlic
|
||||
if (flag & 0x80) // encrypted?
|
||||
{
|
||||
// TODO: implement
|
||||
LogPrint (eLogWarning, "Garlic: clove encrypted");
|
||||
LogPrint (eLogWarning, "Garlic: Clove encrypted");
|
||||
buf += 32;
|
||||
}
|
||||
ptrdiff_t offset = buf - buf1;
|
||||
@@ -666,35 +667,35 @@ namespace garlic
|
||||
switch (deliveryType)
|
||||
{
|
||||
case eGarlicDeliveryTypeLocal:
|
||||
LogPrint (eLogDebug, "Garlic: type local");
|
||||
LogPrint (eLogDebug, "Garlic: Type local");
|
||||
if (offset > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
LogPrint (eLogError, "Garlic: Message is too short");
|
||||
break;
|
||||
}
|
||||
HandleI2NPMessage (buf, len - offset);
|
||||
break;
|
||||
case eGarlicDeliveryTypeDestination:
|
||||
LogPrint (eLogDebug, "Garlic: type destination");
|
||||
LogPrint (eLogDebug, "Garlic: Type destination");
|
||||
buf += 32; // destination. check it later or for multiple destinations
|
||||
offset = buf - buf1;
|
||||
if (offset > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
LogPrint (eLogError, "Garlic: Message is too short");
|
||||
break;
|
||||
}
|
||||
HandleI2NPMessage (buf, len - offset);
|
||||
break;
|
||||
case eGarlicDeliveryTypeTunnel:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: type tunnel");
|
||||
LogPrint (eLogDebug, "Garlic: Type tunnel");
|
||||
// gwHash and gwTunnel sequence is reverted
|
||||
uint8_t * gwHash = buf;
|
||||
buf += 32;
|
||||
offset = buf - buf1;
|
||||
if (offset + 4 > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
LogPrint (eLogError, "Garlic: Message is too short");
|
||||
break;
|
||||
}
|
||||
uint32_t gwTunnel = bufbe32toh (buf);
|
||||
@@ -725,22 +726,22 @@ namespace garlic
|
||||
{
|
||||
if (offset > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
LogPrint (eLogError, "Garlic: Message is too short");
|
||||
break;
|
||||
}
|
||||
i2p::transport::transports.SendMessage (ident,
|
||||
CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len - offset)));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported");
|
||||
LogPrint (eLogWarning, "Garlic: Type router for inbound tunnels not supported");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
|
||||
LogPrint (eLogWarning, "Garlic: Unknown delivery type ", (int)deliveryType);
|
||||
}
|
||||
if (offset > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
LogPrint (eLogError, "Garlic: Message is too short");
|
||||
break;
|
||||
}
|
||||
buf += GetI2NPMessageLength (buf, len - offset); // I2NP
|
||||
@@ -750,7 +751,7 @@ namespace garlic
|
||||
offset = buf - buf1;
|
||||
if (offset > (int)len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: clove is too long");
|
||||
LogPrint (eLogError, "Garlic: Clove is too long");
|
||||
break;
|
||||
}
|
||||
len -= offset;
|
||||
@@ -763,10 +764,10 @@ namespace garlic
|
||||
if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||
return WrapECIESX25519MessageForRouter (msg, router->GetIdentity ()->GetEncryptionPublicKey ());
|
||||
else
|
||||
{
|
||||
{
|
||||
auto session = GetRoutingSession (router, false);
|
||||
return session->WrapSingleMessage (msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
||||
@@ -777,17 +778,17 @@ namespace garlic
|
||||
{
|
||||
ECIESX25519AEADRatchetSessionPtr session;
|
||||
uint8_t staticKey[32];
|
||||
destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key
|
||||
destination->Encrypt (nullptr, staticKey); // we are supposed to get static key
|
||||
auto it = m_ECIESx25519Sessions.find (staticKey);
|
||||
if (it != m_ECIESx25519Sessions.end ())
|
||||
{
|
||||
{
|
||||
session = it->second;
|
||||
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: session restarted");
|
||||
LogPrint (eLogDebug, "Garlic: Session restarted");
|
||||
session = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!session)
|
||||
{
|
||||
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
|
||||
@@ -844,7 +845,7 @@ namespace garlic
|
||||
it->second->GetSharedRoutingPath (); // delete shared path if necessary
|
||||
if (!it->second->CleanupExpiredTags ())
|
||||
{
|
||||
LogPrint (eLogInfo, "Routing session to ", it->first.ToBase32 (), " deleted");
|
||||
LogPrint (eLogInfo, "Garlic: Routing session to ", it->first.ToBase32 (), " deleted");
|
||||
it->second->SetOwner (nullptr);
|
||||
it = m_Sessions.erase (it);
|
||||
}
|
||||
@@ -883,18 +884,18 @@ namespace garlic
|
||||
it->second.tagset->DeleteSymmKey (it->second.index);
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
numExpiredTags++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto session = it->second.tagset->GetSession ();
|
||||
if (!session || session->IsTerminated())
|
||||
{
|
||||
{
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
numExpiredTags++;
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numExpiredTags > 0)
|
||||
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ());
|
||||
@@ -929,7 +930,7 @@ namespace garlic
|
||||
if (session)
|
||||
{
|
||||
session->MessageConfirmed (msgID);
|
||||
LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged");
|
||||
LogPrint (eLogDebug, "Garlic: Message ", msgID, " acknowledged");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1034,7 +1035,7 @@ namespace garlic
|
||||
switch (deliveryType)
|
||||
{
|
||||
case eGarlicDeliveryTypeDestination:
|
||||
LogPrint (eLogDebug, "Garlic: type destination");
|
||||
LogPrint (eLogDebug, "Garlic: Type destination");
|
||||
buf += 32; // TODO: check destination
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
@@ -1042,7 +1043,7 @@ namespace garlic
|
||||
// no break here
|
||||
case eGarlicDeliveryTypeLocal:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: type local");
|
||||
LogPrint (eLogDebug, "Garlic: Type local");
|
||||
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
|
||||
int32_t msgID = bufbe32toh (buf); buf += 4; // msgID
|
||||
buf += 4; // expiration
|
||||
@@ -1050,19 +1051,19 @@ namespace garlic
|
||||
if (offset <= (int)len)
|
||||
HandleCloveI2NPMessage (typeID, buf, len - offset, msgID);
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: clove is too long");
|
||||
LogPrint (eLogError, "Garlic: Clove is too long");
|
||||
break;
|
||||
}
|
||||
case eGarlicDeliveryTypeTunnel:
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: type tunnel");
|
||||
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");
|
||||
LogPrint (eLogError, "Garlic: Message is too short");
|
||||
break;
|
||||
}
|
||||
uint32_t gwTunnel = bufbe32toh (buf); buf += 4;
|
||||
@@ -1083,7 +1084,7 @@ namespace garlic
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType);
|
||||
LogPrint (eLogWarning, "Garlic: Unexpected delivery type ", (int)deliveryType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1103,13 +1104,13 @@ namespace garlic
|
||||
if (it != m_ECIESx25519Sessions.end ())
|
||||
{
|
||||
if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ()))
|
||||
{
|
||||
{
|
||||
it->second->Terminate (); // detach
|
||||
m_ECIESx25519Sessions.erase (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
|
||||
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1131,6 +1132,6 @@ namespace garlic
|
||||
if (!m_PayloadBuffer)
|
||||
m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE];
|
||||
return m_PayloadBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -115,7 +115,7 @@ namespace garlic
|
||||
virtual bool MessageConfirmed (uint32_t msgID);
|
||||
virtual bool IsRatchets () const { return false; };
|
||||
virtual bool IsReadyToSend () const { return true; };
|
||||
virtual bool IsTerminated () const { return !GetOwner (); };
|
||||
virtual bool IsTerminated () const { return !GetOwner (); };
|
||||
virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only
|
||||
|
||||
void SetLeaseSetUpdated ()
|
||||
@@ -245,13 +245,14 @@ namespace garlic
|
||||
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
||||
void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag
|
||||
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
|
||||
virtual void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); // from different thread
|
||||
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
|
||||
uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset);
|
||||
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);
|
||||
void RemoveECIESx25519Session (const uint8_t * staticKey);
|
||||
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
|
||||
uint8_t * GetPayloadBuffer ();
|
||||
|
||||
|
||||
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
virtual void SetLeaseSetUpdated ();
|
||||
@@ -279,7 +280,6 @@ namespace garlic
|
||||
|
||||
private:
|
||||
|
||||
BN_CTX * m_Ctx; // incoming
|
||||
// outgoing sessions
|
||||
int m_NumTags;
|
||||
std::mutex m_SessionsMutex;
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include "Base.h"
|
||||
#include "HTTP.h"
|
||||
|
||||
namespace i2p
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
namespace http
|
||||
{
|
||||
const std::vector<std::string> HTTP_METHODS = {
|
||||
"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods
|
||||
@@ -476,14 +476,14 @@ namespace http
|
||||
return ptr;
|
||||
}
|
||||
|
||||
std::string UrlDecode(const std::string& data, bool allow_null)
|
||||
std::string UrlDecode(const std::string& data, bool allow_null)
|
||||
{
|
||||
std::string decoded(data);
|
||||
size_t pos = 0;
|
||||
while ((pos = decoded.find('%', pos)) != std::string::npos)
|
||||
while ((pos = decoded.find('%', pos)) != std::string::npos)
|
||||
{
|
||||
char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16);
|
||||
if (c == '\0' && !allow_null)
|
||||
if (c == '\0' && !allow_null)
|
||||
{
|
||||
pos += 3;
|
||||
continue;
|
||||
@@ -494,10 +494,10 @@ namespace http
|
||||
return decoded;
|
||||
}
|
||||
|
||||
bool MergeChunkedResponse (std::istream& in, std::ostream& out)
|
||||
bool MergeChunkedResponse (std::istream& in, std::ostream& out)
|
||||
{
|
||||
std::string hexLen;
|
||||
while (!in.eof ())
|
||||
while (!in.eof ())
|
||||
{
|
||||
std::getline (in, hexLen);
|
||||
errno = 0;
|
||||
@@ -522,6 +522,6 @@ namespace http
|
||||
if (user.empty () && pass.empty ()) return "";
|
||||
return "Basic " + i2p::data::ToBase64Standard (user + ":" + pass);
|
||||
}
|
||||
|
||||
|
||||
} // http
|
||||
} // i2p
|
||||
|
||||
@@ -167,8 +167,8 @@ namespace http
|
||||
*/
|
||||
bool MergeChunkedResponse (std::istream& in, std::ostream& out);
|
||||
|
||||
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass);
|
||||
|
||||
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass);
|
||||
|
||||
} // http
|
||||
} // i2p
|
||||
|
||||
|
||||
@@ -38,20 +38,7 @@ namespace i2p
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
|
||||
{
|
||||
I2NPMessage * msg = nullptr;
|
||||
if (endpoint)
|
||||
{
|
||||
// should fit two tunnel message + tunnel gateway header, enough for one garlic encrypted streaming packet
|
||||
msg = new I2NPMessageBuffer<2*i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28>(); // reserved for alignment and NTCP 16 + 6 + 6
|
||||
msg->Align (6);
|
||||
msg->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12
|
||||
msg->Align (12);
|
||||
}
|
||||
return std::shared_ptr<I2NPMessage>(msg);
|
||||
return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint);
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
|
||||
@@ -88,7 +75,7 @@ namespace i2p
|
||||
{
|
||||
auto msg = NewI2NPMessage (len);
|
||||
if (msg->Concat (buf, len) < len)
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen);
|
||||
LogPrint (eLogError, "I2NP: Message length ", len, " exceeds max length ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (msgType, replyMsgID);
|
||||
return msg;
|
||||
}
|
||||
@@ -103,7 +90,7 @@ namespace i2p
|
||||
msg->from = from;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length");
|
||||
LogPrint (eLogError, "I2NP: Message length ", len, " exceeds max length");
|
||||
return msg;
|
||||
}
|
||||
|
||||
@@ -183,8 +170,8 @@ namespace i2p
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
|
||||
const uint8_t * replyTag, bool replyECIES)
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
|
||||
const uint8_t * replyTag, bool replyECIES)
|
||||
{
|
||||
int cnt = excludedFloodfills.size ();
|
||||
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
@@ -222,12 +209,12 @@ namespace i2p
|
||||
{
|
||||
memcpy (buf + 33, replyTag, 8); // 8 bytes tag
|
||||
buf += 41;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (buf + 33, replyTag, 32); // 32 bytes tag
|
||||
buf += 65;
|
||||
}
|
||||
}
|
||||
|
||||
m->len += (buf - m->GetPayload ());
|
||||
m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
|
||||
@@ -256,8 +243,8 @@ namespace i2p
|
||||
return m;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||
{
|
||||
if (!router) // we send own RouterInfo
|
||||
router = context.GetSharedRouterInfo ();
|
||||
@@ -267,7 +254,7 @@ namespace i2p
|
||||
LogPrint (eLogError, "I2NP: Invalid RouterInfo buffer for DatabaseStore");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
|
||||
@@ -285,12 +272,12 @@ namespace i2p
|
||||
buf += 32; // reply tunnel gateway
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
memset (buf, 0, 4); // zero tunnelID means direct reply
|
||||
buf += 4;
|
||||
memcpy (buf, context.GetIdentHash (), 32);
|
||||
buf += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t * sizePtr = buf;
|
||||
@@ -303,7 +290,7 @@ namespace i2p
|
||||
{
|
||||
i2p::data::GzipDeflator deflator;
|
||||
size = deflator.Deflate (router->GetBuffer (), router->GetBufferLen (), buf, m->maxLen -m->len);
|
||||
}
|
||||
}
|
||||
if (size)
|
||||
{
|
||||
htobe16buf (sizePtr, size); // size
|
||||
@@ -391,78 +378,50 @@ namespace i2p
|
||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
|
||||
uint8_t retCode = 0;
|
||||
bool isECIES = i2p::context.IsECIES ();
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels () &&
|
||||
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
|
||||
!i2p::transport::transports.IsBandwidthExceeded () &&
|
||||
!i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||
{
|
||||
auto transitTunnel = isECIES ?
|
||||
i2p::tunnel::CreateTransitTunnel (
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) :
|
||||
i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
|
||||
}
|
||||
else
|
||||
retCode = 30; // always reject with bandwidth reason (30)
|
||||
|
||||
if (isECIES)
|
||||
{
|
||||
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret
|
||||
record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
|
||||
}
|
||||
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
// encrypt reply
|
||||
i2p::crypto::CBCEncryption encryption;
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (isECIES)
|
||||
{
|
||||
if (j == i)
|
||||
if (j == i)
|
||||
{
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12);
|
||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||
{
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12);
|
||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
|
||||
return false;
|
||||
}
|
||||
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -499,75 +458,28 @@ namespace i2p
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i2p::context.IsECIES ())
|
||||
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||
{
|
||||
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||
{
|
||||
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||
{
|
||||
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
|
||||
{
|
||||
if (i2p::context.IsECIES ())
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: TunnelBuild is too old for ECIES router");
|
||||
return;
|
||||
}
|
||||
if (len < NUM_TUNNEL_BUILD_RECORDS*TUNNEL_BUILD_RECORD_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: TunnelBuild message is too short ", len);
|
||||
return;
|
||||
}
|
||||
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, buf, clearText))
|
||||
{
|
||||
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outbound tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
LogPrint (eLogWarning, "I2NP: TunnelBuild is too old for ECIES router");
|
||||
}
|
||||
|
||||
static void HandleTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len, bool isShort)
|
||||
@@ -603,11 +515,6 @@ namespace i2p
|
||||
|
||||
static void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
if (!i2p::context.IsECIES ())
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: ShortTunnelBuild can be handled by ECIES router only");
|
||||
return;
|
||||
}
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
|
||||
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
@@ -640,8 +547,8 @@ namespace i2p
|
||||
{
|
||||
LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours");
|
||||
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
||||
{
|
||||
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i);
|
||||
return;
|
||||
}
|
||||
@@ -649,19 +556,19 @@ namespace i2p
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record");
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto& noiseState = i2p::context.GetCurrentNoiseState ();
|
||||
uint8_t replyKey[32], layerKey[32], ivKey[32];
|
||||
uint8_t replyKey[32], layerKey[32], ivKey[32];
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
|
||||
memcpy (replyKey, noiseState.m_CK + 32, 32);
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
|
||||
memcpy (layerKey, noiseState.m_CK + 32, 32);
|
||||
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
|
||||
if (isEndpoint)
|
||||
{
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK);
|
||||
memcpy (ivKey, noiseState.m_CK + 32, 32);
|
||||
}
|
||||
}
|
||||
else
|
||||
memcpy (ivKey, noiseState.m_CK , 32);
|
||||
|
||||
@@ -673,7 +580,7 @@ namespace i2p
|
||||
i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||
retCode = 30;
|
||||
if (!retCode)
|
||||
{
|
||||
{
|
||||
// create new transit tunnel
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
@@ -684,46 +591,46 @@ namespace i2p
|
||||
clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
|
||||
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
|
||||
}
|
||||
|
||||
|
||||
// encrypt reply
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12);
|
||||
uint8_t * reply = buf + 1;
|
||||
for (int j = 0; j < num; j++)
|
||||
{
|
||||
{
|
||||
nonce[4] = j; // nonce is record #
|
||||
if (j == i)
|
||||
{
|
||||
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
|
||||
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
|
||||
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
}
|
||||
// send reply
|
||||
if (isEndpoint)
|
||||
{
|
||||
{
|
||||
auto replyMsg = NewI2NPShortMessage ();
|
||||
replyMsg->Concat (buf, len);
|
||||
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
||||
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
|
||||
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
|
||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
|
||||
{
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
|
||||
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
|
||||
uint64_t tag;
|
||||
memcpy (&tag, noiseState.m_CK, 8);
|
||||
// we send it to reply tunnel
|
||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// IBGW is local
|
||||
@@ -733,18 +640,18 @@ namespace i2p
|
||||
tunnel->SendTunnelDataMsg (replyMsg);
|
||||
else
|
||||
LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
|
||||
{
|
||||
auto msg = NewI2NPTunnelMessage (false);
|
||||
@@ -778,7 +685,7 @@ namespace i2p
|
||||
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
|
||||
msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
if (msg->Concat (buf, len) < len)
|
||||
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
|
||||
LogPrint (eLogError, "I2NP: Tunnel gateway buffer overflow ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
|
||||
return msg;
|
||||
}
|
||||
@@ -809,7 +716,7 @@ namespace i2p
|
||||
msg->offset += gatewayMsgOffset;
|
||||
msg->len += gatewayMsgOffset;
|
||||
if (msg->Concat (buf, len) < len)
|
||||
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
|
||||
LogPrint (eLogError, "I2NP: Tunnel gateway buffer overflow ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message
|
||||
len = msg->GetLength ();
|
||||
msg->offset -= gatewayMsgOffset;
|
||||
@@ -824,13 +731,13 @@ namespace i2p
|
||||
{
|
||||
if (len < I2NP_HEADER_SIZE_OFFSET + 2)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
|
||||
LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
|
||||
return len;
|
||||
}
|
||||
auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE;
|
||||
if (l > len)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: message length ", l, " exceeds buffer length ", len);
|
||||
LogPrint (eLogError, "I2NP: Message length ", l, " exceeds buffer length ", len);
|
||||
l = len;
|
||||
}
|
||||
return l;
|
||||
@@ -840,18 +747,18 @@ namespace i2p
|
||||
{
|
||||
if (len < I2NP_HEADER_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
|
||||
LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
|
||||
return;
|
||||
}
|
||||
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
|
||||
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
|
||||
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
LogPrint (eLogDebug, "I2NP: Msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
uint8_t * buf = msg + I2NP_HEADER_SIZE;
|
||||
auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
|
||||
len -= I2NP_HEADER_SIZE;
|
||||
if (size > len)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: payload size ", size, " exceeds buffer length ", len);
|
||||
LogPrint (eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
|
||||
size = len;
|
||||
}
|
||||
switch (typeID)
|
||||
@@ -861,13 +768,13 @@ namespace i2p
|
||||
break;
|
||||
case eI2NPShortTunnelBuild:
|
||||
HandleShortTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, buf, size, false);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, buf, size, true);
|
||||
break;
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (buf, size);
|
||||
break;
|
||||
@@ -924,8 +831,8 @@ namespace i2p
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
case eI2NPTunnelBuild:
|
||||
case eI2NPTunnelBuildReply:
|
||||
case eI2NPShortTunnelBuild:
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
case eI2NPShortTunnelBuild:
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
// forward to tunnel thread
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
@@ -940,7 +847,7 @@ namespace i2p
|
||||
Flush ();
|
||||
}
|
||||
|
||||
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage>&& msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
|
||||
@@ -56,32 +56,11 @@ namespace i2p
|
||||
// TunnelBuild
|
||||
const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
|
||||
const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218;
|
||||
|
||||
//BuildRequestRecordClearText
|
||||
const size_t BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0;
|
||||
const size_t BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET = BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4;
|
||||
const size_t BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET = BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET + 32;
|
||||
const size_t BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET = BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET + 4;
|
||||
const size_t BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET = BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET + 32;
|
||||
const size_t BUILD_REQUEST_RECORD_IV_KEY_OFFSET = BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET + 32;
|
||||
const size_t BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET = BUILD_REQUEST_RECORD_IV_KEY_OFFSET + 32;
|
||||
const size_t BUILD_REQUEST_RECORD_REPLY_IV_OFFSET = BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET + 32;
|
||||
const size_t BUILD_REQUEST_RECORD_FLAG_OFFSET = BUILD_REQUEST_RECORD_REPLY_IV_OFFSET + 16;
|
||||
const size_t BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET = BUILD_REQUEST_RECORD_FLAG_OFFSET + 1;
|
||||
const size_t BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
|
||||
const size_t BUILD_REQUEST_RECORD_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
|
||||
const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222;
|
||||
|
||||
// BuildRequestRecordEncrypted
|
||||
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
|
||||
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
|
||||
|
||||
// BuildResponseRecord
|
||||
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
|
||||
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
|
||||
const size_t BUILD_RESPONSE_RECORD_PADDING_SIZE = 495;
|
||||
const size_t BUILD_RESPONSE_RECORD_RET_OFFSET = BUILD_RESPONSE_RECORD_PADDING_OFFSET + BUILD_RESPONSE_RECORD_PADDING_SIZE;
|
||||
|
||||
// ECIES BuildRequestRecordClearText
|
||||
const size_t ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET = 0;
|
||||
const size_t ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET = ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET + 4;
|
||||
@@ -119,7 +98,7 @@ namespace i2p
|
||||
// ShortResponseRecord
|
||||
const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
|
||||
const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201;
|
||||
|
||||
|
||||
enum I2NPMessageType
|
||||
{
|
||||
eI2NPDummyMsg = 0,
|
||||
@@ -294,8 +273,8 @@ namespace tunnel
|
||||
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
|
||||
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
|
||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
|
||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
|
||||
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
||||
|
||||
@@ -322,7 +301,7 @@ namespace tunnel
|
||||
public:
|
||||
|
||||
~I2NPMessagesHandler ();
|
||||
void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void PutNextMessage (std::shared_ptr<I2NPMessage>&& msg);
|
||||
void Flush ();
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -50,42 +50,3 @@ uint64_t be64toh(uint64_t big64)
|
||||
return u64.raw_value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* it can be used in Windows 8
|
||||
#include <Winsock2.h>
|
||||
|
||||
uint16_t htobe16(uint16_t int16)
|
||||
{
|
||||
return htons(int16);
|
||||
}
|
||||
|
||||
uint32_t htobe32(uint32_t int32)
|
||||
{
|
||||
return htonl(int32);
|
||||
}
|
||||
|
||||
uint64_t htobe64(uint64_t int64)
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||
//return htonll(int64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint16_t be16toh(uint16_t big16)
|
||||
{
|
||||
return ntohs(big16);
|
||||
}
|
||||
|
||||
uint32_t be32toh(uint32_t big32)
|
||||
{
|
||||
return ntohl(big32);
|
||||
}
|
||||
|
||||
uint64_t be64toh(uint64_t big64)
|
||||
{
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
|
||||
//return ntohll(big64);
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -13,10 +13,11 @@
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/endian.h>
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__)
|
||||
#include <endian.h>
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#include <libkern/OSByteOrder.h>
|
||||
|
||||
#define htobe16(x) OSSwapHostToBigInt16(x)
|
||||
@@ -34,6 +35,22 @@
|
||||
#define be64toh(x) OSSwapBigToHostInt64(x)
|
||||
#define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||
|
||||
#elif defined(_WIN32)
|
||||
#define htobe16(x) __builtin_bswap16(x)
|
||||
#define htole16(x) (x)
|
||||
#define be16toh(x) __builtin_bswap16(x)
|
||||
#define le16toh(x) (x)
|
||||
|
||||
#define htobe32(x) __builtin_bswap32(x)
|
||||
#define htole32(x) (x)
|
||||
#define be32toh(x) __builtin_bswap32(x)
|
||||
#define le32toh(x) (x)
|
||||
|
||||
#define htobe64(x) __builtin_bswap64(x)
|
||||
#define htole64(x) (x)
|
||||
#define be64toh(x) __builtin_bswap64(x)
|
||||
#define le64toh(x) (x)
|
||||
|
||||
#else
|
||||
#define NEEDS_LOCAL_ENDIAN
|
||||
#include <cstdint>
|
||||
|
||||
@@ -19,7 +19,8 @@ namespace data
|
||||
Identity& Identity::operator=(const Keys& keys)
|
||||
{
|
||||
// copy public and signing keys together
|
||||
memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey));
|
||||
memcpy (publicKey, keys.publicKey, sizeof (publicKey));
|
||||
memcpy (signingKey, keys.signingKey, sizeof (signingKey));
|
||||
memset (certificate, 0, sizeof (certificate));
|
||||
return *this;
|
||||
}
|
||||
@@ -42,7 +43,7 @@ namespace data
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx ():
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,9 +53,9 @@ namespace data
|
||||
{
|
||||
memcpy (m_StandardIdentity.publicKey, publicKey, 32);
|
||||
RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
|
||||
}
|
||||
else
|
||||
memcpy (m_StandardIdentity.publicKey, publicKey, 256);
|
||||
}
|
||||
else
|
||||
memcpy (m_StandardIdentity.publicKey, publicKey, 256);
|
||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
size_t excessLen = 0;
|
||||
@@ -119,11 +120,15 @@ namespace data
|
||||
m_StandardIdentity.certificate[0] = CERTIFICATE_TYPE_KEY;
|
||||
htobe16buf (m_StandardIdentity.certificate + 1, m_ExtendedLen);
|
||||
// fill extended buffer
|
||||
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
|
||||
htobe16buf (m_ExtendedBuffer, type);
|
||||
htobe16buf (m_ExtendedBuffer + 2, cryptoType);
|
||||
if (excessLen && excessBuf)
|
||||
{
|
||||
if (excessLen > MAX_EXTENDED_BUFFER_SIZE - 4)
|
||||
{
|
||||
LogPrint (eLogError, "Identity: Unexpected excessive signing key len ", excessLen);
|
||||
excessLen = MAX_EXTENDED_BUFFER_SIZE - 4;
|
||||
}
|
||||
memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen);
|
||||
delete[] excessBuf;
|
||||
}
|
||||
@@ -136,7 +141,6 @@ namespace data
|
||||
memset (m_StandardIdentity.certificate, 0, sizeof (m_StandardIdentity.certificate));
|
||||
m_IdentHash = m_StandardIdentity.Hash ();
|
||||
m_ExtendedLen = 0;
|
||||
m_ExtendedBuffer = nullptr;
|
||||
}
|
||||
CreateVerifier ();
|
||||
}
|
||||
@@ -154,26 +158,25 @@ namespace data
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx (const uint8_t * buf, size_t len):
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
FromBuffer (buf, len);
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx (const IdentityEx& other):
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx (const Identity& standard):
|
||||
m_ExtendedLen (0), m_ExtendedBuffer (nullptr)
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
*this = standard;
|
||||
}
|
||||
|
||||
IdentityEx::~IdentityEx ()
|
||||
{
|
||||
delete[] m_ExtendedBuffer;
|
||||
delete m_Verifier;
|
||||
}
|
||||
|
||||
@@ -182,15 +185,12 @@ namespace data
|
||||
memcpy (&m_StandardIdentity, &other.m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
|
||||
m_IdentHash = other.m_IdentHash;
|
||||
|
||||
delete[] m_ExtendedBuffer;
|
||||
m_ExtendedLen = other.m_ExtendedLen;
|
||||
if (m_ExtendedLen > 0)
|
||||
{
|
||||
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
|
||||
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
|
||||
memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen);
|
||||
}
|
||||
else
|
||||
m_ExtendedBuffer = nullptr;
|
||||
|
||||
delete m_Verifier;
|
||||
m_Verifier = nullptr;
|
||||
@@ -203,8 +203,6 @@ namespace data
|
||||
m_StandardIdentity = standard;
|
||||
m_IdentHash = m_StandardIdentity.Hash ();
|
||||
|
||||
delete[] m_ExtendedBuffer;
|
||||
m_ExtendedBuffer = nullptr;
|
||||
m_ExtendedLen = 0;
|
||||
|
||||
delete m_Verifier;
|
||||
@@ -217,20 +215,17 @@ namespace data
|
||||
{
|
||||
if (len < DEFAULT_IDENTITY_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "Identity: buffer length ", len, " is too small");
|
||||
LogPrint (eLogError, "Identity: Buffer length ", len, " is too small");
|
||||
return 0;
|
||||
}
|
||||
memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
|
||||
|
||||
if(m_ExtendedBuffer) delete[] m_ExtendedBuffer;
|
||||
m_ExtendedBuffer = nullptr;
|
||||
|
||||
m_ExtendedLen = bufbe16toh (m_StandardIdentity.certificate + 1);
|
||||
if (m_ExtendedLen)
|
||||
{
|
||||
if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len)
|
||||
{
|
||||
m_ExtendedBuffer = new uint8_t[m_ExtendedLen];
|
||||
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
|
||||
memcpy (m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen);
|
||||
}
|
||||
else
|
||||
@@ -241,10 +236,7 @@ namespace data
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ExtendedLen = 0;
|
||||
m_ExtendedBuffer = nullptr;
|
||||
}
|
||||
SHA256(buf, GetFullLen (), m_IdentHash);
|
||||
|
||||
delete m_Verifier;
|
||||
@@ -258,7 +250,7 @@ namespace data
|
||||
const size_t fullLen = GetFullLen();
|
||||
if (fullLen > len) return 0; // buffer is too small and may overflow somewhere else
|
||||
memcpy (buf, &m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
|
||||
if (m_ExtendedLen > 0 && m_ExtendedBuffer)
|
||||
if (m_ExtendedLen > 0)
|
||||
memcpy (buf + DEFAULT_IDENTITY_SIZE, m_ExtendedBuffer, m_ExtendedLen);
|
||||
return fullLen;
|
||||
}
|
||||
@@ -488,7 +480,7 @@ namespace data
|
||||
size_t ret = m_Public->FromBuffer (buf, len);
|
||||
auto cryptoKeyLen = GetPrivateKeyLen ();
|
||||
if (!ret || ret + cryptoKeyLen > len) return 0; // overflow
|
||||
memcpy (m_PrivateKey, buf + ret, cryptoKeyLen);
|
||||
memcpy (m_PrivateKey, buf + ret, cryptoKeyLen);
|
||||
ret += cryptoKeyLen;
|
||||
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
||||
if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
|
||||
@@ -517,7 +509,7 @@ namespace data
|
||||
if (m_Public->GetSignatureLen () + ret > len) return 0;
|
||||
if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret))
|
||||
{
|
||||
LogPrint (eLogError, "Identity: offline signature verification failed");
|
||||
LogPrint (eLogError, "Identity: Offline signature verification failed");
|
||||
return 0;
|
||||
}
|
||||
ret += m_Public->GetSignatureLen ();
|
||||
@@ -662,9 +654,9 @@ namespace data
|
||||
size_t PrivateKeys::GetPrivateKeyLen () const
|
||||
{
|
||||
// private key length always 256, but type 4
|
||||
return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256;
|
||||
}
|
||||
|
||||
return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256;
|
||||
}
|
||||
|
||||
uint8_t * PrivateKeys::GetPadding()
|
||||
{
|
||||
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
|
||||
@@ -689,7 +681,7 @@ namespace data
|
||||
break;
|
||||
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
|
||||
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
|
||||
break;
|
||||
break;
|
||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
||||
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -84,6 +84,7 @@ namespace data
|
||||
typedef uint16_t SigningKeyType;
|
||||
typedef uint16_t CryptoKeyType;
|
||||
|
||||
const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521
|
||||
class IdentityEx
|
||||
{
|
||||
public:
|
||||
@@ -137,7 +138,7 @@ namespace data
|
||||
mutable i2p::crypto::Verifier * m_Verifier = nullptr;
|
||||
mutable std::mutex m_VerifierMutex;
|
||||
size_t m_ExtendedLen;
|
||||
uint8_t * m_ExtendedBuffer;
|
||||
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
class PrivateKeys // for eepsites
|
||||
@@ -222,7 +223,7 @@ namespace data
|
||||
virtual ~RoutingDestination () {};
|
||||
|
||||
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
||||
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const = 0; // encrypt data for
|
||||
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted) const = 0; // encrypt data for
|
||||
virtual bool IsDestination () const = 0; // for garlic
|
||||
|
||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||
@@ -234,7 +235,7 @@ namespace data
|
||||
public:
|
||||
|
||||
virtual ~LocalDestination() {};
|
||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL) const = 0;
|
||||
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL) const = 0;
|
||||
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
||||
|
||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -61,7 +61,7 @@ namespace data
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
if (size > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", m_BufferLen);
|
||||
LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", m_BufferLen);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -77,23 +77,23 @@ namespace data
|
||||
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint8_t num = m_Buffer[size];
|
||||
size++; // num
|
||||
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
|
||||
LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num);
|
||||
if (!num || num > MAX_NUM_LEASES)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num);
|
||||
LogPrint (eLogError, "LeaseSet: Rncorrect number of leases", (int)num);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
if (size + num*LEASE_SIZE > m_BufferLen)
|
||||
{
|
||||
if (size + num*LEASE_SIZE > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UpdateLeasesBegin ();
|
||||
// process leases
|
||||
m_ExpirationTime = 0;
|
||||
@@ -112,7 +112,7 @@ namespace data
|
||||
}
|
||||
if (!m_ExpirationTime)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
|
||||
LogPrint (eLogWarning, "LeaseSet: All leases are expired. Dropped");
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
@@ -121,16 +121,16 @@ namespace data
|
||||
|
||||
// verify
|
||||
if (verifySignature)
|
||||
{
|
||||
{
|
||||
auto signedSize = leases - m_Buffer;
|
||||
if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen);
|
||||
m_IsValid = false;
|
||||
}
|
||||
}
|
||||
else if (!m_Identity->Verify (m_Buffer, signedSize, leases))
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet: verification failed");
|
||||
LogPrint (eLogWarning, "LeaseSet: Verification failed");
|
||||
m_IsValid = false;
|
||||
}
|
||||
}
|
||||
@@ -254,12 +254,12 @@ namespace data
|
||||
return ts > m_ExpirationTime;
|
||||
}
|
||||
|
||||
void LeaseSet::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
|
||||
void LeaseSet::Encrypt (const uint8_t * data, uint8_t * encrypted) const
|
||||
{
|
||||
if (!m_EncryptionKey) return;
|
||||
auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey);
|
||||
if (encryptor)
|
||||
encryptor->Encrypt (data, encrypted, ctx, true);
|
||||
encryptor->Encrypt (data, encrypted);
|
||||
}
|
||||
|
||||
void LeaseSet::SetBuffer (const uint8_t * buf, size_t len)
|
||||
@@ -274,7 +274,7 @@ namespace data
|
||||
{
|
||||
if (len <= m_BufferLen) m_BufferLen = len;
|
||||
else
|
||||
LogPrint (eLogError, "LeaseSet2: actual buffer size ", len , " exceeds full buffer size ", m_BufferLen);
|
||||
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):
|
||||
@@ -331,7 +331,7 @@ namespace data
|
||||
m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset);
|
||||
if (!m_TransientVerifier)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet2: offline signature failed");
|
||||
LogPrint (eLogError, "LeaseSet2: Offline signature failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -378,7 +378,7 @@ namespace data
|
||||
bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset);
|
||||
const_cast<uint8_t *>(buf)[-1] = c;
|
||||
if (!verified)
|
||||
LogPrint (eLogWarning, "LeaseSet2: verification failed");
|
||||
LogPrint (eLogWarning, "LeaseSet2: Verification failed");
|
||||
return verified;
|
||||
}
|
||||
|
||||
@@ -489,7 +489,7 @@ namespace data
|
||||
m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset);
|
||||
if (!m_TransientVerifier)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet2: offline signature failed");
|
||||
LogPrint (eLogError, "LeaseSet2: Offline signature failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -515,7 +515,7 @@ namespace data
|
||||
key->GetBlindedKey (date, blinded.data ());
|
||||
if (memcmp (blindedPublicKey, blinded.data (), blindedKeyLen))
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match");
|
||||
LogPrint (eLogError, "LeaseSet2: Blinded public key doesn't match");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -569,7 +569,7 @@ namespace data
|
||||
ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
|
||||
}
|
||||
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
|
||||
{
|
||||
@@ -653,16 +653,16 @@ namespace data
|
||||
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "LeaseSet2: unknown client auth type ", (int)flag);
|
||||
LogPrint (eLogError, "LeaseSet2: Unknown client auth type ", (int)flag);
|
||||
}
|
||||
return offset - 1;
|
||||
}
|
||||
|
||||
void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
|
||||
void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted) const
|
||||
{
|
||||
auto encryptor = m_Encryptor; // TODO: atomic
|
||||
if (encryptor)
|
||||
encryptor->Encrypt (data, encrypted, ctx, true);
|
||||
encryptor->Encrypt (data, encrypted);
|
||||
}
|
||||
|
||||
uint64_t LeaseSet2::ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const
|
||||
@@ -768,7 +768,7 @@ namespace data
|
||||
size_t size = ident.GetFullLen ();
|
||||
if (size > sz)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", sz);
|
||||
LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", sz);
|
||||
return false;
|
||||
}
|
||||
// encryption key
|
||||
@@ -779,7 +779,7 @@ namespace data
|
||||
++size;
|
||||
if (!numLeases || numLeases > MAX_NUM_LEASES)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)numLeases);
|
||||
LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)numLeases);
|
||||
return false;
|
||||
}
|
||||
const uint8_t * leases = ptr + size;
|
||||
@@ -863,17 +863,17 @@ namespace data
|
||||
}
|
||||
// update expiration
|
||||
if (expirationTime)
|
||||
{
|
||||
{
|
||||
SetExpirationTime (expirationTime*1000LL);
|
||||
auto expires = (int)expirationTime - timestamp;
|
||||
htobe16buf (expiresBuf, expires > 0 ? expires : 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no tunnels or withdraw
|
||||
SetExpirationTime (timestamp*1000LL);
|
||||
memset (expiresBuf, 0, 2); // expires immeditely
|
||||
}
|
||||
}
|
||||
// sign
|
||||
keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
|
||||
}
|
||||
@@ -912,6 +912,11 @@ namespace data
|
||||
uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max
|
||||
size_t publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
|
||||
std::unique_ptr<i2p::crypto::Signer> blindedSigner (i2p::data::PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv));
|
||||
if (!blindedSigner)
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet2: Can't create blinded signer for signature type ", blindedKey.GetSigType ());
|
||||
return;
|
||||
}
|
||||
auto offset = 1;
|
||||
htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type
|
||||
memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key
|
||||
@@ -979,7 +984,7 @@ namespace data
|
||||
m_StoreHash = blindedKey->GetStoreHash ();
|
||||
}
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -93,7 +93,7 @@ namespace data
|
||||
|
||||
// implements RoutingDestination
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
bool IsDestination () const { return true; };
|
||||
|
||||
protected:
|
||||
@@ -156,7 +156,7 @@ namespace data
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
|
||||
// implements RoutingDestination
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
CryptoKeyType GetEncryptionType () const { return m_EncryptionType; };
|
||||
|
||||
private:
|
||||
|
||||
@@ -129,10 +129,10 @@ namespace log {
|
||||
else if (level == "info") { m_MinLevel = eLogInfo; }
|
||||
else if (level == "debug") { m_MinLevel = eLogDebug; }
|
||||
else {
|
||||
LogPrint(eLogError, "Log: unknown loglevel: ", level);
|
||||
LogPrint(eLogError, "Log: Unknown loglevel: ", level);
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogInfo, "Log: min messages level set to ", level);
|
||||
LogPrint(eLogInfo, "Log: Logging level set to ", level);
|
||||
}
|
||||
|
||||
const char * Log::TimeAsString(std::time_t t) {
|
||||
@@ -212,7 +212,7 @@ namespace log {
|
||||
m_LogStream = os;
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogError, "Log: can't open file ", path);
|
||||
LogPrint(eLogError, "Log: Can't open file ", path);
|
||||
}
|
||||
|
||||
void Log::SendTo (std::shared_ptr<std::ostream> os) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "HTTP.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
||||
#include <linux/in6.h>
|
||||
#endif
|
||||
|
||||
@@ -32,14 +32,12 @@ namespace i2p
|
||||
namespace transport
|
||||
{
|
||||
NTCP2Establisher::NTCP2Establisher ():
|
||||
m_SessionRequestBuffer (nullptr), m_SessionCreatedBuffer (nullptr), m_SessionConfirmedBuffer (nullptr)
|
||||
m_SessionConfirmedBuffer (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NTCP2Establisher::~NTCP2Establisher ()
|
||||
{
|
||||
delete[] m_SessionRequestBuffer;
|
||||
delete[] m_SessionCreatedBuffer;
|
||||
delete[] m_SessionConfirmedBuffer;
|
||||
}
|
||||
|
||||
@@ -61,7 +59,7 @@ namespace transport
|
||||
|
||||
void NTCP2Establisher::KDF1Bob ()
|
||||
{
|
||||
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetStaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
|
||||
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
|
||||
}
|
||||
|
||||
void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
|
||||
@@ -93,7 +91,7 @@ namespace transport
|
||||
void NTCP2Establisher::KDF3Alice ()
|
||||
{
|
||||
uint8_t inputKeyMaterial[32];
|
||||
i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
|
||||
i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
|
||||
MixKey (inputKeyMaterial);
|
||||
}
|
||||
|
||||
@@ -112,9 +110,8 @@ namespace transport
|
||||
void NTCP2Establisher::CreateSessionRequestMessage ()
|
||||
{
|
||||
// create buffer and fill padding
|
||||
auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes
|
||||
auto paddingLength = rand () % (NTCP2_SESSION_REQUEST_MAX_SIZE - 64); // message length doesn't exceed 287 bytes
|
||||
m_SessionRequestBufferLen = paddingLength + 64;
|
||||
m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen];
|
||||
RAND_bytes (m_SessionRequestBuffer + 64, paddingLength);
|
||||
// encrypt X
|
||||
i2p::crypto::CBCEncryption encryption;
|
||||
@@ -152,9 +149,8 @@ namespace transport
|
||||
|
||||
void NTCP2Establisher::CreateSessionCreatedMessage ()
|
||||
{
|
||||
auto paddingLen = rand () % (287 - 64);
|
||||
auto paddingLen = rand () % (NTCP2_SESSION_CREATED_MAX_SIZE - 64);
|
||||
m_SessionCreatedBufferLen = paddingLen + 64;
|
||||
m_SessionCreatedBuffer = new uint8_t[m_SessionCreatedBufferLen];
|
||||
RAND_bytes (m_SessionCreatedBuffer + 64, paddingLen);
|
||||
// encrypt Y
|
||||
i2p::crypto::CBCEncryption encryption;
|
||||
@@ -199,8 +195,9 @@ namespace transport
|
||||
MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
|
||||
}
|
||||
|
||||
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen)
|
||||
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew)
|
||||
{
|
||||
clockSkew = false;
|
||||
// decrypt X
|
||||
i2p::crypto::CBCDecryption decryption;
|
||||
decryption.SetKey (i2p::context.GetIdentHash ());
|
||||
@@ -234,10 +231,11 @@ namespace transport
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
uint32_t tsA = bufbe32toh (options + 8);
|
||||
if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew");
|
||||
return false;
|
||||
}
|
||||
clockSkew = true;
|
||||
// we send SessionCreate to let Alice know our time and then close session
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -327,21 +325,22 @@ namespace transport
|
||||
m_Server (server), m_Socket (m_Server.GetService ()),
|
||||
m_IsEstablished (false), m_IsTerminated (false),
|
||||
m_Establisher (new NTCP2Establisher),
|
||||
m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
|
||||
#if OPENSSL_SIPHASH
|
||||
m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr),
|
||||
#else
|
||||
m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
|
||||
#endif
|
||||
m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr),
|
||||
m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_IsSending (false),
|
||||
m_NextPaddingSize (16)
|
||||
m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0),
|
||||
m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16)
|
||||
{
|
||||
if (in_RemoteRouter) // Alice
|
||||
{
|
||||
m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash ();
|
||||
if (addr)
|
||||
{
|
||||
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32);
|
||||
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16);
|
||||
memcpy (m_Establisher->m_RemoteStaticKey, addr->s, 32);
|
||||
memcpy (m_Establisher->m_IV, addr->i, 16);
|
||||
m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port);
|
||||
}
|
||||
else
|
||||
@@ -356,8 +355,6 @@ namespace transport
|
||||
delete[] m_NextReceivedBuffer;
|
||||
delete[] m_NextSendBuffer;
|
||||
#if OPENSSL_SIPHASH
|
||||
if (m_SendSipKey) EVP_PKEY_free (m_SendSipKey);
|
||||
if (m_ReceiveSipKey) EVP_PKEY_free (m_ReceiveSipKey);
|
||||
if (m_SendMDCtx) EVP_MD_CTX_destroy (m_SendMDCtx);
|
||||
if (m_ReceiveMDCtx) EVP_MD_CTX_destroy (m_ReceiveMDCtx);
|
||||
#endif
|
||||
@@ -377,7 +374,7 @@ namespace transport
|
||||
transports.PeerDisconnected (shared_from_this ());
|
||||
m_Server.RemoveNTCP2Session (shared_from_this ());
|
||||
m_SendQueue.clear ();
|
||||
LogPrint (eLogDebug, "NTCP2: session terminated");
|
||||
LogPrint (eLogDebug, "NTCP2: Session terminated");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,6 +402,29 @@ namespace transport
|
||||
htole64buf (nonce + 4, seqn);
|
||||
}
|
||||
|
||||
void NTCP2Session::CreateNextReceivedBuffer (size_t size)
|
||||
{
|
||||
if (m_NextReceivedBuffer)
|
||||
{
|
||||
if (size <= m_NextReceivedBufferSize)
|
||||
return; // buffer is good, do nothing
|
||||
else
|
||||
delete[] m_NextReceivedBuffer;
|
||||
}
|
||||
m_NextReceivedBuffer = new uint8_t[size];
|
||||
m_NextReceivedBufferSize = size;
|
||||
}
|
||||
|
||||
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
|
||||
{
|
||||
if (m_NextReceivedBuffer && !m_IsReceiving &&
|
||||
ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
|
||||
{
|
||||
delete[] m_NextReceivedBuffer;
|
||||
m_NextReceivedBuffer = nullptr;
|
||||
m_NextReceivedBufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void NTCP2Session::KeyDerivationFunctionDataPhase ()
|
||||
{
|
||||
@@ -435,12 +455,11 @@ namespace transport
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: couldn't send SessionRequest message: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP2: Couldn't send SessionRequest message: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Establisher->m_SessionCreatedBuffer = new uint8_t[287]; // TODO: determine actual max size
|
||||
// we receive first 64 bytes (32 Y, and 32 ChaCha/Poly frame) first
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer, 64), boost::asio::transfer_all (),
|
||||
std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -459,11 +478,18 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
|
||||
uint16_t paddingLen = 0;
|
||||
if (m_Establisher->ProcessSessionRequestMessage (paddingLen))
|
||||
bool clockSkew = false;
|
||||
if (m_Establisher->ProcessSessionRequestMessage (paddingLen, clockSkew))
|
||||
{
|
||||
if (paddingLen > 0)
|
||||
if (clockSkew)
|
||||
{
|
||||
if (paddingLen <= 287 - 64) // session request is 287 bytes max
|
||||
// we don't care about padding, send SessionCreated and close session
|
||||
SendSessionCreated ();
|
||||
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ()));
|
||||
}
|
||||
else if (paddingLen > 0)
|
||||
{
|
||||
if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max
|
||||
{
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
|
||||
std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -516,7 +542,7 @@ namespace transport
|
||||
{
|
||||
if (paddingLen > 0)
|
||||
{
|
||||
if (paddingLen <= 287 - 64) // session created is 287 bytes max
|
||||
if (paddingLen <= NTCP2_SESSION_CREATED_MAX_SIZE - 64) // session created is 287 bytes max
|
||||
{
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionCreatedBuffer + 64, paddingLen), boost::asio::transfer_all (),
|
||||
std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -566,7 +592,7 @@ namespace transport
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: couldn't send SessionConfirmed message: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP2: Couldn't send SessionConfirmed message: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
@@ -593,7 +619,7 @@ namespace transport
|
||||
(void) bytes_transferred;
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: couldn't send SessionCreated message: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP2: Couldn't send SessionCreated message: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
@@ -636,7 +662,7 @@ namespace transport
|
||||
// process RI
|
||||
if (buf[0] != eNTCP2BlkRouterInfo)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed");
|
||||
LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -664,7 +690,7 @@ namespace transport
|
||||
auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
|
||||
if (!addr)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: No NTCP2 address wth static key found in SessionConfirmed");
|
||||
LogPrint (eLogError, "NTCP2: No NTCP2 address with static key found in SessionConfirmed");
|
||||
Terminate ();
|
||||
return;
|
||||
}
|
||||
@@ -693,17 +719,19 @@ namespace transport
|
||||
void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey)
|
||||
{
|
||||
#if OPENSSL_SIPHASH
|
||||
m_SendSipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16);
|
||||
EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16);
|
||||
m_SendMDCtx = EVP_MD_CTX_create ();
|
||||
EVP_PKEY_CTX *ctx = nullptr;
|
||||
EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, m_SendSipKey);
|
||||
EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, sipKey);
|
||||
EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
|
||||
EVP_PKEY_free (sipKey);
|
||||
|
||||
m_ReceiveSipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16);
|
||||
sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16);
|
||||
m_ReceiveMDCtx = EVP_MD_CTX_create ();
|
||||
ctx = nullptr;
|
||||
EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, m_ReceiveSipKey);
|
||||
EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, sipKey);
|
||||
EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
|
||||
EVP_PKEY_free (sipKey);
|
||||
#else
|
||||
m_SendSipKey = sendSipKey;
|
||||
m_ReceiveSipKey = receiveSipKey;
|
||||
@@ -719,7 +747,6 @@ namespace transport
|
||||
void NTCP2Session::ServerLogin ()
|
||||
{
|
||||
m_Establisher->CreateEphemeralKey ();
|
||||
m_Establisher->m_SessionRequestBuffer = new uint8_t[287]; // 287 bytes max for now
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (),
|
||||
std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -730,7 +757,7 @@ namespace transport
|
||||
if (IsTerminated ()) return;
|
||||
#ifdef __linux__
|
||||
const int one = 1;
|
||||
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
|
||||
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
|
||||
#endif
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (),
|
||||
std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
@@ -741,7 +768,7 @@ namespace transport
|
||||
if (ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
@@ -756,11 +783,10 @@ namespace transport
|
||||
#endif
|
||||
// m_NextReceivedLen comes from the network in BigEndian
|
||||
m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
|
||||
LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen);
|
||||
LogPrint (eLogDebug, "NTCP2: Received length ", m_NextReceivedLen);
|
||||
if (m_NextReceivedLen >= 16)
|
||||
{
|
||||
if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer;
|
||||
m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen];
|
||||
CreateNextReceivedBuffer (m_NextReceivedLen);
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = m_Socket.available(ec);
|
||||
if (!ec && moreBytes >= m_NextReceivedLen)
|
||||
@@ -774,7 +800,7 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short");
|
||||
LogPrint (eLogError, "NTCP2: Received length ", m_NextReceivedLen, " is too short");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
@@ -787,6 +813,7 @@ namespace transport
|
||||
const int one = 1;
|
||||
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
|
||||
#endif
|
||||
m_IsReceiving = true;
|
||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (),
|
||||
std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
@@ -796,7 +823,7 @@ namespace transport
|
||||
if (ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ());
|
||||
LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
@@ -808,9 +835,9 @@ namespace transport
|
||||
CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
|
||||
if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false))
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: received message decrypted");
|
||||
LogPrint (eLogDebug, "NTCP2: Received message decrypted");
|
||||
ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16);
|
||||
delete[] m_NextReceivedBuffer; m_NextReceivedBuffer = nullptr; // we don't need received buffer anymore
|
||||
m_IsReceiving = false;
|
||||
ReceiveLength ();
|
||||
}
|
||||
else
|
||||
@@ -839,10 +866,10 @@ namespace transport
|
||||
switch (blk)
|
||||
{
|
||||
case eNTCP2BlkDateTime:
|
||||
LogPrint (eLogDebug, "NTCP2: datetime");
|
||||
LogPrint (eLogDebug, "NTCP2: Datetime");
|
||||
break;
|
||||
case eNTCP2BlkOptions:
|
||||
LogPrint (eLogDebug, "NTCP2: options");
|
||||
LogPrint (eLogDebug, "NTCP2: Options");
|
||||
break;
|
||||
case eNTCP2BlkRouterInfo:
|
||||
{
|
||||
@@ -858,25 +885,29 @@ namespace transport
|
||||
LogPrint (eLogError, "NTCP2: I2NP block is too long ", size);
|
||||
break;
|
||||
}
|
||||
auto nextMsg = NewI2NPMessage (size);
|
||||
nextMsg->Align (12); // for possible tunnel msg
|
||||
auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size);
|
||||
nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
|
||||
memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
|
||||
nextMsg->FromNTCP2 ();
|
||||
m_Handler.PutNextMessage (nextMsg);
|
||||
if (nextMsg->len <= nextMsg->maxLen)
|
||||
{
|
||||
memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
|
||||
nextMsg->FromNTCP2 ();
|
||||
m_Handler.PutNextMessage (std::move (nextMsg));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NTCP2: I2NP block is too long for I2NP message");
|
||||
break;
|
||||
}
|
||||
case eNTCP2BlkTermination:
|
||||
if (size >= 9)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 8]));
|
||||
LogPrint (eLogDebug, "NTCP2: Termination. reason=", (int)(frame[offset + 8]));
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "NTCP2: Unexpected termination block size ", size);
|
||||
break;
|
||||
case eNTCP2BlkPadding:
|
||||
LogPrint (eLogDebug, "NTCP2: padding");
|
||||
LogPrint (eLogDebug, "NTCP2: Padding");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk);
|
||||
@@ -888,7 +919,7 @@ namespace transport
|
||||
|
||||
void NTCP2Session::SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf)
|
||||
{
|
||||
#if OPENSSL_SIPHASH
|
||||
#if OPENSSL_SIPHASH
|
||||
EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
|
||||
EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
|
||||
size_t l = 8;
|
||||
@@ -898,7 +929,7 @@ namespace transport
|
||||
#endif
|
||||
// length must be in BigEndian
|
||||
htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key));
|
||||
LogPrint (eLogDebug, "NTCP2: sent length ", frameLen);
|
||||
LogPrint (eLogDebug, "NTCP2: Sent length ", frameLen);
|
||||
}
|
||||
|
||||
void NTCP2Session::SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs)
|
||||
@@ -951,7 +982,7 @@ namespace transport
|
||||
{
|
||||
// allocate send buffer
|
||||
m_NextSendBuffer = new uint8_t[287]; // can be any size > 16, we just allocate 287 frequently
|
||||
// crate padding block
|
||||
// create padding block
|
||||
auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
|
||||
// and padding block to encrypt and send
|
||||
if (paddingLen)
|
||||
@@ -1059,15 +1090,15 @@ namespace transport
|
||||
size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
|
||||
if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
|
||||
if (paddingSize > len) paddingSize = len;
|
||||
if (paddingSize)
|
||||
if (paddingSize)
|
||||
{
|
||||
if (m_NextPaddingSize >= 16)
|
||||
{
|
||||
RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
|
||||
m_NextPaddingSize = 0;
|
||||
}
|
||||
}
|
||||
paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize;
|
||||
}
|
||||
}
|
||||
buf[0] = eNTCP2BlkPadding; // blk
|
||||
htobe16buf (buf + 1, paddingSize); // size
|
||||
memset (buf + 3, 0, paddingSize);
|
||||
@@ -1093,7 +1124,13 @@ namespace transport
|
||||
|
||||
void NTCP2Session::SendTermination (NTCP2TerminationReason reason)
|
||||
{
|
||||
if (!m_SendKey || !m_SendSipKey) return;
|
||||
if (!m_SendKey ||
|
||||
#if OPENSSL_SIPHASH
|
||||
!m_SendMDCtx
|
||||
#else
|
||||
!m_SendSipKey
|
||||
#endif
|
||||
) return;
|
||||
m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block
|
||||
// termination block
|
||||
m_NextSendBuffer[2] = eNTCP2BlkTermination;
|
||||
@@ -1126,7 +1163,7 @@ namespace transport
|
||||
SendQueue ();
|
||||
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: outgoing messages queue size to ",
|
||||
LogPrint (eLogWarning, "NTCP2: Outgoing messages queue size to ",
|
||||
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
|
||||
Terminate ();
|
||||
}
|
||||
@@ -1206,7 +1243,7 @@ namespace transport
|
||||
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
|
||||
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
|
||||
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
||||
if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address
|
||||
{
|
||||
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
|
||||
@@ -1232,7 +1269,7 @@ namespace transport
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: failed to bind to v6 port ", address->port, ": ", ex.what());
|
||||
LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
|
||||
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
|
||||
continue;
|
||||
}
|
||||
@@ -1273,7 +1310,7 @@ namespace transport
|
||||
auto it = m_NTCP2Sessions.find (ident);
|
||||
if (it != m_NTCP2Sessions.end ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP2: session to ", ident.ToBase64 (), " already exists");
|
||||
LogPrint (eLogWarning, "NTCP2: Session to ", ident.ToBase64 (), " already exists");
|
||||
if (incoming)
|
||||
// replace by new session
|
||||
it->second->Terminate ();
|
||||
@@ -1342,7 +1379,7 @@ namespace transport
|
||||
boost::system::error_code ec;
|
||||
conn->GetSocket ().bind (*localAddress, ec);
|
||||
if (ec)
|
||||
LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
|
||||
LogPrint (eLogError, "NTCP2: Can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
|
||||
}
|
||||
conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
|
||||
}
|
||||
@@ -1448,6 +1485,8 @@ namespace transport
|
||||
LogPrint (eLogDebug, "NTCP2: No activity for ", session->GetTerminationTimeout (), " seconds");
|
||||
session->TerminateByTimeout (); // it doesn't change m_NTCP2Session right a way
|
||||
}
|
||||
else
|
||||
it.second->DeleteNextReceiveBuffer (ts);
|
||||
// pending
|
||||
for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();)
|
||||
{
|
||||
@@ -1509,7 +1548,7 @@ namespace transport
|
||||
{
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message());
|
||||
LogPrint(eLogWarning, "NTCP2: Failed to connect to proxy ", ecode.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
@@ -1526,7 +1565,7 @@ namespace transport
|
||||
(void) transferred;
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message());
|
||||
LogPrint(eLogWarning, "NTCP2: SOCKS5 write error ", ec.message());
|
||||
}
|
||||
});
|
||||
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
|
||||
@@ -1535,7 +1574,7 @@ namespace transport
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message());
|
||||
LogPrint(eLogError, "NTCP2: SOCKS5 read error ", ec.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
@@ -1549,14 +1588,14 @@ namespace transport
|
||||
}
|
||||
else if ((*readbuff)[1] == 0xff)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication");
|
||||
LogPrint(eLogError, "NTCP2: SOCKS5 proxy rejected authentication");
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]);
|
||||
}
|
||||
LogPrint(eLogError, "NTCP2: socks5 server gave invalid response");
|
||||
LogPrint(eLogError, "NTCP2: SOCKS5 server gave invalid response");
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
});
|
||||
@@ -1584,7 +1623,7 @@ namespace transport
|
||||
{
|
||||
(void) transferred;
|
||||
if(ec)
|
||||
LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message());
|
||||
LogPrint(eLogError, "NTCP2: HTTP proxy write error ", ec.message());
|
||||
});
|
||||
|
||||
boost::asio::streambuf * readbuff = new boost::asio::streambuf;
|
||||
@@ -1593,7 +1632,7 @@ namespace transport
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message());
|
||||
LogPrint(eLogError, "NTCP2: HTTP proxy read error ", ec.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
}
|
||||
@@ -1611,10 +1650,10 @@ namespace transport
|
||||
return;
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code);
|
||||
LogPrint(eLogError, "NTCP2: HTTP proxy rejected request ", res.code);
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "NTCP2: http proxy gave malformed response");
|
||||
LogPrint(eLogError, "NTCP2: HTTP proxy gave malformed response");
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
delete readbuff;
|
||||
@@ -1623,7 +1662,7 @@ namespace transport
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state");
|
||||
LogPrint(eLogError, "NTCP2: Unknown proxy type, invalid state");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1664,7 +1703,7 @@ namespace transport
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message());
|
||||
LogPrint(eLogError, "NTCP2: Failed to write handshake to socks proxy ", ec.message());
|
||||
return;
|
||||
}
|
||||
});
|
||||
@@ -1674,7 +1713,7 @@ namespace transport
|
||||
{
|
||||
if(e)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message());
|
||||
LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
|
||||
}
|
||||
else if(transferred == sz)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -28,12 +28,15 @@ namespace transport
|
||||
{
|
||||
|
||||
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
|
||||
const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287;
|
||||
const size_t NTCP2_SESSION_CREATED_MAX_SIZE = 287;
|
||||
const int NTCP2_MAX_PADDING_RATIO = 6; // in %
|
||||
|
||||
const int NTCP2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int NTCP2_ESTABLISH_TIMEOUT = 10; // 10 seconds
|
||||
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25*60; // 25 minuntes
|
||||
|
||||
@@ -104,7 +107,7 @@ namespace transport
|
||||
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
||||
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
|
||||
|
||||
bool ProcessSessionRequestMessage (uint16_t& paddingLen);
|
||||
bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew);
|
||||
bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
|
||||
bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
||||
bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
|
||||
@@ -115,7 +118,8 @@ namespace transport
|
||||
i2p::data::IdentHash m_RemoteIdentHash;
|
||||
uint16_t m3p2Len;
|
||||
|
||||
uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer, * m_SessionConfirmedBuffer;
|
||||
uint8_t m_SessionRequestBuffer[NTCP2_SESSION_REQUEST_MAX_SIZE],
|
||||
m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], * m_SessionConfirmedBuffer;
|
||||
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
|
||||
|
||||
};
|
||||
@@ -132,6 +136,7 @@ namespace transport
|
||||
void TerminateByTimeout ();
|
||||
void Done ();
|
||||
void Close () { m_Socket.close (); }; // for accept
|
||||
void DeleteNextReceiveBuffer (uint64_t ts);
|
||||
|
||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||
const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||
@@ -151,6 +156,7 @@ namespace transport
|
||||
void Established ();
|
||||
|
||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||
void CreateNextReceivedBuffer (size_t size);
|
||||
void KeyDerivationFunctionDataPhase ();
|
||||
void SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey);
|
||||
|
||||
@@ -199,13 +205,13 @@ namespace transport
|
||||
uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32];
|
||||
const uint8_t * m_SendKey, * m_ReceiveKey;
|
||||
#if OPENSSL_SIPHASH
|
||||
EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey;
|
||||
EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx;
|
||||
#else
|
||||
const uint8_t * m_SendSipKey, * m_ReceiveSipKey;
|
||||
#endif
|
||||
uint16_t m_NextReceivedLen;
|
||||
uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer;
|
||||
size_t m_NextReceivedBufferSize;
|
||||
union
|
||||
{
|
||||
uint8_t buf[8];
|
||||
@@ -215,12 +221,12 @@ namespace transport
|
||||
|
||||
i2p::I2NPMessagesHandler m_Handler;
|
||||
|
||||
bool m_IsSending;
|
||||
bool m_IsSending, m_IsReceiving;
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
uint64_t m_NextRouterInfoResendTime; // seconds since epoch
|
||||
|
||||
uint16_t m_PaddingSizes[16];
|
||||
int m_NextPaddingSize;
|
||||
int m_NextPaddingSize;
|
||||
};
|
||||
|
||||
class NTCP2Server: private i2p::util::RunnableServiceWithWork
|
||||
@@ -252,7 +258,7 @@ namespace transport
|
||||
void UseProxy(ProxyType proxy, const std::string& address, uint16_t port, const std::string& user, const std::string& pass);
|
||||
|
||||
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
|
||||
@@ -261,7 +267,7 @@ namespace transport
|
||||
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);
|
||||
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
|
||||
|
||||
|
||||
// timer
|
||||
void ScheduleTermination ();
|
||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||
@@ -279,7 +285,7 @@ namespace transport
|
||||
boost::asio::ip::tcp::resolver m_Resolver;
|
||||
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
|
||||
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -55,8 +55,10 @@ namespace data
|
||||
Load ();
|
||||
|
||||
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
|
||||
if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold
|
||||
if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
|
||||
{
|
||||
Reseed ();
|
||||
}
|
||||
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
|
||||
Reseed (); // we don't have a router we can connect to. Trying to reseed
|
||||
|
||||
@@ -64,14 +66,14 @@ namespace data
|
||||
if (it != m_RouterInfos.end ())
|
||||
{
|
||||
// remove own router
|
||||
m_RouterInfos.erase (it);
|
||||
m_Floodfills.remove (it->second);
|
||||
m_RouterInfos.erase (it);
|
||||
}
|
||||
// insert own router
|
||||
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
|
||||
if (i2p::context.IsFloodfill ())
|
||||
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
|
||||
|
||||
|
||||
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
|
||||
|
||||
m_IsRunning = true;
|
||||
@@ -116,7 +118,7 @@ namespace data
|
||||
int numMsgs = 0;
|
||||
while (msg)
|
||||
{
|
||||
LogPrint(eLogDebug, "NetDb: got request with type ", (int) msg->GetTypeID ());
|
||||
LogPrint(eLogDebug, "NetDb: Got request with type ", (int) msg->GetTypeID ());
|
||||
switch (msg->GetTypeID ())
|
||||
{
|
||||
case eI2NPDatabaseStore:
|
||||
@@ -136,7 +138,7 @@ namespace data
|
||||
HandleNTCP2RouterInfoMsg (msg);
|
||||
break;
|
||||
default: // WTF?
|
||||
LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ());
|
||||
LogPrint (eLogError, "NetDb: Unexpected message type ", (int) msg->GetTypeID ());
|
||||
//i2p::HandleI2NPMessage (msg);
|
||||
}
|
||||
if (numMsgs > 100) break;
|
||||
@@ -146,7 +148,7 @@ namespace data
|
||||
}
|
||||
if (!m_IsRunning) break;
|
||||
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
|
||||
|
||||
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
|
||||
{
|
||||
@@ -168,8 +170,8 @@ namespace data
|
||||
lastDestinationCleanup = ts;
|
||||
}
|
||||
|
||||
// publish
|
||||
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
|
||||
// publish
|
||||
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
|
||||
{
|
||||
bool publish = false;
|
||||
if (m_PublishReplyToken)
|
||||
@@ -177,15 +179,15 @@ namespace data
|
||||
// next publishing attempt
|
||||
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
|
||||
}
|
||||
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
|
||||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
|
||||
{
|
||||
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
|
||||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
|
||||
{
|
||||
// new publish
|
||||
m_PublishExcluded.clear ();
|
||||
if (i2p::context.IsFloodfill ())
|
||||
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
|
||||
publish = true;
|
||||
}
|
||||
}
|
||||
if (publish) // update timestamp and publish
|
||||
{
|
||||
i2p::context.UpdateTimestamp (ts);
|
||||
@@ -214,7 +216,7 @@ namespace data
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: runtime exception: ", ex.what ());
|
||||
LogPrint (eLogError, "NetDb: Runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -288,7 +290,7 @@ namespace data
|
||||
if (inserted)
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.push_back (r);
|
||||
@@ -341,7 +343,7 @@ namespace data
|
||||
updated = true;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase32());
|
||||
LogPrint (eLogError, "NetDb: New LeaseSet validation failed: ", ident.ToBase32());
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
@@ -371,7 +373,7 @@ namespace data
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "NetDb: new LeaseSet2 validation failed: ", ident.ToBase32());
|
||||
LogPrint (eLogError, "NetDb: New LeaseSet2 validation failed: ", ident.ToBase32());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -428,7 +430,7 @@ namespace data
|
||||
int riLen = ri->GetBufferLen();
|
||||
if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) {
|
||||
// bad router info
|
||||
LogPrint(eLogError, "NetDb: bad router info");
|
||||
LogPrint(eLogError, "NetDb: Bad router info");
|
||||
return;
|
||||
}
|
||||
m_FloodfillBootstrap = ri;
|
||||
@@ -443,7 +445,7 @@ namespace data
|
||||
|
||||
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
|
||||
{
|
||||
LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64());
|
||||
LogPrint(eLogInfo, "NetDB: Reseeding from floodfill ", ri.GetIdentHashBase64());
|
||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > requests;
|
||||
|
||||
i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
|
||||
@@ -470,22 +472,22 @@ namespace data
|
||||
i2p::transport::transports.SendMessages(ih, requests);
|
||||
}
|
||||
|
||||
bool NetDb::LoadRouterInfo (const std::string & path)
|
||||
bool NetDb::LoadRouterInfo (const std::string& path, uint64_t ts)
|
||||
{
|
||||
auto r = std::make_shared<RouterInfo>(path);
|
||||
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses ())
|
||||
{
|
||||
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses () &&
|
||||
ts < r->GetTimestamp () + 24*60*60*NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT*1000LL)
|
||||
{
|
||||
r->DeleteBuffer ();
|
||||
r->ClearProperties (); // properties are not used for regular routers
|
||||
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
|
||||
{
|
||||
{
|
||||
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||
m_Floodfills.push_back (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid. Delete");
|
||||
LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid or too old. Delete");
|
||||
i2p::fs::Remove(path);
|
||||
}
|
||||
return true;
|
||||
@@ -566,19 +568,20 @@ namespace data
|
||||
m_RouterInfos.clear ();
|
||||
m_Floodfills.clear ();
|
||||
|
||||
m_LastLoad = i2p::util::GetSecondsSinceEpoch();
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
std::vector<std::string> files;
|
||||
m_Storage.Traverse(files);
|
||||
for (const auto& path : files)
|
||||
LoadRouterInfo(path);
|
||||
LoadRouterInfo (path, ts);
|
||||
|
||||
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
|
||||
}
|
||||
|
||||
void NetDb::SaveUpdated ()
|
||||
{
|
||||
int updatedCount = 0, deletedCount = 0;
|
||||
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
|
||||
auto total = m_RouterInfos.size ();
|
||||
auto totalFloodfills = m_Floodfills.size ();
|
||||
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
auto uptime = i2p::context.GetUptime ();
|
||||
@@ -588,24 +591,24 @@ namespace data
|
||||
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;
|
||||
|
||||
auto own = i2p::context.GetSharedRouterInfo ();
|
||||
auto own = i2p::context.GetSharedRouterInfo ();
|
||||
for (auto& it: m_RouterInfos)
|
||||
{
|
||||
if (it.second == own) continue; // skip own
|
||||
std::string ident = it.second->GetIdentHashBase64();
|
||||
std::string path = m_Storage.Path(ident);
|
||||
if (it.second->IsUpdated ())
|
||||
{
|
||||
it.second->SaveToFile (path);
|
||||
it.second->SaveToFile (m_Storage.Path(ident));
|
||||
it.second->SetUpdated (false);
|
||||
it.second->SetUnreachable (false);
|
||||
it.second->DeleteBuffer ();
|
||||
updatedCount++;
|
||||
continue;
|
||||
}
|
||||
// make router reachable back if too few routers
|
||||
if (it.second->IsUnreachable () && total - deletedCount < NETDB_MIN_ROUTERS)
|
||||
it.second->SetUnreachable (false);
|
||||
// make router reachable back if too few routers or floodfills
|
||||
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
|
||||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
|
||||
it.second->SetUnreachable (false);
|
||||
// find & mark expired routers
|
||||
if (!it.second->IsReachable () && it.second->IsSSU (false))
|
||||
{
|
||||
@@ -618,18 +621,21 @@ namespace data
|
||||
|
||||
if (it.second->IsUnreachable ())
|
||||
{
|
||||
if (it.second->IsFloodfill ()) deletedFloodfillsCount++;
|
||||
// delete RI file
|
||||
m_Storage.Remove(ident);
|
||||
deletedCount++;
|
||||
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
|
||||
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
|
||||
}
|
||||
} // m_RouterInfos iteration
|
||||
|
||||
m_RouterInfoBuffersPool.CleanUpMt ();
|
||||
|
||||
if (updatedCount > 0)
|
||||
LogPrint (eLogInfo, "NetDb: saved ", updatedCount, " new/updated routers");
|
||||
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
|
||||
if (deletedCount > 0)
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: deleting ", deletedCount, " unreachable routers");
|
||||
LogPrint (eLogInfo, "NetDb: Deleting ", deletedCount, " unreachable routers");
|
||||
// clean up RouterInfos table
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
@@ -653,7 +659,7 @@ namespace data
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct)
|
||||
@@ -661,7 +667,7 @@ namespace data
|
||||
auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already");
|
||||
LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -669,24 +675,24 @@ namespace data
|
||||
if (floodfill)
|
||||
{
|
||||
if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
|
||||
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||
direct = false; // floodfill can't be reached directly
|
||||
if (direct)
|
||||
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
else
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
|
||||
auto inbound = pool ? pool->GetNextInboundTunnel () : nullptr;
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
||||
auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
||||
if (outbound && inbound)
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound));
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
|
||||
m_Requests.RequestComplete (destination, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Requests.RequestComplete (destination, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found");
|
||||
@@ -700,10 +706,10 @@ namespace data
|
||||
auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already");
|
||||
LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
|
||||
return;
|
||||
}
|
||||
LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64());
|
||||
LogPrint(eLogInfo, "NetDb: Destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64());
|
||||
// direct
|
||||
transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
|
||||
}
|
||||
@@ -727,7 +733,7 @@ namespace data
|
||||
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
|
||||
if (ident.IsZero ())
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: database store with zero ident, dropped");
|
||||
LogPrint (eLogDebug, "NetDb: Database store with zero ident, dropped");
|
||||
return;
|
||||
}
|
||||
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
|
||||
@@ -746,14 +752,14 @@ namespace data
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
|
||||
else
|
||||
LogPrint (eLogWarning, "NetDb: no outbound tunnels for DatabaseStore reply found");
|
||||
LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
|
||||
}
|
||||
offset += 32;
|
||||
}
|
||||
// we must send reply back before this check
|
||||
if (ident == i2p::context.GetIdentHash ())
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: database store with own RouterInfo received, dropped");
|
||||
LogPrint (eLogDebug, "NetDb: Database store with own RouterInfo received, dropped");
|
||||
return;
|
||||
}
|
||||
size_t payloadOffset = offset;
|
||||
@@ -766,24 +772,24 @@ namespace data
|
||||
{
|
||||
if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: store request: LeaseSet for ", ident.ToBase32());
|
||||
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet for ", ident.ToBase32());
|
||||
updated = AddLeaseSet (ident, buf + offset, len - offset);
|
||||
}
|
||||
else // all others are considered as LeaseSet2
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: store request: LeaseSet2 of type ", storeType, " for ", ident.ToBase32());
|
||||
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", storeType, " for ", ident.ToBase32());
|
||||
updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // RouterInfo
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: store request: RouterInfo");
|
||||
LogPrint (eLogDebug, "NetDb: Store request: RouterInfo");
|
||||
size_t size = bufbe16toh (buf + offset);
|
||||
offset += 2;
|
||||
if (size > MAX_RI_BUFFER_SIZE || size > len - offset)
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: invalid RouterInfo length ", (int)size);
|
||||
LogPrint (eLogError, "NetDb: Invalid RouterInfo length ", (int)size);
|
||||
return;
|
||||
}
|
||||
uint8_t uncompressed[MAX_RI_BUFFER_SIZE];
|
||||
@@ -792,7 +798,7 @@ namespace data
|
||||
updated = AddRouterInfo (ident, uncompressed, uncompressedSize);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: decompression failed ", uncompressedSize);
|
||||
LogPrint (eLogInfo, "NetDb: Decompression failed ", uncompressedSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -867,7 +873,7 @@ namespace data
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
}
|
||||
else if(!m_FloodfillBootstrap)
|
||||
LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found");
|
||||
LogPrint (eLogWarning, "NetDb: Requested destination for ", key, " not found");
|
||||
|
||||
// try responses
|
||||
for (int i = 0; i < num; i++)
|
||||
@@ -882,7 +888,7 @@ namespace data
|
||||
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
|
||||
{
|
||||
// router with ident not found or too old (1 hour)
|
||||
LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ...");
|
||||
LogPrint (eLogDebug, "NetDb: Found new/outdated router. Requesting RouterInfo...");
|
||||
if(m_FloodfillBootstrap)
|
||||
RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true);
|
||||
else
|
||||
@@ -923,14 +929,14 @@ namespace data
|
||||
excluded += 2;
|
||||
if (numExcluded > 512)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: number of excluded peers", numExcluded, " exceeds 512");
|
||||
LogPrint (eLogWarning, "NetDb: Number of excluded peers", numExcluded, " exceeds 512");
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> replyMsg;
|
||||
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded");
|
||||
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
||||
std::set<IdentHash> excludedRouters;
|
||||
for (int i = 0; i < numExcluded; i++)
|
||||
{
|
||||
@@ -957,8 +963,9 @@ namespace data
|
||||
auto router = FindRouter (ident);
|
||||
if (router)
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: requested RouterInfo ", key, " found");
|
||||
router->LoadBuffer ();
|
||||
LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
|
||||
if (!router->GetBuffer ())
|
||||
router->LoadBuffer (m_Storage.Path (router->GetIdentHashBase64 ()));
|
||||
if (router->GetBuffer ())
|
||||
replyMsg = CreateDatabaseStoreMsg (router);
|
||||
}
|
||||
@@ -971,11 +978,11 @@ namespace data
|
||||
if (!leaseSet)
|
||||
{
|
||||
// no lease set found
|
||||
LogPrint(eLogDebug, "NetDb: requested LeaseSet not found for ", ident.ToBase32());
|
||||
LogPrint(eLogDebug, "NetDb: Requested LeaseSet not found for ", ident.ToBase32());
|
||||
}
|
||||
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 (ident, leaseSet);
|
||||
}
|
||||
}
|
||||
@@ -1020,10 +1027,10 @@ namespace data
|
||||
replyMsg = garlic.WrapSingleMessage (replyMsg);
|
||||
}
|
||||
if (!replyMsg)
|
||||
LogPrint (eLogError, "NetDb: failed to wrap message");
|
||||
LogPrint (eLogError, "NetDb: Failed to wrap message");
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "NetDb: encrypted reply requested but no tags provided");
|
||||
LogPrint(eLogWarning, "NetDb: Encrypted reply requested but no tags provided");
|
||||
}
|
||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||
@@ -1045,8 +1052,8 @@ namespace data
|
||||
m_PublishExcluded.clear ();
|
||||
m_PublishReplyToken = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NetDb::Explore (int numDestinations)
|
||||
{
|
||||
// new requests
|
||||
@@ -1057,14 +1064,14 @@ namespace data
|
||||
|
||||
uint8_t randomHash[32];
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ...");
|
||||
LogPrint (eLogInfo, "NetDb: Exploring new ", numDestinations, " routers ...");
|
||||
for (int i = 0; i < numDestinations; i++)
|
||||
{
|
||||
RAND_bytes (randomHash, 32);
|
||||
auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: exploratory destination is requested already");
|
||||
LogPrint (eLogWarning, "NetDb: Exploratory destination is requested already");
|
||||
return;
|
||||
}
|
||||
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
|
||||
@@ -1106,7 +1113,7 @@ namespace data
|
||||
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
|
||||
m_PublishExcluded.clear ();
|
||||
}
|
||||
|
||||
|
||||
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
|
||||
if (floodfill)
|
||||
{
|
||||
@@ -1116,19 +1123,19 @@ namespace data
|
||||
m_PublishExcluded.insert (floodfill->GetIdentHash ());
|
||||
m_PublishReplyToken = replyToken;
|
||||
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
|
||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
||||
// send directly
|
||||
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||
else
|
||||
{
|
||||
// otherwise through exploratory
|
||||
// otherwise through exploratory
|
||||
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
|
||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
|
||||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
||||
if (inbound && outbound)
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
|
||||
}
|
||||
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1168,7 +1175,8 @@ namespace data
|
||||
{
|
||||
return !router->IsHidden () && router != compatibleWith &&
|
||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
||||
router->IsReachableFrom (*compatibleWith));
|
||||
router->IsReachableFrom (*compatibleWith)) &&
|
||||
router->IsECIES ();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1177,8 +1185,8 @@ namespace data
|
||||
return GetRandomRouter (
|
||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
return !router->IsHidden () && router->IsPeerTesting (v4) &&
|
||||
!excluded.count (router->GetIdentHash ());
|
||||
return !router->IsHidden () && router->IsECIES () &&
|
||||
router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1187,7 +1195,7 @@ namespace data
|
||||
return GetRandomRouter (
|
||||
[](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
return !router->IsHidden () && router->IsSSUV6 ();
|
||||
return !router->IsHidden () && router->IsECIES () && router->IsSSUV6 ();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1196,8 +1204,8 @@ namespace data
|
||||
return GetRandomRouter (
|
||||
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
return router->IsIntroducer (v4) && !excluded.count (router->GetIdentHash ()) &&
|
||||
!router->IsHidden () && !router->IsFloodfill (); // floodfills don't send relay tag
|
||||
return !router->IsHidden () && router->IsECIES () && !router->IsFloodfill () && // floodfills don't send relay tag
|
||||
router->IsIntroducer (v4) && !excluded.count (router->GetIdentHash ());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1210,11 +1218,8 @@ namespace data
|
||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
||||
router->IsReachableFrom (*compatibleWith)) &&
|
||||
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
||||
#if defined(__x86_64__)
|
||||
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION;
|
||||
#else
|
||||
router->GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
|
||||
#endif
|
||||
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
||||
router->IsECIES ();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1234,12 +1239,12 @@ namespace data
|
||||
return it->second;
|
||||
// try some routers around
|
||||
auto it1 = m_RouterInfos.begin ();
|
||||
if (inds[0])
|
||||
if (inds[0])
|
||||
{
|
||||
// before
|
||||
inds[1] %= inds[0];
|
||||
inds[1] %= inds[0];
|
||||
std::advance (it1, (inds[1] + inds[0])/2);
|
||||
}
|
||||
}
|
||||
else
|
||||
it1 = it;
|
||||
auto it2 = it;
|
||||
@@ -1250,14 +1255,14 @@ namespace data
|
||||
std::advance (it2, inds[2]);
|
||||
}
|
||||
// it1 - from, it2 - to
|
||||
it = it1;
|
||||
it = it1;
|
||||
while (it != it2 && it != m_RouterInfos.end ())
|
||||
{
|
||||
if (!it->second->IsUnreachable () && filter (it->second))
|
||||
return it->second;
|
||||
it++;
|
||||
}
|
||||
// still not found, try from the begining
|
||||
// still not found, try from the beginning
|
||||
it = m_RouterInfos.begin ();
|
||||
while (it != it1 && it != m_RouterInfos.end ())
|
||||
{
|
||||
@@ -1265,7 +1270,7 @@ namespace data
|
||||
return it->second;
|
||||
it++;
|
||||
}
|
||||
// still not found, try to the begining
|
||||
// still not found, try to the beginning
|
||||
it = it2;
|
||||
while (it != m_RouterInfos.end ())
|
||||
{
|
||||
@@ -1359,7 +1364,8 @@ namespace data
|
||||
return res;
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily(const std::string & fam) const {
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily (FamilyID fam) const
|
||||
{
|
||||
return GetRandomRouter(
|
||||
[fam](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -30,19 +30,22 @@
|
||||
#include "NetDbRequests.h"
|
||||
#include "Family.h"
|
||||
#include "version.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_MIN_FLOODFILLS = 5;
|
||||
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
|
||||
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
|
||||
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
|
||||
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
|
||||
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
|
||||
const int NETDB_PUBLISH_INTERVAL = 60 * 40;
|
||||
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
|
||||
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 38); // 0.9.38
|
||||
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
|
||||
@@ -93,7 +96,7 @@ namespace data
|
||||
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
|
||||
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||
|
||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
@@ -119,13 +122,14 @@ namespace data
|
||||
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
|
||||
|
||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||
|
||||
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
|
||||
|
||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||
|
||||
private:
|
||||
|
||||
void Load ();
|
||||
bool LoadRouterInfo (const std::string & path);
|
||||
bool LoadRouterInfo (const std::string& path, uint64_t ts);
|
||||
void SaveUpdated ();
|
||||
void Run (); // exploratory thread
|
||||
void Explore (int numDestinations);
|
||||
@@ -152,7 +156,6 @@ namespace data
|
||||
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
||||
|
||||
bool m_IsRunning;
|
||||
uint64_t m_LastLoad;
|
||||
std::thread * m_Thread;
|
||||
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
|
||||
|
||||
@@ -174,6 +177,8 @@ namespace data
|
||||
|
||||
std::set<IdentHash> m_PublishExcluded;
|
||||
uint32_t m_PublishReplyToken = 0;
|
||||
|
||||
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
|
||||
};
|
||||
|
||||
extern NetDb netdb;
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace data
|
||||
|
||||
if (!i2p::fs::Exists(path))
|
||||
{
|
||||
LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
|
||||
LogPrint(eLogWarning, "Profiling: No profile yet for ", ident);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace data
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
|
||||
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -194,7 +194,7 @@ namespace data
|
||||
continue;
|
||||
}
|
||||
if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
|
||||
LogPrint(eLogDebug, "Profiling: removing expired peer profile: ", path);
|
||||
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
|
||||
i2p::fs::Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -60,19 +60,19 @@ namespace data
|
||||
num = ProcessSU3File (su3FileName.c_str ());
|
||||
}
|
||||
if (num == 0)
|
||||
LogPrint (eLogWarning, "Reseed: failed to reseed from ", su3FileName);
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from ", su3FileName);
|
||||
}
|
||||
else if (zipFileName.length() > 0) // bootstrap from ZIP file
|
||||
{
|
||||
int num = ProcessZIPFile (zipFileName.c_str ());
|
||||
if (num == 0)
|
||||
LogPrint (eLogWarning, "Reseed: failed to reseed from ", zipFileName);
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from ", zipFileName);
|
||||
}
|
||||
else // bootstrap from reseed servers
|
||||
{
|
||||
int num = ReseedFromServers ();
|
||||
if (num == 0)
|
||||
LogPrint (eLogWarning, "Reseed: failed to reseed from servers");
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from servers");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,25 +82,26 @@ namespace data
|
||||
*/
|
||||
int Reseeder::ReseedFromServers ()
|
||||
{
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
bool yggdrasil; i2p::config::GetOption("meshnets.yggdrasil", yggdrasil);
|
||||
|
||||
std::vector<std::string> httpsReseedHostList;
|
||||
if (ipv4 || ipv6)
|
||||
{
|
||||
{
|
||||
std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs);
|
||||
if (!reseedURLs.empty ())
|
||||
boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> yggReseedHostList;
|
||||
if (!i2p::util::net::GetYggdrasilAddress ().is_unspecified ())
|
||||
if (yggdrasil && !i2p::util::net::GetYggdrasilAddress ().is_unspecified ())
|
||||
{
|
||||
LogPrint (eLogInfo, "Reseed: yggdrasil is supported");
|
||||
LogPrint (eLogInfo, "Reseed: Yggdrasil is supported");
|
||||
std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
|
||||
if (!yggReseedURLs.empty ())
|
||||
boost::split(yggReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on);
|
||||
}
|
||||
}
|
||||
|
||||
if (httpsReseedHostList.empty () && yggReseedHostList.empty())
|
||||
{
|
||||
@@ -113,14 +114,14 @@ namespace data
|
||||
{
|
||||
auto ind = rand () % (httpsReseedHostList.size () + yggReseedHostList.size ());
|
||||
bool isHttps = ind < httpsReseedHostList.size ();
|
||||
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
|
||||
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
|
||||
yggReseedHostList[ind - httpsReseedHostList.size ()];
|
||||
reseedUrl += "i2pseeds.su3";
|
||||
auto num = ReseedFromSU3Url (reseedUrl, isHttps);
|
||||
if (num > 0) return num; // success
|
||||
reseedRetries++;
|
||||
}
|
||||
LogPrint (eLogWarning, "Reseed: failed to reseed from servers after 10 attempts");
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from servers after 10 attempts");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -414,13 +415,13 @@ namespace data
|
||||
{
|
||||
if (r && ts > r->GetTimestamp () + 10*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 270 hours
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours");
|
||||
LogPrint (eLogError, "Reseed: Router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours");
|
||||
numOutdated++;
|
||||
}
|
||||
});
|
||||
if (numOutdated > numFiles/2) // more than half
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: mammoth's shit\n"
|
||||
LogPrint (eLogError, "Reseed: Mammoth's shit\n"
|
||||
" *_____*\n"
|
||||
" *_*****_*\n"
|
||||
" *_(O)_(O)_*\n"
|
||||
@@ -478,7 +479,7 @@ namespace data
|
||||
if (terminator) terminator[0] = 0;
|
||||
}
|
||||
// extract RSA key (we need n only, e = 65537)
|
||||
RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
|
||||
const RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
|
||||
const BIGNUM * n, * e, * d;
|
||||
RSA_get0_key(key, &n, &e, &d);
|
||||
PublicKey value;
|
||||
@@ -509,7 +510,7 @@ namespace data
|
||||
|
||||
for (const std::string & file : files) {
|
||||
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
|
||||
LogPrint(eLogWarning, "Reseed: ignoring file ", file);
|
||||
LogPrint(eLogWarning, "Reseed: Ignoring file ", file);
|
||||
continue;
|
||||
}
|
||||
LoadCertificate (file);
|
||||
@@ -533,17 +534,17 @@ namespace data
|
||||
}
|
||||
// check for valid proxy url schema
|
||||
if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") {
|
||||
LogPrint(eLogError, "Reseed: bad proxy url: ", proxy);
|
||||
LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy);
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
LogPrint(eLogError, "Reseed: bad proxy url: ", proxy);
|
||||
LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
i2p::http::URL url;
|
||||
if (!url.parse(address)) {
|
||||
LogPrint(eLogError, "Reseed: failed to parse url: ", address);
|
||||
LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
|
||||
return "";
|
||||
}
|
||||
url.schema = "https";
|
||||
@@ -680,30 +681,30 @@ namespace data
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve (
|
||||
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
{
|
||||
bool connected = false;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
while (it != end)
|
||||
{
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
|
||||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
|
||||
{
|
||||
{
|
||||
s.lowest_layer().connect (ep, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
LogPrint(eLogError, "Reseed: Failed to connect to ", url.host);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ecode)
|
||||
{
|
||||
@@ -743,55 +744,55 @@ namespace data
|
||||
i2p::http::HTTPRes res;
|
||||
int len = res.parse(data);
|
||||
if (len <= 0) {
|
||||
LogPrint(eLogWarning, "Reseed: incomplete/broken response from ", uri);
|
||||
LogPrint(eLogWarning, "Reseed: Incomplete/broken response from ", uri);
|
||||
return "";
|
||||
}
|
||||
if (res.code != 200) {
|
||||
LogPrint(eLogError, "Reseed: failed to reseed from ", uri, ", http code ", res.code);
|
||||
LogPrint(eLogError, "Reseed: Failed to reseed from ", uri, ", http code ", res.code);
|
||||
return "";
|
||||
}
|
||||
data.erase(0, len); /* drop http headers from response */
|
||||
LogPrint(eLogDebug, "Reseed: got ", data.length(), " bytes of data from ", uri);
|
||||
LogPrint(eLogDebug, "Reseed: Got ", data.length(), " bytes of data from ", uri);
|
||||
if (res.is_chunked()) {
|
||||
std::stringstream in(data), out;
|
||||
if (!i2p::http::MergeChunkedResponse(in, out)) {
|
||||
LogPrint(eLogWarning, "Reseed: failed to merge chunked response from ", uri);
|
||||
LogPrint(eLogWarning, "Reseed: Failed to merge chunked response from ", uri);
|
||||
return "";
|
||||
}
|
||||
LogPrint(eLogDebug, "Reseed: got ", data.length(), "(", out.tellg(), ") bytes of data from ", uri);
|
||||
LogPrint(eLogDebug, "Reseed: Got ", data.length(), "(", out.tellg(), ") bytes of data from ", uri);
|
||||
data = out.str();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Reseeder::YggdrasilRequest (const std::string& address)
|
||||
{
|
||||
i2p::http::URL url;
|
||||
if (!url.parse(address))
|
||||
if (!url.parse(address))
|
||||
{
|
||||
LogPrint(eLogError, "Reseed: failed to parse url: ", address);
|
||||
LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
|
||||
return "";
|
||||
}
|
||||
url.schema = "http";
|
||||
if (!url.port) url.port = 80;
|
||||
|
||||
boost::system::error_code ecode;
|
||||
boost::asio::io_service service;
|
||||
boost::asio::io_service service;
|
||||
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
|
||||
|
||||
if (url.host.length () < 2) return ""; // assume []
|
||||
auto host = url.host.substr (1, url.host.length () - 2);
|
||||
LogPrint (eLogDebug, "Reseed: Connecting to yggdrasil ", url.host, ":", url.port);
|
||||
LogPrint (eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port);
|
||||
s.connect (boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v6::from_string (host), url.port), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogDebug, "Reseed: Connected to yggdrasil ", url.host, ":", url.port);
|
||||
LogPrint (eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
|
||||
return ReseedRequest (s, url.to_string());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to yggdrasil ", url.host, ": ", ecode.message ());
|
||||
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ());
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace data
|
||||
std::string HttpsRequest (const std::string& address);
|
||||
std::string YggdrasilRequest (const std::string& address);
|
||||
template<typename Stream>
|
||||
std::string ReseedRequest (Stream& s, const std::string& uri);
|
||||
|
||||
std::string ReseedRequest (Stream& s, const std::string& uri);
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, PublicKey> m_SigningKeys;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -43,11 +43,8 @@ namespace i2p
|
||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||
m_TunnelDecryptor = m_Keys.CreateDecryptor (nullptr);
|
||||
UpdateRouterInfo ();
|
||||
if (IsECIES ())
|
||||
{
|
||||
i2p::crypto::InitNoiseNState (m_InitialNoiseState, GetIdentity ()->GetEncryptionPublicKey ());
|
||||
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState);
|
||||
}
|
||||
i2p::crypto::InitNoiseNState (m_InitialNoiseState, GetIdentity ()->GetEncryptionPublicKey ());
|
||||
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState);
|
||||
}
|
||||
|
||||
void RouterContext::CreateNewRouter ()
|
||||
@@ -60,7 +57,7 @@ namespace i2p
|
||||
|
||||
void RouterContext::NewRouterInfo ()
|
||||
{
|
||||
i2p::data::RouterInfo routerInfo;
|
||||
i2p::data::LocalRouterInfo routerInfo;
|
||||
routerInfo.SetRouterIdentity (GetIdentity ());
|
||||
uint16_t port; i2p::config::GetOption("port", port);
|
||||
if (!port)
|
||||
@@ -72,11 +69,14 @@ namespace i2p
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
|
||||
bool nat; i2p::config::GetOption("nat", nat);
|
||||
|
||||
if ((ntcp2 || ygg) && !m_NTCP2Keys)
|
||||
NewNTCP2Keys ();
|
||||
if (ssu2 && !m_SSU2Keys)
|
||||
NewSSU2Keys ();
|
||||
bool ntcp2Published = false;
|
||||
if (ntcp2)
|
||||
{
|
||||
@@ -87,6 +87,9 @@ namespace i2p
|
||||
if (!ntcp2proxy.empty ()) ntcp2Published = false;
|
||||
}
|
||||
}
|
||||
bool ssu2Published = false;
|
||||
if (ssu2)
|
||||
i2p::config::GetOption("ssu2.published", ssu2Published);
|
||||
uint8_t caps = 0, addressCaps = 0;
|
||||
if (ipv4)
|
||||
{
|
||||
@@ -115,6 +118,16 @@ namespace i2p
|
||||
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
||||
caps |= i2p::data::RouterInfo::eReachable; // R
|
||||
}
|
||||
if (ssu2)
|
||||
{
|
||||
if (ssu2Published)
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), port);
|
||||
else
|
||||
{
|
||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipv6)
|
||||
{
|
||||
@@ -150,6 +163,17 @@ namespace i2p
|
||||
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
||||
caps |= i2p::data::RouterInfo::eReachable; // R
|
||||
}
|
||||
if (ssu2)
|
||||
{
|
||||
if (ssu2Published)
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), port);
|
||||
else
|
||||
{
|
||||
if (!ipv4) // no other ssu2 addresses yet
|
||||
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
|
||||
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ygg)
|
||||
{
|
||||
@@ -160,7 +184,7 @@ namespace i2p
|
||||
|
||||
if (addressCaps)
|
||||
routerInfo.SetUnreachableAddressesTransportCaps (addressCaps);
|
||||
routerInfo.SetCaps (caps); // caps + L
|
||||
routerInfo.UpdateCaps (caps); // caps + L
|
||||
routerInfo.SetProperty ("netId", std::to_string (m_NetID));
|
||||
routerInfo.SetProperty ("router.version", I2P_VERSION);
|
||||
routerInfo.CreateBuffer (m_Keys);
|
||||
@@ -177,17 +201,30 @@ namespace i2p
|
||||
|
||||
void RouterContext::NewNTCP2Keys ()
|
||||
{
|
||||
m_StaticKeys.reset (new i2p::crypto::X25519Keys ());
|
||||
m_StaticKeys->GenerateKeys ();
|
||||
m_NTCP2StaticKeys.reset (new i2p::crypto::X25519Keys ());
|
||||
m_NTCP2StaticKeys->GenerateKeys ();
|
||||
m_NTCP2Keys.reset (new NTCP2PrivateKeys ());
|
||||
m_StaticKeys->GetPrivateKey (m_NTCP2Keys->staticPrivateKey);
|
||||
memcpy (m_NTCP2Keys->staticPublicKey, m_StaticKeys->GetPublicKey (), 32);
|
||||
m_NTCP2StaticKeys->GetPrivateKey (m_NTCP2Keys->staticPrivateKey);
|
||||
memcpy (m_NTCP2Keys->staticPublicKey, m_NTCP2StaticKeys->GetPublicKey (), 32);
|
||||
RAND_bytes (m_NTCP2Keys->iv, 16);
|
||||
// save
|
||||
std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out);
|
||||
fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys));
|
||||
}
|
||||
|
||||
void RouterContext::NewSSU2Keys ()
|
||||
{
|
||||
m_SSU2StaticKeys.reset (new i2p::crypto::X25519Keys ());
|
||||
m_SSU2StaticKeys->GenerateKeys ();
|
||||
m_SSU2Keys.reset (new SSU2PrivateKeys ());
|
||||
m_SSU2StaticKeys->GetPrivateKey (m_SSU2Keys->staticPrivateKey);
|
||||
memcpy (m_SSU2Keys->staticPublicKey, m_SSU2StaticKeys->GetPublicKey (), 32);
|
||||
RAND_bytes (m_SSU2Keys->intro, 32);
|
||||
// save
|
||||
std::ofstream fk (i2p::fs::DataDirPath (SSU2_KEYS), std::ofstream::binary | std::ofstream::out);
|
||||
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||
}
|
||||
|
||||
void RouterContext::SetStatus (RouterStatus status)
|
||||
{
|
||||
if (status != m_Status)
|
||||
@@ -232,7 +269,7 @@ namespace i2p
|
||||
bool updated = false;
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (!address->IsNTCP2 () && address->port != port)
|
||||
if (!address->IsNTCP2 () && !address->IsSSU2 () && address->port != port)
|
||||
{
|
||||
address->port = port;
|
||||
updated = true;
|
||||
@@ -268,7 +305,7 @@ namespace i2p
|
||||
}
|
||||
if (port) address->port = port;
|
||||
address->published = publish;
|
||||
address->ntcp2->iv = m_NTCP2Keys->iv;
|
||||
memcpy (address->i, m_NTCP2Keys->iv, 16);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
@@ -276,7 +313,7 @@ namespace i2p
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
|
||||
void RouterContext::UpdateNTCP2Address (bool enable)
|
||||
{
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
@@ -303,6 +340,59 @@ namespace i2p
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
|
||||
{
|
||||
if (!m_SSU2Keys || (publish && !port)) return;
|
||||
bool updated = false;
|
||||
for (auto& address : m_RouterInfo.GetAddresses ())
|
||||
{
|
||||
if (address->IsSSU2 () && (address->port != port || address->published != publish) &&
|
||||
((v4 && address->IsV4 ()) || (v6 && address->IsV6 ())))
|
||||
{
|
||||
address->port = port;
|
||||
address->published = publish;
|
||||
if (publish)
|
||||
address->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||
else
|
||||
address->caps &= ~i2p::data::RouterInfo::eSSUIntroducer;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateSSU2Address (bool enable)
|
||||
{
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
bool found = false, updated = false;
|
||||
for (auto it = addresses.begin (); it != addresses.end (); ++it)
|
||||
{
|
||||
if ((*it)->IsSSU2 ())
|
||||
{
|
||||
found = true;
|
||||
if (!enable)
|
||||
{
|
||||
addresses.erase (it);
|
||||
updated= true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (enable && !found)
|
||||
{
|
||||
uint8_t addressCaps = 0;
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
|
||||
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
|
||||
updated = true;
|
||||
}
|
||||
if (updated)
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
|
||||
{
|
||||
bool updated = false;
|
||||
@@ -352,10 +442,10 @@ namespace i2p
|
||||
{
|
||||
m_IsFloodfill = floodfill;
|
||||
if (floodfill)
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () | i2p::data::RouterInfo::eFloodfill);
|
||||
else
|
||||
{
|
||||
m_RouterInfo.SetCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||
m_RouterInfo.UpdateCaps (m_RouterInfo.GetCaps () & ~i2p::data::RouterInfo::eFloodfill);
|
||||
// we don't publish number of routers and leaseset for non-floodfill
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_LEASESETS);
|
||||
m_RouterInfo.DeleteProperty (i2p::data::ROUTER_INFO_PROPERTY_ROUTERS);
|
||||
@@ -417,7 +507,7 @@ namespace i2p
|
||||
// no break here, extra + high means 'X'
|
||||
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
|
||||
}
|
||||
m_RouterInfo.SetCaps (caps);
|
||||
m_RouterInfo.UpdateCaps (caps);
|
||||
UpdateRouterInfo ();
|
||||
m_BandwidthLimit = limit;
|
||||
}
|
||||
@@ -472,13 +562,13 @@ namespace i2p
|
||||
caps |= i2p::data::RouterInfo::eUnreachable;
|
||||
if (v6 || !SupportsV6 ())
|
||||
caps &= ~i2p::data::RouterInfo::eFloodfill; // can't be floodfill
|
||||
m_RouterInfo.SetCaps (caps);
|
||||
m_RouterInfo.UpdateCaps (caps);
|
||||
}
|
||||
uint16_t port = 0;
|
||||
// delete previous introducers
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
{
|
||||
addr->published = false;
|
||||
addr->caps &= ~i2p::data::RouterInfo::eSSUIntroducer; // can't be introducer
|
||||
@@ -504,13 +594,13 @@ namespace i2p
|
||||
caps |= i2p::data::RouterInfo::eReachable;
|
||||
if (m_IsFloodfill)
|
||||
caps |= i2p::data::RouterInfo::eFloodfill;
|
||||
m_RouterInfo.SetCaps (caps);
|
||||
m_RouterInfo.UpdateCaps (caps);
|
||||
}
|
||||
uint16_t port = 0;
|
||||
// delete previous introducers
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr : addresses)
|
||||
if (addr->ssu && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
if (addr->ssu && !addr->IsSSU2 () && ((v4 && addr->IsV4 ()) || (v6 && addr->IsV6 ())))
|
||||
{
|
||||
addr->published = true;
|
||||
addr->caps |= i2p::data::RouterInfo::eSSUIntroducer;
|
||||
@@ -539,17 +629,26 @@ namespace i2p
|
||||
if (supportsV6)
|
||||
{
|
||||
// insert v6 addresses if necessary
|
||||
bool foundSSU = false, foundNTCP2 = false;
|
||||
bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
|
||||
uint16_t port = 0;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
for (auto& addr: addresses)
|
||||
{
|
||||
if (addr->IsV6 () && !i2p::util::net::IsYggdrasilAddress (addr->host))
|
||||
{
|
||||
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
||||
foundSSU = true;
|
||||
else if (addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
||||
foundNTCP2 = true;
|
||||
switch (addr->transportStyle)
|
||||
{
|
||||
case i2p::data::RouterInfo::eTransportSSU:
|
||||
foundSSU = true;
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportNTCP:
|
||||
foundNTCP2 = true;
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportSSU2:
|
||||
foundSSU2 = true;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
port = addr->port;
|
||||
}
|
||||
@@ -569,10 +668,10 @@ namespace i2p
|
||||
{
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
|
||||
if (ntcp2)
|
||||
if (ntcp2)
|
||||
{
|
||||
if (ntcp2Published)
|
||||
{
|
||||
{
|
||||
std::string ntcp2Host;
|
||||
if (!i2p::config::IsDefault ("ntcp2.addressv6"))
|
||||
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
|
||||
@@ -581,11 +680,27 @@ namespace i2p
|
||||
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
|
||||
if (!ntcp2Port) ntcp2Port = port;
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
|
||||
}
|
||||
}
|
||||
else
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
|
||||
}
|
||||
}
|
||||
// SSU2
|
||||
if (!foundSSU2)
|
||||
{
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
|
||||
if (ssu2Published)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
|
||||
}
|
||||
else
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
|
||||
}
|
||||
}
|
||||
m_RouterInfo.EnableV6 ();
|
||||
}
|
||||
else
|
||||
@@ -601,7 +716,7 @@ namespace i2p
|
||||
// update
|
||||
if (supportsV4)
|
||||
{
|
||||
bool foundSSU = false, foundNTCP2 = false;
|
||||
bool foundSSU = false, foundNTCP2 = false, foundSSU2 = false;
|
||||
std::string host = "127.0.0.1";
|
||||
uint16_t port = 0;
|
||||
auto& addresses = m_RouterInfo.GetAddresses ();
|
||||
@@ -609,10 +724,19 @@ namespace i2p
|
||||
{
|
||||
if (addr->IsV4 ())
|
||||
{
|
||||
if (addr->transportStyle == i2p::data::RouterInfo::eTransportSSU)
|
||||
foundSSU = true;
|
||||
else if (addr->transportStyle == i2p::data::RouterInfo::eTransportNTCP)
|
||||
foundNTCP2 = true;
|
||||
switch (addr->transportStyle)
|
||||
{
|
||||
case i2p::data::RouterInfo::eTransportSSU:
|
||||
foundSSU = true;
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportNTCP:
|
||||
foundNTCP2 = true;
|
||||
break;
|
||||
case i2p::data::RouterInfo::eTransportSSU2:
|
||||
foundSSU2 = true;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
if (addr->port) port = addr->port;
|
||||
}
|
||||
@@ -641,6 +765,22 @@ namespace i2p
|
||||
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
|
||||
}
|
||||
}
|
||||
// SSU2
|
||||
if (!foundSSU2)
|
||||
{
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
|
||||
if (ssu2Published)
|
||||
{
|
||||
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
|
||||
}
|
||||
else
|
||||
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
|
||||
}
|
||||
}
|
||||
m_RouterInfo.EnableV4 ();
|
||||
}
|
||||
else
|
||||
@@ -797,6 +937,30 @@ namespace i2p
|
||||
else
|
||||
UpdateNTCP2Address (false); // disable NTCP2
|
||||
|
||||
// read SSU2
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
if (ssu2)
|
||||
{
|
||||
// read SSU2 keys if available
|
||||
std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
|
||||
if (s2k)
|
||||
{
|
||||
s2k.seekg (0, std::ios::end);
|
||||
size_t len = s2k.tellg();
|
||||
s2k.seekg (0, std::ios::beg);
|
||||
if (len == sizeof (SSU2PrivateKeys))
|
||||
{
|
||||
m_SSU2Keys.reset (new SSU2PrivateKeys ());
|
||||
s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||
}
|
||||
s2k.close ();
|
||||
}
|
||||
if (!m_SSU2Keys) NewSSU2Keys ();
|
||||
UpdateSSU2Address (true); // enable SSU2
|
||||
}
|
||||
else
|
||||
UpdateSSU2Address (false); // disable SSU2
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -833,27 +997,22 @@ namespace i2p
|
||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||
if (IsECIES ())
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
uint32_t len = bufbe32toh (buf);
|
||||
if (len > msg->GetLength ())
|
||||
{
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
uint32_t len = bufbe32toh (buf);
|
||||
if (len > msg->GetLength ())
|
||||
{
|
||||
LogPrint (eLogWarning, "Router: garlic message length ", len, " exceeds I2NP message length ", msg->GetLength ());
|
||||
return;
|
||||
}
|
||||
buf += 4;
|
||||
if (!HandleECIESx25519TagMessage (buf, len)) // try tag first
|
||||
{
|
||||
// then Noise_N one-time decryption
|
||||
if (m_ECIESSession)
|
||||
m_ECIESSession->HandleNextMessage (buf, len);
|
||||
else
|
||||
LogPrint (eLogError, "Router: Session is not set for ECIES router");
|
||||
}
|
||||
LogPrint (eLogWarning, "Router: garlic message length ", len, " exceeds I2NP message length ", msg->GetLength ());
|
||||
return;
|
||||
}
|
||||
buf += 4;
|
||||
if (!HandleECIESx25519TagMessage (buf, len)) // try tag first
|
||||
{
|
||||
// then Noise_N one-time decryption
|
||||
if (m_ECIESSession)
|
||||
m_ECIESSession->HandleNextMessage (buf, len);
|
||||
else
|
||||
LogPrint (eLogError, "Router: Session is not set for ECIES router");
|
||||
}
|
||||
else
|
||||
i2p::garlic::GarlicDestination::ProcessGarlicMessage (msg);
|
||||
}
|
||||
|
||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
@@ -878,32 +1037,23 @@ namespace i2p
|
||||
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, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const
|
||||
{
|
||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data) : false;
|
||||
}
|
||||
|
||||
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
if (IsECIES ())
|
||||
return DecryptECIESTunnelBuildRecord (encrypted, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE);
|
||||
else
|
||||
{
|
||||
if (!m_TunnelDecryptor) return false;
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
bool success = m_TunnelDecryptor->Decrypt (encrypted, data, ctx, false);
|
||||
BN_CTX_free (ctx);
|
||||
return success;
|
||||
}
|
||||
return DecryptECIESTunnelBuildRecord (encrypted, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE);
|
||||
}
|
||||
|
||||
bool RouterContext::DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize)
|
||||
{
|
||||
{
|
||||
// m_InitialNoiseState is h = SHA256(h || hepk)
|
||||
m_CurrentNoiseState = m_InitialNoiseState;
|
||||
m_CurrentNoiseState.MixHash (encrypted, 32); // h = SHA256(h || sepk)
|
||||
uint8_t sharedSecret[32];
|
||||
if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret, nullptr, false))
|
||||
if (!m_TunnelDecryptor->Decrypt (encrypted, sharedSecret))
|
||||
{
|
||||
LogPrint (eLogWarning, "Router: Incorrect ephemeral public key");
|
||||
return false;
|
||||
@@ -912,7 +1062,7 @@ namespace i2p
|
||||
encrypted += 32;
|
||||
uint8_t nonce[12];
|
||||
memset (nonce, 0, 12);
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState.m_H, 32,
|
||||
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, clearTextSize, m_CurrentNoiseState.m_H, 32,
|
||||
m_CurrentNoiseState.m_CK + 32, nonce, data, clearTextSize, false)) // decrypt
|
||||
{
|
||||
LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed");
|
||||
@@ -924,26 +1074,34 @@ namespace i2p
|
||||
|
||||
bool RouterContext::DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
if (IsECIES ())
|
||||
return DecryptECIESTunnelBuildRecord (encrypted, data, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Router: Can't decrypt short request record on non-ECIES router");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
|
||||
return DecryptECIESTunnelBuildRecord (encrypted, data, SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE);
|
||||
}
|
||||
|
||||
i2p::crypto::X25519Keys& RouterContext::GetNTCP2StaticKeys ()
|
||||
{
|
||||
if (!m_StaticKeys)
|
||||
if (!m_NTCP2StaticKeys)
|
||||
{
|
||||
if (!m_NTCP2Keys) NewNTCP2Keys ();
|
||||
auto x = new i2p::crypto::X25519Keys (m_NTCP2Keys->staticPrivateKey, m_NTCP2Keys->staticPublicKey);
|
||||
if (!m_StaticKeys)
|
||||
m_StaticKeys.reset (x);
|
||||
if (!m_NTCP2StaticKeys)
|
||||
m_NTCP2StaticKeys.reset (x);
|
||||
else
|
||||
delete x;
|
||||
}
|
||||
return *m_StaticKeys;
|
||||
return *m_NTCP2StaticKeys;
|
||||
}
|
||||
|
||||
i2p::crypto::X25519Keys& RouterContext::GetSSU2StaticKeys ()
|
||||
{
|
||||
if (!m_SSU2StaticKeys)
|
||||
{
|
||||
if (!m_SSU2Keys) NewSSU2Keys ();
|
||||
auto x = new i2p::crypto::X25519Keys (m_SSU2Keys->staticPrivateKey, m_SSU2Keys->staticPublicKey);
|
||||
if (!m_SSU2StaticKeys)
|
||||
m_SSU2StaticKeys.reset (x);
|
||||
else
|
||||
delete x;
|
||||
}
|
||||
return *m_SSU2StaticKeys;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "Garlic.h"
|
||||
#include "I18N_langs.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -30,6 +29,7 @@ namespace garlic
|
||||
const char ROUTER_INFO[] = "router.info";
|
||||
const char ROUTER_KEYS[] = "router.keys";
|
||||
const char NTCP2_KEYS[] = "ntcp2.keys";
|
||||
const char SSU2_KEYS[] = "ssu2.keys";
|
||||
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
||||
|
||||
enum RouterStatus
|
||||
@@ -62,13 +62,20 @@ namespace garlic
|
||||
uint8_t iv[16];
|
||||
};
|
||||
|
||||
struct SSU2PrivateKeys
|
||||
{
|
||||
uint8_t staticPublicKey[32];
|
||||
uint8_t staticPrivateKey[32];
|
||||
uint8_t intro[32];
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
RouterContext ();
|
||||
void Init ();
|
||||
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo ()
|
||||
{
|
||||
return std::shared_ptr<i2p::data::RouterInfo> (&m_RouterInfo,
|
||||
@@ -79,11 +86,17 @@ namespace garlic
|
||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||
[](i2p::garlic::GarlicDestination *) {});
|
||||
}
|
||||
|
||||
const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
|
||||
const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; };
|
||||
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
||||
i2p::crypto::X25519Keys& GetStaticKeys ();
|
||||
i2p::crypto::X25519Keys& GetNTCP2StaticKeys ();
|
||||
|
||||
const uint8_t * GetSSU2StaticPublicKey () const { return m_SSU2Keys ? m_SSU2Keys->staticPublicKey : nullptr; };
|
||||
const uint8_t * GetSSU2StaticPrivateKey () const { return m_SSU2Keys ? m_SSU2Keys->staticPrivateKey : nullptr; };
|
||||
const uint8_t * GetSSU2IntroKey () const { return m_SSU2Keys ? m_SSU2Keys->intro : nullptr; };
|
||||
i2p::crypto::X25519Keys& GetSSU2StaticKeys ();
|
||||
|
||||
uint32_t GetUptime () const; // in seconds
|
||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
|
||||
@@ -98,11 +111,13 @@ namespace garlic
|
||||
void SetNetID (int netID) { m_NetID = netID; };
|
||||
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data);
|
||||
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
|
||||
|
||||
|
||||
void UpdatePort (int port); // called from Daemon
|
||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
|
||||
void UpdateNTCP2Address (bool enable);
|
||||
void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
|
||||
void UpdateSSU2Address (bool enable);
|
||||
void RemoveNTCPAddress (bool v4only = true); // delete NTCP address for older routers. TODO: remove later
|
||||
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||
@@ -124,7 +139,6 @@ namespace garlic
|
||||
void SetSupportsV6 (bool supportsV6);
|
||||
void SetSupportsV4 (bool supportsV4);
|
||||
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
|
||||
bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||
|
||||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||
@@ -134,7 +148,7 @@ namespace garlic
|
||||
|
||||
// implements LocalDestination
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, i2p::data::CryptoKeyType preferredCrypto) const;
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
void SetLeaseSetUpdated () {};
|
||||
|
||||
@@ -146,10 +160,6 @@ namespace garlic
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
// i18n
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLanguage () { return m_Language; };
|
||||
void SetLanguage (const std::shared_ptr<const i2p::i18n::Locale> language) { m_Language = language; };
|
||||
|
||||
protected:
|
||||
|
||||
// implements GarlicDestination
|
||||
@@ -162,14 +172,15 @@ namespace garlic
|
||||
void NewRouterInfo ();
|
||||
void UpdateRouterInfo ();
|
||||
void NewNTCP2Keys ();
|
||||
void NewSSU2Keys ();
|
||||
bool Load ();
|
||||
void SaveKeys ();
|
||||
|
||||
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::RouterInfo m_RouterInfo;
|
||||
i2p::data::LocalRouterInfo m_RouterInfo;
|
||||
i2p::data::PrivateKeys m_Keys;
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor, m_TunnelDecryptor;
|
||||
std::shared_ptr<i2p::garlic::RouterIncomingRatchetSession> m_ECIESSession;
|
||||
@@ -183,12 +194,10 @@ namespace garlic
|
||||
int m_NetID;
|
||||
std::mutex m_GarlicMutex;
|
||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||
std::unique_ptr<i2p::crypto::X25519Keys> m_StaticKeys;
|
||||
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
|
||||
std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys;
|
||||
// for ECIESx25519
|
||||
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
|
||||
|
||||
// i18n
|
||||
std::shared_ptr<const i2p::i18n::Locale> m_Language;
|
||||
};
|
||||
|
||||
extern RouterContext context;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -13,12 +13,13 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "Identity.h"
|
||||
#include "Profiling.h"
|
||||
#include "Family.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
@@ -51,10 +52,12 @@ namespace data
|
||||
|
||||
const uint8_t COST_NTCP2_PUBLISHED = 3;
|
||||
const uint8_t COST_NTCP2_NON_PUBLISHED = 14;
|
||||
const uint8_t COST_SSU2_DIRECT = 8;
|
||||
const uint8_t COST_SSU_DIRECT = 9;
|
||||
const uint8_t COST_SSU_THROUGH_INTRODUCERS = 11;
|
||||
const uint8_t COST_SSU2_NON_PUBLISHED = 15;
|
||||
|
||||
const int MAX_RI_BUFFER_SIZE = 2048; // if RouterInfo exceeds 2048 we consider it as malformed, might be changed later
|
||||
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
|
||||
class RouterInfo: public RoutingDestination
|
||||
{
|
||||
public:
|
||||
@@ -65,8 +68,12 @@ namespace data
|
||||
eNTCP2V6 = 0x02,
|
||||
eSSUV4 = 0x04,
|
||||
eSSUV6 = 0x08,
|
||||
eNTCP2V6Mesh = 0x10
|
||||
eNTCP2V6Mesh = 0x10,
|
||||
eSSU2V4 = 0x20,
|
||||
eSSU2V6 = 0x40,
|
||||
eAllTransports = 0xFF
|
||||
};
|
||||
typedef uint8_t CompatibleTransports;
|
||||
|
||||
enum Caps
|
||||
{
|
||||
@@ -85,12 +92,13 @@ namespace data
|
||||
eSSUTesting = 0x04,
|
||||
eSSUIntroducer = 0x08
|
||||
};
|
||||
|
||||
|
||||
enum TransportStyle
|
||||
{
|
||||
eTransportUnknown = 0,
|
||||
eTransportNTCP,
|
||||
eTransportSSU
|
||||
eTransportSSU,
|
||||
eTransportSSU2
|
||||
};
|
||||
|
||||
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
|
||||
@@ -99,7 +107,7 @@ namespace data
|
||||
Introducer (): iPort (0), iExp (0) {};
|
||||
boost::asio::ip::address iHost;
|
||||
int iPort;
|
||||
IntroKey iKey;
|
||||
IntroKey iKey; // or ih for SSU2
|
||||
uint32_t iTag;
|
||||
uint32_t iExp;
|
||||
};
|
||||
@@ -107,26 +115,19 @@ namespace data
|
||||
struct SSUExt
|
||||
{
|
||||
int mtu;
|
||||
IntroKey key; // intro key for SSU
|
||||
std::vector<Introducer> introducers;
|
||||
};
|
||||
|
||||
struct NTCP2Ext
|
||||
{
|
||||
Tag<32> staticKey;
|
||||
Tag<16> iv;
|
||||
};
|
||||
|
||||
struct Address
|
||||
{
|
||||
TransportStyle transportStyle;
|
||||
boost::asio::ip::address host;
|
||||
Tag<32> s, i; // keys, i is first 16 bytes for NTCP2 and 32 bytes intro key for SSU
|
||||
int port;
|
||||
uint64_t date;
|
||||
uint8_t caps;
|
||||
bool published = false;
|
||||
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
||||
std::unique_ptr<NTCP2Ext> ntcp2; // not null for NTCP2
|
||||
|
||||
bool IsCompatible (const boost::asio::ip::address& other) const
|
||||
{
|
||||
@@ -136,7 +137,7 @@ namespace data
|
||||
|
||||
bool operator==(const Address& other) const
|
||||
{
|
||||
return transportStyle == other.transportStyle && IsNTCP2 () == other.IsNTCP2 () &&
|
||||
return transportStyle == other.transportStyle &&
|
||||
host == other.host && port == other.port;
|
||||
}
|
||||
|
||||
@@ -145,87 +146,103 @@ namespace data
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool IsNTCP2 () const { return (bool)ntcp2; };
|
||||
bool IsNTCP2 () const { return transportStyle == eTransportNTCP; };
|
||||
bool IsSSU2 () const { return transportStyle == eTransportSSU2; };
|
||||
bool IsPublishedNTCP2 () const { return IsNTCP2 () && published; };
|
||||
bool IsReachableSSU () const { return (bool)ssu && (published || !ssu->introducers.empty ()); };
|
||||
bool IsReachableSSU () const { return (bool)ssu && (published || UsesIntroducer ()); };
|
||||
bool UsesIntroducer () const { return (bool)ssu && !ssu->introducers.empty (); };
|
||||
|
||||
|
||||
bool IsIntroducer () const { return caps & eSSUIntroducer; };
|
||||
bool IsPeerTesting () const { return caps & eSSUTesting; };
|
||||
|
||||
bool IsV4 () const { return (caps & AddressCaps::eV4) || (host.is_v4 () && !host.is_unspecified ()); };
|
||||
bool IsV6 () const { return (caps & AddressCaps::eV6) || (host.is_v6 () && !host.is_unspecified ()); };
|
||||
};
|
||||
typedef std::list<std::shared_ptr<Address> > Addresses;
|
||||
|
||||
RouterInfo ();
|
||||
class Buffer: public std::array<uint8_t, MAX_RI_BUFFER_SIZE>
|
||||
{
|
||||
public:
|
||||
|
||||
Buffer () = default;
|
||||
Buffer (const uint8_t * buf, size_t len);
|
||||
};
|
||||
|
||||
typedef std::vector<std::shared_ptr<Address> > Addresses;
|
||||
|
||||
RouterInfo (const std::string& fullPath);
|
||||
RouterInfo (const RouterInfo& ) = default;
|
||||
RouterInfo& operator=(const RouterInfo& ) = default;
|
||||
RouterInfo (const uint8_t * buf, int len);
|
||||
~RouterInfo ();
|
||||
RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len);
|
||||
RouterInfo (const uint8_t * buf, size_t len);
|
||||
virtual ~RouterInfo ();
|
||||
|
||||
std::shared_ptr<const IdentityEx> GetRouterIdentity () const { return m_RouterIdentity; };
|
||||
void SetRouterIdentity (std::shared_ptr<const IdentityEx> identity);
|
||||
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
|
||||
uint64_t GetTimestamp () const { return m_Timestamp; };
|
||||
int GetVersion () const { return m_Version; };
|
||||
virtual void SetProperty (const std::string& key, const std::string& value) {};
|
||||
virtual void ClearProperties () {};
|
||||
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
|
||||
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
||||
std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
|
||||
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
|
||||
std::shared_ptr<const Address> GetSSUV6Address () const;
|
||||
std::shared_ptr<const Address> GetYggdrasilAddress () const;
|
||||
std::shared_ptr<const Address> GetSSU2V4Address () const;
|
||||
std::shared_ptr<const Address> GetSSU2V6Address () const;
|
||||
|
||||
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
||||
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
||||
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
|
||||
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
|
||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
|
||||
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
|
||||
const boost::asio::ip::address& host, int port); // published
|
||||
bool AddIntroducer (const Introducer& introducer);
|
||||
bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||
void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only
|
||||
void DeleteProperty (const std::string& key); // called from RouterContext only
|
||||
std::string GetProperty (const std::string& key) const; // called from RouterContext only
|
||||
void ClearProperties () { m_Properties.clear (); };
|
||||
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
||||
void UpdateSupportedTransports ();
|
||||
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
||||
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
||||
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||
bool IsSSU (bool v4only = true) const;
|
||||
bool IsSSUV6 () const;
|
||||
bool IsSSUV6 () const { return m_SupportedTransports & eSSUV6; };
|
||||
bool IsNTCP2 (bool v4only = true) const;
|
||||
bool IsNTCP2V6 () const;
|
||||
bool IsV6 () const;
|
||||
bool IsV4 () const;
|
||||
bool IsMesh () const;
|
||||
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
||||
bool IsSSU2V4 () const { return m_SupportedTransports & eSSU2V4; };
|
||||
bool IsSSU2V6 () const { return m_SupportedTransports & eSSU2V6; };
|
||||
bool IsV6 () const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); };
|
||||
bool IsV4 () const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); };
|
||||
bool IsMesh () const { return m_SupportedTransports & eNTCP2V6Mesh; };
|
||||
void EnableV6 ();
|
||||
void DisableV6 ();
|
||||
void EnableV4 ();
|
||||
void DisableV4 ();
|
||||
void EnableMesh ();
|
||||
void DisableMesh ();
|
||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||
void DisableMesh ();
|
||||
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
|
||||
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; };
|
||||
bool IsReachableBy (uint8_t transports) const { return m_ReachableTransports & transports; };
|
||||
bool IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
|
||||
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
|
||||
bool HasValidAddresses () const { return m_SupportedTransports; };
|
||||
bool IsHidden () const { return m_Caps & eHidden; };
|
||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
bool IsEligibleFloodfill () const;
|
||||
bool IsPeerTesting (bool v4) const;
|
||||
bool IsIntroducer (bool v4) const;
|
||||
|
||||
bool IsPeerTesting (bool v4) const;
|
||||
bool IsIntroducer (bool v4) const;
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t caps);
|
||||
void SetCaps (const char * caps);
|
||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||
|
||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||
const uint8_t * LoadBuffer (); // load if necessary
|
||||
int GetBufferLen () const { return m_BufferLen; };
|
||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||
const uint8_t * GetBuffer () const { return m_Buffer->data (); };
|
||||
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
|
||||
bool IsUpdated () const { return m_IsUpdated; };
|
||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||
@@ -235,47 +252,79 @@ namespace data
|
||||
void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
|
||||
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
|
||||
void DeleteBuffer () { m_Buffer = nullptr; };
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
|
||||
/** return true if we are in a router family and the signature is valid */
|
||||
bool IsFamily(const std::string & fam) const;
|
||||
bool IsFamily (FamilyID famid) const;
|
||||
|
||||
// implements RoutingDestination
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; };
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
|
||||
bool IsDestination () const { return false; };
|
||||
|
||||
protected:
|
||||
|
||||
RouterInfo ();
|
||||
uint8_t * GetBufferPointer (size_t offset = 0 ) { return m_Buffer->data () + offset; };
|
||||
void UpdateBuffer (const uint8_t * buf, size_t len);
|
||||
void SetBufferLen (size_t len) { m_BufferLen = len; };
|
||||
void RefreshTimestamp ();
|
||||
const Addresses& GetAddresses () const { return *m_Addresses; };
|
||||
|
||||
private:
|
||||
|
||||
bool LoadFile ();
|
||||
void ReadFromFile ();
|
||||
bool LoadFile (const std::string& fullPath);
|
||||
void ReadFromFile (const std::string& fullPath);
|
||||
void ReadFromStream (std::istream& s);
|
||||
void ReadFromBuffer (bool verifySignature);
|
||||
void WriteToStream (std::ostream& s) const;
|
||||
size_t ReadString (char* str, size_t len, std::istream& s) const;
|
||||
void WriteString (const std::string& str, std::ostream& s) const;
|
||||
void ExtractCaps (const char * value);
|
||||
uint8_t ExtractAddressCaps (const char * value) const;
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const Address> GetAddress (Filter filter) const;
|
||||
void UpdateCapsProperty ();
|
||||
|
||||
virtual std::shared_ptr<Buffer> NewBuffer () const;
|
||||
|
||||
private:
|
||||
|
||||
std::string m_FullPath, m_Family;
|
||||
FamilyID m_FamilyID;
|
||||
std::shared_ptr<const IdentityEx> m_RouterIdentity;
|
||||
uint8_t * m_Buffer;
|
||||
std::shared_ptr<Buffer> m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
uint64_t m_Timestamp;
|
||||
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||
std::map<std::string, std::string> m_Properties;
|
||||
bool m_IsUpdated, m_IsUnreachable;
|
||||
uint8_t m_SupportedTransports, m_ReachableTransports, m_Caps;
|
||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
|
||||
uint8_t m_Caps;
|
||||
int m_Version;
|
||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||
};
|
||||
|
||||
class LocalRouterInfo: public RouterInfo
|
||||
{
|
||||
public:
|
||||
|
||||
LocalRouterInfo () = default;
|
||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||
void UpdateCaps (uint8_t caps);
|
||||
|
||||
void SetProperty (const std::string& key, const std::string& value) override;
|
||||
void DeleteProperty (const std::string& key);
|
||||
std::string GetProperty (const std::string& key) const;
|
||||
void ClearProperties () override { m_Properties.clear (); };
|
||||
|
||||
private:
|
||||
|
||||
void WriteToStream (std::ostream& s) const;
|
||||
void UpdateCapsProperty ();
|
||||
void WriteString (const std::string& str, std::ostream& s) const;
|
||||
std::shared_ptr<Buffer> NewBuffer () const override;
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, std::string> m_Properties;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -11,10 +11,11 @@
|
||||
#include "Timestamp.h"
|
||||
#include "RouterContext.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "SSU.h"
|
||||
#include "Config.h"
|
||||
#include "util.h"
|
||||
#include "SSU.h"
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
||||
#include <linux/in6.h>
|
||||
#endif
|
||||
|
||||
@@ -33,7 +34,8 @@ namespace transport
|
||||
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
|
||||
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
|
||||
m_IntroducersUpdateTimer (m_Service), m_IntroducersUpdateTimerV6 (m_Service),
|
||||
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service)
|
||||
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_Service),
|
||||
m_IsSyncClockFromPeers (true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -53,7 +55,7 @@ namespace transport
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint (eLogError, "SSU: failed to bind to v4 port ", m_Endpoint.port(), ": ", ex.what());
|
||||
LogPrint (eLogError, "SSU: Failed to bind to v4 port ", m_Endpoint.port(), ": ", ex.what());
|
||||
ThrowFatal ("Unable to start IPv4 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
@@ -66,7 +68,7 @@ namespace transport
|
||||
m_SocketV6.set_option (boost::asio::ip::v6_only (true));
|
||||
m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
|
||||
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
||||
if (m_EndpointV6.address() == boost::asio::ip::address().from_string("::")) // only if not binded to address
|
||||
{
|
||||
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
|
||||
@@ -83,13 +85,14 @@ namespace transport
|
||||
}
|
||||
catch ( std::exception & ex )
|
||||
{
|
||||
LogPrint (eLogError, "SSU: failed to bind to v6 port ", m_EndpointV6.port(), ": ", ex.what());
|
||||
LogPrint (eLogError, "SSU: Failed to bind to v6 port ", m_EndpointV6.port(), ": ", ex.what());
|
||||
ThrowFatal ("Unable to start IPv6 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::Start ()
|
||||
{
|
||||
i2p::config::GetOption("nettime.frompeers", m_IsSyncClockFromPeers);
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
|
||||
if (context.SupportsV4 ())
|
||||
@@ -156,7 +159,7 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ());
|
||||
LogPrint (eLogError, "SSU: Server runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +176,7 @@ namespace transport
|
||||
}
|
||||
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
|
||||
@@ -218,7 +221,7 @@ namespace transport
|
||||
|
||||
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
|
||||
{
|
||||
m_Relays[tag] = relay;
|
||||
m_Relays.emplace (tag, relay);
|
||||
}
|
||||
|
||||
void SSUServer::RemoveRelay (uint32_t tag)
|
||||
@@ -249,20 +252,20 @@ namespace transport
|
||||
|
||||
if (ec)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: send exception: ", ec.message (), " while trying to send data to ", to.address (), ":", to.port (), " (length: ", len, ")");
|
||||
LogPrint (eLogError, "SSU: Send exception: ", ec.message (), " while trying to send data to ", to.address (), ":", to.port (), " (length: ", len, ")");
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::Receive ()
|
||||
{
|
||||
SSUPacket * packet = new SSUPacket ();
|
||||
SSUPacket * packet = m_PacketsPool.AcquireMt ();
|
||||
m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from,
|
||||
std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet));
|
||||
}
|
||||
|
||||
void SSUServer::ReceiveV6 ()
|
||||
{
|
||||
SSUPacket * packet = new SSUPacket ();
|
||||
SSUPacket * packet = m_PacketsPool.AcquireMt ();
|
||||
m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from,
|
||||
std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet));
|
||||
}
|
||||
@@ -293,7 +296,7 @@ namespace transport
|
||||
{
|
||||
while (moreBytes && packets.size () < 25)
|
||||
{
|
||||
packet = new SSUPacket ();
|
||||
packet = m_PacketsPool.AcquireMt ();
|
||||
packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec);
|
||||
if (!ec)
|
||||
{
|
||||
@@ -304,7 +307,7 @@ namespace transport
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU: receive_from error: code ", ec.value(), ": ", ec.message ());
|
||||
delete packet;
|
||||
m_PacketsPool.ReleaseMt (packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -315,10 +318,10 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
delete packet;
|
||||
m_PacketsPool.ReleaseMt (packet);
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: receive error: code ", ecode.value(), ": ", ecode.message ());
|
||||
LogPrint (eLogError, "SSU: Receive error: code ", ecode.value(), ": ", ecode.message ());
|
||||
m_Socket.close ();
|
||||
OpenSocket ();
|
||||
Receive ();
|
||||
@@ -352,7 +355,7 @@ namespace transport
|
||||
{
|
||||
while (moreBytes && packets.size () < 25)
|
||||
{
|
||||
packet = new SSUPacket ();
|
||||
packet = m_PacketsPool.AcquireMt ();
|
||||
packet->len = m_SocketV6.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from, 0, ec);
|
||||
if (!ec)
|
||||
{
|
||||
@@ -363,7 +366,7 @@ namespace transport
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU: v6 receive_from error: code ", ec.value(), ": ", ec.message ());
|
||||
delete packet;
|
||||
m_PacketsPool.ReleaseMt (packet);;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -374,7 +377,7 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
delete packet;
|
||||
m_PacketsPool.ReleaseMt (packet);
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: v6 receive error: code ", ecode.value(), ": ", ecode.message ());
|
||||
@@ -409,7 +412,7 @@ namespace transport
|
||||
session = std::make_shared<SSUSession> (*this, packet->from);
|
||||
session->WaitForConnect ();
|
||||
(*sessions)[packet->from] = session;
|
||||
LogPrint (eLogDebug, "SSU: new session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
|
||||
LogPrint (eLogDebug, "SSU: New session from ", packet->from.address ().to_string (), ":", packet->from.port (), " created");
|
||||
}
|
||||
}
|
||||
if (session)
|
||||
@@ -421,8 +424,8 @@ namespace transport
|
||||
if (session) session->FlushData ();
|
||||
session = nullptr;
|
||||
}
|
||||
delete packet;
|
||||
}
|
||||
m_PacketsPool.ReleaseMt (packets);
|
||||
if (session) session->FlushData ();
|
||||
}
|
||||
|
||||
@@ -797,7 +800,7 @@ namespace transport
|
||||
if (sessions.empty () && !introducers.empty ())
|
||||
{
|
||||
// bump creation time for previous introducers if no new sessions found
|
||||
LogPrint (eLogDebug, "SSU: no new introducers found. Trying to reuse existing");
|
||||
LogPrint (eLogDebug, "SSU: No new introducers found. Trying to reuse existing");
|
||||
for (const auto& it : introducers)
|
||||
{
|
||||
auto session = FindSession (it);
|
||||
@@ -847,7 +850,7 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: can't find more introducers");
|
||||
LogPrint (eLogDebug, "SSU: Can't find more introducers");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -919,13 +922,19 @@ namespace transport
|
||||
}
|
||||
if (numDeleted > 0)
|
||||
LogPrint (eLogDebug, "SSU: ", numDeleted, " peer tests have been expired");
|
||||
// some cleaups. TODO: use separate timer
|
||||
m_FragmentsPool.CleanUp ();
|
||||
m_IncompleteMessagesPool.CleanUp ();
|
||||
m_SentMessagesPool.CleanUp ();
|
||||
|
||||
SchedulePeerTestsCleanupTimer ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::ScheduleTermination ()
|
||||
{
|
||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_CHECK_TIMEOUT));
|
||||
uint64_t timeout = SSU_TERMINATION_CHECK_TIMEOUT + (rand () % SSU_TERMINATION_CHECK_TIMEOUT)/5;
|
||||
m_TerminationTimer.expires_from_now (boost::posix_time::seconds(timeout));
|
||||
m_TerminationTimer.async_wait (std::bind (&SSUServer::HandleTerminationTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
@@ -940,20 +949,23 @@ namespace transport
|
||||
{
|
||||
auto session = it.second;
|
||||
if (it.first != session->GetRemoteEndpoint ())
|
||||
LogPrint (eLogWarning, "SSU: remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first, " adjusted");
|
||||
LogPrint (eLogWarning, "SSU: Remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first, " adjusted");
|
||||
m_Service.post ([session]
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||
LogPrint (eLogWarning, "SSU: No activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||
session->Failed ();
|
||||
});
|
||||
}
|
||||
else
|
||||
it.second->CleanUp (ts);
|
||||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::ScheduleTerminationV6 ()
|
||||
{
|
||||
m_TerminationTimerV6.expires_from_now (boost::posix_time::seconds(SSU_TERMINATION_CHECK_TIMEOUT));
|
||||
uint64_t timeout = SSU_TERMINATION_CHECK_TIMEOUT + (rand () % SSU_TERMINATION_CHECK_TIMEOUT)/5;
|
||||
m_TerminationTimerV6.expires_from_now (boost::posix_time::seconds(timeout));
|
||||
m_TerminationTimerV6.async_wait (std::bind (&SSUServer::HandleTerminationTimerV6,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
@@ -968,13 +980,15 @@ namespace transport
|
||||
{
|
||||
auto session = it.second;
|
||||
if (it.first != session->GetRemoteEndpoint ())
|
||||
LogPrint (eLogWarning, "SSU: remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first);
|
||||
LogPrint (eLogWarning, "SSU: Remote endpoint ", session->GetRemoteEndpoint (), " doesn't match key ", it.first);
|
||||
m_Service.post ([session]
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||
LogPrint (eLogWarning, "SSU: No activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||
session->Failed ();
|
||||
});
|
||||
}
|
||||
else
|
||||
it.second->CleanUp (ts);
|
||||
ScheduleTerminationV6 ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <mutex>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Crypto.h"
|
||||
#include "util.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
@@ -63,16 +64,21 @@ namespace transport
|
||||
void DeleteAllSessions ();
|
||||
|
||||
boost::asio::io_service& GetService () { return m_Service; };
|
||||
i2p::util::MemoryPool<Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
|
||||
i2p::util::MemoryPool<IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
|
||||
i2p::util::MemoryPool<SentMessage>& GetSentMessagesPool () { return m_SentMessagesPool; };
|
||||
|
||||
uint16_t GetPort () const { return m_Endpoint.port (); };
|
||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||
|
||||
|
||||
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
|
||||
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
|
||||
void RemoveRelay (uint32_t tag);
|
||||
std::shared_ptr<SSUSession> FindRelaySession (uint32_t tag);
|
||||
void RescheduleIntroducersUpdateTimer ();
|
||||
void RescheduleIntroducersUpdateTimerV6 ();
|
||||
|
||||
|
||||
void NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
|
||||
PeerTestParticipant GetPeerTestParticipant (uint32_t nonce);
|
||||
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
|
||||
@@ -93,7 +99,7 @@ namespace transport
|
||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
|
||||
|
||||
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
||||
template<typename Filter>
|
||||
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
|
||||
@@ -129,13 +135,19 @@ namespace transport
|
||||
boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6;
|
||||
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
|
||||
boost::asio::ip::udp::socket m_Socket, m_SocketV6;
|
||||
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6,
|
||||
boost::asio::deadline_timer m_IntroducersUpdateTimer, m_IntroducersUpdateTimerV6,
|
||||
m_PeerTestsCleanupTimer, m_TerminationTimer, m_TerminationTimerV6;
|
||||
bool m_IsSyncClockFromPeers;
|
||||
std::list<boost::asio::ip::udp::endpoint> m_Introducers, m_IntroducersV6; // introducers we are connected to
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
|
||||
std::map<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer
|
||||
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
|
||||
|
||||
i2p::util::MemoryPool<Fragment> m_FragmentsPool;
|
||||
i2p::util::MemoryPool<IncompleteMessage> m_IncompleteMessagesPool;
|
||||
i2p::util::MemoryPool<SentMessage> m_SentMessagesPool;
|
||||
i2p::util::MemoryPoolMt<SSUPacket> m_PacketsPool;
|
||||
|
||||
public:
|
||||
// for HTTP only
|
||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||
|
||||
1988
libi2pd/SSU2.cpp
Normal file
1988
libi2pd/SSU2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
325
libi2pd/SSU2.h
Normal file
325
libi2pd/SSU2.h
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* Copyright (c) 2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
* See full license text in LICENSE file at top of project tree
|
||||
*/
|
||||
|
||||
#ifndef SSU2_H__
|
||||
#define SSU2_H__
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <boost/asio.hpp>
|
||||
#include "Crypto.h"
|
||||
#include "RouterInfo.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // in seconds
|
||||
const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds
|
||||
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_MTU = 1488;
|
||||
const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32;
|
||||
const int SSU2_RESEND_INTERVAL = 3; // in seconds
|
||||
const int SSU2_MAX_NUM_RESENDS = 5;
|
||||
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
||||
const size_t SSU2_MAX_WINDOW_SIZE = 128; // in packets
|
||||
|
||||
enum SSU2MessageType
|
||||
{
|
||||
eSSU2SessionRequest = 0,
|
||||
eSSU2SessionCreated = 1,
|
||||
eSSU2SessionConfirmed = 2,
|
||||
eSSU2Data = 6,
|
||||
eSSU2Retry = 9,
|
||||
eSSU2TokenRequest = 10
|
||||
};
|
||||
|
||||
enum SSU2BlockType
|
||||
{
|
||||
eSSU2BlkDateTime = 0,
|
||||
eSSU2BlkOptions, // 1
|
||||
eSSU2BlkRouterInfo, // 2
|
||||
eSSU2BlkI2NPMessage, // 3
|
||||
eSSU2BlkFirstFragment, // 4
|
||||
eSSU2BlkFollowOnFragment, // 5
|
||||
eSSU2BlkTermination, // 6
|
||||
eSSU2BlkRelayRequest, // 7
|
||||
eSSU2BlkRelayResponse, // 8
|
||||
eSSU2BlkRelayIntro, // 9
|
||||
eSSU2BlkPeerTest, // 10
|
||||
eSSU2BlkNextNonce, // 11
|
||||
eSSU2BlkAck, // 12
|
||||
eSSU2BlkAddress, // 13
|
||||
eSSU2BlkIntroKey, // 14
|
||||
eSSU2BlkRelayTagRequest, // 15
|
||||
eSSU2BlkRelayTag, // 16
|
||||
eSSU2BlkNewToken, // 17
|
||||
eSSU2BlkPathChallenge, // 18
|
||||
eSSU2BlkPathResponse, // 19
|
||||
eSSU2BlkFirstPacketNumber, // 20
|
||||
eSSU2BlkPadding = 254
|
||||
};
|
||||
|
||||
enum SSU2SessionState
|
||||
{
|
||||
eSSU2SessionStateUnknown,
|
||||
eSSU2SessionStateIntroduced,
|
||||
eSSU2SessionStateEstablished,
|
||||
eSSU2SessionStateTerminated,
|
||||
eSSU2SessionStateFailed
|
||||
};
|
||||
|
||||
struct SSU2IncompleteMessage
|
||||
{
|
||||
struct Fragment
|
||||
{
|
||||
uint8_t buf[SSU2_MTU];
|
||||
size_t len;
|
||||
bool isLast;
|
||||
};
|
||||
|
||||
std::shared_ptr<I2NPMessage> msg;
|
||||
int nextFragmentNum;
|
||||
uint32_t lastFragmentInsertTime; // in seconds
|
||||
std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
|
||||
};
|
||||
|
||||
// RouterInfo flags
|
||||
const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
||||
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
|
||||
|
||||
class SSU2Server;
|
||||
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
|
||||
{
|
||||
union Header
|
||||
{
|
||||
uint64_t ll[2];
|
||||
uint8_t buf[16];
|
||||
struct
|
||||
{
|
||||
uint64_t connID;
|
||||
uint32_t packetNum;
|
||||
uint8_t type;
|
||||
uint8_t flags[3];
|
||||
} h;
|
||||
};
|
||||
|
||||
struct SentPacket
|
||||
{
|
||||
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
|
||||
size_t payloadSize = 0;
|
||||
uint32_t nextResendTime; // in seconds
|
||||
int numResends = 0;
|
||||
};
|
||||
|
||||
struct SessionConfirmedFragment
|
||||
{
|
||||
Header header;
|
||||
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
|
||||
size_t payloadSize;
|
||||
};
|
||||
|
||||
typedef std::function<void ()> OnEstablished;
|
||||
|
||||
public:
|
||||
|
||||
SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
|
||||
~SSU2Session ();
|
||||
|
||||
void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; };
|
||||
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () const { return m_RemoteEndpoint; };
|
||||
void SetOnEstablished (OnEstablished e) { m_OnEstablished = e; };
|
||||
|
||||
void Connect ();
|
||||
bool Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag);
|
||||
void Terminate ();
|
||||
void TerminateByTimeout ();
|
||||
void CleanUp (uint64_t ts);
|
||||
void FlushData ();
|
||||
void Done () override;
|
||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
|
||||
void Resend (uint64_t ts);
|
||||
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
|
||||
uint64_t GetConnID () const { return m_SourceConnID; };
|
||||
SSU2SessionState GetState () const { return m_State; };
|
||||
void SetState (SSU2SessionState state) { m_State = state; };
|
||||
|
||||
bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len);
|
||||
bool ProcessSessionCreated (uint8_t * buf, size_t len);
|
||||
bool ProcessSessionConfirmed (uint8_t * buf, size_t len);
|
||||
bool ProcessRetry (uint8_t * buf, size_t len);
|
||||
void ProcessData (uint8_t * buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
void Established ();
|
||||
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||
bool SendQueue ();
|
||||
void SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
|
||||
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
|
||||
|
||||
void SendSessionRequest (uint64_t token = 0);
|
||||
void SendSessionCreated (const uint8_t * X);
|
||||
void SendSessionConfirmed (const uint8_t * Y);
|
||||
void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba);
|
||||
void SendTokenRequest ();
|
||||
void SendRetry ();
|
||||
uint32_t SendData (const uint8_t * buf, size_t len); // returns packet num
|
||||
void SendQuickAck ();
|
||||
void SendTermination ();
|
||||
|
||||
void HandlePayload (const uint8_t * buf, size_t len);
|
||||
void HandleAck (const uint8_t * buf, size_t len);
|
||||
void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum);
|
||||
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
|
||||
size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
|
||||
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
|
||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||
bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate
|
||||
void HandleFirstFragment (const uint8_t * buf, size_t len);
|
||||
void HandleFollowOnFragment (const uint8_t * buf, size_t len);
|
||||
bool ConcatOutOfSequenceFragments (std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete
|
||||
void HandleRelayRequest (const uint8_t * buf, size_t len);
|
||||
void HandleRelayIntro (const uint8_t * buf, size_t len);
|
||||
void HandleRelayResponse (const uint8_t * buf, size_t len);
|
||||
|
||||
size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len);
|
||||
size_t CreateAckBlock (uint8_t * buf, size_t len);
|
||||
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
|
||||
size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg);
|
||||
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
|
||||
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
|
||||
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
|
||||
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, uint32_t nonce); // Charlie
|
||||
|
||||
private:
|
||||
|
||||
SSU2Server& m_Server;
|
||||
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
|
||||
std::unique_ptr<SessionConfirmedFragment> m_SessionConfirmedFragment1; // for Bob if applicable
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
|
||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||
uint64_t m_DestConnID, m_SourceConnID;
|
||||
SSU2SessionState m_State;
|
||||
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
|
||||
uint32_t m_SendPacketNum, m_ReceivePacketNum;
|
||||
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
||||
std::map<uint32_t, std::shared_ptr<SentPacket> > m_SentPackets; // packetNum -> packet
|
||||
std::map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // I2NP
|
||||
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
i2p::I2NPMessagesHandler m_Handler;
|
||||
bool m_IsDataReceived;
|
||||
size_t m_WindowSize;
|
||||
uint32_t m_RelayTag; // between Bob and Charlie
|
||||
OnEstablished m_OnEstablished; // callback from Established
|
||||
};
|
||||
|
||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
struct Packet
|
||||
{
|
||||
uint8_t buf[SSU2_MTU];
|
||||
size_t len;
|
||||
boost::asio::ip::udp::endpoint from;
|
||||
};
|
||||
|
||||
class ReceiveService: public i2p::util::RunnableService
|
||||
{
|
||||
public:
|
||||
|
||||
ReceiveService (const std::string& name): RunnableService (name) {};
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
void Start () { StartIOService (); };
|
||||
void Stop () { StopIOService (); };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
SSU2Server ();
|
||||
~SSU2Server () {};
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
|
||||
void AddSession (std::shared_ptr<SSU2Session> session);
|
||||
void RemoveSession (uint64_t connID);
|
||||
void AddSessionByRouterHash (std::shared_ptr<SSU2Session> session);
|
||||
void AddPendingOutgoingSession (std::shared_ptr<SSU2Session> session);
|
||||
|
||||
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
||||
void RemoveRelay (uint32_t tag);
|
||||
std::shared_ptr<SSU2Session> FindRelaySession (uint32_t tag);
|
||||
|
||||
void Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen,
|
||||
const boost::asio::ip::udp::endpoint& to);
|
||||
void Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
|
||||
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);
|
||||
void SendHolePunch (const boost::asio::ip::udp::endpoint& to);
|
||||
|
||||
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address);
|
||||
|
||||
void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp);
|
||||
uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const;
|
||||
uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep);
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint);
|
||||
void Receive (boost::asio::ip::udp::socket& socket);
|
||||
void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred,
|
||||
Packet * packet, boost::asio::ip::udp::socket& socket);
|
||||
void HandleReceivedPacket (Packet * packet);
|
||||
void HandleReceivedPackets (std::vector<Packet *> packets);
|
||||
void ProcessNextPacket (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
|
||||
|
||||
void ScheduleTermination ();
|
||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
void ConnectThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address);
|
||||
|
||||
private:
|
||||
|
||||
ReceiveService m_ReceiveService;
|
||||
boost::asio::ip::udp::socket m_SocketV4, m_SocketV6;
|
||||
std::unordered_map<uint64_t, std::shared_ptr<SSU2Session> > m_Sessions;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<SSU2Session> > m_SessionsByRouterHash;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
|
||||
std::map<boost::asio::ip::udp::endpoint, std::pair<uint64_t, uint32_t> > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds)
|
||||
std::map<uint32_t, std::shared_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
|
||||
i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
|
||||
boost::asio::deadline_timer m_TerminationTimer, m_ResendTimer;
|
||||
std::shared_ptr<SSU2Session> m_LastSession;
|
||||
|
||||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
const decltype(m_Sessions)& GetSSU2Sessions () const { return m_Sessions; };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -33,7 +33,6 @@ namespace transport
|
||||
|
||||
SSUData::SSUData (SSUSession& session):
|
||||
m_Session (session), m_ResendTimer (session.GetService ()),
|
||||
m_IncompleteMessagesCleanupTimer (session.GetService ()),
|
||||
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
|
||||
m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
|
||||
{
|
||||
@@ -45,13 +44,11 @@ namespace transport
|
||||
|
||||
void SSUData::Start ()
|
||||
{
|
||||
ScheduleIncompleteMessagesCleanup ();
|
||||
}
|
||||
|
||||
void SSUData::Stop ()
|
||||
{
|
||||
m_ResendTimer.cancel ();
|
||||
m_IncompleteMessagesCleanupTimer.cancel ();
|
||||
m_IncompleteMessages.clear ();
|
||||
m_SentMessages.clear ();
|
||||
m_ReceivedMessages.clear ();
|
||||
@@ -140,7 +137,7 @@ namespace transport
|
||||
if (bitfield & mask)
|
||||
{
|
||||
if (fragment < numSentFragments)
|
||||
it->second->fragments[fragment].reset (nullptr);
|
||||
it->second->fragments[fragment] = nullptr;
|
||||
}
|
||||
fragment++;
|
||||
mask <<= 1;
|
||||
@@ -182,15 +179,15 @@ namespace transport
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
msg->len -= I2NP_SHORT_HEADER_SIZE;
|
||||
it = m_IncompleteMessages.insert (std::make_pair (msgID,
|
||||
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
|
||||
m_Session.GetServer ().GetIncompleteMessagesPool ().AcquireShared (std::move (msg)))).first;
|
||||
}
|
||||
std::unique_ptr<IncompleteMessage>& incompleteMessage = it->second;
|
||||
auto& incompleteMessage = it->second;
|
||||
// mark fragment as received
|
||||
if (fragmentNum < 64)
|
||||
incompleteMessage->receivedFragmentsBits |= (0x01 << fragmentNum);
|
||||
incompleteMessage->receivedFragmentsBits |= (uint64_t(0x01) << fragmentNum);
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
|
||||
|
||||
|
||||
// handle current fragment
|
||||
if (fragmentNum == incompleteMessage->nextFragmentNum)
|
||||
{
|
||||
@@ -224,8 +221,8 @@ namespace transport
|
||||
{
|
||||
// missing fragment
|
||||
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
||||
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
|
||||
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
|
||||
auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast);
|
||||
if (incompleteMessage->savedFragments.insert (savedFragment).second)
|
||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
||||
@@ -246,11 +243,11 @@ namespace transport
|
||||
{
|
||||
if (!m_ReceivedMessages.count (msgID))
|
||||
{
|
||||
m_ReceivedMessages.insert (msgID);
|
||||
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_ReceivedMessages.emplace (msgID, m_LastMessageReceivedTime);
|
||||
if (!msg->IsExpired ())
|
||||
{
|
||||
m_Handler.PutNextMessage (msg);
|
||||
m_Handler.PutNextMessage (std::move (msg));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "SSU: message expired");
|
||||
@@ -313,8 +310,8 @@ namespace transport
|
||||
if (m_SentMessages.empty ()) // schedule resend at first message only
|
||||
ScheduleResend ();
|
||||
|
||||
auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage)));
|
||||
std::unique_ptr<SentMessage>& sentMessage = ret.first->second;
|
||||
auto ret = m_SentMessages.emplace (msgID, m_Session.GetServer ().GetSentMessagesPool ().AcquireShared ());
|
||||
auto& sentMessage = ret.first->second;
|
||||
if (ret.second)
|
||||
{
|
||||
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
||||
@@ -328,7 +325,7 @@ namespace transport
|
||||
uint32_t fragmentNum = 0;
|
||||
while (len > 0 && fragmentNum <= 127)
|
||||
{
|
||||
Fragment * fragment = new Fragment;
|
||||
auto fragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared ();
|
||||
fragment->fragmentNum = fragmentNum;
|
||||
uint8_t * payload = fragment->buf + sizeof (SSUHeader);
|
||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||
@@ -352,13 +349,13 @@ namespace transport
|
||||
size += payload - fragment->buf;
|
||||
uint8_t rem = size & 0x0F;
|
||||
if (rem) // make sure 16 bytes boundary
|
||||
{
|
||||
{
|
||||
auto padding = 16 - rem;
|
||||
memset (fragment->buf + size, 0, padding);
|
||||
size += padding;
|
||||
}
|
||||
}
|
||||
fragment->len = size;
|
||||
fragments.push_back (std::unique_ptr<Fragment> (fragment));
|
||||
fragments.push_back (fragment);
|
||||
|
||||
// encrypt message with session key
|
||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
||||
@@ -411,14 +408,14 @@ namespace transport
|
||||
// one ack
|
||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||
payload += 4;
|
||||
size_t len = 0;
|
||||
size_t len = 0;
|
||||
while (bits)
|
||||
{
|
||||
*payload = (bits & 0x7F); // next 7 bits
|
||||
bits >>= 7;
|
||||
if (bits) *payload &= 0x80; // 0x80 means non-last
|
||||
payload++; len++;
|
||||
}
|
||||
}
|
||||
*payload = 0; // number of fragments
|
||||
len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4
|
||||
// encrypt message with session key
|
||||
@@ -452,7 +449,7 @@ namespace transport
|
||||
if (f)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
|
||||
m_Session.Send (buf, f->len); // resend
|
||||
numResent++;
|
||||
@@ -487,36 +484,32 @@ namespace transport
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ScheduleIncompleteMessagesCleanup ()
|
||||
void SSUData::CleanUp (uint64_t ts)
|
||||
{
|
||||
m_IncompleteMessagesCleanupTimer.cancel ();
|
||||
m_IncompleteMessagesCleanupTimer.expires_from_now (boost::posix_time::seconds(INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT));
|
||||
auto s = m_Session.shared_from_this();
|
||||
m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||
{ s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); });
|
||||
}
|
||||
|
||||
void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
|
||||
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");
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
}
|
||||
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || ts > m_LastMessageReceivedTime + DECAY_INTERVAL)
|
||||
// decay
|
||||
m_ReceivedMessages.clear ();
|
||||
else
|
||||
{
|
||||
// delete old received messages
|
||||
for (auto it = m_ReceivedMessages.begin (); it != m_ReceivedMessages.end ();)
|
||||
{
|
||||
if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT)
|
||||
it = m_ReceivedMessages.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
// decay
|
||||
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES ||
|
||||
i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL)
|
||||
m_ReceivedMessages.clear ();
|
||||
|
||||
ScheduleIncompleteMessagesCleanup ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <boost/asio.hpp>
|
||||
#include "I2NPProtocol.h"
|
||||
@@ -26,11 +26,7 @@ namespace transport
|
||||
{
|
||||
|
||||
const size_t SSU_MTU_V4 = 1484;
|
||||
#ifdef MESHNET
|
||||
const size_t SSU_MTU_V6 = 1286;
|
||||
#else
|
||||
const size_t SSU_MTU_V6 = 1488;
|
||||
#endif
|
||||
const size_t IPV4_HEADER_SIZE = 20;
|
||||
const size_t IPV6_HEADER_SIZE = 40;
|
||||
const size_t UDP_HEADER_SIZE = 8;
|
||||
@@ -40,6 +36,7 @@ namespace transport
|
||||
const int MAX_NUM_RESENDS = 5;
|
||||
const int DECAY_INTERVAL = 20; // in seconds
|
||||
const int INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
|
||||
const int RECEIVED_MESSAGES_CLEANUP_TIMEOUT = 40; // in seconds
|
||||
const unsigned int MAX_NUM_RECEIVED_MESSAGES = 1000; // how many msgID we store for duplicates check
|
||||
const int MAX_OUTGOING_WINDOW_SIZE = 200; // how many unacked message we can store
|
||||
// data flags
|
||||
@@ -64,7 +61,7 @@ namespace transport
|
||||
|
||||
struct FragmentCmp
|
||||
{
|
||||
bool operator() (const std::unique_ptr<Fragment>& f1, const std::unique_ptr<Fragment>& f2) const
|
||||
bool operator() (const std::shared_ptr<Fragment>& f1, const std::shared_ptr<Fragment>& f2) const
|
||||
{
|
||||
return f1->fragmentNum < f2->fragmentNum;
|
||||
};
|
||||
@@ -76,16 +73,16 @@ namespace transport
|
||||
int nextFragmentNum;
|
||||
uint32_t lastFragmentInsertTime; // in seconds
|
||||
uint64_t receivedFragmentsBits;
|
||||
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
|
||||
std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
|
||||
|
||||
IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0),
|
||||
IncompleteMessage (std::shared_ptr<I2NPMessage>&& m): msg (m), nextFragmentNum (0),
|
||||
lastFragmentInsertTime (0), receivedFragmentsBits (0) {};
|
||||
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
||||
};
|
||||
|
||||
struct SentMessage
|
||||
{
|
||||
std::vector<std::unique_ptr<Fragment> > fragments;
|
||||
std::vector<std::shared_ptr<Fragment> > fragments;
|
||||
uint32_t nextResendTime; // in seconds
|
||||
int numResends;
|
||||
};
|
||||
@@ -100,6 +97,7 @@ namespace transport
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
void CleanUp (uint64_t ts);
|
||||
|
||||
void ProcessMessage (uint8_t * buf, size_t len);
|
||||
void FlushReceivedMessage ();
|
||||
@@ -119,17 +117,13 @@ namespace transport
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
void ScheduleIncompleteMessagesCleanup ();
|
||||
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
SSUSession& m_Session;
|
||||
std::unordered_map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
|
||||
std::unordered_map<uint32_t, std::unique_ptr<SentMessage> > m_SentMessages;
|
||||
std::unordered_set<uint32_t> m_ReceivedMessages;
|
||||
boost::asio::deadline_timer m_ResendTimer, m_IncompleteMessagesCleanupTimer;
|
||||
std::map<uint32_t, std::shared_ptr<IncompleteMessage> > m_IncompleteMessages;
|
||||
std::map<uint32_t, std::shared_ptr<SentMessage> > m_SentMessages;
|
||||
std::unordered_map<uint32_t, uint64_t> m_ReceivedMessages; // msgID -> timestamp in seconds
|
||||
boost::asio::deadline_timer m_ResendTimer;
|
||||
int m_MaxPacketSize, m_PacketSize;
|
||||
i2p::I2NPMessagesHandler m_Handler;
|
||||
uint32_t m_LastMessageReceivedTime; // in second
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
@@ -31,7 +31,7 @@ namespace transport
|
||||
{
|
||||
// we are client
|
||||
auto address = IsV6 () ? router->GetSSUV6Address () : router->GetSSUAddress (true);
|
||||
if (address) m_IntroKey = address->ssu->key;
|
||||
if (address) m_IntroKey = address->i;
|
||||
m_Data.AdjustPacketSize (router); // mtu
|
||||
}
|
||||
else
|
||||
@@ -39,7 +39,7 @@ namespace transport
|
||||
// we are server
|
||||
auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
|
||||
i2p::context.GetRouterInfo ().GetSSUAddress (true);
|
||||
if (address) m_IntroKey = address->ssu->key;
|
||||
if (address) m_IntroKey = address->i;
|
||||
}
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace transport
|
||||
nonZero++;
|
||||
if (nonZero - sharedKey > 32)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored");
|
||||
LogPrint (eLogWarning, "SSU: First 32 bytes of shared key is all zeros. Ignored");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -124,11 +124,11 @@ namespace transport
|
||||
i2p::context.GetRouterInfo ().GetSSUAddress (true);
|
||||
if (!address)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
LogPrint (eLogInfo, "SSU: SSU is not supported");
|
||||
return;
|
||||
}
|
||||
if (Validate (buf, len, address->ssu->key))
|
||||
Decrypt (buf, len, address->ssu->key);
|
||||
if (Validate (buf, len, address->i))
|
||||
Decrypt (buf, len, address->i);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
|
||||
@@ -158,7 +158,7 @@ namespace transport
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "SSU header size ", headerSize, " exceeds packet length ", len);
|
||||
LogPrint (eLogError, "SSU: SSU header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
@@ -177,12 +177,12 @@ namespace transport
|
||||
ProcessSessionConfirmed (buf, len); // buf with header
|
||||
break;
|
||||
case PAYLOAD_TYPE_PEER_TEST:
|
||||
LogPrint (eLogDebug, "SSU: peer test received");
|
||||
LogPrint (eLogDebug, "SSU: Peer test received");
|
||||
ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: session destroy received");
|
||||
LogPrint (eLogDebug, "SSU: Session destroy received");
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
break;
|
||||
}
|
||||
@@ -192,11 +192,11 @@ namespace transport
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
break;
|
||||
case PAYLOAD_TYPE_RELAY_REQUEST:
|
||||
LogPrint (eLogDebug, "SSU: relay request received");
|
||||
LogPrint (eLogDebug, "SSU: Relay request received");
|
||||
ProcessRelayRequest (buf + headerSize, len - headerSize, senderEndpoint);
|
||||
break;
|
||||
case PAYLOAD_TYPE_RELAY_INTRO:
|
||||
LogPrint (eLogDebug, "SSU: relay intro received");
|
||||
LogPrint (eLogDebug, "SSU: Relay intro received");
|
||||
ProcessRelayIntro (buf + headerSize, len - headerSize);
|
||||
break;
|
||||
default:
|
||||
@@ -206,7 +206,7 @@ namespace transport
|
||||
|
||||
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU message: session request");
|
||||
LogPrint (eLogDebug, "SSU message: Session request");
|
||||
bool sendRelayTag = true;
|
||||
auto headerSize = sizeof (SSUHeader);
|
||||
if (((SSUHeader *)buf)->IsExtendedOptions ())
|
||||
@@ -222,7 +222,7 @@ namespace transport
|
||||
}
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "Session request header size ", headerSize, " exceeds packet length ", len);
|
||||
LogPrint (eLogError, "SSU message: Session request header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
if (!m_DHKeysPair)
|
||||
@@ -230,7 +230,7 @@ namespace transport
|
||||
auto pair = std::make_shared<i2p::crypto::DHKeys> ();
|
||||
pair->GenerateKeys ();
|
||||
m_DHKeysPair = pair;
|
||||
}
|
||||
}
|
||||
CreateAESandMacKey (buf + headerSize);
|
||||
SendSessionCreated (buf + headerSize, sendRelayTag);
|
||||
}
|
||||
@@ -249,7 +249,7 @@ namespace transport
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len);
|
||||
LogPrint (eLogError, "SSU message: Session created header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
uint8_t * payload = buf + headerSize;
|
||||
@@ -259,7 +259,7 @@ namespace transport
|
||||
s.Insert (y, 256); // y
|
||||
payload += 256;
|
||||
boost::asio::ip::address ourIP;
|
||||
uint16_t ourPort = 0;
|
||||
uint16_t ourPort = 0;
|
||||
auto addressAndPortLen = ExtractIPAddressAndPort (payload, len, ourIP, ourPort);
|
||||
if (!addressAndPortLen) return;
|
||||
uint8_t * ourAddressAndPort = payload + 1;
|
||||
@@ -274,16 +274,7 @@ namespace transport
|
||||
s.Insert (payload, 8); // relayTag and signed on time
|
||||
m_RelayTag = bufbe32toh (payload);
|
||||
payload += 4; // relayTag
|
||||
if (ourIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
uint32_t signedOnTime = bufbe32toh(payload);
|
||||
if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: clock skew detected ", (int)ts - signedOnTime, ". Check your clock");
|
||||
i2p::context.SetError (eRouterErrorClockSkew);
|
||||
}
|
||||
}
|
||||
uint32_t signedOnTime = bufbe32toh(payload);
|
||||
payload += 4; // signed on time
|
||||
// decrypt signature
|
||||
size_t signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
||||
@@ -295,21 +286,39 @@ namespace transport
|
||||
// verify signature
|
||||
if (s.Verify (m_RemoteIdentity, payload))
|
||||
{
|
||||
if (ourIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
int offset = (int)ts - signedOnTime;
|
||||
if (m_Server.IsSyncClockFromPeers ())
|
||||
{
|
||||
if (std::abs (offset) > SSU_CLOCK_THRESHOLD)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Clock adjusted by ", -offset, " seconds");
|
||||
i2p::util::AdjustTimeOffset (-offset);
|
||||
}
|
||||
}
|
||||
else if (std::abs (offset) > SSU_CLOCK_SKEW)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Clock skew detected ", offset, ". Check your clock");
|
||||
i2p::context.SetError (eRouterErrorClockSkew);
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "SSU: Our external address is ", ourIP.to_string (), ":", ourPort);
|
||||
if (!i2p::util::net::IsInReservedRange (ourIP))
|
||||
{
|
||||
{
|
||||
i2p::context.UpdateAddress (ourIP);
|
||||
SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen);
|
||||
}
|
||||
SendSessionConfirmed (y, ourAddressAndPort, addressAndPortLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Wrong external address ", ourIP.to_string ());
|
||||
{
|
||||
LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU: message 'created' signature verification failed");
|
||||
LogPrint (eLogError, "SSU: Message 'created' signature verification failed");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
@@ -317,7 +326,7 @@ namespace transport
|
||||
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: Session confirmed received");
|
||||
m_ConnectTimer.cancel ();
|
||||
m_ConnectTimer.cancel ();
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
@@ -331,7 +340,7 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Session confirmed identity size ", identitySize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
payload += 2; // size of identity fragment
|
||||
auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize);
|
||||
auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already
|
||||
@@ -342,7 +351,7 @@ namespace transport
|
||||
uint32_t signedOnTime = bufbe32toh(payload);
|
||||
if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
|
||||
{
|
||||
LogPrint (eLogError, "SSU message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew");
|
||||
LogPrint (eLogError, "SSU: Message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew");
|
||||
Failed ();
|
||||
return;
|
||||
}
|
||||
@@ -357,7 +366,7 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Session confirmed message is too short ", len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// verify signature
|
||||
if (m_SignedData && m_SignedData->Verify (m_RemoteIdentity, payload))
|
||||
{
|
||||
@@ -366,7 +375,7 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU message 'confirmed' signature verification failed");
|
||||
LogPrint (eLogError, "SSU: Message 'confirmed' signature verification failed");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
@@ -413,7 +422,7 @@ namespace transport
|
||||
i2p::context.GetRouterInfo ().GetSSUAddress (true);
|
||||
if (!address)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
LogPrint (eLogInfo, "SSU: SSU is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -427,7 +436,7 @@ namespace transport
|
||||
payload += 2;
|
||||
*payload = 0; // challenge
|
||||
payload++;
|
||||
memcpy (payload, (const uint8_t *)address->ssu->key, 32);
|
||||
memcpy (payload, (const uint8_t *)address->i, 32);
|
||||
payload += 32;
|
||||
htobe32buf (payload, nonce); // nonce
|
||||
|
||||
@@ -438,7 +447,7 @@ namespace transport
|
||||
else
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
|
||||
m_Server.Send (buf, 96, m_RemoteEndpoint);
|
||||
LogPrint (eLogDebug, "SSU: relay request sent");
|
||||
LogPrint (eLogDebug, "SSU: Relay request sent");
|
||||
}
|
||||
|
||||
void SSUSession::SendSessionCreated (const uint8_t * x, bool sendRelayTag)
|
||||
@@ -447,7 +456,7 @@ namespace transport
|
||||
i2p::context.GetRouterInfo ().GetSSUAddress (true); //v4 only
|
||||
if (!address)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
LogPrint (eLogInfo, "SSU: SSU is not supported");
|
||||
return;
|
||||
}
|
||||
SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
|
||||
@@ -599,19 +608,19 @@ namespace transport
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
// Charlie
|
||||
if (isV4)
|
||||
{
|
||||
{
|
||||
*payload = 4;
|
||||
payload++; // size
|
||||
memcpy (payload, to.address ().to_v4 ().to_bytes ().data (), 4); // Charlie's IP V4
|
||||
payload += 4; // address
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*payload = 16;
|
||||
payload++; // size
|
||||
memcpy (payload, to.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6
|
||||
memcpy (payload, to.address ().to_v6 ().to_bytes ().data (), 16); // Charlie's IP V6
|
||||
payload += 16; // address
|
||||
}
|
||||
}
|
||||
htobe16buf (payload, to.port ()); // Charlie's port
|
||||
payload += 2; // port
|
||||
// Alice
|
||||
@@ -647,7 +656,7 @@ namespace transport
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
|
||||
m_Server.Send (buf, isV4 ? 64 : 80, from);
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU: relay response sent");
|
||||
LogPrint (eLogDebug, "SSU: Relay response sent");
|
||||
}
|
||||
|
||||
void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from)
|
||||
@@ -683,7 +692,7 @@ namespace transport
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, isV4 ? 48 : 64, session->m_SessionKey, iv, session->m_MacKey);
|
||||
m_Server.Send (buf, isV4 ? 48 : 64, session->m_RemoteEndpoint);
|
||||
LogPrint (eLogDebug, "SSU: relay intro sent");
|
||||
LogPrint (eLogDebug, "SSU: Relay intro sent");
|
||||
}
|
||||
|
||||
void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
|
||||
@@ -703,17 +712,17 @@ namespace transport
|
||||
if (!i2p::util::net::IsInReservedRange (ourIP))
|
||||
i2p::context.UpdateAddress (ourIP);
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Wrong external address ", ourIP.to_string ());
|
||||
LogPrint (eLogError, "SSU: External address ", ourIP.to_string (), " is in reserved range");
|
||||
if (ourIP.is_v4 ())
|
||||
{
|
||||
{
|
||||
if (ourPort != m_Server.GetPort ())
|
||||
{
|
||||
{
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
i2p::context.SetError (eRouterErrorSymmetricNAT);
|
||||
}
|
||||
else if (i2p::context.GetStatus () == eRouterStatusError && i2p::context.GetError () == eRouterErrorSymmetricNAT)
|
||||
i2p::context.SetStatus (eRouterStatusTesting);
|
||||
}
|
||||
}
|
||||
uint32_t nonce = bufbe32toh (buf);
|
||||
buf += 4; // nonce
|
||||
auto it = m_RelayRequests.find (nonce);
|
||||
@@ -727,10 +736,10 @@ namespace transport
|
||||
// now we do
|
||||
LogPrint (eLogInfo, "SSU: RelayReponse connecting to endpoint ", remoteEndpoint);
|
||||
if ((remoteIP.is_v4 () && i2p::context.GetStatus () == eRouterStatusFirewalled) ||
|
||||
(remoteIP.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
|
||||
(remoteIP.is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusFirewalled))
|
||||
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||
// we assume that HolePunch has been sent by this time and our SessionRequest will go through
|
||||
m_Server.CreateDirectSession (it->second, remoteEndpoint, false);
|
||||
m_Server.CreateDirectSession (it->second.first, remoteEndpoint, false);
|
||||
}
|
||||
// delete request
|
||||
m_RelayRequests.erase (it);
|
||||
@@ -803,7 +812,7 @@ namespace transport
|
||||
htobe16buf (out + len + 16, (netid == I2PD_NET_ID) ? encryptedLen : encryptedLen ^ ((netid - 2) << 8));
|
||||
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
|
||||
}
|
||||
|
||||
|
||||
void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
@@ -872,7 +881,7 @@ namespace transport
|
||||
if (!IsOutgoing ()) // incoming session
|
||||
ScheduleConnectTimer ();
|
||||
else
|
||||
LogPrint (eLogError, "SSU: wait for connect for outgoing session");
|
||||
LogPrint (eLogError, "SSU: Wait for connect for outgoing session");
|
||||
}
|
||||
|
||||
void SSUSession::ScheduleConnectTimer ()
|
||||
@@ -888,7 +897,7 @@ namespace transport
|
||||
if (!ecode)
|
||||
{
|
||||
// timeout expired
|
||||
LogPrint (eLogWarning, "SSU: session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
|
||||
LogPrint (eLogWarning, "SSU: Session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
@@ -905,7 +914,8 @@ namespace transport
|
||||
}
|
||||
uint32_t nonce;
|
||||
RAND_bytes ((uint8_t *)&nonce, 4);
|
||||
m_RelayRequests[nonce] = to;
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_RelayRequests.emplace (nonce, std::make_pair (to, ts));
|
||||
SendRelayRequest (introducer, nonce);
|
||||
}
|
||||
|
||||
@@ -1004,10 +1014,22 @@ namespace transport
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::CleanUp (uint64_t ts)
|
||||
{
|
||||
m_Data.CleanUp (ts);
|
||||
for (auto it = m_RelayRequests.begin (); it != m_RelayRequests.end ();)
|
||||
{
|
||||
if (ts > it->second.second + SSU_CONNECT_TIMEOUT)
|
||||
it = m_RelayRequests.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
{
|
||||
uint32_t nonce = bufbe32toh (buf); // 4 bytes
|
||||
boost::asio::ip::address addr; // Alice's addresss
|
||||
boost::asio::ip::address addr; // Alice's address
|
||||
uint16_t port = 0; // and port
|
||||
auto size = ExtractIPAddressAndPort (buf + 4, len - 4, addr, port);
|
||||
if (port && (size != 7) && (size != 19))
|
||||
@@ -1023,29 +1045,29 @@ namespace transport
|
||||
{
|
||||
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Alice");
|
||||
if (IsV6 ())
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
||||
{
|
||||
i2p::context.SetStatusV6 (eRouterStatusFirewalled);
|
||||
m_Server.RescheduleIntroducersUpdateTimerV6 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (i2p::context.GetStatus () == eRouterStatusTesting) // still not OK
|
||||
{
|
||||
{
|
||||
i2p::context.SetStatus (eRouterStatusFirewalled);
|
||||
m_Server.RescheduleIntroducersUpdateTimer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: first peer test from Charlie. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: First peer test from Charlie. We are Alice");
|
||||
if (m_State == eSessionStateEstablished)
|
||||
LogPrint (eLogWarning, "SSU: first peer test from Charlie through established session. We are Alice");
|
||||
LogPrint (eLogWarning, "SSU: First peer test from Charlie through established session. We are Alice");
|
||||
if (IsV6 ())
|
||||
i2p::context.SetStatusV6 (eRouterStatusOK);
|
||||
else
|
||||
else
|
||||
i2p::context.SetStatus (eRouterStatusOK);
|
||||
m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2);
|
||||
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
|
||||
@@ -1055,14 +1077,14 @@ namespace transport
|
||||
case ePeerTestParticipantAlice2:
|
||||
{
|
||||
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
|
||||
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Alice");
|
||||
else
|
||||
{
|
||||
// peer test successive
|
||||
LogPrint (eLogDebug, "SSU: second peer test from Charlie. We are Alice");
|
||||
LogPrint (eLogDebug, "SSU: Second peer test from Charlie. We are Alice");
|
||||
if (IsV6 ())
|
||||
i2p::context.SetStatusV6 (eRouterStatusOK);
|
||||
else
|
||||
i2p::context.SetStatusV6 (eRouterStatusOK);
|
||||
else
|
||||
i2p::context.SetStatus (eRouterStatusOK);
|
||||
m_Server.RemovePeerTest (nonce);
|
||||
}
|
||||
@@ -1070,19 +1092,19 @@ namespace transport
|
||||
}
|
||||
case ePeerTestParticipantBob:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob");
|
||||
LogPrint (eLogDebug, "SSU: Peer test from Charlie. We are Bob");
|
||||
auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
|
||||
if (session && session->m_State == eSessionStateEstablished)
|
||||
{
|
||||
const auto& ep = session->GetRemoteEndpoint (); // Alice's endpoint as known to Bob
|
||||
session->SendPeerTest (nonce, ep.address (), ep.port (), introKey, false, true); // send back to Alice
|
||||
}
|
||||
}
|
||||
m_Server.RemovePeerTest (nonce); // nonce has been used
|
||||
break;
|
||||
}
|
||||
case ePeerTestParticipantCharlie:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
|
||||
LogPrint (eLogDebug, "SSU: Peer test from Alice. We are Charlie");
|
||||
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address
|
||||
m_Server.RemovePeerTest (nonce); // nonce has been used
|
||||
break;
|
||||
@@ -1095,17 +1117,17 @@ namespace transport
|
||||
// new test
|
||||
if (port)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Charlie");
|
||||
LogPrint (eLogDebug, "SSU: Peer test from Bob. We are Charlie");
|
||||
Send (PAYLOAD_TYPE_PEER_TEST, buf, len); // back to Bob
|
||||
if (!addr.is_unspecified () && !i2p::util::net::IsInReservedRange(addr))
|
||||
{
|
||||
{
|
||||
m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie);
|
||||
SendPeerTest (nonce, addr, port, introKey); // to Alice with her address received from Bob
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Bob");
|
||||
LogPrint (eLogDebug, "SSU: Peer test from Alice. We are Bob");
|
||||
auto session = senderEndpoint.address ().is_v4 () ? m_Server.GetRandomEstablishedV4Session (shared_from_this ()) : m_Server.GetRandomEstablishedV6Session (shared_from_this ()); // Charlie
|
||||
if (session)
|
||||
{
|
||||
@@ -1115,7 +1137,7 @@ namespace transport
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU: unexpected peer test");
|
||||
LogPrint (eLogError, "SSU: Unexpected peer test");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1161,9 +1183,9 @@ namespace transport
|
||||
auto addr = address.is_v4 () ? i2p::context.GetRouterInfo ().GetSSUAddress (true) : // ipv4
|
||||
i2p::context.GetRouterInfo ().GetSSUV6Address ();
|
||||
if (addr)
|
||||
memcpy (payload, addr->ssu->key, 32); // intro key
|
||||
memcpy (payload, addr->i, 32); // intro key
|
||||
else
|
||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||
LogPrint (eLogInfo, "SSU: SSU is not supported. Can't send peer test");
|
||||
}
|
||||
else
|
||||
memcpy (payload, introKey, 32); // intro key
|
||||
@@ -1188,11 +1210,11 @@ namespace transport
|
||||
void SSUSession::SendPeerTest ()
|
||||
{
|
||||
// we are Alice
|
||||
LogPrint (eLogDebug, "SSU: sending peer test");
|
||||
LogPrint (eLogDebug, "SSU: Sending peer test");
|
||||
auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : i2p::context.GetRouterInfo ().GetSSUAddress (true);
|
||||
if (!address)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||
LogPrint (eLogInfo, "SSU: SSU is not supported. Can't send peer test");
|
||||
return;
|
||||
}
|
||||
uint32_t nonce;
|
||||
@@ -1200,7 +1222,7 @@ namespace transport
|
||||
if (!nonce) nonce = 1;
|
||||
m_IsPeerTest = false;
|
||||
m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ());
|
||||
SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice
|
||||
SendPeerTest (nonce, boost::asio::ip::address(), 0, address->i, false, false); // address and port always zero for Alice
|
||||
}
|
||||
|
||||
void SSUSession::SendKeepAlive ()
|
||||
@@ -1233,9 +1255,9 @@ namespace transport
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: exception while sending session destoroyed: ", ex.what ());
|
||||
LogPrint (eLogWarning, "SSU: Exception while sending session destoroyed: ", ex.what ());
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU: session destroyed sent");
|
||||
LogPrint (eLogDebug, "SSU: Session destroyed sent");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,7 +1269,7 @@ namespace transport
|
||||
if (paddingSize > 0) msgSize += (16 - paddingSize);
|
||||
if (msgSize > SSU_MTU_V4)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU");
|
||||
LogPrint (eLogWarning, "SSU: Payload size ", msgSize, " exceeds MTU");
|
||||
return;
|
||||
}
|
||||
memcpy (buf + sizeof (SSUHeader), payload, len);
|
||||
@@ -1268,12 +1290,12 @@ namespace transport
|
||||
if (!len) return 0;
|
||||
uint8_t size = *buf;
|
||||
size_t s = 1 + size + 2; // size + address + port
|
||||
if (len < s)
|
||||
if (len < s)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Address is too short ", len);
|
||||
port = 0;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
buf++; // size
|
||||
if (size == 4)
|
||||
{
|
||||
@@ -1286,12 +1308,12 @@ namespace transport
|
||||
boost::asio::ip::address_v6::bytes_type bytes;
|
||||
memcpy (bytes.data (), buf, 16);
|
||||
ip = boost::asio::ip::address_v6 (bytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported");
|
||||
LogPrint (eLogWarning, "SSU: Address size ", int(size), " is not supported");
|
||||
buf += size;
|
||||
port = bufbe16toh (buf);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user