mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-23 05:47:17 +01:00
commit
612f51ba7f
|
@ -34,3 +34,6 @@ trim_trailing_whitespace = false
|
|||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.patch]
|
||||
trim_trailing_whitespace = false
|
||||
|
|
20
.github/workflows/build-deb.yml
vendored
20
.github/workflows/build-deb.yml
vendored
|
@ -1,6 +1,24 @@
|
|||
name: Build Debian packages
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-deb.yml
|
||||
- contrib/**
|
||||
- daemon/**
|
||||
- debian/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.linux
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
24
.github/workflows/build-freebsd.yml
vendored
24
.github/workflows/build-freebsd.yml
vendored
|
@ -1,10 +1,28 @@
|
|||
name: Build on FreeBSD
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-freebsd.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.homebrew
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-12
|
||||
runs-on: ubuntu-latest
|
||||
name: with UPnP
|
||||
|
||||
steps:
|
||||
|
@ -13,7 +31,7 @@ jobs:
|
|||
|
||||
- name: Test in FreeBSD
|
||||
id: test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
mem: 2048
|
||||
|
|
18
.github/workflows/build-osx.yml
vendored
18
.github/workflows/build-osx.yml
vendored
|
@ -1,6 +1,22 @@
|
|||
name: Build on OSX
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-osx.yml
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.homebrew
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
52
.github/workflows/build-windows-msvc.yml
vendored
52
.github/workflows/build-windows-msvc.yml
vendored
|
@ -1,52 +0,0 @@
|
|||
name: Build on Windows with MSVC
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build and install zlib
|
||||
run: |
|
||||
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
|
||||
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
|
||||
set BUILD_TYPE=Debug
|
||||
./install_zlib.bat
|
||||
set BUILD_TYPE=Release
|
||||
./install_zlib.bat
|
||||
del install_zlib.bat
|
||||
|
||||
- name: Install Boost
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install boost-msvc-14.3
|
||||
|
||||
- name: Install OpenSSL
|
||||
uses: crazy-max/ghaction-chocolatey@v2
|
||||
with:
|
||||
args: install openssl
|
||||
|
||||
- name: Configure
|
||||
working-directory: build
|
||||
run: cmake -DWITH_STATIC=ON .
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config Debug -- -m
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd-msvc
|
||||
path: build/Debug/i2pd.*
|
||||
|
80
.github/workflows/build-windows-msvc.yml-disabled
vendored
Normal file
80
.github/workflows/build-windows-msvc.yml-disabled
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
name: Build on Windows with MSVC
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-windows-msvc.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Win32/**
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: windows-latest
|
||||
env:
|
||||
boost_path: ${{ github.workspace }}\boost_1_83_0
|
||||
openssl_path: ${{ github.workspace }}\openssl_3_2_1
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build and install zlib
|
||||
run: |
|
||||
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
|
||||
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
|
||||
set BUILD_TYPE=Debug
|
||||
./install_zlib.bat
|
||||
set BUILD_TYPE=Release
|
||||
./install_zlib.bat
|
||||
del install_zlib.bat
|
||||
|
||||
- name: Install Boost
|
||||
run: |
|
||||
powershell -Command "(Start-BitsTransfer -Source https://sourceforge.net/projects/boost/files/boost-binaries/1.83.0/boost_1_83_0-msvc-14.3-64.exe/download -Destination boost_1_83_0-msvc-14.3-64.exe)"
|
||||
./boost_1_83_0-msvc-14.3-64.exe /DIR="${{env.boost_path}}" /VERYSILENT /SUPPRESSMSGBOXES /SP-
|
||||
|
||||
- name: Install OpenSSL
|
||||
run: |
|
||||
powershell -Command "(Start-BitsTransfer -Source https://slproweb.com/download/Win64OpenSSL-3_2_1.exe -Destination Win64OpenSSL-3_2_1.exe)"
|
||||
./Win64OpenSSL-3_2_1.exe /DIR="${{env.openssl_path}}" /TASKS="copytobin" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
|
||||
|
||||
- name: Make copy of the OpenSSL libraries for CMake
|
||||
run: |
|
||||
dir ${{ github.workspace }}
|
||||
dir ${{env.openssl_path}}\lib\VC
|
||||
dir ${{env.openssl_path}}\lib\VC\x64\
|
||||
dir ${{env.openssl_path}}\lib\VC\x64\MTd\
|
||||
xcopy /s /y "${{env.openssl_path}}\lib\VC\x64\MTd" "${{env.openssl_path}}\lib"
|
||||
|
||||
- name: Configure
|
||||
working-directory: build
|
||||
run: cmake -DBoost_ROOT="${{env.boost_path}}" -DOPENSSL_ROOT_DIR="${{env.openssl_path}}" -DWITH_STATIC=ON .
|
||||
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config Debug -- -m
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: i2pd-msvc
|
||||
path: build/Debug/i2pd.*
|
||||
|
21
.github/workflows/build-windows.yml
vendored
21
.github/workflows/build-windows.yml
vendored
|
@ -1,6 +1,25 @@
|
|||
name: Build on Windows
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build-windows.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Win32/**
|
||||
- Makefile
|
||||
- Makefile.mingw
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
20
.github/workflows/build.yml
vendored
20
.github/workflows/build.yml
vendored
|
@ -1,6 +1,24 @@
|
|||
name: Build on Ubuntu
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- .github/workflows/build.yml
|
||||
- build/CMakeLists.txt
|
||||
- build/cmake_modules/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.linux
|
||||
tags:
|
||||
- '*'
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build-make:
|
||||
|
|
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
|
@ -5,6 +5,16 @@ on:
|
|||
branches:
|
||||
- openssl
|
||||
- docker
|
||||
paths:
|
||||
- .github/workflows/docker.yml
|
||||
- contrib/docker/**
|
||||
- contrib/certificates/**
|
||||
- daemon/**
|
||||
- i18n/**
|
||||
- libi2pd/**
|
||||
- libi2pd_client/**
|
||||
- Makefile
|
||||
- Makefile.linux
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
|
|
80
ChangeLog
80
ChangeLog
|
@ -1,6 +1,86 @@
|
|||
# for this file format description,
|
||||
# see https://github.com/olivierlacan/keep-a-changelog
|
||||
|
||||
## [2.50.2] - 2024-01-06
|
||||
###Fixed
|
||||
- Crash with OpenSSL 3.2.0
|
||||
- False positive clock skew detection
|
||||
|
||||
## [2.50.1] - 2023-12-23
|
||||
###Fixed
|
||||
- Support for new EdDSA usage behavior in OpenSSL 3.2.0
|
||||
|
||||
## [2.50.0] - 2023-12-18
|
||||
### Added
|
||||
- Support of concurrent ACCEPTs on SAM 3.1
|
||||
- Haiku OS support
|
||||
- Low bandwidth and far routers can expire before 1 hour
|
||||
### Changed
|
||||
- Don't pick too active peer for first hop
|
||||
- Try peer test again if status is Unknown
|
||||
- Send peer tests with random delay
|
||||
- Reseeds list
|
||||
### Fixed
|
||||
- XSS vulnerability in addresshelper
|
||||
- Publishing NAT64 ipv6 addresses
|
||||
- Deadlock in AsyncSend callback
|
||||
|
||||
## [2.49.0] - 2023-09-18
|
||||
### Added
|
||||
- Handle SOCK5 authorization with empty user/password
|
||||
- Drop incoming transport sessions from too old or from future routers
|
||||
- Memory pool for router profiles
|
||||
- Allow 0 hops in explicitPeers
|
||||
### Changed
|
||||
- Separate network and testing status
|
||||
- Remove AVX code
|
||||
- Improve NTCP2 transport session logging
|
||||
- Select router with ipv4 for tunnel endpoint
|
||||
- Consider all addresses non-published for U and H routers even if they have host/port
|
||||
- Don't pick completely unreachable routers for tunnels
|
||||
- Exclude SSU1 introducers from SSU2 addresses
|
||||
- Don't create paired inbound tunnel if length is different
|
||||
- Remove introducer from RouterInfo after 60 minutes
|
||||
- Reduce SSU2 keep alive interval and add keep alive interval variance
|
||||
- Don't pick too old sessions for introducer
|
||||
### Fixed
|
||||
- Version of the subnegotiation in user/password SOCKS5 response
|
||||
- Send keepalive for existing session with introducer
|
||||
- Buffer offset for EVP_EncryptFinal_ex() to include outlen
|
||||
- Termination block size processing for transport sessions
|
||||
- Crash if deleted BOB destination was shared between few BOB sessions
|
||||
- Introducers with zero tag
|
||||
- Padding for SSU2 path response
|
||||
|
||||
## [2.48.0] - 2023-06-12
|
||||
### Added
|
||||
- Allow user/password authentication method for SOCK5 proxy
|
||||
- Publish reject all congestion cap 'G' if transit is not accepted
|
||||
- 'critical' log level
|
||||
- Print b32 on webconsole destination page
|
||||
- Webconsole button to drop a remote LeaseSet
|
||||
- limits.zombies param - minimum percentage of successfully created tunnels for routers cleanup
|
||||
- Recognize real routers if successfully connected or responded to tunnel build request
|
||||
### Changed
|
||||
- Bypass slow transport sessions for first hop selection
|
||||
- Limit AESNI inline asm to x86/x64
|
||||
- Create smaller I2NP packets if possible
|
||||
- Make router unreachable if AEAD tag verification fails in SessionCreated
|
||||
- Don't include a router to floodfills list until it's confirmed as real
|
||||
- Drop LeaseSet store request if not floodfill
|
||||
- Bypass medium congestion('D') routers for client tunnels
|
||||
- Publish encrypted RouterInfo through tunnels
|
||||
- Check if s is valid x25519 public key
|
||||
- Check if socket is open before sending data in SSU2
|
||||
### Fixed
|
||||
- Webconsole empty page if destination is not found
|
||||
- i2p.streaming.answerPings param
|
||||
- Reload tunnels
|
||||
- Address caps for unspecified ipv6 address
|
||||
- Incomplete HTTP headers in I2P tunnels
|
||||
- SSU2 socket network exceptions on Windows
|
||||
- Use of 'server' type tunnel port as inport (#1936)
|
||||
|
||||
## [2.47.0] - 2023-03-11
|
||||
### Added
|
||||
- Congestion caps
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
5
Makefile
5
Makefile
|
@ -67,6 +67,9 @@ else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
|
|||
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
include Makefile.bsd
|
||||
else ifneq (, $(findstring haiku, $(SYS)))
|
||||
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
|
||||
include Makefile.haiku
|
||||
else # not supported
|
||||
$(error Not supported platform)
|
||||
endif
|
||||
|
@ -118,7 +121,7 @@ obj/%.o: %.cpp | mk_obj_dir
|
|||
-include $(DEPS)
|
||||
|
||||
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
|
||||
$(CXX) -o $@ $(DEFINES) $(LDFLAGS) $^ $(LDLIBS)
|
||||
$(CXX) $(DEFINES) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||
|
||||
$(SHLIB): $(LIB_OBJS)
|
||||
ifneq ($(USE_STATIC),yes)
|
||||
|
|
10
Makefile.haiku
Normal file
10
Makefile.haiku
Normal file
|
@ -0,0 +1,10 @@
|
|||
CXX = g++
|
||||
CXXFLAGS := -Wall -std=c++11
|
||||
INCFLAGS = -I/system/develop/headers
|
||||
DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE
|
||||
LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
DEFINES += -DUSE_UPNP
|
||||
LDLIBS += -lminiupnpc
|
||||
endif
|
|
@ -5,14 +5,11 @@ WINDRES = windres
|
|||
|
||||
CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
|
||||
INCFLAGS := -I$(DAEMON_SRC_DIR) -IWin32
|
||||
LDFLAGS := ${LD_DEBUG} -static
|
||||
LDFLAGS := ${LD_DEBUG} -static -fPIC -msse
|
||||
|
||||
NEEDED_CXXFLAGS += -std=c++17
|
||||
DEFINES += -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
# Boost libraries suffix
|
||||
BOOST_SUFFIX = -mt
|
||||
|
||||
# UPNP Support
|
||||
ifeq ($(USE_UPNP),yes)
|
||||
DEFINES += -DUSE_UPNP -DMINIUPNP_STATICLIB
|
||||
|
@ -20,17 +17,18 @@ ifeq ($(USE_UPNP),yes)
|
|||
endif
|
||||
|
||||
LDLIBS += \
|
||||
-lboost_system$(BOOST_SUFFIX) \
|
||||
-lboost_date_time$(BOOST_SUFFIX) \
|
||||
-lboost_filesystem$(BOOST_SUFFIX) \
|
||||
-lboost_program_options$(BOOST_SUFFIX) \
|
||||
-lssl \
|
||||
-lcrypto \
|
||||
-lz \
|
||||
$(MINGW_PREFIX)/lib/libboost_system-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libboost_date_time-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libboost_program_options-mt.a \
|
||||
$(MINGW_PREFIX)/lib/libssl.a \
|
||||
$(MINGW_PREFIX)/lib/libcrypto.a \
|
||||
$(MINGW_PREFIX)/lib/libz.a \
|
||||
-lwsock32 \
|
||||
-lws2_32 \
|
||||
-lgdi32 \
|
||||
-liphlpapi \
|
||||
-lcrypt32 \
|
||||
-lgdi32 \
|
||||
-lole32 \
|
||||
-luuid \
|
||||
-lpthread
|
||||
|
@ -48,6 +46,7 @@ endif
|
|||
|
||||
ifeq ($(USE_AESNI),yes)
|
||||
NEEDED_CXXFLAGS += -maes
|
||||
LDFLAGS += -maes
|
||||
DEFINES += -D__AES__
|
||||
endif
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ DEFINES := -DMAC_OSX
|
|||
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||
LDFLAGS += -Wl,-dead_strip
|
||||
LDFLAGS += -Wl,-dead_strip_dylibs
|
||||
LDFLAGS += -Wl,-bind_at_load
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||
|
|
24
README.md
24
README.md
|
@ -99,13 +99,23 @@ Current status: [![Crowdin](https://badges.crowdin.net/i2pd/localized.svg)](http
|
|||
Donations
|
||||
---------
|
||||
|
||||
BTC: 3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f
|
||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||
ETH: 0x9e5bac70d20d1079ceaa111127f4fb3bccce379d
|
||||
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
|
||||
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
|
||||
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
|
||||
XMR: 497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH
|
||||
**E-Mail**: ```i2porignal at yandex.com```
|
||||
|
||||
**BTC**: ```3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f```
|
||||
|
||||
**LTC**: ```LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59```
|
||||
|
||||
**ETH**: ```0x9e5bac70d20d1079ceaa111127f4fb3bccce379d```
|
||||
|
||||
**GST**: ```GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG```
|
||||
|
||||
**DASH**: ```Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF```
|
||||
|
||||
**ZEC**: ```t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ```
|
||||
|
||||
**ANC**: ```AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z```
|
||||
|
||||
**XMR**: ```497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH```
|
||||
|
||||
License
|
||||
-------
|
||||
|
|
|
@ -145,18 +145,19 @@ namespace win32
|
|||
s << bytes << " Bytes\n";
|
||||
}
|
||||
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status)
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case eRouterStatusOK: s << "OK"; break;
|
||||
case eRouterStatusTesting: s << "Test"; break;
|
||||
case eRouterStatusFirewalled: s << "FW"; break;
|
||||
case eRouterStatusUnknown: s << "Unk"; break;
|
||||
case eRouterStatusProxy: s << "Proxy"; break;
|
||||
case eRouterStatusMesh: s << "Mesh"; break;
|
||||
default: s << "Unk";
|
||||
};
|
||||
if (testing)
|
||||
s << " (Test)";
|
||||
if (i2p::context.GetError () != eRouterErrorNone)
|
||||
{
|
||||
switch (i2p::context.GetError ())
|
||||
|
@ -179,11 +180,11 @@ namespace win32
|
|||
{
|
||||
s << "\n";
|
||||
s << "Status: ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting ());
|
||||
if (i2p::context.SupportsV6 ())
|
||||
{
|
||||
s << " / ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6 ());
|
||||
}
|
||||
s << "; ";
|
||||
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
||||
|
@ -348,6 +349,9 @@ namespace win32
|
|||
}
|
||||
}
|
||||
}
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
[[fallthrough]];
|
||||
#endif
|
||||
}
|
||||
case WM_TRAYICON:
|
||||
{
|
||||
|
|
BIN
Win32/mask.bmp
BIN
Win32/mask.bmp
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
|
@ -25,7 +25,7 @@ project(
|
|||
i2pd
|
||||
VERSION ${PROJECT_VERSION}
|
||||
HOMEPAGE_URL "https://i2pd.website/"
|
||||
LANGUAGES CXX
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
# configurable options
|
||||
|
@ -121,7 +121,7 @@ if(WIN32)
|
|||
)
|
||||
|
||||
file(GLOB WIN32_RC ${WIN32_SRC_DIR}/*.rc)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN -DNOMINMAX")
|
||||
|
||||
endif()
|
||||
|
||||
|
@ -139,6 +139,10 @@ if(APPLE)
|
|||
add_definitions(-DMAC_OSX)
|
||||
endif()
|
||||
|
||||
if(HAIKU)
|
||||
add_definitions(-D_DEFAULT_SOURCE -D_GNU_SOURCE)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-DWINVER=0x0600)
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
|
@ -197,14 +201,11 @@ endif()
|
|||
|
||||
# Note: AES-NI and AVX is available on x86-based CPU's.
|
||||
# Here also ARM64 implementation, but currently we don't support it.
|
||||
# MSVC is not supported.
|
||||
if(MSVC)
|
||||
message(STATUS "AES-NI is not supported on MSVC, option was disabled")
|
||||
set(WITH_AESNI OFF)
|
||||
endif()
|
||||
|
||||
# MSVC is not supported due to different ASM processing, so we hope OpenSSL has its own checks to run optimized code.
|
||||
if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386"))
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||
endif()
|
||||
add_definitions(-D__AES__)
|
||||
endif()
|
||||
|
||||
|
@ -329,7 +330,11 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
|
|||
message(STATUS " BINARY : ${WITH_BINARY}")
|
||||
message(STATUS " STATIC BUILD : ${WITH_STATIC}")
|
||||
message(STATUS " UPnP : ${WITH_UPNP}")
|
||||
if(WITH_GIT_VERSION)
|
||||
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION} (${GIT_VERSION})")
|
||||
else()
|
||||
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}")
|
||||
endif()
|
||||
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
|
||||
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
|
||||
message(STATUS "---------------------------------------")
|
||||
|
|
42
contrib/apparmor/docker-i2pd
Normal file
42
contrib/apparmor/docker-i2pd
Normal file
|
@ -0,0 +1,42 @@
|
|||
# _________________________________________
|
||||
# / Copy this file to the right location \
|
||||
# | then load with: |
|
||||
# | |
|
||||
# | apparmor_parser -r -W |
|
||||
# | /etc/apparmor.d/docker-i2pd |
|
||||
# | |
|
||||
# | docker run --security-opt |
|
||||
# | "apparmor=docker-i2pd" ... |
|
||||
# | purplei2p/i2pd |
|
||||
# | |
|
||||
# \ And "aa-status" to verify it's loaded. /
|
||||
# -----------------------------------------
|
||||
# \ ^__^
|
||||
# \ (oo)\_______
|
||||
# (__)\ )\/\
|
||||
# ||----w |
|
||||
# || ||
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
profile docker-i2pd flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/openssl>
|
||||
#include <abstractions/nameservice>
|
||||
|
||||
/bin/busybox ix,
|
||||
/usr/local/bin/i2pd ix,
|
||||
/entrypoint.sh ixr,
|
||||
|
||||
/i2pd_certificates/** r,
|
||||
|
||||
/home/i2pd/data/** rw,
|
||||
|
||||
/home/i2pd/data/i2pd.pid k,
|
||||
|
||||
deny /home/i2pd/data/i2pd.conf w,
|
||||
deny /home/i2pd/data/tunnels.conf w,
|
||||
deny /home/i2pd/data/tunnels.d/** w,
|
||||
deny /home/i2pd/data/certificates/** w,
|
||||
deny /home/i2pd/data/i2pd.log r,
|
||||
}
|
34
contrib/certificates/reseed/admin_at_stormycloud.org.crt
Normal file
34
contrib/certificates/reseed/admin_at_stormycloud.org.crt
Normal file
|
@ -0,0 +1,34 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIF1zCCA7+gAwIBAgIRAMDqFR09Xuj8ZUu+oetSvAEwDQYJKoZIhvcNAQELBQAw
|
||||
dTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
|
||||
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxHjAcBgNVBAMM
|
||||
FWFkbWluQHN0b3JteWNsb3VkLm9yZzAeFw0yNDAxMjUxNDE1MzBaFw0zNDAxMjUx
|
||||
NDE1MzBaMHUxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx
|
||||
HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR4w
|
||||
HAYDVQQDDBVhZG1pbkBzdG9ybXljbG91ZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUA
|
||||
A4ICDwAwggIKAoICAQDbGX+GikPzQXr9zvkrhfO9g0l49KHLNQhUKYqd6T+PfnGo
|
||||
Fm0d3ZZVVQZ045vWgroOXDGGZZWxUIlb2inRaR2DF1TxN3pPYt59RgY9ZQ9+TL7o
|
||||
isY91krCRygY8EcAmHIjlfZQ9dBVcL7CfyT0MYZA5Efee9+NDHSewTfQP9T2faIE
|
||||
83Fcyd93a2mIHYjKUbJnojng/wgsy8srbsEuuTok4MIQmDj+B5nz+za2FgI0/ydh
|
||||
srlMt4aGJF4/DIem9z9d0zBCOkwrmtFIzjNF1mOSA8ES4m5YnKA/y9rZlRidLPGu
|
||||
prbXhPVnqHeOnHMz2QCw1wbVo504kl0bMqyEz2tVWsO9ep7iZoQs2xkFAEaegYNT
|
||||
QLUpwVGlyuq3wXXwopFRffOSimGSazICwWI6j+K0pOtgefNJaWrqKYvtkj1SbK2L
|
||||
LBNUIENz6VnB7KPRckuX6zxC8PpOiBK9BcftfO+xAz/wC6qq3riBPw30KKSym0nC
|
||||
Zp5KciDn4Phtw9PGq8Bkl8SyWl0jtFnfTB1tzJkisf2qKcNHaFTEe2JW763YLbh/
|
||||
AU+8X8evFu40qLgvOgKoyy5DLy6i8zetX+3t9K0Fxt9+Vzzq6lm5V/RS8iIPPn+M
|
||||
q1/3Z5kD0KQBG9h/Gl8BH+lB71ZxPAOZ3SMu8DJZcxBLVmDWqQPCr5CKnoz0swID
|
||||
AQABo2IwYDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
|
||||
AQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHgYDVR0OBBcEFWFkbWluQHN0b3JteWNs
|
||||
b3VkLm9yZzANBgkqhkiG9w0BAQsFAAOCAgEARWOJ69vTHMneSXYscha+4Ytjg0RM
|
||||
faewJNEGj8qy/Qvh9si2bWYNPRK6BlbHFS7pRYBLAnhaeLBGVv1CCR6GUMMe74zQ
|
||||
UuMeAoWU6qMDmB3GfYoZJh8sIxpwHqyJeTdeccRbZ4sX4F6u3IHPXYiU/AgbYqH7
|
||||
pYXQg2lCjXZYaDFAlEf5SlYUDOhhXe5kR8Edhlrsu32/JzA1DQK0JjxKCBp+DQmA
|
||||
ltdOpQtAg03fHP4ssdj7VvjIDl28iIlATwBvHrdNm7T0tYWn6TWhvxbRqvfTxfaH
|
||||
MvxnPdIJwNP4/9TyQkwjwHb1h+ucho3CnxI/AxspdOvT1ElMhP6Ce6rcS9pk11Rl
|
||||
x0ChsqpWwDg7KYpg0qZFSKCTBp4zBq9xoMJ6BQcgMfyl736WbsCzFTEyfifp8beg
|
||||
NxUa/Qk7w7cuSPGyMIKNOmOR7FLlFbtocy8sXVsUQdqnp/edelufdNe39U9uNtY6
|
||||
yoXI9//Tc6NgOwy2Oyia0slZ5qHRkB7e4USXMRzJ3p4q9eCVKjAJs81Utp7O2U+9
|
||||
vhbhwWP8CAnNTT1E5WS6EKtfrdqF7wjkV+noPGLDGmrXi01J1fSMAjMfVO+7/LOL
|
||||
UN+G4ybKWnEhhOO27yidN8Xx6UrCS23DBlPPQAeA74dTsTExiOxf1o1EXzcQiMyO
|
||||
LAj3/Ojbi1xkWhI=
|
||||
-----END CERTIFICATE-----
|
32
contrib/certificates/reseed/ls_at_mail.i2p.crt
Normal file
32
contrib/certificates/reseed/ls_at_mail.i2p.crt
Normal file
|
@ -0,0 +1,32 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdTCCA12gAwIBAgIEQ5vCxzANBgkqhkiG9w0BAQ0FADBrMQswCQYDVQQGEwJY
|
||||
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
|
||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAw
|
||||
HhcNMjMxMDE2MjAwNTA5WhcNMzMxMDEzMjAwNTA5WjBrMQswCQYDVQQGEwJYWDEL
|
||||
MAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnltb3Vz
|
||||
IE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEUMBIGA1UEAwwLbHNAbWFpbC5pMnAwggIi
|
||||
MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDPcbKRtf4PzrDa0iRit0XrwnmA
|
||||
2c1fJhkBipdPor7gMOAlkR82H1lkZSizR7kTZnr7vYqjDrOQr7bl5Dy3qo8/YCbZ
|
||||
jsnUCTIIgIJQUxUlR40RjaSXphqzUEiXKHR6b0RahhFisQ3hlbbgzSch5YgSLKws
|
||||
hOLi+eDSXw+HlwHlWFlT1XOKxSTJ/F3Bv40gxqZVC2pbxiPOeRZHQ6Ojw75lxTSF
|
||||
gww2WzgztiWt4X9BO1yepnVqhAVRPmTfGUMfKzq9jkMzZKeQFV4uZSP9nCqzEpYd
|
||||
WNDUfpTWiAQ9F+BwFXGusXXA3tGVwS7s6IEoiJFM5fsoJYfRoWGh3/1eirhBXW7U
|
||||
M6oubMSTADyrvfjLfJBMmMnc2hNblRlKr0ZKUjMfv8cnyT4kQxlXLAHHXY2P89TM
|
||||
TEVODkU48gnv6tC4t1JCb1/Da+3yVMjNX6rCzQfUwnLFrWthrwiI0NivAKFtiZjq
|
||||
w1/ZQcYke2YyeqcfXMn+NTUA22Sm2mJoMo7jUf+rbM9Pi27/DncJgRGj5qwY0D3S
|
||||
gc7829EjuZNPttGBmae1EmO7WQMB32cqdmItnV2FXpMhnn9h0u5H52kYqwn+mdtc
|
||||
dTJRcbfKG1RTr3UjFISaTwL8qigMIkVXIzcpnr/R/sSeEs8xCqfsJ6rb4dCyFx+M
|
||||
hqQcOCL5tumyd4W/LQIDAQABoyEwHzAdBgNVHQ4EFgQUgfaOG5HCnlW82wZ5BahL
|
||||
GRO06igwDQYJKoZIhvcNAQENBQADggIBAKdVpqS9qF7gGotgXaVA1iP5YNsWlTvG
|
||||
daGqeA/87//U21W6gpq82FhzsmsvUtXZfIeVIlDPI7WNDzS+A3K/KKrwM7dLgSie
|
||||
r9eMl3D8WYPU95QF4mAlRyl7PCCsYoVjyvfro0iq3/iudIA5476rjfLdTXRi5hAT
|
||||
qemPj0S+6sRjKEldRtGXrQATFlvLIWVYpgHijdDDx5M2hAz2y0mFxlDZTlA4BhL4
|
||||
DwtGlVKmbc2x5MvIQM4UhbQqkxYS4gXnzf5Qx9QIytHfTr/hmbrkhKR1GCO31BSk
|
||||
x9LhZxdI8LlwKSo6YgwXEB9E0M/tplaK9iZJFv4HPYLZrVJpb4IklMumyLMrgW5P
|
||||
fR0dgKn+R9lk0emJ1Cu+qyyzf1vsLycYBwaEztINn4VK+/HfDFpnVCvJOyNuDmj5
|
||||
KBLIoGdGoVfylmnc+e8zAXe+DY41fgniHMISOO78P8Bx9vTB+rhqnOUr9MzlUxPB
|
||||
sKGjbXy2YynEqiGb+9g344v/+ukTSDenqTPHVzJ5uOi0iedy+3ASzUNN6GJocovP
|
||||
167VOhwaETM0FwiKe0VdZRLLbbZ79CtJC0tmgcgPQPRa9Ldr6KN7u1J3D6lUp6zl
|
||||
byPom10ueKONRb36t7ai79l2SEUZRSMkx6AXIU0JJ1SMtQtav7b5LkpYJfdL7+vO
|
||||
dDx2/Za0VmdD
|
||||
-----END CERTIFICATE-----
|
|
@ -1,2 +1,5 @@
|
|||
This forder contain systemd unit files.
|
||||
To use systemd daemon control, place files from this directory to debian folder before building package.
|
||||
This forder contain files required for building debian packages.
|
||||
|
||||
The trunk repository is contains the packaging files for the latest stable version of Debian (if we not forgot to update them).
|
||||
|
||||
Files in subdirectories contains fixes to make possible to build package on specific versions of Debian/Ubuntu. They are used when building the release package.
|
||||
|
|
1
contrib/debian/bionic/compat
Normal file
1
contrib/debian/bionic/compat
Normal file
|
@ -0,0 +1 @@
|
|||
11
|
18
contrib/debian/bionic/control
Normal file
18
contrib/debian/bionic/control
Normal file
|
@ -0,0 +1,18 @@
|
|||
Source: i2pd
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: r4sas <r4sas@i2pmail.org>
|
||||
Build-Depends: debhelper (>= 11~), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
|
||||
Standards-Version: 4.2.0
|
||||
Homepage: http://i2pd.website/
|
||||
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
|
||||
Vcs-Browser: https://github.com/PurpleI2P/i2pd
|
||||
|
||||
Package: i2pd
|
||||
Architecture: any
|
||||
Pre-Depends: ${misc:Pre-Depends}, adduser
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
|
||||
Description: Full-featured C++ implementation of I2P client.
|
||||
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
||||
communications over I2P are anonymous and end-to-end encrypted, participants
|
||||
don't reveal their real IP addresses.
|
1
contrib/debian/trusty/compat
Normal file
1
contrib/debian/trusty/compat
Normal file
|
@ -0,0 +1 @@
|
|||
9
|
18
contrib/debian/trusty/control
Normal file
18
contrib/debian/trusty/control
Normal file
|
@ -0,0 +1,18 @@
|
|||
Source: i2pd
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: r4sas <r4sas@i2pmail.org>
|
||||
Build-Depends: debhelper (>= 9), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: http://i2pd.website/
|
||||
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
|
||||
Vcs-Browser: https://github.com/PurpleI2P/i2pd
|
||||
|
||||
Package: i2pd
|
||||
Architecture: any
|
||||
Pre-Depends: ${misc:Pre-Depends}, adduser
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
|
||||
Description: Full-featured C++ implementation of I2P client.
|
||||
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
||||
communications over I2P are anonymous and end-to-end encrypted, participants
|
||||
don't reveal their real IP addresses.
|
17
contrib/debian/trusty/patches/01-upnp.patch
Normal file
17
contrib/debian/trusty/patches/01-upnp.patch
Normal file
|
@ -0,0 +1,17 @@
|
|||
Description: Enable UPnP usage in package
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2022-03-23
|
||||
|
||||
--- i2pd.orig/Makefile
|
||||
+++ i2pd/Makefile
|
||||
@@ -31,7 +31,7 @@ include filelist.mk
|
||||
|
||||
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
|
19
contrib/debian/trusty/patches/02-service.patch
Normal file
19
contrib/debian/trusty/patches/02-service.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
Description: Disable LogsDirectory and LogsDirectoryMode options in service
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2023-05-17
|
||||
|
||||
--- a/contrib/i2pd.service
|
||||
+++ b/contrib/i2pd.service
|
||||
@@ -8,8 +8,8 @@ User=i2pd
|
||||
Group=i2pd
|
||||
RuntimeDirectory=i2pd
|
||||
RuntimeDirectoryMode=0700
|
||||
-LogsDirectory=i2pd
|
||||
-LogsDirectoryMode=0700
|
||||
+#LogsDirectory=i2pd
|
||||
+#LogsDirectoryMode=0700
|
||||
Type=forking
|
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
2
contrib/debian/trusty/patches/series
Normal file
2
contrib/debian/trusty/patches/series
Normal file
|
@ -0,0 +1,2 @@
|
|||
01-upnp.patch
|
||||
02-service.patch
|
18
contrib/debian/trusty/rules
Executable file
18
contrib/debian/trusty/rules
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/make -f
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
|
||||
|
||||
include /usr/share/dpkg/architecture.mk
|
||||
|
||||
ifeq ($(DEB_HOST_ARCH),i386)
|
||||
export DEB_BUILD_OPTIONS=parallel=1
|
||||
endif
|
||||
|
||||
export DEB_CXXFLAGS_MAINT_APPEND=-Wall -pedantic
|
||||
export DEB_LDFLAGS_MAINT_APPEND=
|
||||
|
||||
%:
|
||||
dh $@ --parallel
|
||||
|
||||
override_dh_auto_install:
|
1
contrib/debian/xenial/compat
Normal file
1
contrib/debian/xenial/compat
Normal file
|
@ -0,0 +1 @@
|
|||
9
|
18
contrib/debian/xenial/control
Normal file
18
contrib/debian/xenial/control
Normal file
|
@ -0,0 +1,18 @@
|
|||
Source: i2pd
|
||||
Section: net
|
||||
Priority: optional
|
||||
Maintainer: r4sas <r4sas@i2pmail.org>
|
||||
Build-Depends: debhelper (>= 9), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: http://i2pd.website/
|
||||
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
|
||||
Vcs-Browser: https://github.com/PurpleI2P/i2pd
|
||||
|
||||
Package: i2pd
|
||||
Architecture: any
|
||||
Pre-Depends: ${misc:Pre-Depends}, adduser
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
|
||||
Description: Full-featured C++ implementation of I2P client.
|
||||
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
|
||||
communications over I2P are anonymous and end-to-end encrypted, participants
|
||||
don't reveal their real IP addresses.
|
17
contrib/debian/xenial/patches/01-upnp.patch
Normal file
17
contrib/debian/xenial/patches/01-upnp.patch
Normal file
|
@ -0,0 +1,17 @@
|
|||
Description: Enable UPnP usage in package
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2022-03-23
|
||||
|
||||
--- i2pd.orig/Makefile
|
||||
+++ i2pd/Makefile
|
||||
@@ -31,7 +31,7 @@ include filelist.mk
|
||||
|
||||
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
|
19
contrib/debian/xenial/patches/02-service.patch
Normal file
19
contrib/debian/xenial/patches/02-service.patch
Normal file
|
@ -0,0 +1,19 @@
|
|||
Description: Disable LogsDirectory and LogsDirectoryMode options in service
|
||||
Author: r4sas <r4sas@i2pmail.org>
|
||||
|
||||
Reviewed-By: r4sas <r4sas@i2pmail.org>
|
||||
Last-Update: 2023-05-17
|
||||
|
||||
--- a/contrib/i2pd.service
|
||||
+++ b/contrib/i2pd.service
|
||||
@@ -8,8 +8,8 @@ User=i2pd
|
||||
Group=i2pd
|
||||
RuntimeDirectory=i2pd
|
||||
RuntimeDirectoryMode=0700
|
||||
-LogsDirectory=i2pd
|
||||
-LogsDirectoryMode=0700
|
||||
+#LogsDirectory=i2pd
|
||||
+#LogsDirectoryMode=0700
|
||||
Type=forking
|
||||
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
|
||||
ExecReload=/bin/sh -c "kill -HUP $MAINPID"
|
2
contrib/debian/xenial/patches/series
Normal file
2
contrib/debian/xenial/patches/series
Normal file
|
@ -0,0 +1,2 @@
|
|||
01-upnp.patch
|
||||
02-service.patch
|
13
contrib/debian/xenial/rules
Executable file
13
contrib/debian/xenial/rules
Executable file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/make -f
|
||||
#export DH_VERBOSE=1
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
include /usr/share/dpkg/architecture.mk
|
||||
|
||||
export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
|
||||
export DEB_LDFLAGS_MAINT_APPEND =
|
||||
|
||||
%:
|
||||
dh $@ --parallel
|
||||
|
||||
override_dh_auto_install:
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: i2pd\n"
|
||||
"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n"
|
||||
"POT-Creation-Date: 2023-01-19 04:18\n"
|
||||
"POT-Creation-Date: 2023-06-10 01:25\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
@ -18,28 +18,28 @@ msgstr ""
|
|||
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
|
||||
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
|
||||
|
||||
#: daemon/HTTPServer.cpp:106
|
||||
#: daemon/HTTPServer.cpp:107
|
||||
#, c-format
|
||||
msgid "%d day"
|
||||
msgid_plural "%d days"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:110
|
||||
#: daemon/HTTPServer.cpp:111
|
||||
#, c-format
|
||||
msgid "%d hour"
|
||||
msgid_plural "%d hours"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:114
|
||||
#: daemon/HTTPServer.cpp:115
|
||||
#, c-format
|
||||
msgid "%d minute"
|
||||
msgid_plural "%d minutes"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:117
|
||||
#: daemon/HTTPServer.cpp:118
|
||||
#, c-format
|
||||
msgid "%d second"
|
||||
msgid_plural "%d seconds"
|
||||
|
@ -47,560 +47,578 @@ msgstr[0] ""
|
|||
msgstr[1] ""
|
||||
|
||||
#. tr: Kibibyte
|
||||
#: daemon/HTTPServer.cpp:125 daemon/HTTPServer.cpp:153
|
||||
#: daemon/HTTPServer.cpp:126
|
||||
#, c-format
|
||||
msgid "%.2f KiB"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Mebibyte
|
||||
#: daemon/HTTPServer.cpp:127
|
||||
#: daemon/HTTPServer.cpp:128
|
||||
#, c-format
|
||||
msgid "%.2f MiB"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Gibibyte
|
||||
#: daemon/HTTPServer.cpp:129
|
||||
#: daemon/HTTPServer.cpp:130
|
||||
#, c-format
|
||||
msgid "%.2f GiB"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:146
|
||||
#: daemon/HTTPServer.cpp:147
|
||||
msgid "building"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:147
|
||||
#: daemon/HTTPServer.cpp:148
|
||||
msgid "failed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:148
|
||||
#: daemon/HTTPServer.cpp:149
|
||||
msgid "expiring"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:149
|
||||
#: daemon/HTTPServer.cpp:150
|
||||
msgid "established"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:150
|
||||
#: daemon/HTTPServer.cpp:151
|
||||
msgid "unknown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:152
|
||||
#: daemon/HTTPServer.cpp:153
|
||||
msgid "exploratory"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Webconsole page title
|
||||
#: daemon/HTTPServer.cpp:183
|
||||
#: daemon/HTTPServer.cpp:185
|
||||
msgid "Purple I2P Webconsole"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:188
|
||||
#: daemon/HTTPServer.cpp:190
|
||||
msgid "<b>i2pd</b> webconsole"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:191
|
||||
#: daemon/HTTPServer.cpp:193
|
||||
msgid "Main page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:192 daemon/HTTPServer.cpp:712
|
||||
#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:742
|
||||
msgid "Router commands"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:193 daemon/HTTPServer.cpp:387
|
||||
#: daemon/HTTPServer.cpp:399
|
||||
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:395
|
||||
#: daemon/HTTPServer.cpp:407
|
||||
msgid "Local Destinations"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:357
|
||||
#: daemon/HTTPServer.cpp:443 daemon/HTTPServer.cpp:449
|
||||
#: daemon/HTTPServer.cpp:609 daemon/HTTPServer.cpp:652
|
||||
#: daemon/HTTPServer.cpp:656
|
||||
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:365
|
||||
#: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:474
|
||||
#: daemon/HTTPServer.cpp:636 daemon/HTTPServer.cpp:682
|
||||
#: daemon/HTTPServer.cpp:686
|
||||
msgid "LeaseSets"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:662
|
||||
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:692
|
||||
msgid "Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:364
|
||||
#: daemon/HTTPServer.cpp:781 daemon/HTTPServer.cpp:797
|
||||
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:372
|
||||
#: daemon/HTTPServer.cpp:813 daemon/HTTPServer.cpp:830
|
||||
msgid "Transit Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:855
|
||||
#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:898
|
||||
msgid "Transports"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:202
|
||||
#: daemon/HTTPServer.cpp:204
|
||||
msgid "I2P tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:204 daemon/HTTPServer.cpp:884
|
||||
#: daemon/HTTPServer.cpp:894
|
||||
#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:927
|
||||
#: daemon/HTTPServer.cpp:937
|
||||
msgid "SAM sessions"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:220 daemon/HTTPServer.cpp:1278
|
||||
#: daemon/HTTPServer.cpp:1281 daemon/HTTPServer.cpp:1284
|
||||
#: daemon/HTTPServer.cpp:1298 daemon/HTTPServer.cpp:1343
|
||||
#: daemon/HTTPServer.cpp:1346 daemon/HTTPServer.cpp:1349
|
||||
#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1329
|
||||
#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1335
|
||||
#: daemon/HTTPServer.cpp:1362 daemon/HTTPServer.cpp:1365
|
||||
#: daemon/HTTPServer.cpp:1379 daemon/HTTPServer.cpp:1424
|
||||
#: daemon/HTTPServer.cpp:1427 daemon/HTTPServer.cpp:1430
|
||||
msgid "ERROR"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:227
|
||||
#: daemon/HTTPServer.cpp:229
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:228
|
||||
#: daemon/HTTPServer.cpp:230
|
||||
msgid "Testing"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:229
|
||||
#: daemon/HTTPServer.cpp:231
|
||||
msgid "Firewalled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:230 daemon/HTTPServer.cpp:233
|
||||
#: daemon/HTTPServer.cpp:329
|
||||
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:235
|
||||
#: daemon/HTTPServer.cpp:336
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:231 daemon/HTTPServer.cpp:374
|
||||
#: daemon/HTTPServer.cpp:375 daemon/HTTPServer.cpp:952
|
||||
#: daemon/HTTPServer.cpp:961
|
||||
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:382
|
||||
#: daemon/HTTPServer.cpp:383 daemon/HTTPServer.cpp:1003
|
||||
#: daemon/HTTPServer.cpp:1011
|
||||
msgid "Proxy"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:232
|
||||
#: daemon/HTTPServer.cpp:234
|
||||
msgid "Mesh"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:240
|
||||
#: daemon/HTTPServer.cpp:242
|
||||
msgid "Clock skew"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:243
|
||||
#: daemon/HTTPServer.cpp:245
|
||||
msgid "Offline"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:246
|
||||
#: daemon/HTTPServer.cpp:248
|
||||
msgid "Symmetric NAT"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:249
|
||||
#: daemon/HTTPServer.cpp:251
|
||||
msgid "Full cone NAT"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:252
|
||||
#: daemon/HTTPServer.cpp:254
|
||||
msgid "No Descriptors"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:261
|
||||
#: daemon/HTTPServer.cpp:263
|
||||
msgid "Uptime"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:264
|
||||
#: daemon/HTTPServer.cpp:266
|
||||
msgid "Network status"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:269
|
||||
#: daemon/HTTPServer.cpp:271
|
||||
msgid "Network status v6"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:275 daemon/HTTPServer.cpp:282
|
||||
#: daemon/HTTPServer.cpp:277 daemon/HTTPServer.cpp:284
|
||||
msgid "Stopping in"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:289
|
||||
#: daemon/HTTPServer.cpp:291
|
||||
msgid "Family"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:290
|
||||
#: daemon/HTTPServer.cpp:292
|
||||
msgid "Tunnel creation success rate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:291
|
||||
#: daemon/HTTPServer.cpp:296
|
||||
msgid "Total tunnel creation success rate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:298
|
||||
msgid "Received"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Kibibyte/s
|
||||
#: daemon/HTTPServer.cpp:293 daemon/HTTPServer.cpp:296
|
||||
#: daemon/HTTPServer.cpp:299
|
||||
#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:303
|
||||
#: daemon/HTTPServer.cpp:306
|
||||
#, c-format
|
||||
msgid "%.2f KiB/s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:294
|
||||
#: daemon/HTTPServer.cpp:301
|
||||
msgid "Sent"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:297
|
||||
#: daemon/HTTPServer.cpp:304
|
||||
msgid "Transit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:300
|
||||
#: daemon/HTTPServer.cpp:307
|
||||
msgid "Data path"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:303
|
||||
#: daemon/HTTPServer.cpp:310
|
||||
msgid "Hidden content. Press on text to see."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:307
|
||||
#: daemon/HTTPServer.cpp:314
|
||||
msgid "Router Ident"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:309
|
||||
#: daemon/HTTPServer.cpp:316
|
||||
msgid "Router Family"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:310
|
||||
#: daemon/HTTPServer.cpp:317
|
||||
msgid "Router Caps"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:311
|
||||
#: daemon/HTTPServer.cpp:318
|
||||
msgid "Version"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:312
|
||||
#: daemon/HTTPServer.cpp:319
|
||||
msgid "Our external address"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Shown when router doesn't publish itself and have "Firewalled" state
|
||||
#: daemon/HTTPServer.cpp:341
|
||||
#: daemon/HTTPServer.cpp:349
|
||||
msgid "supported"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:355
|
||||
#: daemon/HTTPServer.cpp:363
|
||||
msgid "Routers"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:356
|
||||
#: daemon/HTTPServer.cpp:364
|
||||
msgid "Floodfills"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:363 daemon/HTTPServer.cpp:938
|
||||
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:987
|
||||
msgid "Client Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:373
|
||||
#: daemon/HTTPServer.cpp:381
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:374 daemon/HTTPServer.cpp:375
|
||||
#: daemon/HTTPServer.cpp:376 daemon/HTTPServer.cpp:377
|
||||
#: daemon/HTTPServer.cpp:378 daemon/HTTPServer.cpp:379
|
||||
#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383
|
||||
#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385
|
||||
#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387
|
||||
msgid "Enabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:374 daemon/HTTPServer.cpp:375
|
||||
#: daemon/HTTPServer.cpp:376 daemon/HTTPServer.cpp:377
|
||||
#: daemon/HTTPServer.cpp:378 daemon/HTTPServer.cpp:379
|
||||
#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383
|
||||
#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385
|
||||
#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:422
|
||||
#: daemon/HTTPServer.cpp:434
|
||||
msgid "Encrypted B33 address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:431
|
||||
#: daemon/HTTPServer.cpp:442
|
||||
msgid "Address registration line"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:436
|
||||
#: daemon/HTTPServer.cpp:447
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:437
|
||||
#: daemon/HTTPServer.cpp:448
|
||||
msgid "Generate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:438
|
||||
#: daemon/HTTPServer.cpp:449
|
||||
msgid ""
|
||||
"<b>Note:</b> result string can be used only for registering 2LD domains "
|
||||
"(example.i2p). For registering subdomains please use i2pd-tools."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:444
|
||||
#: daemon/HTTPServer.cpp:457
|
||||
msgid "Address"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:444
|
||||
#: daemon/HTTPServer.cpp:459
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:444
|
||||
#: daemon/HTTPServer.cpp:460
|
||||
msgid "EncType"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:667
|
||||
#: daemon/HTTPServer.cpp:467
|
||||
msgid "Expire LeaseSet"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:697
|
||||
msgid "Inbound tunnels"
|
||||
msgstr ""
|
||||
|
||||
#. tr: Milliseconds
|
||||
#: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:489
|
||||
#: daemon/HTTPServer.cpp:681 daemon/HTTPServer.cpp:701
|
||||
#: daemon/HTTPServer.cpp:494 daemon/HTTPServer.cpp:514
|
||||
#: daemon/HTTPServer.cpp:711 daemon/HTTPServer.cpp:731
|
||||
#, c-format
|
||||
msgid "%dms"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:474 daemon/HTTPServer.cpp:686
|
||||
#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:716
|
||||
msgid "Outbound tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:496
|
||||
#: daemon/HTTPServer.cpp:521
|
||||
msgid "Tags"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:497
|
||||
#: daemon/HTTPServer.cpp:522
|
||||
msgid "Incoming"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:510
|
||||
#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:535
|
||||
msgid "Outgoing"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:507 daemon/HTTPServer.cpp:526
|
||||
#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:551
|
||||
msgid "Destination"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:507
|
||||
#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:814
|
||||
msgid "Amount"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:515
|
||||
#: daemon/HTTPServer.cpp:540
|
||||
msgid "Incoming Tags"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:523 daemon/HTTPServer.cpp:529
|
||||
#: daemon/HTTPServer.cpp:548 daemon/HTTPServer.cpp:554
|
||||
msgid "Tags sessions"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:526
|
||||
#: daemon/HTTPServer.cpp:551
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:536 daemon/HTTPServer.cpp:594
|
||||
#: daemon/HTTPServer.cpp:561 daemon/HTTPServer.cpp:621
|
||||
msgid "Local Destination"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:547 daemon/HTTPServer.cpp:917
|
||||
#: daemon/HTTPServer.cpp:572 daemon/HTTPServer.cpp:960
|
||||
msgid "Streams"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:570
|
||||
#: daemon/HTTPServer.cpp:595
|
||||
msgid "Close stream"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:599
|
||||
#: daemon/HTTPServer.cpp:613 daemon/HTTPServer.cpp:1430
|
||||
msgid "Such destination is not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:626
|
||||
msgid "I2CP session not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:602
|
||||
#: daemon/HTTPServer.cpp:629
|
||||
msgid "I2CP is not enabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:628
|
||||
#: daemon/HTTPServer.cpp:658
|
||||
msgid "Invalid"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:631
|
||||
#: daemon/HTTPServer.cpp:661
|
||||
msgid "Store type"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:632
|
||||
#: daemon/HTTPServer.cpp:662
|
||||
msgid "Expires"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:637
|
||||
#: daemon/HTTPServer.cpp:667
|
||||
msgid "Non Expired Leases"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:640
|
||||
#: daemon/HTTPServer.cpp:670
|
||||
msgid "Gateway"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:641
|
||||
#: daemon/HTTPServer.cpp:671
|
||||
msgid "TunnelID"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:642
|
||||
#: daemon/HTTPServer.cpp:672
|
||||
msgid "EndDate"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:652
|
||||
#: daemon/HTTPServer.cpp:682
|
||||
msgid "floodfill mode is disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:663
|
||||
#: daemon/HTTPServer.cpp:693
|
||||
msgid "Queue size"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:713
|
||||
#: daemon/HTTPServer.cpp:743
|
||||
msgid "Run peer test"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:714
|
||||
#: daemon/HTTPServer.cpp:744
|
||||
msgid "Reload tunnels configuration"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:717
|
||||
#: daemon/HTTPServer.cpp:747
|
||||
msgid "Decline transit tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:719
|
||||
#: daemon/HTTPServer.cpp:749
|
||||
msgid "Accept transit tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:723 daemon/HTTPServer.cpp:728
|
||||
#: daemon/HTTPServer.cpp:753 daemon/HTTPServer.cpp:758
|
||||
msgid "Cancel graceful shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:725 daemon/HTTPServer.cpp:730
|
||||
#: daemon/HTTPServer.cpp:755 daemon/HTTPServer.cpp:760
|
||||
msgid "Start graceful shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:733
|
||||
#: daemon/HTTPServer.cpp:763
|
||||
msgid "Force shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:734
|
||||
#: daemon/HTTPServer.cpp:764
|
||||
msgid "Reload external CSS styles"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:737
|
||||
#: daemon/HTTPServer.cpp:767
|
||||
msgid ""
|
||||
"<b>Note:</b> any action done here are not persistent and not changes your "
|
||||
"config files."
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:739
|
||||
#: daemon/HTTPServer.cpp:770
|
||||
msgid "Logging level"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:747
|
||||
#: daemon/HTTPServer.cpp:779
|
||||
msgid "Transit tunnels limit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:752 daemon/HTTPServer.cpp:771
|
||||
#: daemon/HTTPServer.cpp:784 daemon/HTTPServer.cpp:803
|
||||
msgid "Change"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:759
|
||||
#: daemon/HTTPServer.cpp:791
|
||||
msgid "Change language"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:797
|
||||
#: daemon/HTTPServer.cpp:830
|
||||
msgid "no transit tunnels currently built"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:878 daemon/HTTPServer.cpp:901
|
||||
#: daemon/HTTPServer.cpp:921 daemon/HTTPServer.cpp:944
|
||||
msgid "SAM disabled"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:894
|
||||
#: daemon/HTTPServer.cpp:937
|
||||
msgid "no sessions currently running"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:907
|
||||
#: daemon/HTTPServer.cpp:950
|
||||
msgid "SAM session not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:912
|
||||
#: daemon/HTTPServer.cpp:955
|
||||
msgid "SAM Session"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:969
|
||||
#: daemon/HTTPServer.cpp:1020
|
||||
msgid "Server Tunnels"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:985
|
||||
#: daemon/HTTPServer.cpp:1036
|
||||
msgid "Client Forwards"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:999
|
||||
#: daemon/HTTPServer.cpp:1050
|
||||
msgid "Server Forwards"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1199
|
||||
#: daemon/HTTPServer.cpp:1250
|
||||
msgid "Unknown page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1218
|
||||
#: daemon/HTTPServer.cpp:1269
|
||||
msgid "Invalid token"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1276 daemon/HTTPServer.cpp:1333
|
||||
#: daemon/HTTPServer.cpp:1373
|
||||
#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1359
|
||||
#: daemon/HTTPServer.cpp:1414 daemon/HTTPServer.cpp:1454
|
||||
msgid "SUCCESS"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1276
|
||||
#: daemon/HTTPServer.cpp:1327
|
||||
msgid "Stream closed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1278
|
||||
#: daemon/HTTPServer.cpp:1329
|
||||
msgid "Stream not found or already was closed"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1281
|
||||
#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1365
|
||||
msgid "Destination not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1284
|
||||
#: daemon/HTTPServer.cpp:1335
|
||||
msgid "StreamID can't be null"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1286 daemon/HTTPServer.cpp:1351
|
||||
#: daemon/HTTPServer.cpp:1337 daemon/HTTPServer.cpp:1367
|
||||
#: daemon/HTTPServer.cpp:1432
|
||||
msgid "Return to destination page"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1287 daemon/HTTPServer.cpp:1300
|
||||
#: daemon/HTTPServer.cpp:1375
|
||||
#: daemon/HTTPServer.cpp:1338 daemon/HTTPServer.cpp:1368
|
||||
#: daemon/HTTPServer.cpp:1381 daemon/HTTPServer.cpp:1456
|
||||
#, c-format
|
||||
msgid "You will be redirected in %d seconds"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1298
|
||||
#: daemon/HTTPServer.cpp:1359
|
||||
msgid "LeaseSet expiration time updated"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1362
|
||||
msgid "LeaseSet is not found or already expired"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1379
|
||||
#, c-format
|
||||
msgid "Transit tunnels count must not exceed %d"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1299 daemon/HTTPServer.cpp:1374
|
||||
#: daemon/HTTPServer.cpp:1380 daemon/HTTPServer.cpp:1455
|
||||
msgid "Back to commands list"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1335
|
||||
#: daemon/HTTPServer.cpp:1416
|
||||
msgid "Register at reg.i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1336
|
||||
#: daemon/HTTPServer.cpp:1417
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1336
|
||||
#: daemon/HTTPServer.cpp:1417
|
||||
msgid "A bit information about service on domain"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1337
|
||||
#: daemon/HTTPServer.cpp:1418
|
||||
msgid "Submit"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1343
|
||||
#: daemon/HTTPServer.cpp:1424
|
||||
msgid "Domain can't end with .b32.i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1346
|
||||
#: daemon/HTTPServer.cpp:1427
|
||||
msgid "Domain must end with .i2p"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1349
|
||||
msgid "Such destination is not found"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1369
|
||||
#: daemon/HTTPServer.cpp:1450
|
||||
msgid "Unknown command"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/HTTPServer.cpp:1373
|
||||
#: daemon/HTTPServer.cpp:1454
|
||||
msgid "Command accepted"
|
||||
msgstr ""
|
||||
|
||||
|
@ -624,20 +642,20 @@ msgstr ""
|
|||
msgid "You may try to find this host on jump services below"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:309 libi2pd_client/HTTPProxy.cpp:324
|
||||
#: libi2pd_client/HTTPProxy.cpp:392 libi2pd_client/HTTPProxy.cpp:435
|
||||
#: libi2pd_client/HTTPProxy.cpp:333 libi2pd_client/HTTPProxy.cpp:348
|
||||
#: libi2pd_client/HTTPProxy.cpp:417 libi2pd_client/HTTPProxy.cpp:460
|
||||
msgid "Invalid request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:309
|
||||
#: libi2pd_client/HTTPProxy.cpp:333
|
||||
msgid "Proxy unable to parse your request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:324
|
||||
#: libi2pd_client/HTTPProxy.cpp:348
|
||||
msgid "Addresshelper is not supported"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:349
|
||||
#: libi2pd_client/HTTPProxy.cpp:373
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Host %s is <font color=red>already in router's addressbook</font>. <b>Be "
|
||||
|
@ -645,121 +663,121 @@ msgid ""
|
|||
"<a href=\"%s%s%s&update=true\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:351
|
||||
#: libi2pd_client/HTTPProxy.cpp:375
|
||||
msgid "Addresshelper forced update rejected"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:358
|
||||
#: libi2pd_client/HTTPProxy.cpp:382
|
||||
#, c-format
|
||||
msgid ""
|
||||
"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s"
|
||||
"\">Continue</a>."
|
||||
"To add host <b>%s</b> in router's addressbook, click here: <a "
|
||||
"href=\"%s%s%s\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:360
|
||||
#: libi2pd_client/HTTPProxy.cpp:384
|
||||
msgid "Addresshelper request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:369
|
||||
#: libi2pd_client/HTTPProxy.cpp:393
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Host %s added to router's addressbook from helper. Click here to proceed: <a "
|
||||
"href=\"%s\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:370
|
||||
#: libi2pd_client/HTTPProxy.cpp:395
|
||||
msgid "Addresshelper adding"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:377
|
||||
#: libi2pd_client/HTTPProxy.cpp:402
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Host %s is <font color=red>already in router's addressbook</font>. Click "
|
||||
"here to update record: <a href=\"%s%s%s&update=true\">Continue</a>."
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:379
|
||||
#: libi2pd_client/HTTPProxy.cpp:404
|
||||
msgid "Addresshelper update"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:392
|
||||
#: libi2pd_client/HTTPProxy.cpp:417
|
||||
msgid "Invalid request URI"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:435
|
||||
#: libi2pd_client/HTTPProxy.cpp:460
|
||||
msgid "Can't detect destination host from request"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:452 libi2pd_client/HTTPProxy.cpp:456
|
||||
#: libi2pd_client/HTTPProxy.cpp:477 libi2pd_client/HTTPProxy.cpp:481
|
||||
msgid "Outproxy failure"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:452
|
||||
#: libi2pd_client/HTTPProxy.cpp:477
|
||||
msgid "Bad outproxy settings"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:455
|
||||
#: libi2pd_client/HTTPProxy.cpp:480
|
||||
#, c-format
|
||||
msgid "Host %s is not inside I2P network, but outproxy is not enabled"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:544
|
||||
#: libi2pd_client/HTTPProxy.cpp:569
|
||||
msgid "Unknown outproxy URL"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:550
|
||||
#: libi2pd_client/HTTPProxy.cpp:575
|
||||
msgid "Cannot resolve upstream proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:558
|
||||
#: libi2pd_client/HTTPProxy.cpp:583
|
||||
msgid "Hostname is too long"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:585
|
||||
#: libi2pd_client/HTTPProxy.cpp:610
|
||||
msgid "Cannot connect to upstream SOCKS proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:591
|
||||
#: libi2pd_client/HTTPProxy.cpp:616
|
||||
msgid "Cannot negotiate with SOCKS proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:633
|
||||
#: libi2pd_client/HTTPProxy.cpp:658
|
||||
msgid "CONNECT error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:633
|
||||
#: libi2pd_client/HTTPProxy.cpp:658
|
||||
msgid "Failed to connect"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:644 libi2pd_client/HTTPProxy.cpp:670
|
||||
#: libi2pd_client/HTTPProxy.cpp:669 libi2pd_client/HTTPProxy.cpp:695
|
||||
msgid "SOCKS proxy error"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:652
|
||||
#: libi2pd_client/HTTPProxy.cpp:677
|
||||
msgid "Failed to send request to upstream"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:673
|
||||
#: libi2pd_client/HTTPProxy.cpp:698
|
||||
msgid "No reply from SOCKS proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:680
|
||||
#: libi2pd_client/HTTPProxy.cpp:705
|
||||
msgid "Cannot connect"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:680
|
||||
#: libi2pd_client/HTTPProxy.cpp:705
|
||||
msgid "HTTP out proxy not implemented"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:681
|
||||
#: libi2pd_client/HTTPProxy.cpp:706
|
||||
msgid "Cannot connect to upstream HTTP proxy"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:714
|
||||
#: libi2pd_client/HTTPProxy.cpp:739
|
||||
msgid "Host is down"
|
||||
msgstr ""
|
||||
|
||||
#: libi2pd_client/HTTPProxy.cpp:714
|
||||
#: libi2pd_client/HTTPProxy.cpp:739
|
||||
msgid ""
|
||||
"Can't create connection to requested host, it may be down. Please try again "
|
||||
"later."
|
||||
|
|
|
@ -2,12 +2,17 @@
|
|||
---
|
||||
|
||||
```
|
||||
xgettext --omit-header -ctr: -ktr -ktr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
|
||||
xgettext --omit-header -ctr: -ktr -kntr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
|
||||
```
|
||||
|
||||
Regex for transforming gettext translations to our format:
|
||||
---
|
||||
|
||||
```
|
||||
in: ^(\"|#[:.,]|msgctxt)(.*)$\n
|
||||
out: <to empty line>
|
||||
```
|
||||
|
||||
```
|
||||
in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
|
||||
out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n
|
||||
|
@ -18,10 +23,6 @@ in: msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
|
|||
out: {"$1", "$2"},\n
|
||||
```
|
||||
|
||||
```
|
||||
in: ^#[:.,](.*)$\n
|
||||
out: <to empty line>
|
||||
```
|
||||
|
||||
```
|
||||
in: \n\n
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates
|
||||
# certsdir = /var/lib/i2pd/certificates
|
||||
|
||||
## Where to write pidfile (default: i2pd.pid, not used in Windows)
|
||||
## Where to write pidfile (default: /run/i2pd.pid, not used in Windows)
|
||||
# pidfile = /run/i2pd.pid
|
||||
|
||||
## Logging configuration section
|
||||
|
@ -31,7 +31,7 @@
|
|||
## * file - log entries to a file
|
||||
## * syslog - use syslog, see man 3 syslog
|
||||
# log = file
|
||||
## Path to logfile (default - autodetect)
|
||||
## Path to logfile (default: autodetect)
|
||||
# logfile = /var/log/i2pd/i2pd.log
|
||||
## Log messages above this level (debug, info, *warn, error, critical, none)
|
||||
## If you set it to none, logging will be disabled
|
||||
|
@ -40,6 +40,7 @@
|
|||
# logclftime = true
|
||||
|
||||
## Daemon mode. Router will go to background after start. Ignored on Windows
|
||||
## (default: true)
|
||||
# daemon = true
|
||||
|
||||
## Specify a family, router belongs to (default - none)
|
||||
|
@ -70,58 +71,60 @@
|
|||
## don't just uncomment this
|
||||
# port = 4567
|
||||
|
||||
## Enable communication through ipv4
|
||||
## Enable communication through ipv4 (default: true)
|
||||
ipv4 = true
|
||||
## Enable communication through ipv6
|
||||
## Enable communication through ipv6 (default: false)
|
||||
ipv6 = false
|
||||
|
||||
## Enable SSU transport
|
||||
ssu = false
|
||||
|
||||
## Bandwidth configuration
|
||||
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
|
||||
## L limit bandwidth to 32 KB/sec, O - to 256 KB/sec, P - to 2048 KB/sec,
|
||||
## X - unlimited
|
||||
## 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
|
||||
## 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. Value can be set to
|
||||
## integer in kilobytes, it will apply that limit and flag will be used
|
||||
## from next upper limit (example: if you set 4096 flag will be X, but real
|
||||
## limit will be 4096 KB/s). Same can be done when floodfill mode is used,
|
||||
## but keep in mind that low values may be negatively evaluated by Java
|
||||
## router algorithms.
|
||||
# bandwidth = L
|
||||
## Max % of bandwidth limit for transit. 0-100. 100 by default
|
||||
## Max % of bandwidth limit for transit. 0-100 (default: 100)
|
||||
# share = 100
|
||||
|
||||
## Router will not accept transit tunnels, disabling transit traffic completely
|
||||
## (default = false)
|
||||
## (default: false)
|
||||
# notransit = true
|
||||
|
||||
## Router will be floodfill
|
||||
## Router will be floodfill (default: false)
|
||||
## Note: that mode uses much more network connections and CPU!
|
||||
# floodfill = true
|
||||
|
||||
[ntcp2]
|
||||
## Enable NTCP2 transport (default = true)
|
||||
## Enable NTCP2 transport (default: true)
|
||||
# enabled = true
|
||||
## Publish address in RouterInfo (default = true)
|
||||
## Publish address in RouterInfo (default: true)
|
||||
# published = true
|
||||
## Port for incoming connections (default is global port option value)
|
||||
# port = 4567
|
||||
|
||||
[ssu2]
|
||||
## Enable SSU2 transport
|
||||
## Enable SSU2 transport (default: true)
|
||||
# enabled = true
|
||||
## Publish address in RouterInfo
|
||||
## Publish address in RouterInfo (default: true)
|
||||
# published = true
|
||||
## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled)
|
||||
## Port for incoming connections (default is global port option value)
|
||||
# port = 4567
|
||||
|
||||
[http]
|
||||
## Web Console settings
|
||||
## Uncomment and set to 'false' to disable Web Console
|
||||
## Enable the Web Console (default: true)
|
||||
# enabled = true
|
||||
## Address and port service will listen on
|
||||
address = 127.0.0.1
|
||||
port = 7070
|
||||
## Path to web console, default "/"
|
||||
## Address and port service will listen on (default: 127.0.0.1:7070)
|
||||
# address = 127.0.0.1
|
||||
# port = 7070
|
||||
## Path to web console (default: /)
|
||||
# webroot = /
|
||||
## Uncomment following lines to enable Web Console authentication
|
||||
## Enable Web Console authentication (default: false)
|
||||
## You should not use Web Console via public networks without additional encryption.
|
||||
## HTTP authentication is not encryption layer!
|
||||
# auth = true
|
||||
|
@ -134,12 +137,12 @@ port = 7070
|
|||
# lang = english
|
||||
|
||||
[httpproxy]
|
||||
## Uncomment and set to 'false' to disable HTTP Proxy
|
||||
## Enable the HTTP proxy (default: true)
|
||||
# enabled = true
|
||||
## Address and port service will listen on
|
||||
address = 127.0.0.1
|
||||
port = 4444
|
||||
## Optional keys file for proxy local destination
|
||||
## Address and port service will listen on (default: 127.0.0.1:4444)
|
||||
# address = 127.0.0.1
|
||||
# port = 4444
|
||||
## Optional keys file for proxy local destination (default: http-proxy-keys.dat)
|
||||
# keys = http-proxy-keys.dat
|
||||
## Enable address helper for adding .i2p domains with "jump URLs" (default: true)
|
||||
## You should disable this feature if your i2pd HTTP Proxy is public,
|
||||
|
@ -150,15 +153,15 @@ port = 4444
|
|||
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||
|
||||
[socksproxy]
|
||||
## Uncomment and set to 'false' to disable SOCKS Proxy
|
||||
## Enable the SOCKS proxy (default: true)
|
||||
# enabled = true
|
||||
## Address and port service will listen on
|
||||
address = 127.0.0.1
|
||||
port = 4447
|
||||
## Optional keys file for proxy local destination
|
||||
## Address and port service will listen on (default: 127.0.0.1:4447)
|
||||
# address = 127.0.0.1
|
||||
# port = 4447
|
||||
## Optional keys file for proxy local destination (default: socks-proxy-keys.dat)
|
||||
# keys = socks-proxy-keys.dat
|
||||
## Socks outproxy. Example below is set to use Tor for all connections except i2p
|
||||
## Uncomment and set to 'true' to enable using of SOCKS outproxy
|
||||
## Enable using of SOCKS outproxy (works only with SOCKS4, default: false)
|
||||
# outproxy.enabled = false
|
||||
## Address and port of outproxy
|
||||
# outproxy = 127.0.0.1
|
||||
|
@ -166,34 +169,34 @@ port = 4447
|
|||
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
|
||||
|
||||
[sam]
|
||||
## Comment or set to 'false' to disable SAM Bridge
|
||||
enabled = true
|
||||
## Address and ports service will listen on
|
||||
## Enable the SAM bridge (default: true)
|
||||
# enabled = false
|
||||
## Address and ports service will listen on (default: 127.0.0.1:7656, udp: 7655)
|
||||
# address = 127.0.0.1
|
||||
# port = 7656
|
||||
# portudp = 7655
|
||||
|
||||
[bob]
|
||||
## Uncomment and set to 'true' to enable BOB command channel
|
||||
## Enable the BOB command channel (default: false)
|
||||
# enabled = false
|
||||
## Address and port service will listen on
|
||||
## Address and port service will listen on (default: 127.0.0.1:2827)
|
||||
# address = 127.0.0.1
|
||||
# port = 2827
|
||||
|
||||
[i2cp]
|
||||
## Uncomment and set to 'true' to enable I2CP protocol
|
||||
## Enable the I2CP protocol (default: false)
|
||||
# enabled = false
|
||||
## Address and port service will listen on
|
||||
## Address and port service will listen on (default: 127.0.0.1:7654)
|
||||
# address = 127.0.0.1
|
||||
# port = 7654
|
||||
|
||||
[i2pcontrol]
|
||||
## Uncomment and set to 'true' to enable I2PControl protocol
|
||||
## Enable the I2PControl protocol (default: false)
|
||||
# enabled = false
|
||||
## Address and port service will listen on
|
||||
## Address and port service will listen on (default: 127.0.0.1:7650)
|
||||
# address = 127.0.0.1
|
||||
# port = 7650
|
||||
## Authentication password. "itoopie" by default
|
||||
## Authentication password (default: itoopie)
|
||||
# password = itoopie
|
||||
|
||||
[precomputation]
|
||||
|
@ -204,11 +207,11 @@ enabled = true
|
|||
[upnp]
|
||||
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
|
||||
# enabled = false
|
||||
## Name i2pd appears in UPnP forwardings list (default = I2Pd)
|
||||
## Name i2pd appears in UPnP forwardings list (default: I2Pd)
|
||||
# name = I2Pd
|
||||
|
||||
[meshnets]
|
||||
## Enable connectivity over the Yggdrasil network
|
||||
## Enable connectivity over the Yggdrasil network (default: false)
|
||||
# yggdrasil = false
|
||||
## You can bind address from your Yggdrasil subnet 300::/64
|
||||
## The address must first be added to the network interface
|
||||
|
@ -216,13 +219,13 @@ enabled = true
|
|||
|
||||
[reseed]
|
||||
## Options for bootstrapping into I2P network, aka reseeding
|
||||
## Enable or disable reseed data verification.
|
||||
## Enable reseed data verification (default: true)
|
||||
verify = true
|
||||
## URLs to request reseed data from, separated by comma
|
||||
## Default: "mainline" I2P Network reseeds
|
||||
# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/
|
||||
## Reseed URLs through the Yggdrasil, separated by comma
|
||||
# yggurls = http://[324:9de3:fea4:f6ac::ace]:7070/
|
||||
# yggurls = http://[324:71e:281a:9ed3::ace]:7070/
|
||||
## Path to local reseed data file (.su3) for manual reseeding
|
||||
# file = /path/to/i2pseeds.su3
|
||||
## or HTTPS URL to reseed from
|
||||
|
@ -232,7 +235,7 @@ verify = true
|
|||
## If you run i2pd behind a proxy server, set proxy server for reseeding here
|
||||
## Should be http://address:port or socks://address:port
|
||||
# proxy = http://127.0.0.1:8118
|
||||
## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default
|
||||
## Minimum number of known routers, below which i2pd triggers reseeding (default: 25)
|
||||
# threshold = 25
|
||||
|
||||
[addressbook]
|
||||
|
@ -252,13 +255,13 @@ verify = true
|
|||
# coresize = 0
|
||||
|
||||
[trust]
|
||||
## Enable explicit trust options. false by default
|
||||
## Enable explicit trust options. (default: false)
|
||||
# enabled = true
|
||||
## Make direct I2P connections only to routers in specified Family.
|
||||
# family = MyFamily
|
||||
## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities.
|
||||
# routers =
|
||||
## Should we hide our router from other routers? false by default
|
||||
## Should we hide our router from other routers? (default: false)
|
||||
# hidden = true
|
||||
|
||||
[exploratory]
|
||||
|
@ -277,8 +280,6 @@ verify = true
|
|||
[cpuext]
|
||||
## Use CPU AES-NI instructions set when work with cryptography when available (default: true)
|
||||
# aesni = true
|
||||
## Use CPU AVX instructions set when work with cryptography when available (default: true)
|
||||
# avx = true
|
||||
## Force usage of CPU instructions set, even if they not found
|
||||
## Force usage of CPU instructions set, even if they not found (default: false)
|
||||
## DO NOT TOUCH that option if you really don't know what are you doing!
|
||||
# force = false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||
|
||||
Name: i2pd-git
|
||||
Version: 2.47.0
|
||||
Version: 2.50.2
|
||||
Release: git%{git_hash}%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd
|
||||
|
@ -28,9 +28,11 @@ Requires: logrotate
|
|||
Requires: systemd
|
||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||
|
||||
|
||||
%description
|
||||
C++ implementation of I2P.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q -n i2pd-openssl
|
||||
|
||||
|
@ -38,72 +40,56 @@ C++ implementation of I2P.
|
|||
%build
|
||||
cd build
|
||||
%if 0%{?rhel} == 7
|
||||
%cmake3 \
|
||||
%cmake3 \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
-DWITH_HARDENING=ON \
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
%else
|
||||
%cmake \
|
||||
%cmake \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
-DWITH_HARDENING=ON \
|
||||
%if 0%{?fedora} > 29
|
||||
%if 0%{?fedora} > 29
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF \
|
||||
.
|
||||
%else
|
||||
%else
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
%endif
|
||||
%endif
|
||||
%endif
|
||||
|
||||
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
pushd redhat-linux-build
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
pushd redhat-linux-build
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
%endif
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
pushd build
|
||||
%if 0%{?mageia} > 7
|
||||
pushd build
|
||||
%endif
|
||||
%endif
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%if 0%{?rhel} == 9
|
||||
popd
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
|
||||
%install
|
||||
pushd build
|
||||
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
pushd redhat-linux-build
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
pushd redhat-linux-build
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
%endif
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia}
|
||||
pushd build
|
||||
%if 0%{?mageia}
|
||||
pushd build
|
||||
%endif
|
||||
%endif
|
||||
|
||||
chrpath -d i2pd
|
||||
|
@ -158,6 +144,21 @@ getent passwd i2pd >/dev/null || \
|
|||
|
||||
|
||||
%changelog
|
||||
* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
|
||||
- update to 2.50.2
|
||||
|
||||
* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
|
||||
- update to 2.50.1
|
||||
|
||||
* Mon Dec 18 2023 orignal <orignal@i2pmail.org> - 2.50.0
|
||||
- update to 2.50.0
|
||||
|
||||
* Mon Sep 18 2023 orignal <orignal@i2pmail.org> - 2.49.0
|
||||
- update to 2.49.0
|
||||
|
||||
* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
|
||||
- update to 2.48.0
|
||||
|
||||
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
|
||||
- update to 2.47.0
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Name: i2pd
|
||||
Version: 2.47.0
|
||||
Version: 2.50.2
|
||||
Release: 1%{?dist}
|
||||
Summary: I2P router written in C++
|
||||
Conflicts: i2pd-git
|
||||
|
@ -26,9 +26,11 @@ Requires: logrotate
|
|||
Requires: systemd
|
||||
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
|
||||
|
||||
|
||||
%description
|
||||
C++ implementation of I2P.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
|
@ -36,71 +38,56 @@ C++ implementation of I2P.
|
|||
%build
|
||||
cd build
|
||||
%if 0%{?rhel} == 7
|
||||
%cmake3 \
|
||||
%cmake3 \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
-DWITH_HARDENING=ON \
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
%else
|
||||
%cmake \
|
||||
%cmake \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
-DWITH_HARDENING=ON \
|
||||
%if 0%{?fedora} > 29
|
||||
%if 0%{?fedora} > 29
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF \
|
||||
.
|
||||
%else
|
||||
%else
|
||||
-DBUILD_SHARED_LIBS:BOOL=OFF
|
||||
%endif
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
pushd redhat-linux-build
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
pushd redhat-linux-build
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
%endif
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
pushd build
|
||||
%if 0%{?mageia} > 7
|
||||
pushd build
|
||||
%endif
|
||||
%endif
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%if 0%{?rhel} == 9
|
||||
popd
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 33
|
||||
popd
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia} > 7
|
||||
popd
|
||||
%endif
|
||||
|
||||
%install
|
||||
pushd build
|
||||
|
||||
%if 0%{?rhel} == 9
|
||||
pushd redhat-linux-build
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 35
|
||||
pushd redhat-linux-build
|
||||
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln}
|
||||
pushd redhat-linux-build
|
||||
%else
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
%endif
|
||||
%if 0%{?fedora} >= 33
|
||||
pushd %{_target_platform}
|
||||
%endif
|
||||
|
||||
%if 0%{?mageia}
|
||||
pushd build
|
||||
%if 0%{?mageia}
|
||||
pushd build
|
||||
%endif
|
||||
%endif
|
||||
|
||||
chrpath -d i2pd
|
||||
|
@ -155,6 +142,21 @@ getent passwd i2pd >/dev/null || \
|
|||
|
||||
|
||||
%changelog
|
||||
* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
|
||||
- update to 2.50.2
|
||||
|
||||
* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
|
||||
- update to 2.50.1
|
||||
|
||||
* Mon Dec 18 2023 orignal <orignal@i2pmail.org> - 2.50.0
|
||||
- update to 2.50.0
|
||||
|
||||
* Mon Sep 18 2023 orignal <orignal@i2pmail.org> - 2.49.0
|
||||
- update to 2.49.0
|
||||
|
||||
* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
|
||||
- update to 2.48.0
|
||||
|
||||
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
|
||||
- update to 2.47.0
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -150,17 +150,20 @@ namespace util
|
|||
|
||||
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
|
||||
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
||||
bool avx; i2p::config::GetOption("cpuext.avx", avx);
|
||||
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
|
||||
bool ssu; i2p::config::GetOption("ssu", ssu);
|
||||
if (!ssu && i2p::config::IsDefault ("precomputation.elgamal"))
|
||||
precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly
|
||||
i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
|
||||
i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt);
|
||||
|
||||
i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces
|
||||
|
||||
int netID; i2p::config::GetOption("netid", netID);
|
||||
i2p::context.SetNetID (netID);
|
||||
|
||||
bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved);
|
||||
i2p::transport::transports.SetCheckReserved(checkReserved);
|
||||
|
||||
i2p::context.Init ();
|
||||
|
||||
i2p::transport::InitTransports ();
|
||||
|
@ -176,7 +179,7 @@ namespace util
|
|||
|
||||
bool transit; i2p::config::GetOption("notransit", transit);
|
||||
i2p::context.SetAcceptsTunnels (!transit);
|
||||
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
|
||||
uint32_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
|
||||
if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels"))
|
||||
transitTunnels *= 2; // double default number of transit tunnels for floodfill
|
||||
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels);
|
||||
|
@ -299,12 +302,10 @@ namespace util
|
|||
|
||||
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
|
||||
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
|
||||
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
|
||||
LogPrint(eLogInfo, "Daemon: Starting Transports");
|
||||
if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled");
|
||||
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
|
||||
|
||||
i2p::transport::transports.SetCheckReserved(checkInReserved);
|
||||
i2p::transport::transports.Start(ntcp2, ssu2);
|
||||
if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
|
||||
LogPrint(eLogInfo, "Daemon: Transports started");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -87,6 +87,7 @@ 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";
|
||||
const char HTTP_COMMAND_EXPIRELEASE[] = "expirelease";
|
||||
|
||||
static std::string ConvertTime (uint64_t time)
|
||||
{
|
||||
|
@ -132,23 +133,19 @@ namespace http {
|
|||
static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes)
|
||||
{
|
||||
std::string state, stateText;
|
||||
switch (eState) {
|
||||
switch (eState)
|
||||
{
|
||||
case i2p::tunnel::eTunnelStateBuildReplyReceived :
|
||||
case i2p::tunnel::eTunnelStatePending : state = "building"; break;
|
||||
case i2p::tunnel::eTunnelStateBuildFailed :
|
||||
case i2p::tunnel::eTunnelStateTestFailed :
|
||||
case i2p::tunnel::eTunnelStateBuildFailed : state = "failed"; stateText = "declined"; break;
|
||||
case i2p::tunnel::eTunnelStateTestFailed : state = "failed"; stateText = "test failed"; break;
|
||||
case i2p::tunnel::eTunnelStateFailed : state = "failed"; break;
|
||||
case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break;
|
||||
case i2p::tunnel::eTunnelStateEstablished : state = "established"; break;
|
||||
default: state = "unknown"; break;
|
||||
}
|
||||
|
||||
if (state == "building") stateText = tr("building");
|
||||
else if (state == "failed") stateText = tr("failed");
|
||||
else if (state == "expiring") stateText = tr("expiring");
|
||||
else if (state == "established") stateText = tr("established");
|
||||
else stateText = tr("unknown");
|
||||
|
||||
if (stateText.empty ()) stateText = tr(state);
|
||||
|
||||
s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, ";
|
||||
ShowTraffic(s, bytes);
|
||||
s << "\r\n";
|
||||
|
@ -221,18 +218,19 @@ namespace http {
|
|||
s << "<b>" << tr("ERROR") << ":</b> " << string << "<br>\r\n";
|
||||
}
|
||||
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error)
|
||||
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case eRouterStatusOK: s << tr("OK"); break;
|
||||
case eRouterStatusTesting: s << tr("Testing"); break;
|
||||
case eRouterStatusFirewalled: s << tr("Firewalled"); break;
|
||||
case eRouterStatusUnknown: s << tr("Unknown"); break;
|
||||
case eRouterStatusProxy: s << tr("Proxy"); break;
|
||||
case eRouterStatusMesh: s << tr("Mesh"); break;
|
||||
default: s << tr("Unknown");
|
||||
}
|
||||
if (testing)
|
||||
s << " (" << tr("Testing") << ")";
|
||||
if (error != eRouterErrorNone)
|
||||
{
|
||||
switch (error)
|
||||
|
@ -263,12 +261,12 @@ namespace http {
|
|||
ShowUptime(s, i2p::context.GetUptime ());
|
||||
s << "<br>\r\n";
|
||||
s << "<b>" << tr("Network status") << ":</b> ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ());
|
||||
s << "<br>\r\n";
|
||||
if (i2p::context.SupportsV6 ())
|
||||
{
|
||||
s << "<b>" << tr("Network status v6") << ":</b> ";
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
|
||||
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ());
|
||||
s << "<br>\r\n";
|
||||
}
|
||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||
|
@ -421,8 +419,12 @@ namespace http {
|
|||
|
||||
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
|
||||
{
|
||||
s << "<b>Base32:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"1\">";
|
||||
s << dest->GetIdentHash ().ToBase32 () << "</textarea><br>\r\n<br>\r\n";
|
||||
|
||||
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"8\">";
|
||||
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
|
||||
|
||||
if (dest->IsEncryptedLeaseSet ())
|
||||
{
|
||||
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
|
||||
|
@ -434,12 +436,11 @@ namespace http {
|
|||
if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ())
|
||||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
auto base32 = dest->GetIdentHash ().ToBase32 ();
|
||||
s << "<div class='slide'><label for='slide-regaddr'><b>" << tr("Address registration line") << "</b></label>\r\n<input type=\"checkbox\" id=\"slide-regaddr\" />\r\n<div class=\"slidecontent\">\r\n"
|
||||
"<form method=\"get\" action=\"" << webroot << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_GET_REG_STRING << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"b32\" value=\"" << base32 << "\">\r\n"
|
||||
" <input type=\"hidden\" name=\"b32\" value=\"" << dest->GetIdentHash ().ToBase32 () << "\">\r\n"
|
||||
" <b>" << tr("Domain") << ":</b>\r\n<input type=\"text\" maxlength=\"67\" name=\"name\" placeholder=\"domain.i2p\" required>\r\n"
|
||||
" <button type=\"submit\">" << tr("Generate") << "</button>\r\n"
|
||||
"</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";
|
||||
|
@ -448,9 +449,23 @@ namespace http {
|
|||
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\">";
|
||||
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n"
|
||||
<< "<table><thead>"
|
||||
<< "<th>" << tr("Address") << "</th>"
|
||||
<< "<th style=\"width:5px;\"> </th>" // LeaseSet expiration button column
|
||||
<< "<th>" << tr("Type") << "</th>"
|
||||
<< "<th>" << tr("EncType") << "</th>"
|
||||
<< "</thead><tbody class=\"tableitem\">";
|
||||
for(auto& it: dest->GetLeaseSets ())
|
||||
s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
|
||||
{
|
||||
s << "<tr>"
|
||||
<< "<td>" << it.first.ToBase32 () << "</td>"
|
||||
<< "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_EXPIRELEASE<< "&b32=" << dest->GetIdentHash ().ToBase32 ()
|
||||
<< "&lease=" << it.first.ToBase32 () << "&token=" << token << "\" title=\"" << tr("Expire LeaseSet") << "\"> ✘ </a></td>"
|
||||
<< "<td>" << (int)it.second->GetStoreType () << "</td>"
|
||||
<< "<td>" << (int)it.second->GetEncryptionType () <<"</td>"
|
||||
<< "</tr>\r\n";
|
||||
}
|
||||
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
|
||||
} else
|
||||
s << "<b>" << tr("LeaseSets") << ":</b> <i>0</i><br>\r\n<br>\r\n";
|
||||
|
@ -591,6 +606,8 @@ namespace http {
|
|||
}
|
||||
s << "</tbody>\r\n</table>";
|
||||
}
|
||||
else
|
||||
ShowError(s, tr("Such destination is not found"));
|
||||
}
|
||||
|
||||
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
|
||||
|
@ -755,7 +772,7 @@ namespace http {
|
|||
s << " <a class=\"button" << (loglevel == eLogInfo ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
|
||||
s << " <a class=\"button" << (loglevel == eLogDebug ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
|
||||
|
||||
uint16_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
|
||||
uint32_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
|
||||
s << "<b>" << tr("Transit tunnels limit") << "</b><br>\r\n";
|
||||
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
|
||||
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n";
|
||||
|
@ -958,34 +975,42 @@ namespace http {
|
|||
void ShowI2PTunnels (std::stringstream& s)
|
||||
{
|
||||
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
|
||||
s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
for (auto& it: i2p::client::context.GetClientTunnels ())
|
||||
{
|
||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << it.second->GetName () << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
|
||||
auto& clientTunnels = i2p::client::context.GetClientTunnels ();
|
||||
auto httpProxy = i2p::client::context.GetHttpProxy ();
|
||||
if (httpProxy)
|
||||
{
|
||||
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "HTTP " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
auto socksProxy = i2p::client::context.GetSocksProxy ();
|
||||
if (socksProxy)
|
||||
if (!clientTunnels.empty () || httpProxy || socksProxy)
|
||||
{
|
||||
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "SOCKS " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
|
||||
if (!clientTunnels.empty ())
|
||||
{
|
||||
for (auto& it: clientTunnels)
|
||||
{
|
||||
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << it.second->GetName () << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
}
|
||||
if (httpProxy)
|
||||
{
|
||||
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "HTTP " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
if (socksProxy)
|
||||
{
|
||||
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
|
||||
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
|
||||
s << "SOCKS " << tr("Proxy") << "</a> ⇐ ";
|
||||
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
|
||||
s << "</div>\r\n"<< std::endl;
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
}
|
||||
s << "</div>\r\n";
|
||||
|
||||
auto& serverTunnels = i2p::client::context.GetServerTunnels ();
|
||||
if (!serverTunnels.empty ()) {
|
||||
|
@ -1312,6 +1337,36 @@ namespace http {
|
|||
res.add_header("Refresh", redirect.c_str());
|
||||
return;
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_EXPIRELEASE)
|
||||
{
|
||||
std::string b32 = params["b32"];
|
||||
std::string lease = params["lease"];
|
||||
|
||||
i2p::data::IdentHash ident, leaseident;
|
||||
ident.FromBase32 (b32);
|
||||
leaseident.FromBase32 (lease);
|
||||
auto dest = i2p::client::context.FindLocalDestination (ident);
|
||||
|
||||
if (dest)
|
||||
{
|
||||
auto leaseset = dest->FindLeaseSet (leaseident);
|
||||
if (leaseset)
|
||||
{
|
||||
leaseset->ExpireLease ();
|
||||
s << "<b>" << tr("SUCCESS") << "</b>: " << tr("LeaseSet expiration time updated") << "<br>\r\n<br>\r\n";
|
||||
}
|
||||
else
|
||||
s << "<b>" << tr("ERROR") << "</b>: " << tr("LeaseSet is not found or already expired") << "<br>\r\n<br>\r\n";
|
||||
}
|
||||
else
|
||||
s << "<b>" << tr("ERROR") << "</b>: " << tr("Destination not found") << "<br>\r\n<br>\r\n";
|
||||
|
||||
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a><br>\r\n";
|
||||
s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
|
||||
redirect = std::to_string(COMMAND_REDIRECT_TIMEOUT) + "; url=" + webroot + "?page=local_destination&b32=" + b32;
|
||||
res.add_header("Refresh", redirect.c_str());
|
||||
return;
|
||||
}
|
||||
else if (cmd == HTTP_COMMAND_LIMITTRANSIT)
|
||||
{
|
||||
uint32_t limit = std::stoul(params["limit"], nullptr);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -25,7 +25,7 @@ namespace http
|
|||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
|
||||
const int COMMAND_REDIRECT_TIMEOUT = 5; // in seconds
|
||||
const int TRANSIT_TUNNELS_LIMIT = 65535;
|
||||
const int TRANSIT_TUNNELS_LIMIT = 1000000;
|
||||
|
||||
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
|
||||
{
|
||||
|
|
30
debian/changelog
vendored
30
debian/changelog
vendored
|
@ -1,3 +1,33 @@
|
|||
i2pd (2.50.2) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.50.2/0.9.61
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sat, 06 Jan 2024 16:00:00 +0000
|
||||
|
||||
i2pd (2.50.1-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.50.1/0.9.61
|
||||
|
||||
-- r4sas <r4sas@i2pmail.org> Sat, 23 Dec 2023 18:30:00 +0000
|
||||
|
||||
i2pd (2.50.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.50.0/0.9.61
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 18 Dec 2023 16:00:00 +0000
|
||||
|
||||
i2pd (2.49.0-1) unstable; urgency=medium
|
||||
|
||||
* updated to version 2.49.0/0.9.60
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 18 Sep 2023 16:00:00 +0000
|
||||
|
||||
i2pd (2.48.0-1) unstable; urgency=high
|
||||
|
||||
* updated to version 2.48.0/0.9.59
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Mon, 12 Jun 2023 16:00:00 +0000
|
||||
|
||||
i2pd (2.47.0-1) unstable; urgency=high
|
||||
|
||||
* updated to version 2.47.0/0.9.58
|
||||
|
|
2
debian/i2pd.1
vendored
2
debian/i2pd.1
vendored
|
@ -64,7 +64,7 @@ The network interface to bind to for IPv4 connections
|
|||
The network interface to bind to for IPv6 connections
|
||||
.TP
|
||||
\fB\-\-ipv4=\fR
|
||||
Enable communication through ipv6 (\fIenabled\fR by default)
|
||||
Enable communication through ipv4 (\fIenabled\fR by default)
|
||||
.TP
|
||||
\fB\-\-ipv6\fR
|
||||
Enable communication through ipv6 (\fIdisabled\fR by default)
|
||||
|
|
|
@ -109,6 +109,7 @@ namespace chinese // language namespace
|
|||
{"Local Destination", "本地目标"},
|
||||
{"Streams", "流"},
|
||||
{"Close stream", "断开流"},
|
||||
{"Such destination is not found", "找不到此目标"},
|
||||
{"I2CP session not found", "未找到 I2CP 会话"},
|
||||
{"I2CP is not enabled", "I2CP 未启用"},
|
||||
{"Invalid", "无效"},
|
||||
|
@ -158,7 +159,6 @@ namespace chinese // language namespace
|
|||
{"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", "代理错误"},
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace french // language namespace
|
|||
{"Stopping in", "Arrêt dans"},
|
||||
{"Family", "Famille"},
|
||||
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
|
||||
{"Total tunnel creation success rate", "Taux de réussite de création de tunnel"},
|
||||
{"Received", "Reçu"},
|
||||
{"%.2f KiB/s", "%.2f Kio/s"},
|
||||
{"Sent", "Envoyé"},
|
||||
|
@ -91,10 +92,11 @@ namespace french // language namespace
|
|||
{"Address registration line", "Ligne d'inscription de l'adresse"},
|
||||
{"Domain", "Domaine"},
|
||||
{"Generate", "Générer"},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note:</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
|
||||
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note :</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
|
||||
{"Address", "Adresse"},
|
||||
{"Type", "Type"},
|
||||
{"EncType", "EncType"},
|
||||
{"Expire LeaseSet", "Expirer le jeu de baux"},
|
||||
{"Inbound tunnels", "Tunnels entrants"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Tunnels sortants"},
|
||||
|
@ -109,6 +111,7 @@ namespace french // language namespace
|
|||
{"Local Destination", "Destination locale"},
|
||||
{"Streams", "Flux"},
|
||||
{"Close stream", "Fermer le flux"},
|
||||
{"Such destination is not found", "Cette destination est introuvable"},
|
||||
{"I2CP session not found", "Session I2CP introuvable"},
|
||||
{"I2CP is not enabled", "I2CP est désactivé"},
|
||||
{"Invalid", "Invalide"},
|
||||
|
@ -128,7 +131,7 @@ namespace french // language namespace
|
|||
{"Start graceful shutdown", "Démarrer l'arrêt gracieux"},
|
||||
{"Force shutdown", "Forcer l'arrêt"},
|
||||
{"Reload external CSS styles", "Rafraîchir les styles CSS externes"},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note:</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
|
||||
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note :</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
|
||||
{"Logging level", "Niveau de journalisation"},
|
||||
{"Transit tunnels limit", "Limite sur les tunnels transitoires"},
|
||||
{"Change", "Changer"},
|
||||
|
@ -150,6 +153,8 @@ namespace french // language namespace
|
|||
{"StreamID can't be null", "StreamID ne peut pas être vide"},
|
||||
{"Return to destination page", "Retourner à la page de destination"},
|
||||
{"You will be redirected in %d seconds", "Vous serez redirigé dans %d secondes"},
|
||||
{"LeaseSet expiration time updated", "Temps d'expiration du jeu de baux mis à jour"},
|
||||
{"LeaseSet is not found or already expired", "Le jeu de baux est introuvable ou a déjà expiré"},
|
||||
{"Transit tunnels count must not exceed %d", "Le nombre de tunnels de transit ne doit pas excéder %d"},
|
||||
{"Back to commands list", "Retour à la liste des commandes"},
|
||||
{"Register at reg.i2p", "Inscription à reg.i2p"},
|
||||
|
@ -158,24 +163,23 @@ namespace french // language namespace
|
|||
{"Submit", "Soumettre"},
|
||||
{"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Le domaine doit terminer par .i2p"},
|
||||
{"Such destination is not found", "Cette destination est introuvable"},
|
||||
{"Unknown command", "Commande inconnue"},
|
||||
{"Command accepted", "Commande acceptée"},
|
||||
{"Proxy error", "Erreur de proxy"},
|
||||
{"Proxy info", "Information sur le proxy"},
|
||||
{"Proxy error: Host not found", "Erreur de proxy: Hôte introuvable"},
|
||||
{"Proxy error: Host not found", "Erreur de proxy : Hôte introuvable"},
|
||||
{"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"},
|
||||
{"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"},
|
||||
{"Invalid request", "Requête invalide"},
|
||||
{"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"},
|
||||
{"Addresshelper is not supported", "Assistant d'adresse non supporté"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. <b>Attention : la source de cette URL peut être nuisible !</b> Cliquez ici pour mettre à jour l'enregistrement : <a href=\"%s%s%s&update=true\">Continuer</a>."},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. <b>Attention : la source de cette URL peut être nuisible !</b> Cliquez ici pour mettre à jour l'enregistrement : <a href=\"%s%s%s&update=true\">Continuer</a>."},
|
||||
{"Addresshelper forced update rejected", "Mise à jour forcée des assistants d'adresses rejetée"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pour ajouter l'hôte <b>%s</b> au carnet d'adresses du routeur, cliquez ici : <a href=\"%s%s%s\">Continuer</a>."},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pour ajouter l'hôte <b>%s</b> au carnet d'adresses du routeur, cliquez ici : <a href=\"%s%s%s\">Continuer</a>."},
|
||||
{"Addresshelper request", "Demande à l'assistant d'adresse"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'hôte %s a été ajouté au carnet d'adresses du routeur depuis l'assistant. Cliquez ici pour continuer : <a href=\"%s\">Continuer</a>."},
|
||||
{"Addresshelper adding", "Ajout de l'assistant d'adresse"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. Cliquez ici pour mettre à jour le dossier : <a href=\"%s%s%s&update=true\">Continuer</a>."},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. Cliquez ici pour mettre à jour le dossier : <a href=\"%s%s%s&update=true\">Continuer</a>."},
|
||||
{"Addresshelper update", "Mise à jour de l'assistant d'adresse"},
|
||||
{"Invalid request URI", "URI de la requête invalide"},
|
||||
{"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"},
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace italian // language namespace
|
|||
{"Stopping in", "Arresto in"},
|
||||
{"Family", "Famiglia"},
|
||||
{"Tunnel creation success rate", "Percentuale di tunnel creati con successo"},
|
||||
{"Total tunnel creation success rate", "Percentuale di successo totale nella creazione del tunnel"},
|
||||
{"Received", "Ricevuti"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Inviati"},
|
||||
|
@ -95,6 +96,7 @@ namespace italian // language namespace
|
|||
{"Address", "Indirizzo"},
|
||||
{"Type", "Tipologia"},
|
||||
{"EncType", "Tipo di crittografia"},
|
||||
{"Expire LeaseSet", "Scadenza LeaseSet"},
|
||||
{"Inbound tunnels", "Tunnel in entrata"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Tunnel in uscita"},
|
||||
|
@ -109,6 +111,7 @@ namespace italian // language namespace
|
|||
{"Local Destination", "Destinazione locale"},
|
||||
{"Streams", "Flussi"},
|
||||
{"Close stream", "Interrompi il flusso"},
|
||||
{"Such destination is not found", "Questa destinazione non è stata trovata"},
|
||||
{"I2CP session not found", "Sessione I2CP non trovata"},
|
||||
{"I2CP is not enabled", "I2CP non è abilitato"},
|
||||
{"Invalid", "Invalido"},
|
||||
|
@ -150,6 +153,8 @@ namespace italian // language namespace
|
|||
{"StreamID can't be null", "Lo StreamID non può essere null"},
|
||||
{"Return to destination page", "Ritorna alla pagina di destinazione"},
|
||||
{"You will be redirected in %d seconds", "Sarai reindirizzato tra %d secondi"},
|
||||
{"LeaseSet expiration time updated", "Tempo di scadenza LeaseSet aggiornato"},
|
||||
{"LeaseSet is not found or already expired", "LeaseSet non trovato o già scaduto"},
|
||||
{"Transit tunnels count must not exceed %d", "Il conteggio dei tunnel di transito non deve superare %d"},
|
||||
{"Back to commands list", "Ritorna alla lista dei comandi"},
|
||||
{"Register at reg.i2p", "Registra a reg.i2p"},
|
||||
|
@ -158,7 +163,6 @@ namespace italian // language namespace
|
|||
{"Submit", "Invia"},
|
||||
{"Domain can't end with .b32.i2p", "I domini non possono terminare con .b32.i2p"},
|
||||
{"Domain must end with .i2p", "I domini devono terminare con .i2p"},
|
||||
{"Such destination is not found", "Questa destinazione non è stata trovata"},
|
||||
{"Unknown command", "Comando sconosciuto"},
|
||||
{"Command accepted", "Comando accettato"},
|
||||
{"Proxy error", "Errore del proxy"},
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace portuguese // language namespace
|
|||
{"Stopping in", "Parando em"},
|
||||
{"Family", "Família"},
|
||||
{"Tunnel creation success rate", "Taxa de sucesso na criação de túneis"},
|
||||
{"Total tunnel creation success rate", "Taxa total de sucesso na criação de túneis"},
|
||||
{"Received", "Recebido"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Enviado"},
|
||||
|
@ -95,6 +96,7 @@ namespace portuguese // language namespace
|
|||
{"Address", "Endereço"},
|
||||
{"Type", "Tipo"},
|
||||
{"EncType", "Tipo de Criptografia"},
|
||||
{"Expire LeaseSet", "Expirar LeaseSet"},
|
||||
{"Inbound tunnels", "Túneis de Entrada"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Túneis de Saída"},
|
||||
|
@ -109,6 +111,7 @@ namespace portuguese // language namespace
|
|||
{"Local Destination", "Destinos Locais"},
|
||||
{"Streams", "Fluxos"},
|
||||
{"Close stream", "Fechar fluxo"},
|
||||
{"Such destination is not found", "Tal destino não foi encontrado"},
|
||||
{"I2CP session not found", "Sessão do I2CP não encontrada"},
|
||||
{"I2CP is not enabled", "I2CP não está ativado"},
|
||||
{"Invalid", "Inválido"},
|
||||
|
@ -150,6 +153,8 @@ namespace portuguese // language namespace
|
|||
{"StreamID can't be null", "StreamID não pode ser nulo"},
|
||||
{"Return to destination page", "Retornar para à página de destino"},
|
||||
{"You will be redirected in %d seconds", "Você será redirecionado em %d segundos"},
|
||||
{"LeaseSet expiration time updated", "Tempo de validade do LeaseSet atualizado"},
|
||||
{"LeaseSet is not found or already expired", "LeaseSet não foi encontrado ou já expirou"},
|
||||
{"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
|
||||
{"Back to commands list", "Voltar para a lista de comandos"},
|
||||
{"Register at reg.i2p", "Registrar na reg.i2p"},
|
||||
|
@ -158,7 +163,6 @@ namespace portuguese // language namespace
|
|||
{"Submit", "Enviar"},
|
||||
{"Domain can't end with .b32.i2p", "O domínio não pode terminar com .b32.i2p"},
|
||||
{"Domain must end with .i2p", "O domínio não pode terminar com .i2p"},
|
||||
{"Such destination is not found", "Tal destino não foi encontrado"},
|
||||
{"Unknown command", "Comando desconhecido"},
|
||||
{"Command accepted", "Comando aceito"},
|
||||
{"Proxy error", "Erro no proxy"},
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace russian // language namespace
|
|||
{"Stopping in", "Остановка через"},
|
||||
{"Family", "Семейство"},
|
||||
{"Tunnel creation success rate", "Успешно построенных туннелей"},
|
||||
{"Total tunnel creation success rate", "Общий процент успешно построенных туннелей"},
|
||||
{"Received", "Получено"},
|
||||
{"%.2f KiB/s", "%.2f КиБ/с"},
|
||||
{"Sent", "Отправлено"},
|
||||
|
@ -95,6 +96,7 @@ namespace russian // language namespace
|
|||
{"Address", "Адрес"},
|
||||
{"Type", "Тип"},
|
||||
{"EncType", "ТипШифр"},
|
||||
{"Expire LeaseSet", "Просрочить Лизсет"},
|
||||
{"Inbound tunnels", "Входящие туннели"},
|
||||
{"%dms", "%dмс"},
|
||||
{"Outbound tunnels", "Исходящие туннели"},
|
||||
|
@ -109,6 +111,7 @@ namespace russian // language namespace
|
|||
{"Local Destination", "Локальное назначение"},
|
||||
{"Streams", "Стримы"},
|
||||
{"Close stream", "Закрыть стрим"},
|
||||
{"Such destination is not found", "Такая точка назначения не найдена"},
|
||||
{"I2CP session not found", "I2CP сессия не найдена"},
|
||||
{"I2CP is not enabled", "I2CP не включен"},
|
||||
{"Invalid", "Некорректный"},
|
||||
|
@ -150,6 +153,8 @@ namespace russian // language namespace
|
|||
{"StreamID can't be null", "StreamID не может быть пустым"},
|
||||
{"Return to destination page", "Вернуться на страницу точки назначения"},
|
||||
{"You will be redirected in %d seconds", "Вы будете переадресованы через %d секунд"},
|
||||
{"LeaseSet expiration time updated", "Время действия LeaseSet обновлено"},
|
||||
{"LeaseSet is not found or already expired", "Лизсет не найден или время действия уже истекло"},
|
||||
{"Transit tunnels count must not exceed %d", "Число транзитных туннелей не должно превышать %d"},
|
||||
{"Back to commands list", "Вернуться к списку команд"},
|
||||
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
|
||||
|
@ -158,7 +163,6 @@ namespace russian // language namespace
|
|||
{"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", "Ошибка прокси"},
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace swedish // language namespace
|
|||
{"Clock skew", "Tidsförskjutning"},
|
||||
{"Offline", "Nedkopplad"},
|
||||
{"Symmetric NAT", "Symmetrisk NAT"},
|
||||
{"Full cone NAT", "Full kon NAT"},
|
||||
{"No Descriptors", "Inga Beskrivningar"},
|
||||
{"Uptime", "Upptid"},
|
||||
{"Network status", "Nätverkstillstånd"},
|
||||
{"Network status v6", "Nätverkstillstånd v6"},
|
||||
|
@ -107,6 +109,7 @@ namespace swedish // language namespace
|
|||
{"Local Destination", "Lokal Plats"},
|
||||
{"Streams", "Strömmar"},
|
||||
{"Close stream", "Stäng strömmen"},
|
||||
{"Such destination is not found", "En sådan plats hittas ej"},
|
||||
{"I2CP session not found", "I2CP-period hittades inte"},
|
||||
{"I2CP is not enabled", "I2CP är inte påslaget"},
|
||||
{"Invalid", "Ogiltig"},
|
||||
|
@ -116,8 +119,10 @@ namespace swedish // language namespace
|
|||
{"Gateway", "Gateway"},
|
||||
{"TunnelID", "TunnelID"},
|
||||
{"EndDate", "EndDate"},
|
||||
{"floodfill mode is disabled", "Floodfill läget är inaktiverat"},
|
||||
{"Queue size", "Köstorlek"},
|
||||
{"Run peer test", "Utför utsiktstest"},
|
||||
{"Reload tunnels configuration", "Ladda om tunnelkonfiguration"},
|
||||
{"Decline transit tunnels", "Avvisa förmedlande tunnlar"},
|
||||
{"Accept transit tunnels", "Tillåt förmedlande tunnlar"},
|
||||
{"Cancel graceful shutdown", "Avbryt välvillig avstängning"},
|
||||
|
@ -154,7 +159,6 @@ namespace swedish // language namespace
|
|||
{"Submit", "Skicka"},
|
||||
{"Domain can't end with .b32.i2p", "Domänen får inte sluta med .b32.i2p"},
|
||||
{"Domain must end with .i2p", "Domänen måste sluta med .i2p"},
|
||||
{"Such destination is not found", "En sådan plats hittas ej"},
|
||||
{"Unknown command", "Okänt kommando"},
|
||||
{"Command accepted", "Kommando accepterades"},
|
||||
{"Proxy error", "Proxyfel"},
|
||||
|
@ -165,6 +169,14 @@ namespace swedish // language namespace
|
|||
{"Invalid request", "Ogiltig förfrågan"},
|
||||
{"Proxy unable to parse your request", "Proxyt kan inte behandla din förfrågan"},
|
||||
{"Addresshelper is not supported", "Adresshjälparen stöds ej"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. <b>Var försiktig: källan till denna URL kan vara skadlig!</b> Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
|
||||
{"Addresshelper forced update rejected", "Tvingad uppdatering av adresshjälparen nekad"},
|
||||
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "För att lägga till värd <b>%s</b> i routerns adressbok, klicka här: <a href=\"%s%s%s\">Fortsätt</a>."},
|
||||
{"Addresshelper request", "Adresshjälpare förfrågan"},
|
||||
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Värd %s tillagd i routerns adressbok från hjälparen. Klicka här för att fortsätta: <a href=\"%s\">Fortsätt</a>."},
|
||||
{"Addresshelper adding", "Adresshjälpare tilläggning"},
|
||||
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
|
||||
{"Addresshelper update", "Adresshjälpare uppdatering"},
|
||||
{"Invalid request URI", "Ogiltig förfrågnings-URI"},
|
||||
{"Can't detect destination host from request", "Kan inte upptäcka platsvärden från förfrågan"},
|
||||
{"Outproxy failure", "Utproxyfel"},
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace ukrainian // language namespace
|
|||
{"Stopping in", "Зупинка через"},
|
||||
{"Family", "Сімейство"},
|
||||
{"Tunnel creation success rate", "Успішно побудованих тунелів"},
|
||||
{"Total tunnel creation success rate", "Загальна кількість створених тунелів"},
|
||||
{"Received", "Отримано"},
|
||||
{"%.2f KiB/s", "%.2f КіБ/с"},
|
||||
{"Sent", "Відправлено"},
|
||||
|
@ -95,6 +96,7 @@ namespace ukrainian // language namespace
|
|||
{"Address", "Адреса"},
|
||||
{"Type", "Тип"},
|
||||
{"EncType", "ТипШифр"},
|
||||
{"Expire LeaseSet", "Завершити LeaseSet"},
|
||||
{"Inbound tunnels", "Вхідні тунелі"},
|
||||
{"%dms", "%dмс"},
|
||||
{"Outbound tunnels", "Вихідні тунелі"},
|
||||
|
@ -109,6 +111,7 @@ namespace ukrainian // language namespace
|
|||
{"Local Destination", "Локальні Призначення"},
|
||||
{"Streams", "Потоки"},
|
||||
{"Close stream", "Закрити потік"},
|
||||
{"Such destination is not found", "Така точка призначення не знайдена"},
|
||||
{"I2CP session not found", "I2CP сесія не знайдена"},
|
||||
{"I2CP is not enabled", "I2CP не увікнуто"},
|
||||
{"Invalid", "Некоректний"},
|
||||
|
@ -150,6 +153,8 @@ namespace ukrainian // language namespace
|
|||
{"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"},
|
||||
{"Return to destination page", "Повернутися на сторінку точки призначення"},
|
||||
{"You will be redirected in %d seconds", "Ви будете переадресовані через %d секунд"},
|
||||
{"LeaseSet expiration time updated", "Час закінчення LeaseSet оновлено"},
|
||||
{"LeaseSet is not found or already expired", "LeaseSet не знайдено або вже закінчився"},
|
||||
{"Transit tunnels count must not exceed %d", "Кількість транзитних тунелів не повинна перевищувати %d"},
|
||||
{"Back to commands list", "Повернутися до списку команд"},
|
||||
{"Register at reg.i2p", "Зареєструвати на reg.i2p"},
|
||||
|
@ -158,7 +163,6 @@ namespace ukrainian // language namespace
|
|||
{"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", "Помилка проксі"},
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace uzbek // language namespace
|
|||
{"Stopping in", "Ichida to'xtatish"},
|
||||
{"Family", "Oila"},
|
||||
{"Tunnel creation success rate", "Tunnel yaratish muvaffaqiyat darajasi"},
|
||||
{"Total tunnel creation success rate", "Tunnel yaratishning umumiy muvaffaqiyat darajasi"},
|
||||
{"Received", "Qabul qilindi"},
|
||||
{"%.2f KiB/s", "%.2f KiB/s"},
|
||||
{"Sent", "Yuborilgan"},
|
||||
|
@ -95,6 +96,7 @@ namespace uzbek // language namespace
|
|||
{"Address", "Manzil"},
|
||||
{"Type", "Turi"},
|
||||
{"EncType", "ShifrlashTuri"},
|
||||
{"Expire LeaseSet", "LeaseSet muddati tugaydi"},
|
||||
{"Inbound tunnels", "Kirish tunnellari"},
|
||||
{"%dms", "%dms"},
|
||||
{"Outbound tunnels", "Chiquvchi tunnellar"},
|
||||
|
@ -109,6 +111,7 @@ namespace uzbek // language namespace
|
|||
{"Local Destination", "Mahalliy joylanish"},
|
||||
{"Streams", "Strim"},
|
||||
{"Close stream", "Strimni o'chirish"},
|
||||
{"Such destination is not found", "Bunday yo'nalish topilmadi"},
|
||||
{"I2CP session not found", "I2CP sessiyasi topilmadi"},
|
||||
{"I2CP is not enabled", "I2CP yoqilmagan"},
|
||||
{"Invalid", "Noto'g'ri"},
|
||||
|
@ -150,6 +153,8 @@ namespace uzbek // language namespace
|
|||
{"StreamID can't be null", "StreamID bo'sh bo'lishi mumkin emas"},
|
||||
{"Return to destination page", "Manzilgoh sahifasiga qaytish"},
|
||||
{"You will be redirected in %d seconds", "Siz %d soniyadan so‘ng boshqa yo‘nalishga yo‘naltirilasiz"},
|
||||
{"LeaseSet expiration time updated", "LeaseSet amal qilish muddati yangilandi"},
|
||||
{"LeaseSet is not found or already expired", "LeaseSet topilmadi yoki muddati tugagan"},
|
||||
{"Transit tunnels count must not exceed %d", "Tranzit tunnellar soni %d dan oshmasligi kerak"},
|
||||
{"Back to commands list", "Buyruqlar ro'yxatiga qaytish"},
|
||||
{"Register at reg.i2p", "Reg.i2p-da ro'yxatdan o'ting"},
|
||||
|
@ -158,7 +163,6 @@ namespace uzbek // language namespace
|
|||
{"Submit", "Yuborish"},
|
||||
{"Domain can't end with .b32.i2p", "Domen .b32.i2p bilan tugashi mumkin emas"},
|
||||
{"Domain must end with .i2p", "Domen .i2p bilan tugashi kerak"},
|
||||
{"Such destination is not found", "Bunday yo'nalish topilmadi"},
|
||||
{"Unknown command", "Noma'lum buyruq"},
|
||||
{"Command accepted", "Buyruq qabul qilindi"},
|
||||
{"Proxy error", "Proksi xatosi"},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -28,6 +28,11 @@ namespace data
|
|||
return T32;
|
||||
}
|
||||
|
||||
bool IsBase32 (char ch)
|
||||
{
|
||||
return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7');
|
||||
}
|
||||
|
||||
static void iT64Build(void);
|
||||
|
||||
/*
|
||||
|
@ -55,6 +60,11 @@ namespace data
|
|||
return T64;
|
||||
}
|
||||
|
||||
bool IsBase64 (char ch)
|
||||
{
|
||||
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '~';
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse Substitution Table (built in run time)
|
||||
*/
|
||||
|
@ -187,6 +197,9 @@ namespace data
|
|||
else
|
||||
return 0;
|
||||
|
||||
if(*InBuffer == P64)
|
||||
return 0;
|
||||
|
||||
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||
while ( *ps-- == P64 )
|
||||
outCount--;
|
||||
|
@ -269,7 +282,7 @@ namespace data
|
|||
|
||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
|
||||
{
|
||||
int tmp = 0, bits = 0;
|
||||
unsigned int tmp = 0, bits = 0;
|
||||
size_t ret = 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
|
@ -298,7 +311,7 @@ namespace data
|
|||
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
|
||||
{
|
||||
size_t ret = 0, pos = 1;
|
||||
int bits = 8, tmp = inBuf[0];
|
||||
unsigned int bits = 8, tmp = inBuf[0];
|
||||
while (ret < outLen && (bits > 0 || pos < len))
|
||||
{
|
||||
if (bits < 5)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -19,9 +19,11 @@ namespace data {
|
|||
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
|
||||
const char * GetBase32SubstitutionTable ();
|
||||
const char * GetBase64SubstitutionTable ();
|
||||
bool IsBase64 (char ch);
|
||||
|
||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
||||
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
||||
bool IsBase32 (char ch);
|
||||
|
||||
/**
|
||||
* Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -7,52 +7,62 @@
|
|||
*/
|
||||
|
||||
#include "CPU.h"
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
#include "Log.h"
|
||||
|
||||
#ifndef bit_AES
|
||||
#define bit_AES (1 << 25)
|
||||
#endif
|
||||
#ifndef bit_AVX
|
||||
#define bit_AVX (1 << 28)
|
||||
#define bit_AES (1 << 25)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ < 6 && IS_X86
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
bool aesni = false;
|
||||
bool avx = false;
|
||||
|
||||
void Detect(bool AesSwitch, bool AvxSwitch, bool force)
|
||||
inline bool cpu_support_aes()
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
int info[4];
|
||||
__cpuid(0, info[0], info[1], info[2], info[3]);
|
||||
if (info[0] >= 0x00000001) {
|
||||
__cpuid(0x00000001, info[0], info[1], info[2], info[3]);
|
||||
#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
|
||||
if (AesSwitch && force) { // only if forced
|
||||
#else
|
||||
if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) {
|
||||
#endif
|
||||
aesni = true;
|
||||
}
|
||||
#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
|
||||
if (AvxSwitch && force) { // only if forced
|
||||
#else
|
||||
if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) {
|
||||
#endif
|
||||
avx = true;
|
||||
}
|
||||
#if IS_X86
|
||||
#if defined(__clang__)
|
||||
# if (__clang_major__ >= 6)
|
||||
__builtin_cpu_init();
|
||||
# endif
|
||||
return __builtin_cpu_supports("aes");
|
||||
#elif (defined(__GNUC__) && __GNUC__ >= 6)
|
||||
__builtin_cpu_init();
|
||||
return __builtin_cpu_supports("aes");
|
||||
#elif (defined(__GNUC__) && __GNUC__ < 6)
|
||||
int cpu_info[4];
|
||||
bool flag = false;
|
||||
__cpuid(0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
|
||||
if (cpu_info[0] >= 0x00000001) {
|
||||
__cpuid(0x00000001, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
|
||||
flag = ((cpu_info[2] & bit_AES) != 0);
|
||||
}
|
||||
return flag;
|
||||
#elif defined(_MSC_VER)
|
||||
int cpu_info[4];
|
||||
__cpuid(cpu_info, 1);
|
||||
return ((cpu_info[2] & bit_AES) != 0);
|
||||
#endif
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void Detect(bool AesSwitch, bool force)
|
||||
{
|
||||
if ((cpu_support_aes() && AesSwitch) || (AesSwitch && force)) {
|
||||
aesni = true;
|
||||
}
|
||||
#endif // defined(__x86_64__) || defined(__i386__)
|
||||
|
||||
LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled"));
|
||||
LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -9,14 +9,31 @@
|
|||
#ifndef LIBI2PD_CPU_H
|
||||
#define LIBI2PD_CPU_H
|
||||
|
||||
#if defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IX86) || defined(__i386__)
|
||||
# define IS_X86 1
|
||||
# if defined(_M_AMD64) || defined(__x86_64__)
|
||||
# define IS_X86_64 1
|
||||
# else
|
||||
# define IS_X86_64 0
|
||||
# endif
|
||||
#else
|
||||
# define IS_X86 0
|
||||
# define IS_X86_64 0
|
||||
#endif
|
||||
|
||||
#if defined(__AES__) && !defined(_MSC_VER) && IS_X86
|
||||
# define SUPPORTS_AES 1
|
||||
#else
|
||||
# define SUPPORTS_AES 0
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
extern bool aesni;
|
||||
extern bool avx;
|
||||
|
||||
void Detect(bool AesSwitch, bool AvxSwitch, bool force);
|
||||
void Detect(bool AesSwitch, bool force);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -77,7 +77,8 @@ namespace config {
|
|||
limits.add_options()
|
||||
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
||||
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
|
||||
("limits.transittunnels", value<uint16_t>()->default_value(5000), "Maximum active transit tunnels (default:5000)")
|
||||
("limits.transittunnels", value<uint32_t>()->default_value(10000), "Maximum active transit tunnels (default:10000)")
|
||||
("limits.zombies", value<double>()->default_value(0), "Minimum percentage of successfully created tunnels under which tunnel cleanup is paused (default [%]: 0.00)")
|
||||
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
|
||||
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
|
||||
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
|
||||
|
@ -192,7 +193,7 @@ namespace config {
|
|||
options_description precomputation("Precomputation options");
|
||||
precomputation.add_options()
|
||||
("precomputation.elgamal",
|
||||
#if defined(__x86_64__)
|
||||
#if (defined(_M_AMD64) || defined(__x86_64__))
|
||||
value<bool>()->default_value(false),
|
||||
#else
|
||||
value<bool>()->default_value(true),
|
||||
|
@ -220,14 +221,16 @@ namespace config {
|
|||
"https://reseed-pl.i2pd.xyz/,"
|
||||
"https://www2.mk16.de/,"
|
||||
"https://i2p.ghativega.in/,"
|
||||
"https://i2p.novg.net/"
|
||||
"https://i2p.novg.net/,"
|
||||
"https://reseed.stormycloud.org/"
|
||||
), "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://[306:3834:97b9:a00a::1]/,"
|
||||
"http://[316:f9e0:f22e:a74f::216]/"
|
||||
"http://[316:f9e0:f22e:a74f::216]/,"
|
||||
"http://[300:eaff:7fab:181b::e621]:7170"
|
||||
), "Reseed URLs through the Yggdrasil, separated by comma")
|
||||
;
|
||||
|
||||
|
@ -307,7 +310,7 @@ namespace config {
|
|||
options_description cpuext("CPU encryption extensions options");
|
||||
cpuext.add_options()
|
||||
("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used")
|
||||
("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used")
|
||||
("cpuext.avx", bool_switch()->default_value(false), "Deprecated option")
|
||||
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines")
|
||||
;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -28,6 +28,7 @@
|
|||
#include "I2PEndian.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
|
@ -159,7 +160,7 @@ namespace crypto
|
|||
|
||||
// DH/ElGamal
|
||||
|
||||
#if !defined(__x86_64__)
|
||||
#if !IS_X86_64
|
||||
const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226;
|
||||
const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1;
|
||||
#endif
|
||||
|
@ -361,7 +362,7 @@ namespace crypto
|
|||
BIGNUM * b1 = BN_CTX_get (ctx);
|
||||
BIGNUM * b = BN_CTX_get (ctx);
|
||||
// select random k
|
||||
#if defined(__x86_64__)
|
||||
#if IS_X86_64
|
||||
BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64
|
||||
#else
|
||||
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
|
||||
|
@ -428,7 +429,7 @@ namespace crypto
|
|||
|
||||
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
|
||||
#if IS_X86 || defined(_MSC_VER)
|
||||
RAND_bytes (priv, 256);
|
||||
#else
|
||||
// lower 226 bits (28 bytes and 2 bits) only. short exponent
|
||||
|
@ -555,7 +556,7 @@ namespace crypto
|
|||
}
|
||||
|
||||
// AES
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
#define KeyExpansion256(round0,round1) \
|
||||
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
||||
"movaps %%xmm1, %%xmm4 \n" \
|
||||
|
@ -580,7 +581,7 @@ namespace crypto
|
|||
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
||||
#endif
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
|
||||
{
|
||||
__asm__
|
||||
|
@ -621,7 +622,7 @@ namespace crypto
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
#define EncryptAES256(sched) \
|
||||
"pxor (%["#sched"]), %%xmm0 \n" \
|
||||
"aesenc 16(%["#sched"]), %%xmm0 \n" \
|
||||
|
@ -642,16 +643,18 @@ namespace crypto
|
|||
|
||||
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||
);
|
||||
(
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
:
|
||||
: [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -660,7 +663,7 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
#define DecryptAES256(sched) \
|
||||
"pxor 224(%["#sched"]), %%xmm0 \n" \
|
||||
"aesdec 208(%["#sched"]), %%xmm0 \n" \
|
||||
|
@ -681,16 +684,18 @@ namespace crypto
|
|||
|
||||
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
DecryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||
);
|
||||
(
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
DecryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
:
|
||||
: [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -699,7 +704,7 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
#define CallAESIMC(offset) \
|
||||
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
||||
"aesimc %%xmm0, %%xmm0 \n" \
|
||||
|
@ -708,7 +713,7 @@ namespace crypto
|
|||
|
||||
void ECBEncryption::SetKey (const AESKey& key)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
ExpandKey (key);
|
||||
|
@ -722,28 +727,30 @@ namespace crypto
|
|||
|
||||
void ECBDecryption::SetKey (const AESKey& key)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
ExpandKey (key); // expand encryption key first
|
||||
// then invert it using aesimc
|
||||
__asm__
|
||||
(
|
||||
CallAESIMC(16)
|
||||
CallAESIMC(32)
|
||||
CallAESIMC(48)
|
||||
CallAESIMC(64)
|
||||
CallAESIMC(80)
|
||||
CallAESIMC(96)
|
||||
CallAESIMC(112)
|
||||
CallAESIMC(128)
|
||||
CallAESIMC(144)
|
||||
CallAESIMC(160)
|
||||
CallAESIMC(176)
|
||||
CallAESIMC(192)
|
||||
CallAESIMC(208)
|
||||
: : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
|
||||
);
|
||||
(
|
||||
CallAESIMC(16)
|
||||
CallAESIMC(32)
|
||||
CallAESIMC(48)
|
||||
CallAESIMC(64)
|
||||
CallAESIMC(80)
|
||||
CallAESIMC(96)
|
||||
CallAESIMC(112)
|
||||
CallAESIMC(128)
|
||||
CallAESIMC(144)
|
||||
CallAESIMC(160)
|
||||
CallAESIMC(176)
|
||||
CallAESIMC(192)
|
||||
CallAESIMC(208)
|
||||
:
|
||||
: [shed]"r"(GetKeySchedule ())
|
||||
: "%xmm0", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -754,28 +761,28 @@ namespace crypto
|
|||
|
||||
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"1: \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
"movups %%xmm1, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||
: "%xmm0", "%xmm1", "cc", "memory"
|
||||
);
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"1: \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
"movups %%xmm1, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||
: "%xmm0", "%xmm1", "cc", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -799,22 +806,22 @@ namespace crypto
|
|||
|
||||
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movups %%xmm0, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movups %%xmm0, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -823,29 +830,29 @@ namespace crypto
|
|||
|
||||
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"1: \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movaps %%xmm0, %%xmm2 \n"
|
||||
DecryptAES256(sched)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movaps %%xmm2, %%xmm1 \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
"movups %%xmm1, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||
);
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"1: \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movaps %%xmm0, %%xmm2 \n"
|
||||
DecryptAES256(sched)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movaps %%xmm2, %%xmm1 \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
"movups %%xmm1, (%[iv]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -869,22 +876,22 @@ namespace crypto
|
|||
|
||||
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movups %%xmm0, (%[iv]) \n"
|
||||
DecryptAES256(sched)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
(
|
||||
"movups (%[iv]), %%xmm1 \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movups %%xmm0, (%[iv]) \n"
|
||||
DecryptAES256(sched)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
:
|
||||
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -893,34 +900,34 @@ namespace crypto
|
|||
|
||||
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
// encrypt IV
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
EncryptAES256(sched_iv)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
// double IV encryption
|
||||
EncryptAES256(sched_iv)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
// encrypt data, IV is xmm1
|
||||
"1: \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched_l)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
:
|
||||
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||
: "%xmm0", "%xmm1", "cc", "memory"
|
||||
);
|
||||
(
|
||||
// encrypt IV
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
EncryptAES256(sched_iv)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
// double IV encryption
|
||||
EncryptAES256(sched_iv)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
// encrypt data, IV is xmm1
|
||||
"1: \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
EncryptAES256(sched_l)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
:
|
||||
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||
: "%xmm0", "%xmm1", "cc", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -934,35 +941,35 @@ namespace crypto
|
|||
|
||||
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
|
||||
{
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
// decrypt IV
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
DecryptAES256(sched_iv)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
// double IV encryption
|
||||
DecryptAES256(sched_iv)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
// decrypt data, IV is xmm1
|
||||
"1: \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movaps %%xmm0, %%xmm2 \n"
|
||||
DecryptAES256(sched_l)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movaps %%xmm2, %%xmm1 \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
:
|
||||
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||
);
|
||||
(
|
||||
// decrypt IV
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
DecryptAES256(sched_iv)
|
||||
"movaps %%xmm0, %%xmm1 \n"
|
||||
// double IV encryption
|
||||
DecryptAES256(sched_iv)
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
// decrypt data, IV is xmm1
|
||||
"1: \n"
|
||||
"add $16, %[in] \n"
|
||||
"add $16, %[out] \n"
|
||||
"movups (%[in]), %%xmm0 \n"
|
||||
"movaps %%xmm0, %%xmm2 \n"
|
||||
DecryptAES256(sched_l)
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[out]) \n"
|
||||
"movaps %%xmm2, %%xmm1 \n"
|
||||
"dec %[num] \n"
|
||||
"jnz 1b \n"
|
||||
:
|
||||
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
|
||||
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
|
||||
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
@ -991,7 +998,7 @@ namespace crypto
|
|||
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
|
||||
EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen);
|
||||
EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen);
|
||||
EVP_EncryptFinal_ex(ctx, buf, &outlen);
|
||||
EVP_EncryptFinal_ex(ctx, buf + outlen, &outlen);
|
||||
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen);
|
||||
}
|
||||
else
|
||||
|
@ -1285,9 +1292,9 @@ namespace crypto
|
|||
}
|
||||
}*/
|
||||
|
||||
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force)
|
||||
void InitCrypto (bool precomputation, bool aesni, bool force)
|
||||
{
|
||||
i2p::cpu::Detect (aesni, avx, force);
|
||||
i2p::cpu::Detect (aesni, force);
|
||||
#if LEGACY_OPENSSL
|
||||
SSL_library_init ();
|
||||
#endif
|
||||
|
@ -1297,7 +1304,7 @@ namespace crypto
|
|||
CRYPTO_set_locking_callback (OpensslLockingCallback);*/
|
||||
if (precomputation)
|
||||
{
|
||||
#if defined(__x86_64__)
|
||||
#if IS_X86_64
|
||||
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
|
||||
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
|
||||
#else
|
||||
|
@ -1312,7 +1319,7 @@ namespace crypto
|
|||
if (g_ElggTable)
|
||||
{
|
||||
DestroyElggTable (g_ElggTable,
|
||||
#if defined(__x86_64__)
|
||||
#if IS_X86_64
|
||||
ELGAMAL_FULL_EXPONENT_NUM_BYTES
|
||||
#else
|
||||
ELGAMAL_SHORT_EXPONENT_NUM_BYTES
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -150,7 +150,7 @@ namespace crypto
|
|||
};
|
||||
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
class ECBCryptoAESNI
|
||||
{
|
||||
public:
|
||||
|
@ -167,7 +167,7 @@ namespace crypto
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
class ECBEncryption: public ECBCryptoAESNI
|
||||
#else
|
||||
class ECBEncryption
|
||||
|
@ -183,7 +183,7 @@ namespace crypto
|
|||
AES_KEY m_Key;
|
||||
};
|
||||
|
||||
#ifdef __AES__
|
||||
#if SUPPORTS_AES
|
||||
class ECBDecryption: public ECBCryptoAESNI
|
||||
#else
|
||||
class ECBDecryption
|
||||
|
@ -307,7 +307,7 @@ namespace crypto
|
|||
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 InitCrypto (bool precomputation, bool aesni, bool force);
|
||||
void TerminateCrypto ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -19,7 +19,7 @@ namespace i2p
|
|||
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)
|
||||
m_Owner (owner), m_DefaultReceiver (nullptr), m_DefaultRawReceiver (nullptr), m_Gzip (gzip)
|
||||
{
|
||||
if (m_Gzip)
|
||||
m_Deflator.reset (new i2p::data::GzipDeflator);
|
||||
|
@ -119,19 +119,79 @@ namespace datagram
|
|||
|
||||
void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (m_RawReceiver)
|
||||
m_RawReceiver (fromPort, toPort, buf, len);
|
||||
auto r = FindRawReceiver(toPort);
|
||||
|
||||
if (r)
|
||||
r (fromPort, toPort, buf, len);
|
||||
else
|
||||
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
|
||||
}
|
||||
|
||||
void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
m_ReceiversByPorts[port] = receiver;
|
||||
if (!m_DefaultReceiver) {
|
||||
m_DefaultReceiver = receiver;
|
||||
m_DefaultReceiverPort = port;
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramDestination::ResetReceiver (uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
m_ReceiversByPorts.erase (port);
|
||||
if (m_DefaultReceiverPort == port) {
|
||||
m_DefaultReceiver = nullptr;
|
||||
m_DefaultReceiverPort = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DatagramDestination::SetRawReceiver (const RawReceiver& receiver, uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
|
||||
m_RawReceiversByPorts[port] = receiver;
|
||||
if (!m_DefaultRawReceiver) {
|
||||
m_DefaultRawReceiver = receiver;
|
||||
m_DefaultRawReceiverPort = port;
|
||||
}
|
||||
}
|
||||
|
||||
void DatagramDestination::ResetRawReceiver (uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
|
||||
m_RawReceiversByPorts.erase (port);
|
||||
if (m_DefaultRawReceiverPort == port) {
|
||||
m_DefaultRawReceiver = nullptr;
|
||||
m_DefaultRawReceiverPort = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
Receiver r = m_Receiver;
|
||||
Receiver r = nullptr;
|
||||
auto itr = m_ReceiversByPorts.find(port);
|
||||
if (itr != m_ReceiversByPorts.end())
|
||||
r = itr->second;
|
||||
else {
|
||||
r = m_DefaultReceiver;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
DatagramDestination::RawReceiver DatagramDestination::FindRawReceiver(uint16_t port)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
|
||||
RawReceiver r = nullptr;
|
||||
auto itr = m_RawReceiversByPorts.find(port);
|
||||
if (itr != m_RawReceiversByPorts.end())
|
||||
r = itr->second;
|
||||
else {
|
||||
r = m_DefaultRawReceiver;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -126,14 +126,12 @@ namespace datagram
|
|||
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
||||
|
||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||
void ResetReceiver () { m_Receiver = nullptr; };
|
||||
|
||||
void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; };
|
||||
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
|
||||
void SetReceiver (const Receiver& receiver, uint16_t port);
|
||||
void ResetReceiver (uint16_t port);
|
||||
|
||||
void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; };
|
||||
void ResetRawReceiver () { m_RawReceiver = nullptr; };
|
||||
void SetRawReceiver (const RawReceiver& receiver, uint16_t port);
|
||||
void ResetRawReceiver (uint16_t port);
|
||||
|
||||
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
|
||||
|
||||
|
@ -150,20 +148,26 @@ namespace datagram
|
|||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
||||
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
|
||||
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
|
||||
Receiver FindReceiver(uint16_t port);
|
||||
RawReceiver FindRawReceiver(uint16_t port);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
||||
Receiver m_Receiver; // default
|
||||
RawReceiver m_RawReceiver; // default
|
||||
bool m_Gzip; // gzip compression of data messages
|
||||
|
||||
std::mutex m_SessionsMutex;
|
||||
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
|
||||
std::mutex m_ReceiversMutex;
|
||||
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
|
||||
Receiver m_DefaultReceiver;
|
||||
RawReceiver m_DefaultRawReceiver;
|
||||
uint16_t m_DefaultReceiverPort;
|
||||
uint16_t m_DefaultRawReceiverPort;
|
||||
std::mutex m_ReceiversMutex;
|
||||
std::mutex m_RawReceiversMutex;
|
||||
std::unordered_map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
std::unordered_map<uint16_t, RawReceiver> m_RawReceiversByPorts;
|
||||
|
||||
bool m_Gzip; // gzip compression of data messages
|
||||
i2p::data::GzipInflator m_Inflator;
|
||||
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
|
||||
std::vector<uint8_t> m_From, m_Signature;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -262,17 +262,6 @@ namespace client
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ls = i2p::data::netdb.FindLeaseSet (ident);
|
||||
if (ls && !ls->IsExpired ())
|
||||
{
|
||||
ls->PopulateLeases (); // since we don't store them in netdb
|
||||
std::lock_guard<std::mutex> _lock(m_RemoteLeaseSetsMutex);
|
||||
m_RemoteLeaseSets[ident] = ls;
|
||||
return ls;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -378,8 +367,9 @@ namespace client
|
|||
HandleDataMessage (payload, len);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
// we assume tunnel tests non-encrypted
|
||||
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
|
||||
// try tunnel test first
|
||||
if (!m_Pool || !m_Pool->ProcessDeliveryStatus (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET), bufbe64toh (payload + DELIVERY_STATUS_TIMESTAMP_OFFSET)))
|
||||
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
|
||||
break;
|
||||
case eI2NPDatabaseStore:
|
||||
HandleDatabaseStoreMessage (payload, len);
|
||||
|
@ -513,38 +503,43 @@ namespace client
|
|||
if (it != m_LeaseSetRequests.end ())
|
||||
{
|
||||
auto request = it->second;
|
||||
bool found = false;
|
||||
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
i2p::data::IdentHash peerHash (buf + 33 + i*32);
|
||||
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
|
||||
{
|
||||
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");
|
||||
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
|
||||
}
|
||||
}
|
||||
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ());
|
||||
if (SendLeaseSetRequest (key, floodfill, request))
|
||||
found = true;
|
||||
LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
|
||||
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
|
||||
request->Complete (nullptr);
|
||||
m_LeaseSetRequests.erase (key);
|
||||
}
|
||||
SendNextLeaseSetRequest (key, request);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
||||
}
|
||||
|
||||
void LeaseSetDestination::SendNextLeaseSetRequest (const i2p::data::IdentHash& key,
|
||||
std::shared_ptr<LeaseSetRequest> request)
|
||||
{
|
||||
bool found = false;
|
||||
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
|
||||
{
|
||||
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
|
||||
if (floodfill)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ());
|
||||
if (SendLeaseSetRequest (key, floodfill, request))
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
|
||||
request->Complete (nullptr);
|
||||
m_LeaseSetRequests.erase (key);
|
||||
}
|
||||
}
|
||||
|
||||
void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||
{
|
||||
if (msgID == m_PublishReplyToken)
|
||||
|
@ -632,6 +627,15 @@ namespace client
|
|||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||
auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound));
|
||||
auto s = shared_from_this ();
|
||||
msg->onDrop = [s]()
|
||||
{
|
||||
s->GetService ().post([s]()
|
||||
{
|
||||
s->m_PublishConfirmationTimer.cancel ();
|
||||
s->HandlePublishConfirmationTimer (boost::system::error_code());
|
||||
});
|
||||
};
|
||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
|
@ -648,7 +652,7 @@ namespace client
|
|||
m_PublishReplyToken = 0;
|
||||
if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
|
||||
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds or failed. will try again");
|
||||
Publish ();
|
||||
}
|
||||
else
|
||||
|
@ -833,8 +837,17 @@ namespace client
|
|||
AddECIESx25519Key (replyKey, replyTag);
|
||||
else
|
||||
AddSessionKey (replyKey, replyTag);
|
||||
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
|
||||
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
|
||||
|
||||
auto msg = WrapMessageForRouter (nextFloodfill,
|
||||
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
|
||||
auto s = shared_from_this ();
|
||||
msg->onDrop = [s, dest, request]()
|
||||
{
|
||||
s->GetService ().post([s, dest, request]()
|
||||
{
|
||||
s->SendNextLeaseSetRequest (dest, request);
|
||||
});
|
||||
};
|
||||
request->outboundTunnel->SendTunnelDataMsgs (
|
||||
{
|
||||
i2p::tunnel::TunnelMessageBlock
|
||||
|
@ -930,7 +943,7 @@ namespace client
|
|||
bool isPublic, const std::map<std::string, std::string> * params):
|
||||
LeaseSetDestination (service, isPublic, params),
|
||||
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
|
||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
|
||||
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0),
|
||||
m_DatagramDestination (nullptr), m_RefCounter (0),
|
||||
m_ReadyChecker(service)
|
||||
{
|
||||
|
@ -1047,22 +1060,30 @@ namespace client
|
|||
|
||||
void ClientDestination::Stop ()
|
||||
{
|
||||
LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
|
||||
LeaseSetDestination::Stop ();
|
||||
m_ReadyChecker.cancel();
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
|
||||
m_StreamingDestination->Stop ();
|
||||
//m_StreamingDestination->SetOwner (nullptr);
|
||||
m_StreamingDestination = nullptr;
|
||||
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination by ports");
|
||||
for (auto& it: m_StreamingDestinationsByPorts)
|
||||
{
|
||||
it.second->Stop ();
|
||||
//it.second->SetOwner (nullptr);
|
||||
}
|
||||
m_StreamingDestinationsByPorts.clear ();
|
||||
m_LastStreamingDestination = nullptr;
|
||||
|
||||
if (m_DatagramDestination)
|
||||
{
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping Datagram Destination");
|
||||
delete m_DatagramDestination;
|
||||
m_DatagramDestination = nullptr;
|
||||
}
|
||||
LogPrint(eLogDebug, "Destination: -> Stopping done");
|
||||
}
|
||||
|
||||
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
|
||||
|
@ -1082,9 +1103,15 @@ namespace client
|
|||
case PROTOCOL_TYPE_STREAMING:
|
||||
{
|
||||
// streaming protocol
|
||||
auto dest = GetStreamingDestination (toPort);
|
||||
if (dest)
|
||||
dest->HandleDataMessagePayload (buf, length);
|
||||
if (toPort != m_LastPort || !m_LastStreamingDestination)
|
||||
{
|
||||
m_LastStreamingDestination = GetStreamingDestination (toPort);
|
||||
if (!m_LastStreamingDestination)
|
||||
m_LastStreamingDestination = m_StreamingDestination; // if no destination on port use default
|
||||
m_LastPort = toPort;
|
||||
}
|
||||
if (m_LastStreamingDestination)
|
||||
m_LastStreamingDestination->HandleDataMessagePayload (buf, length);
|
||||
else
|
||||
LogPrint (eLogError, "Destination: Missing streaming destination");
|
||||
}
|
||||
|
@ -1108,7 +1135,7 @@ namespace client
|
|||
}
|
||||
}
|
||||
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port)
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
|
@ -1138,7 +1165,7 @@ namespace client
|
|||
}
|
||||
}
|
||||
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
|
||||
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port)
|
||||
{
|
||||
if (!streamRequestComplete)
|
||||
{
|
||||
|
@ -1157,7 +1184,7 @@ namespace client
|
|||
}
|
||||
|
||||
template<typename Dest>
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, int port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, uint16_t port)
|
||||
{
|
||||
volatile bool done = false;
|
||||
std::shared_ptr<i2p::stream::Stream> stream;
|
||||
|
@ -1181,17 +1208,17 @@ namespace client
|
|||
return stream;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, int port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, uint16_t port)
|
||||
{
|
||||
return CreateStreamSync (dest, port);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port)
|
||||
{
|
||||
return CreateStreamSync (dest, port);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
|
||||
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port)
|
||||
{
|
||||
if (m_StreamingDestination)
|
||||
return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
|
||||
|
@ -1228,7 +1255,7 @@ namespace client
|
|||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (uint16_t port) const
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
|
@ -1236,8 +1263,9 @@ namespace client
|
|||
if (it != m_StreamingDestinationsByPorts.end ())
|
||||
return it->second;
|
||||
}
|
||||
// if port is zero or not found, use default destination
|
||||
return m_StreamingDestination;
|
||||
else // if port is zero, use default destination
|
||||
return m_StreamingDestination;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
|
||||
|
@ -1265,7 +1293,7 @@ namespace client
|
|||
m_StreamingDestination->AcceptOnce (acceptor);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (uint16_t port, bool gzip)
|
||||
{
|
||||
auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip);
|
||||
if (port)
|
||||
|
@ -1275,7 +1303,7 @@ namespace client
|
|||
return dest;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (int port)
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (uint16_t port)
|
||||
{
|
||||
if (port)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -14,6 +14,7 @@
|
|||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
@ -175,6 +176,7 @@ namespace client
|
|||
|
||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||
void SendNextLeaseSetRequest (const i2p::data::IdentHash& key, std::shared_ptr<LeaseSetRequest> request);
|
||||
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
void CleanupRemoteLeaseSets ();
|
||||
|
@ -184,8 +186,8 @@ namespace client
|
|||
|
||||
boost::asio::io_service& m_Service;
|
||||
mutable std::mutex m_RemoteLeaseSetsMutex;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
|
||||
std::mutex m_LeaseSetMutex;
|
||||
|
@ -241,15 +243,15 @@ namespace client
|
|||
int GetRefCounter () const { return m_RefCounter; };
|
||||
|
||||
// streaming
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (int port);
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (uint16_t port, bool gzip = true); // additional
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (uint16_t port = 0) const;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (uint16_t port);
|
||||
// following methods operate with default streaming destination
|
||||
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 (const i2p::data::IdentHash& dest, int port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port = 0);
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0);
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, uint16_t port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0); // sync
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t 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);
|
||||
|
@ -285,7 +287,7 @@ namespace client
|
|||
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
|
||||
|
||||
template<typename Dest>
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, int port);
|
||||
std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, uint16_t port);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -297,6 +299,7 @@ namespace client
|
|||
bool m_IsStreamingAnswerPings;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels
|
||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||
int m_RefCounter; // how many clients(tunnels) use this destination
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -117,6 +117,12 @@ namespace garlic
|
|||
return session->HandleNextMessage (buf, len, shared_from_this (), index);
|
||||
}
|
||||
|
||||
bool ReceiveRatchetTagSet::IsSessionTerminated () const
|
||||
{
|
||||
return !m_Session || m_Session->IsTerminated ();
|
||||
}
|
||||
|
||||
|
||||
SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
|
||||
ReceiveRatchetTagSet (nullptr), m_Destination (destination)
|
||||
{
|
||||
|
@ -1148,7 +1154,7 @@ namespace garlic
|
|||
return len;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<I2NPMessage> msg, const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
|
||||
m->Align (12); // in order to get buf aligned to 16 (12 + 4)
|
||||
|
@ -1168,10 +1174,16 @@ namespace garlic
|
|||
htobe32buf (m->GetPayload (), offset);
|
||||
m->len += offset + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
if (msg->onDrop)
|
||||
{
|
||||
// move onDrop to the wrapping I2NP messages
|
||||
m->onDrop = msg->onDrop;
|
||||
msg->onDrop = nullptr;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey)
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<I2NPMessage> msg, const uint8_t * routerPublicKey)
|
||||
{
|
||||
// Noise_N, we are Alice, routerPublicKey is Bob's
|
||||
i2p::crypto::NoiseSymmetricState noiseState;
|
||||
|
@ -1205,6 +1217,12 @@ namespace garlic
|
|||
htobe32buf (m->GetPayload (), offset);
|
||||
m->len += offset + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
if (msg->onDrop)
|
||||
{
|
||||
// move onDrop to the wrapping I2NP messages
|
||||
m->onDrop = msg->onDrop;
|
||||
msg->onDrop = nullptr;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -86,7 +86,8 @@ namespace garlic
|
|||
|
||||
virtual bool IsIndexExpired (int index) const;
|
||||
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
|
||||
virtual bool IsSessionTerminated () const;
|
||||
|
||||
private:
|
||||
|
||||
int m_TrimBehindIndex = 0;
|
||||
|
@ -101,9 +102,10 @@ namespace garlic
|
|||
|
||||
SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key);
|
||||
|
||||
bool IsIndexExpired (int index) const { return false; };
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
|
||||
bool IsIndexExpired (int index) const override { return false; };
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, int index) override;
|
||||
bool IsSessionTerminated () const override { return false; }
|
||||
|
||||
private:
|
||||
|
||||
GarlicDestination * m_Destination;
|
||||
|
@ -245,8 +247,8 @@ namespace garlic
|
|||
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);
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<I2NPMessage> msg, const uint8_t * key, uint64_t tag);
|
||||
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<I2NPMessage> msg, const uint8_t * routerPublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,6 +136,14 @@ namespace fs {
|
|||
dataDir = (home != NULL && strlen(home) > 0) ? home : "";
|
||||
dataDir += "/Library/Application Support/" + appName;
|
||||
return;
|
||||
#elif defined(__HAIKU__)
|
||||
char *home = getenv("HOME");
|
||||
if (home != NULL && strlen(home) > 0) {
|
||||
dataDir = std::string(home) + "/config/settings/" + appName;
|
||||
} else {
|
||||
dataDir = "/tmp/" + appName;
|
||||
}
|
||||
return;
|
||||
#else /* other unix */
|
||||
#if defined(ANDROID)
|
||||
const char * ext = getenv("EXTERNAL_STORAGE");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -431,7 +431,8 @@ namespace garlic
|
|||
}
|
||||
|
||||
GarlicDestination::GarlicDestination (): m_NumTags (32), // 32 tags by default
|
||||
m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0) // 0 means standard
|
||||
m_PayloadBuffer (nullptr), m_NumRatchetInboundTags (0), // 0 means standard
|
||||
m_NumUsedECIESx25519Tags (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -588,11 +589,18 @@ namespace garlic
|
|||
auto it = m_ECIESx25519Tags.find (tag);
|
||||
if (it != m_ECIESx25519Tags.end ())
|
||||
{
|
||||
if (!it->second.tagset) return true; // duplicate
|
||||
if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
|
||||
{
|
||||
m_LastTagset = it->second.tagset;
|
||||
it->second.tagset = nullptr; // mark as used
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
|
||||
m_ECIESx25519Tags.erase (it);
|
||||
m_ECIESx25519Tags.erase (it);
|
||||
}
|
||||
m_NumUsedECIESx25519Tags++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -877,18 +885,41 @@ namespace garlic
|
|||
}
|
||||
|
||||
numExpiredTags = 0;
|
||||
for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();)
|
||||
if (m_NumUsedECIESx25519Tags > ECIESX25519_TAGSET_MAX_NUM_TAGS) // too many used tags
|
||||
{
|
||||
if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index))
|
||||
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> oldTags;
|
||||
std::swap (m_ECIESx25519Tags, oldTags); // re-create
|
||||
for (auto& it: oldTags)
|
||||
if (it.second.tagset)
|
||||
{
|
||||
if (it.second.tagset->IsExpired (ts) || it.second.tagset->IsIndexExpired (it.second.index))
|
||||
{
|
||||
it.second.tagset->DeleteSymmKey (it.second.index);
|
||||
numExpiredTags++;
|
||||
}
|
||||
else if (it.second.tagset->IsSessionTerminated())
|
||||
numExpiredTags++;
|
||||
else
|
||||
m_ECIESx25519Tags.emplace (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();)
|
||||
{
|
||||
it->second.tagset->DeleteSymmKey (it->second.index);
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
numExpiredTags++;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto session = it->second.tagset->GetSession ();
|
||||
if (!session || session->IsTerminated())
|
||||
if (!it->second.tagset)
|
||||
{
|
||||
// delete used tag
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
continue;
|
||||
}
|
||||
if (it->second.tagset->IsExpired (ts) || it->second.tagset->IsIndexExpired (it->second.index))
|
||||
{
|
||||
it->second.tagset->DeleteSymmKey (it->second.index);
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
numExpiredTags++;
|
||||
}
|
||||
else if (it->second.tagset->IsSessionTerminated())
|
||||
{
|
||||
it = m_ECIESx25519Tags.erase (it);
|
||||
numExpiredTags++;
|
||||
|
@ -896,7 +927,8 @@ namespace garlic
|
|||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_NumUsedECIESx25519Tags = 0;
|
||||
if (numExpiredTags > 0)
|
||||
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ());
|
||||
if (m_LastTagset && m_LastTagset->IsExpired (ts))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -221,7 +221,7 @@ namespace garlic
|
|||
struct ECIESX25519AEADRatchetIndexTagset
|
||||
{
|
||||
int index;
|
||||
ReceiveRatchetTagSetPtr tagset;
|
||||
ReceiveRatchetTagSetPtr tagset; // null if used
|
||||
};
|
||||
|
||||
class GarlicDestination: public i2p::data::LocalDestination
|
||||
|
@ -291,6 +291,7 @@ namespace garlic
|
|||
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
||||
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
|
||||
ReceiveRatchetTagSetPtr m_LastTagset; // tagset last message came for
|
||||
int m_NumUsedECIESx25519Tags;
|
||||
// DeliveryStatus
|
||||
std::mutex m_DeliveryStatusSessionsMutex;
|
||||
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
||||
|
@ -299,7 +300,7 @@ namespace garlic
|
|||
|
||||
// for HTTP only
|
||||
size_t GetNumIncomingTags () const { return m_Tags.size (); }
|
||||
size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size (); }
|
||||
size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size () - m_NumUsedECIESx25519Tags; }
|
||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||
const decltype(m_ECIESx25519Sessions)& GetECIESx25519Sessions () const { return m_ECIESx25519Sessions; }
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -40,7 +40,7 @@ namespace i2p
|
|||
{
|
||||
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MEDIUM_MESSAGE_SIZE> >();
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
|
||||
{
|
||||
return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint);
|
||||
|
@ -51,7 +51,7 @@ namespace i2p
|
|||
len += I2NP_HEADER_SIZE + 2;
|
||||
if (len <= I2NP_MAX_SHORT_MESSAGE_SIZE) return NewI2NPShortMessage ();
|
||||
if (len <= I2NP_MAX_MEDIUM_MESSAGE_SIZE) return NewI2NPMediumMessage ();
|
||||
return NewI2NPMessage ();
|
||||
return NewI2NPMessage ();
|
||||
}
|
||||
|
||||
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum)
|
||||
|
@ -72,11 +72,15 @@ namespace i2p
|
|||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
|
||||
bool I2NPMessage::IsExpired () const
|
||||
bool I2NPMessage::IsExpired (uint64_t ts) const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
auto exp = GetExpiration ();
|
||||
return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future
|
||||
}
|
||||
|
||||
bool I2NPMessage::IsExpired () const
|
||||
{
|
||||
return IsExpired (i2p::util::GetMillisecondsSinceEpoch ());
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
||||
|
@ -369,10 +373,20 @@ namespace i2p
|
|||
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||
{
|
||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
|
||||
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Failed to decrypt tunnel build record");
|
||||
return false;
|
||||
}
|
||||
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32) && // if next ident is now ours
|
||||
!(clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG)) // and not endpoint
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Next ident is ours in tunnel build record");
|
||||
return false;
|
||||
}
|
||||
uint8_t retCode = 0;
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ())
|
||||
if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < CONGESTION_LEVEL_FULL)
|
||||
{
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
|
@ -424,6 +438,11 @@ namespace i2p
|
|||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num);
|
||||
return;
|
||||
}
|
||||
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
|
||||
|
@ -477,6 +496,11 @@ namespace i2p
|
|||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num);
|
||||
return;
|
||||
}
|
||||
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
|
||||
if (len < num*recordSize + 1)
|
||||
{
|
||||
|
@ -508,6 +532,11 @@ namespace i2p
|
|||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
|
||||
if (num > i2p::tunnel::MAX_NUM_RECORDS)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num);
|
||||
return;
|
||||
}
|
||||
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
|
||||
|
@ -562,16 +591,24 @@ namespace i2p
|
|||
memcpy (ivKey, noiseState.m_CK + 32, 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // if next ident is now ours
|
||||
{
|
||||
LogPrint (eLogWarning, "I2NP: Next ident is ours in short request record");
|
||||
return;
|
||||
}
|
||||
memcpy (ivKey, noiseState.m_CK , 32);
|
||||
}
|
||||
|
||||
// check if we accept this tunnel
|
||||
std::shared_ptr<i2p::tunnel::TransitTunnel> transitTunnel;
|
||||
uint8_t retCode = 0;
|
||||
if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ())
|
||||
if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL)
|
||||
retCode = 30;
|
||||
if (!retCode)
|
||||
{
|
||||
// create new transit tunnel
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
|
@ -605,11 +642,22 @@ namespace i2p
|
|||
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
}
|
||||
// send reply
|
||||
auto onDrop = [transitTunnel]()
|
||||
{
|
||||
if (transitTunnel)
|
||||
{
|
||||
auto t = transitTunnel->GetCreationTime ();
|
||||
if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT)
|
||||
// make transit tunnel expired
|
||||
transitTunnel->SetCreationTime (t - i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
};
|
||||
if (isEndpoint)
|
||||
{
|
||||
auto replyMsg = NewI2NPShortMessage ();
|
||||
replyMsg->Concat (buf, len);
|
||||
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
||||
if (transitTunnel) replyMsg->onDrop = onDrop;
|
||||
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
|
||||
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
|
||||
{
|
||||
|
@ -627,15 +675,21 @@ namespace i2p
|
|||
uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
|
||||
auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID);
|
||||
if (tunnel)
|
||||
{
|
||||
tunnel->SendTunnelDataMsg (replyMsg);
|
||||
tunnel->FlushTunnelDataMsgs ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
|
||||
}
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
{
|
||||
auto msg = CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
|
||||
if (transitTunnel) msg->onDrop = onDrop;
|
||||
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
|
@ -695,7 +749,11 @@ namespace i2p
|
|||
return msg;
|
||||
}
|
||||
else
|
||||
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
|
||||
{
|
||||
auto newMsg = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
|
||||
if (msg->onDrop) newMsg->onDrop = msg->onDrop;
|
||||
return newMsg;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
|
||||
|
@ -733,46 +791,38 @@ namespace i2p
|
|||
return l;
|
||||
}
|
||||
|
||||
void HandleI2NPMessage (uint8_t * msg, size_t len)
|
||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (len < I2NP_HEADER_SIZE)
|
||||
if (msg)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
size = len;
|
||||
}
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
case eI2NPShortTunnelBuild:
|
||||
HandleShortTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, buf, size, false);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, buf, size, true);
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (buf, size);
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
|
||||
uint8_t typeID = msg->GetTypeID();
|
||||
uint32_t msgID = msg->GetMsgID();
|
||||
LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
|
||||
uint8_t * payload = msg->GetPayload();
|
||||
auto size = msg->GetPayloadLength();
|
||||
switch (typeID)
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg (msgID, payload, size);
|
||||
break;
|
||||
case eI2NPShortTunnelBuild:
|
||||
HandleShortTunnelBuildMsg (msgID, payload, size);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, payload, size, false);
|
||||
break;
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
HandleTunnelBuildReplyMsg (msgID, payload, size, true);
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (payload, size);
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
// TODO:
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -785,10 +835,12 @@ namespace i2p
|
|||
switch (typeID)
|
||||
{
|
||||
case eI2NPTunnelData:
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
if (!msg->from)
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPTunnelGateway:
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
if (!msg->from)
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPGarlic:
|
||||
{
|
||||
|
@ -799,10 +851,16 @@ namespace i2p
|
|||
break;
|
||||
}
|
||||
case eI2NPDatabaseStore:
|
||||
case eI2NPDatabaseSearchReply:
|
||||
case eI2NPDatabaseSearchReply:
|
||||
// forward to netDb if came directly or through exploratory tunnel as response to our request
|
||||
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
break;
|
||||
|
||||
case eI2NPDatabaseLookup:
|
||||
// forward to netDb
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
// forward to netDb if floodfill and came directly
|
||||
if (!msg->from && i2p::context.IsFloodfill ())
|
||||
i2p::data::netdb.PostI2NPMsg (msg);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
{
|
||||
|
@ -813,16 +871,20 @@ namespace i2p
|
|||
break;
|
||||
}
|
||||
case eI2NPVariableTunnelBuild:
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
case eI2NPTunnelBuild:
|
||||
case eI2NPTunnelBuildReply:
|
||||
case eI2NPShortTunnelBuild:
|
||||
// forward to tunnel thread
|
||||
if (!msg->from)
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
case eI2NPTunnelBuildReply:
|
||||
case eI2NPShortTunnelBuildReply:
|
||||
// forward to tunnel thread
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
default:
|
||||
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
|
||||
LogPrint(eLogError, "I2NP: Unexpected I2NP message with type ", int(typeID), " during handling; skipping");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -13,6 +13,7 @@
|
|||
#include <string.h>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include "Crypto.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Identity.h"
|
||||
|
@ -138,6 +139,10 @@ namespace tunnel
|
|||
class TunnelPool;
|
||||
}
|
||||
|
||||
const int CONGESTION_LEVEL_MEDIUM = 70;
|
||||
const int CONGESTION_LEVEL_HIGH = 90;
|
||||
const int CONGESTION_LEVEL_FULL = 100;
|
||||
|
||||
const size_t I2NP_MAX_MESSAGE_SIZE = 62708;
|
||||
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
||||
const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384;
|
||||
|
@ -149,7 +154,8 @@ namespace tunnel
|
|||
uint8_t * buf;
|
||||
size_t len, offset, maxLen;
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
|
||||
|
||||
std::function<void ()> onDrop;
|
||||
|
||||
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
|
||||
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
|
||||
|
||||
|
@ -241,7 +247,6 @@ namespace tunnel
|
|||
SetSize (len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks (0);
|
||||
}
|
||||
|
||||
void ToNTCP2 ()
|
||||
{
|
||||
uint8_t * ntcp2 = GetNTCP2Header ();
|
||||
|
@ -252,6 +257,9 @@ namespace tunnel
|
|||
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true);
|
||||
void RenewI2NPMessageHeader ();
|
||||
bool IsExpired () const;
|
||||
bool IsExpired (uint64_t ts) const; // in milliseconds
|
||||
|
||||
void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; }
|
||||
};
|
||||
|
||||
template<int sz>
|
||||
|
@ -295,7 +303,7 @@ namespace tunnel
|
|||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
|
||||
void HandleI2NPMessage (uint8_t * msg, size_t len);
|
||||
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
class I2NPMessagesHandler
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/endian.h>
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__)
|
||||
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__) || defined(__HAIKU__)
|
||||
#include <endian.h>
|
||||
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
|
|
|
@ -581,7 +581,7 @@ namespace data
|
|||
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
|
||||
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
|
||||
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
|
||||
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey + (sizeof(Identity::signingKey) - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH))); // TODO: remove public key check
|
||||
else
|
||||
{
|
||||
// public key is not required
|
||||
|
@ -803,29 +803,12 @@ namespace data
|
|||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
|
||||
{
|
||||
XORMetric m;
|
||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
|
||||
if(i2p::cpu::avx)
|
||||
{
|
||||
__asm__
|
||||
(
|
||||
"vmovups %1, %%ymm0 \n"
|
||||
"vmovups %2, %%ymm1 \n"
|
||||
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
|
||||
"vmovups %%ymm1, %0 \n"
|
||||
: "=m"(*m.metric)
|
||||
: "m"(*key1), "m"(*key2)
|
||||
: "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler
|
||||
);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
|
||||
m.metric_ll[0] = hash1[0] ^ hash2[0];
|
||||
m.metric_ll[1] = hash1[1] ^ hash2[1];
|
||||
m.metric_ll[2] = hash1[2] ^ hash2[2];
|
||||
m.metric_ll[3] = hash1[3] ^ hash2[3];
|
||||
}
|
||||
|
||||
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
|
||||
m.metric_ll[0] = hash1[0] ^ hash2[0];
|
||||
m.metric_ll[1] = hash1[1] ^ hash2[1];
|
||||
m.metric_ll[2] = hash1[2] ^ hash2[2];
|
||||
m.metric_ll[3] = hash1[3] ^ hash2[3];
|
||||
|
||||
return m;
|
||||
}
|
||||
|
|
|
@ -96,6 +96,9 @@ namespace data
|
|||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
bool IsDestination () const { return true; };
|
||||
|
||||
// used in webconsole
|
||||
void ExpireLease () { m_ExpirationTime = i2p::util::GetSecondsSinceEpoch (); };
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateLeasesBegin ();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -87,8 +87,8 @@ namespace log {
|
|||
Log ();
|
||||
~Log ();
|
||||
|
||||
LogType GetLogType () { return m_Destination; };
|
||||
LogLevel GetLogLevel () { return m_MinLevel; };
|
||||
LogType GetLogType () const { return m_Destination; };
|
||||
LogLevel GetLogLevel () const { return m_MinLevel; };
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
@ -160,6 +160,11 @@ namespace log {
|
|||
} // log
|
||||
} // i2p
|
||||
|
||||
inline bool CheckLogLevel (LogLevel level) noexcept
|
||||
{
|
||||
return level <= i2p::log::Logger().GetLogLevel ();
|
||||
}
|
||||
|
||||
/** internal usage only -- folding args array to single string */
|
||||
template<typename TValue>
|
||||
void LogPrint (std::stringstream& s, TValue&& arg) noexcept
|
||||
|
@ -185,9 +190,7 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
|||
template<typename... TArgs>
|
||||
void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
||||
{
|
||||
i2p::log::Log &log = i2p::log::Logger();
|
||||
if (level > log.GetLogLevel ())
|
||||
return;
|
||||
if (!CheckLogLevel (level)) return;
|
||||
|
||||
// fold message to single string
|
||||
std::stringstream ss;
|
||||
|
@ -200,7 +203,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
|||
|
||||
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str());
|
||||
msg->tid = std::this_thread::get_id();
|
||||
log.Append(msg);
|
||||
i2p::log::Logger().Append(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -19,9 +19,10 @@
|
|||
#include "RouterContext.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "NTCP2.h"
|
||||
#include "HTTP.h"
|
||||
#include "util.h"
|
||||
#include "Socks5.h"
|
||||
#include "NTCP2.h"
|
||||
|
||||
#if defined(__linux__) && !defined(_NETINET_IN_H)
|
||||
#include <linux/in6.h>
|
||||
|
@ -373,9 +374,20 @@ namespace transport
|
|||
m_Socket.close ();
|
||||
transports.PeerDisconnected (shared_from_this ());
|
||||
m_Server.RemoveNTCP2Session (shared_from_this ());
|
||||
for (auto& it: m_SendQueue)
|
||||
it->Drop ();
|
||||
m_SendQueue.clear ();
|
||||
m_SendQueueSize = 0;
|
||||
LogPrint (eLogDebug, "NTCP2: Session terminated");
|
||||
SetSendQueueSize (0);
|
||||
auto remoteIdentity = GetRemoteIdentity ();
|
||||
if (remoteIdentity)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (), " terminated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,7 +436,7 @@ namespace transport
|
|||
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
|
||||
{
|
||||
if (m_NextReceivedBuffer && !m_IsReceiving &&
|
||||
ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
|
||||
ts > GetLastActivityTimestamp () + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
|
||||
{
|
||||
delete[] m_NextReceivedBuffer;
|
||||
m_NextReceivedBuffer = nullptr;
|
||||
|
@ -566,7 +578,11 @@ namespace transport
|
|||
SendSessionConfirmed ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetRemoteIdentity ())
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,16 +703,25 @@ namespace transport
|
|||
i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
|
||||
if (ri.IsUnreachable ())
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed");
|
||||
LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ());
|
||||
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
|
||||
return;
|
||||
}
|
||||
if (i2p::util::GetMillisecondsSinceEpoch () > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
||||
LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed");
|
||||
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
|
||||
SendTerminationAndTerminate (eNTCP2Message3Error);
|
||||
return;
|
||||
}
|
||||
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds");
|
||||
SendTerminationAndTerminate (eNTCP2Message3Error);
|
||||
return;
|
||||
}
|
||||
auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri.GetNTCP2V4Address () :
|
||||
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri.GetYggdrasilAddress () : ri.GetNTCP2V6Address ());
|
||||
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
|
||||
|
@ -767,7 +792,7 @@ namespace transport
|
|||
void NTCP2Session::ServerLogin ()
|
||||
{
|
||||
SetTerminationTimeout (NTCP2_ESTABLISH_TIMEOUT);
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
SetLastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ());
|
||||
m_Establisher->CreateEphemeralKey ();
|
||||
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 (),
|
||||
|
@ -811,14 +836,19 @@ namespace transport
|
|||
CreateNextReceivedBuffer (m_NextReceivedLen);
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = m_Socket.available(ec);
|
||||
if (!ec && moreBytes >= m_NextReceivedLen)
|
||||
{
|
||||
// read and process message immediately if available
|
||||
moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
|
||||
HandleReceived (ec, moreBytes);
|
||||
}
|
||||
if (!ec)
|
||||
{
|
||||
if (moreBytes >= m_NextReceivedLen)
|
||||
{
|
||||
// read and process message immediately if available
|
||||
moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
|
||||
HandleReceived (ec, moreBytes);
|
||||
}
|
||||
else
|
||||
Receive ();
|
||||
}
|
||||
else
|
||||
Receive ();
|
||||
LogPrint (eLogWarning, "NTCP2: Socket error: ", ec.message ());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -844,15 +874,14 @@ namespace transport
|
|||
{
|
||||
if (ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ());
|
||||
Terminate ();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumReceivedBytes += bytes_transferred + 2; // + length
|
||||
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
|
||||
UpdateNumReceivedBytes (bytes_transferred + 2);
|
||||
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2);
|
||||
uint8_t nonce[12];
|
||||
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))
|
||||
|
@ -880,7 +909,7 @@ namespace transport
|
|||
auto size = bufbe16toh (frame + offset);
|
||||
offset += 2;
|
||||
LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
|
||||
if (size > len)
|
||||
if (offset + size > len)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
|
||||
break;
|
||||
|
@ -1025,6 +1054,11 @@ namespace transport
|
|||
macBuf = m_NextSendBuffer + paddingLen;
|
||||
totalLen += paddingLen;
|
||||
}
|
||||
if (totalLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Frame to send is too long ", totalLen);
|
||||
return;
|
||||
}
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
||||
i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers
|
||||
|
@ -1049,6 +1083,12 @@ namespace transport
|
|||
delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
|
||||
return;
|
||||
}
|
||||
if (payloadLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: Buffer to send is too long ", payloadLen);
|
||||
delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
|
||||
return;
|
||||
}
|
||||
// encrypt
|
||||
uint8_t nonce[12];
|
||||
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
|
||||
|
@ -1073,11 +1113,10 @@ namespace transport
|
|||
}
|
||||
else
|
||||
{
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumSentBytes += bytes_transferred;
|
||||
UpdateNumSentBytes (bytes_transferred);
|
||||
i2p::transport::transports.UpdateSentBytes (bytes_transferred);
|
||||
LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred);
|
||||
if (m_LastActivityTimestamp > m_NextRouterInfoResendTime)
|
||||
if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime)
|
||||
{
|
||||
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
|
||||
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
|
||||
|
@ -1086,7 +1125,7 @@ namespace transport
|
|||
else
|
||||
{
|
||||
SendQueue ();
|
||||
m_SendQueueSize = m_SendQueue.size ();
|
||||
SetSendQueueSize (m_SendQueue.size ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1096,20 +1135,31 @@ namespace transport
|
|||
if (!m_SendQueue.empty ())
|
||||
{
|
||||
std::vector<std::shared_ptr<I2NPMessage> > msgs;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
size_t s = 0;
|
||||
while (!m_SendQueue.empty ())
|
||||
{
|
||||
auto msg = m_SendQueue.front ();
|
||||
if (!msg || msg->IsExpired (ts))
|
||||
{
|
||||
// drop null or expired message
|
||||
if (msg) msg->Drop ();
|
||||
m_SendQueue.pop_front ();
|
||||
continue;
|
||||
}
|
||||
size_t len = msg->GetNTCP2Length ();
|
||||
if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header
|
||||
{
|
||||
msgs.push_back (msg);
|
||||
s += (len + 3);
|
||||
m_SendQueue.pop_front ();
|
||||
if (s >= NTCP2_SEND_AFTER_FRAME_SIZE)
|
||||
break; // send frame right a way
|
||||
}
|
||||
else if (len + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "NTCP2: I2NP message of size ", len, " can't be sent. Dropped");
|
||||
msg->Drop ();
|
||||
m_SendQueue.pop_front ();
|
||||
}
|
||||
else
|
||||
|
@ -1125,7 +1175,12 @@ namespace transport
|
|||
len -= 3;
|
||||
if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero
|
||||
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 (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
|
||||
{
|
||||
int l = (int)NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
|
||||
if (l <= 0) return 0;
|
||||
paddingSize = l;
|
||||
}
|
||||
if (paddingSize > len) paddingSize = len;
|
||||
if (paddingSize)
|
||||
{
|
||||
|
@ -1134,7 +1189,7 @@ namespace transport
|
|||
RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
|
||||
m_NextPaddingSize = 0;
|
||||
}
|
||||
paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize;
|
||||
paddingSize = m_PaddingSizes[m_NextPaddingSize++] % (paddingSize + 1);
|
||||
}
|
||||
buf[0] = eNTCP2BlkPadding; // blk
|
||||
htobe16buf (buf + 1, paddingSize); // size
|
||||
|
@ -1199,8 +1254,13 @@ namespace transport
|
|||
void NTCP2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
||||
{
|
||||
if (m_IsTerminated) return;
|
||||
bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2;
|
||||
for (auto it: msgs)
|
||||
m_SendQueue.push_back (std::move (it));
|
||||
if (isSemiFull && it->onDrop)
|
||||
it->Drop (); // drop earlier because we can handle it
|
||||
else
|
||||
m_SendQueue.push_back (std::move (it));
|
||||
|
||||
if (!m_IsSending)
|
||||
SendQueue ();
|
||||
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
|
||||
|
@ -1209,12 +1269,12 @@ namespace transport
|
|||
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
|
||||
Terminate ();
|
||||
}
|
||||
m_SendQueueSize = m_SendQueue.size ();
|
||||
SetSendQueueSize (m_SendQueue.size ());
|
||||
}
|
||||
|
||||
void NTCP2Session::SendLocalRouterInfo (bool update)
|
||||
{
|
||||
if (update || !IsOutgoing ()) // we send it in SessionConfirmed for ougoing session
|
||||
if (update || !IsOutgoing ()) // we send it in SessionConfirmed for outgoing session
|
||||
m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
|
||||
}
|
||||
|
||||
|
@ -1380,7 +1440,11 @@ namespace transport
|
|||
void NTCP2Server::RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session)
|
||||
{
|
||||
if (session && session->GetRemoteIdentity ())
|
||||
m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ());
|
||||
{
|
||||
auto it = m_NTCP2Sessions.find (session->GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (it != m_NTCP2Sessions.end () && it->second == session)
|
||||
m_NTCP2Sessions.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<NTCP2Session> NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident)
|
||||
|
@ -1398,7 +1462,8 @@ namespace transport
|
|||
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
|
||||
return;
|
||||
}
|
||||
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
|
||||
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
|
||||
GetService ().post([this, conn]()
|
||||
{
|
||||
if (this->AddNTCP2Session (conn))
|
||||
|
@ -1454,7 +1519,8 @@ namespace transport
|
|||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ());
|
||||
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
|
||||
conn->ClientLogin ();
|
||||
}
|
||||
}
|
||||
|
@ -1468,7 +1534,7 @@ namespace transport
|
|||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||
if (!i2p::util::net::IsInReservedRange(ep.address ()))
|
||||
if (!i2p::transport::transports.IsInReservedRange(ep.address ()))
|
||||
{
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
{
|
||||
|
@ -1515,7 +1581,7 @@ namespace transport
|
|||
if (!ec)
|
||||
{
|
||||
LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
|
||||
if (!i2p::util::net::IsInReservedRange(ep.address ()) ||
|
||||
if (!i2p::transport::transports.IsInReservedRange(ep.address ()) ||
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()))
|
||||
{
|
||||
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
|
||||
|
@ -1663,47 +1729,18 @@ namespace transport
|
|||
case eSocksProxy:
|
||||
{
|
||||
// TODO: support username/password auth etc
|
||||
static const uint8_t buff[3] = {SOCKS5_VER, 0x01, 0x00};
|
||||
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
|
||||
[] (const boost::system::error_code & ec, std::size_t transferred)
|
||||
{
|
||||
(void) transferred;
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogWarning, "NTCP2: SOCKS5 write error ", ec.message());
|
||||
}
|
||||
});
|
||||
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
|
||||
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
|
||||
[this, readbuff, timer, conn](const boost::system::error_code & ec, std::size_t transferred)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: SOCKS5 read error ", ec.message());
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
return;
|
||||
}
|
||||
else if(transferred == 2)
|
||||
{
|
||||
if((*readbuff)[1] == 0x00)
|
||||
{
|
||||
AfterSocksHandshake(conn, timer);
|
||||
return;
|
||||
}
|
||||
else if ((*readbuff)[1] == 0xff)
|
||||
{
|
||||
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");
|
||||
Socks5Handshake (conn->GetSocket(), conn->GetRemoteEndpoint (),
|
||||
[conn, timer](const boost::system::error_code& ec)
|
||||
{
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
});
|
||||
if (!ec)
|
||||
conn->ClientLogin();
|
||||
else
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: SOCKS proxy handshake error ", ec.message());
|
||||
conn->Terminate();
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case eHTTPProxy:
|
||||
|
@ -1771,71 +1808,6 @@ namespace transport
|
|||
}
|
||||
}
|
||||
|
||||
void NTCP2Server::AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
|
||||
{
|
||||
// build request
|
||||
size_t sz = 6; // header + port
|
||||
auto buff = std::make_shared<std::vector<int8_t> >(256);
|
||||
auto readbuff = std::make_shared<std::vector<int8_t> >(256);
|
||||
(*buff)[0] = SOCKS5_VER;
|
||||
(*buff)[1] = SOCKS5_CMD_CONNECT;
|
||||
(*buff)[2] = 0x00;
|
||||
|
||||
auto& ep = conn->GetRemoteEndpoint ();
|
||||
if(ep.address ().is_v4 ())
|
||||
{
|
||||
(*buff)[3] = SOCKS5_ATYP_IPV4;
|
||||
auto addrbytes = ep.address ().to_v4().to_bytes();
|
||||
sz += 4;
|
||||
memcpy(buff->data () + 4, addrbytes.data(), 4);
|
||||
}
|
||||
else if (ep.address ().is_v6 ())
|
||||
{
|
||||
(*buff)[3] = SOCKS5_ATYP_IPV6;
|
||||
auto addrbytes = ep.address ().to_v6().to_bytes();
|
||||
sz += 16;
|
||||
memcpy(buff->data () + 4, addrbytes.data(), 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We mustn't really fall here because all connections are made to IP addresses
|
||||
LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy");
|
||||
return;
|
||||
}
|
||||
htobe16buf(buff->data () + sz - 2, ep.port ());
|
||||
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(),
|
||||
[buff](const boost::system::error_code & ec, std::size_t written)
|
||||
{
|
||||
if(ec)
|
||||
{
|
||||
LogPrint(eLogError, "NTCP2: Failed to write handshake to socks proxy ", ec.message());
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), // read min reply size
|
||||
boost::asio::transfer_all(),
|
||||
[timer, conn, readbuff](const boost::system::error_code & e, std::size_t transferred)
|
||||
{
|
||||
if (e)
|
||||
LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
|
||||
else if (!(*readbuff)[1]) // succeeded
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = conn->GetSocket ().available(ec);
|
||||
if (moreBytes) // read remaining portion of reply if ipv6 received
|
||||
boost::asio::read (conn->GetSocket (), boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec);
|
||||
timer->cancel();
|
||||
conn->ClientLogin();
|
||||
return;
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "NTCP2: Proxy reply error ", (int)(*readbuff)[1]);
|
||||
timer->cancel();
|
||||
conn->Terminate();
|
||||
});
|
||||
}
|
||||
|
||||
void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
|
||||
{
|
||||
auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -28,6 +28,7 @@ namespace transport
|
|||
{
|
||||
|
||||
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
|
||||
const size_t NTCP2_SEND_AFTER_FRAME_SIZE = 16386; // send frame when exceeds this size
|
||||
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 %
|
||||
|
@ -266,8 +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);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -59,7 +59,7 @@ namespace data
|
|||
{
|
||||
Reseed ();
|
||||
}
|
||||
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
|
||||
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false, false))
|
||||
Reseed (); // we don't have a router we can connect to. Trying to reseed
|
||||
|
||||
auto it = m_RouterInfos.find (i2p::context.GetIdentHash ());
|
||||
|
@ -106,7 +106,7 @@ namespace data
|
|||
{
|
||||
i2p::util::SetThreadName("NetDB");
|
||||
|
||||
uint64_t lastSave = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
|
||||
uint64_t lastManage = 0, lastExploratory = 0, lastManageRequest = 0;
|
||||
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
|
||||
int16_t profilesCleanupVariance = 0;
|
||||
|
||||
|
@ -149,32 +149,26 @@ namespace data
|
|||
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
|
||||
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (ts - lastManageRequest >= 15 || ts + 15 < lastManageRequest) // manage requests every 15 seconds
|
||||
if (ts - lastManageRequest >= MANAGE_REQUESTS_INTERVAL || ts + MANAGE_REQUESTS_INTERVAL < lastManageRequest) // manage requests every 15 seconds
|
||||
{
|
||||
m_Requests.ManageRequests ();
|
||||
lastManageRequest = ts;
|
||||
}
|
||||
|
||||
if (ts - lastSave >= 60 || ts + 60 < lastSave) // save routers, manage leasesets and validate subscriptions every minute
|
||||
if (ts - lastManage >= 60 || ts + 60 < lastManage) // manage routers and leasesets every minute
|
||||
{
|
||||
if (lastSave)
|
||||
if (lastManage)
|
||||
{
|
||||
SaveUpdated ();
|
||||
ManageRouterInfos ();
|
||||
ManageLeaseSets ();
|
||||
}
|
||||
lastSave = ts;
|
||||
}
|
||||
|
||||
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT ||
|
||||
ts + i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT < lastDestinationCleanup)
|
||||
{
|
||||
i2p::context.CleanupDestination ();
|
||||
lastDestinationCleanup = ts;
|
||||
lastManage = ts;
|
||||
}
|
||||
|
||||
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance) ||
|
||||
ts + i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT < lastProfilesCleanup)
|
||||
{
|
||||
m_RouterProfilesPool.CleanUpMt ();
|
||||
if (m_PersistProfiles) PersistProfiles ();
|
||||
DeleteObsoleteProfiles ();
|
||||
lastProfilesCleanup = ts;
|
||||
|
@ -225,7 +219,8 @@ namespace data
|
|||
bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
|
||||
{
|
||||
bool updated;
|
||||
AddRouterInfo (ident, buf, len, updated);
|
||||
if (!AddRouterInfo (ident, buf, len, updated))
|
||||
updated = false;
|
||||
return updated;
|
||||
}
|
||||
|
||||
|
@ -239,40 +234,49 @@ namespace data
|
|||
{
|
||||
bool wasFloodfill = r->IsFloodfill ();
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
if (!r->Update (buf, len))
|
||||
{
|
||||
updated = false;
|
||||
m_Requests.RequestComplete (ident, r);
|
||||
return r;
|
||||
}
|
||||
if (r->IsUnreachable ())
|
||||
}
|
||||
if (r->IsUnreachable () ||
|
||||
i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < r->GetTimestamp ())
|
||||
{
|
||||
// delete router as invalid after update
|
||||
// delete router as invalid or from future after update
|
||||
m_RouterInfos.erase (ident);
|
||||
if (wasFloodfill)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Remove (r->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
||||
if (CheckLogLevel (eLogInfo))
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
|
||||
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
|
||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||
if (wasFloodfill)
|
||||
m_Floodfills.Remove (r->GetIdentHash ());
|
||||
else if (r->IsEligibleFloodfill ())
|
||||
m_Floodfills.Insert (r);
|
||||
{
|
||||
if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD || r->GetProfile ()->IsReal ())
|
||||
m_Floodfills.Insert (r);
|
||||
else
|
||||
r->ResetFlooldFill ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64());
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDb: RouterInfo is older: ", ident.ToBase64());
|
||||
updated = false;
|
||||
}
|
||||
}
|
||||
|
@ -284,16 +288,23 @@ namespace data
|
|||
{
|
||||
bool inserted = false;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
inserted = m_RouterInfos.insert ({r->GetIdentHash (), r}).second;
|
||||
}
|
||||
if (inserted)
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||
if (CheckLogLevel (eLogInfo))
|
||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Insert (r);
|
||||
if (m_Floodfills.GetSize () < NETDB_NUM_FLOODFILLS_THRESHOLD ||
|
||||
r->GetProfile ()->IsReal ()) // don't insert floodfill until it's known real if we have enough
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Insert (r);
|
||||
}
|
||||
else
|
||||
r->ResetFlooldFill ();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -312,7 +323,7 @@ namespace data
|
|||
|
||||
bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
|
||||
std::lock_guard<std::mutex> lock(m_LeaseSetsMutex);
|
||||
bool updated = false;
|
||||
auto it = m_LeaseSets.find(ident);
|
||||
if (it != m_LeaseSets.end () && it->second->GetStoreType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||
|
@ -324,10 +335,11 @@ namespace data
|
|||
if(it->second->GetExpirationTime() < expires)
|
||||
{
|
||||
it->second->Update (buf, len, false); // signature is verified already
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
|
||||
if (CheckLogLevel (eLogInfo))
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet updated: ", ident.ToBase32());
|
||||
updated = true;
|
||||
}
|
||||
else
|
||||
else if (CheckLogLevel (eLogDebug))
|
||||
LogPrint(eLogDebug, "NetDb: LeaseSet is older: ", ident.ToBase32());
|
||||
}
|
||||
else
|
||||
|
@ -338,7 +350,8 @@ namespace data
|
|||
auto leaseSet = std::make_shared<LeaseSet> (buf, len, false); // we don't need leases in netdb
|
||||
if (leaseSet->IsValid ())
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32());
|
||||
if (CheckLogLevel (eLogInfo))
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet added: ", ident.ToBase32());
|
||||
m_LeaseSets[ident] = leaseSet;
|
||||
updated = true;
|
||||
}
|
||||
|
@ -353,7 +366,7 @@ namespace data
|
|||
auto leaseSet = std::make_shared<LeaseSet2> (storeType, buf, len, false); // we don't need leases in netdb
|
||||
if (leaseSet->IsValid ())
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
|
||||
std::lock_guard<std::mutex> lock(m_LeaseSetsMutex);
|
||||
auto it = m_LeaseSets.find(ident);
|
||||
if (it == m_LeaseSets.end () || it->second->GetStoreType () != storeType ||
|
||||
leaseSet->GetPublishedTimestamp () > it->second->GetPublishedTimestamp ())
|
||||
|
@ -362,7 +375,8 @@ namespace data
|
|||
i2p::util::GetSecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD > leaseSet->GetPublishedTimestamp ())
|
||||
{
|
||||
// TODO: implement actual update
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
|
||||
if (CheckLogLevel (eLogInfo))
|
||||
LogPrint (eLogInfo, "NetDb: LeaseSet2 updated: ", ident.ToBase32());
|
||||
m_LeaseSets[ident] = leaseSet;
|
||||
return true;
|
||||
}
|
||||
|
@ -380,7 +394,7 @@ namespace data
|
|||
|
||||
std::shared_ptr<RouterInfo> NetDb::FindRouter (const IdentHash& ident) const
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
auto it = m_RouterInfos.find (ident);
|
||||
if (it != m_RouterInfos.end ())
|
||||
return it->second;
|
||||
|
@ -390,7 +404,7 @@ namespace data
|
|||
|
||||
std::shared_ptr<LeaseSet> NetDb::FindLeaseSet (const IdentHash& destination) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
|
||||
std::lock_guard<std::mutex> lock(m_LeaseSetsMutex);
|
||||
auto it = m_LeaseSets.find (destination);
|
||||
if (it != m_LeaseSets.end ())
|
||||
return it->second;
|
||||
|
@ -409,16 +423,23 @@ namespace data
|
|||
|
||||
void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable)
|
||||
{
|
||||
auto it = m_RouterInfos.find (ident);
|
||||
if (it != m_RouterInfos.end ())
|
||||
auto r = FindRouter (ident);
|
||||
if (r)
|
||||
{
|
||||
it->second->SetUnreachable (unreachable);
|
||||
if (unreachable)
|
||||
{
|
||||
auto profile = it->second->GetProfile ();
|
||||
if (profile)
|
||||
profile->Unreachable ();
|
||||
}
|
||||
r->SetUnreachable (unreachable);
|
||||
auto profile = r->GetProfile ();
|
||||
if (profile)
|
||||
profile->Unreachable (unreachable);
|
||||
}
|
||||
}
|
||||
|
||||
void NetDb::ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports)
|
||||
{
|
||||
auto r = FindRouter (ident);
|
||||
if (r)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
r->ExcludeReachableTransports (transports);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -507,7 +528,7 @@ namespace data
|
|||
|
||||
void NetDb::VisitLeaseSets(LeaseSetVisitor v)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_LeaseSetsMutex);
|
||||
std::lock_guard<std::mutex> lock(m_LeaseSetsMutex);
|
||||
for ( auto & entry : m_LeaseSets)
|
||||
v(entry.first, entry.second);
|
||||
}
|
||||
|
@ -523,7 +544,7 @@ namespace data
|
|||
|
||||
void NetDb::VisitRouterInfos(RouterInfoVisitor v)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_RouterInfosMutex);
|
||||
std::lock_guard<std::mutex> lock(m_RouterInfosMutex);
|
||||
for ( const auto & item : m_RouterInfos )
|
||||
v(item.second);
|
||||
}
|
||||
|
@ -535,7 +556,7 @@ namespace data
|
|||
size_t iters = max_iters_per_cyle;
|
||||
while(n > 0)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_RouterInfosMutex);
|
||||
std::lock_guard<std::mutex> lock(m_RouterInfosMutex);
|
||||
uint32_t idx = rand () % m_RouterInfos.size ();
|
||||
uint32_t i = 0;
|
||||
for (const auto & it : m_RouterInfos) {
|
||||
|
@ -597,7 +618,9 @@ namespace data
|
|||
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
auto uptime = i2p::context.GetUptime ();
|
||||
bool isLowRate = i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () < NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE;
|
||||
double minTunnelCreationSuccessRate;
|
||||
i2p::config::GetOption("limits.zombies", minTunnelCreationSuccessRate);
|
||||
bool isLowRate = i2p::tunnel::tunnels.GetPreciseTunnelCreationSuccessRate () < minTunnelCreationSuccessRate;
|
||||
// routers don't expire if less than 90 or uptime is less than 1 hour
|
||||
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
|
||||
if (checkForExpiration && uptime > 3600) // 1 hour
|
||||
|
@ -607,17 +630,18 @@ namespace data
|
|||
auto own = i2p::context.GetSharedRouterInfo ();
|
||||
for (auto& it: m_RouterInfos)
|
||||
{
|
||||
if (it.second == own) continue; // skip own
|
||||
if (!it.second || it.second == own) continue; // skip own
|
||||
std::string ident = it.second->GetIdentHashBase64();
|
||||
if (it.second->IsUpdated ())
|
||||
{
|
||||
if (it.second->GetBuffer ())
|
||||
{
|
||||
{
|
||||
// we have something to save
|
||||
it.second->SaveToFile (m_Storage.Path(ident));
|
||||
it.second->SetUnreachable (false);
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex); // possible collision between DeleteBuffer and Update
|
||||
it.second->DeleteBuffer ();
|
||||
}
|
||||
}
|
||||
it.second->SetUpdated (false);
|
||||
updatedCount++;
|
||||
continue;
|
||||
|
@ -629,25 +653,28 @@ namespace data
|
|||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
|
||||
it.second->SetUnreachable (false);
|
||||
if (!it.second->IsUnreachable ())
|
||||
{
|
||||
{
|
||||
// find & mark expired routers
|
||||
if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & RouterInfo::eSSU2V4))
|
||||
// non-reachable router, but reachable by ipv4 SSU2 means introducers
|
||||
{
|
||||
if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
|
||||
// RouterInfo expires after 1 hour if uses introducer
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
else if (checkForExpiration && ts > it.second->GetTimestamp () + expirationTimeout)
|
||||
if (!it.second->GetCompatibleTransports (true)) // non reachable by any transport
|
||||
it.second->SetUnreachable (true);
|
||||
else if (ts + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < it.second->GetTimestamp ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds");
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
else if (checkForExpiration)
|
||||
{
|
||||
if (ts > it.second->GetTimestamp () + expirationTimeout)
|
||||
it.second->SetUnreachable (true);
|
||||
else if ((ts > it.second->GetTimestamp () + expirationTimeout/2) && // more than half of expiration
|
||||
total > NETDB_NUM_ROUTERS_THRESHOLD && !it.second->IsHighBandwidth() && // low bandwidth
|
||||
!it.second->IsFloodfill() && (!i2p::context.IsFloodfill () || // non floodfill
|
||||
(CreateRoutingKey (it.second->GetIdentHash ()) ^ i2p::context.GetIdentHash ()).metric[0] >= 0x02)) // different first 7 bits
|
||||
it.second->SetUnreachable (true);
|
||||
}
|
||||
if (it.second->IsUnreachable () && i2p::transport::transports.IsConnected (it.second->GetIdentHash ()))
|
||||
it.second->SetUnreachable (false); // don't expire connected router
|
||||
}
|
||||
}
|
||||
|
||||
if (it.second->IsUnreachable ())
|
||||
{
|
||||
|
@ -662,7 +689,7 @@ namespace data
|
|||
m_RouterInfoBuffersPool.CleanUpMt ();
|
||||
m_RouterInfoAddressesPool.CleanUpMt ();
|
||||
m_RouterInfoAddressVectorsPool.CleanUpMt ();
|
||||
m_IdentitiesPool.CleanUpMt ();
|
||||
m_IdentitiesPool.CleanUpMt ();
|
||||
|
||||
if (updatedCount > 0)
|
||||
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
|
||||
|
@ -671,21 +698,21 @@ namespace data
|
|||
LogPrint (eLogInfo, "NetDb: Deleting ", deletedCount, " unreachable routers");
|
||||
// clean up RouterInfos table
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
|
||||
{
|
||||
if (it->second->IsUnreachable ())
|
||||
if (!it->second || it->second->IsUnreachable ())
|
||||
it = m_RouterInfos.erase (it);
|
||||
else
|
||||
{
|
||||
{
|
||||
it->second->DropProfile ();
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clean up expired floodfills or not floodfills anymore
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||
m_Floodfills.Cleanup ([](const std::shared_ptr<RouterInfo>& r)->bool
|
||||
{
|
||||
return r && r->IsFloodfill () && !r->IsUnreachable ();
|
||||
|
@ -696,7 +723,8 @@ namespace data
|
|||
|
||||
void NetDb::RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete, bool direct)
|
||||
{
|
||||
auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
|
||||
if (direct && i2p::transport::transports.RoutesRestricted ()) direct = false; // always use tunnels for restricted routes
|
||||
auto dest = m_Requests.CreateRequest (destination, false, direct, requestComplete); // non-exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
|
||||
|
@ -710,14 +738,23 @@ namespace data
|
|||
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
|
||||
direct = false; // floodfill can't be reached directly
|
||||
if (direct)
|
||||
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
|
||||
{
|
||||
auto msg = dest->CreateRequestMessage (floodfill->GetIdentHash ());
|
||||
msg->onDrop = [this, dest]() { this->m_Requests.SendNextRequest (dest); };
|
||||
transports.SendMessage (floodfill->GetIdentHash (), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
||||
auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
||||
if (outbound && inbound)
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound));
|
||||
{
|
||||
auto msg = dest->CreateRequestMessage (floodfill, inbound);
|
||||
msg->onDrop = [this, dest]() { this->m_Requests.SendNextRequest (dest); };
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
|
||||
|
@ -732,10 +769,10 @@ namespace data
|
|||
}
|
||||
}
|
||||
|
||||
void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete)
|
||||
void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploratory, RequestedDestination::RequestComplete requestComplete)
|
||||
{
|
||||
|
||||
auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory
|
||||
auto dest = m_Requests.CreateRequest (destination, exploratory, true, requestComplete); // non-exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
|
||||
|
@ -782,19 +819,22 @@ namespace data
|
|||
LogPrint (eLogError, "NetDb: Database store msg with reply token is too short ", len, ". Dropped");
|
||||
return;
|
||||
}
|
||||
auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
|
||||
uint32_t tunnelID = bufbe32toh (buf + offset);
|
||||
offset += 4;
|
||||
if (!tunnelID) // send response directly
|
||||
transports.SendMessage (buf + offset, deliveryStatus);
|
||||
else
|
||||
if (replyToken != 0xFFFFFFFFU) // if not caught on OBEP or IBGW
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsgTo (buf + offset, tunnelID, deliveryStatus);
|
||||
auto deliveryStatus = CreateDeliveryStatusMsg (replyToken);
|
||||
if (!tunnelID) // send response directly
|
||||
transports.SendMessage (buf + offset, deliveryStatus);
|
||||
else
|
||||
LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
|
||||
if (outbound)
|
||||
outbound->SendTunnelDataMsgTo (buf + offset, tunnelID, deliveryStatus);
|
||||
else
|
||||
LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
|
||||
}
|
||||
}
|
||||
offset += 32;
|
||||
}
|
||||
|
@ -815,23 +855,31 @@ namespace data
|
|||
LogPrint (eLogError, "NetDb: Database store message is too long ", len);
|
||||
return;
|
||||
}
|
||||
if (!m->from) // unsolicited LS must be received directly
|
||||
if (!context.IsFloodfill ())
|
||||
{
|
||||
LogPrint (eLogInfo, "NetDb: Not Floodfill, LeaseSet store request ignored for ", ident.ToBase32());
|
||||
return;
|
||||
}
|
||||
else if (!m->from) // unsolicited LS must be received directly
|
||||
{
|
||||
if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet for ", ident.ToBase32());
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
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 ", int(storeType), " for ", ident.ToBase32());
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", int(storeType), " for ", ident.ToBase32());
|
||||
updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // RouterInfo
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: Store request: RouterInfo");
|
||||
if (CheckLogLevel (eLogDebug))
|
||||
LogPrint (eLogDebug, "NetDb: Store request: RouterInfo ", ident.ToBase64());
|
||||
size_t size = bufbe16toh (buf + offset);
|
||||
offset += 2;
|
||||
if (size > MAX_RI_BUFFER_SIZE || size > len - offset)
|
||||
|
@ -882,39 +930,9 @@ namespace data
|
|||
auto dest = m_Requests.FindRequest (ident);
|
||||
if (dest)
|
||||
{
|
||||
bool deleteDest = true;
|
||||
if (num > 0)
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
|
||||
auto inbound = pool ? pool->GetNextInboundTunnel () : nullptr;
|
||||
if (!dest->IsExploratory ())
|
||||
{
|
||||
// reply to our destination. Try other floodfills
|
||||
if (outbound && inbound)
|
||||
{
|
||||
auto count = dest->GetExcludedPeers ().size ();
|
||||
if (count < 7)
|
||||
{
|
||||
auto nextFloodfill = GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill)
|
||||
{
|
||||
// request destination
|
||||
LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||
deleteDest = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "NetDb: ", key, " was not found on ", count, " floodfills");
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteDest)
|
||||
// no more requests for the destinationation. delete it
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
}
|
||||
// try to send next requests
|
||||
m_Requests.SendNextRequest (dest);
|
||||
else
|
||||
// no more requests for destination possible. delete it
|
||||
m_Requests.RequestComplete (ident, nullptr);
|
||||
|
@ -983,6 +1001,11 @@ namespace data
|
|||
std::shared_ptr<I2NPMessage> replyMsg;
|
||||
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
|
||||
{
|
||||
if (!context.IsFloodfill ())
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Exploratory lookup to non-floodfill dropped");
|
||||
return;
|
||||
}
|
||||
LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
|
||||
std::set<IdentHash> excludedRouters;
|
||||
const uint8_t * excluded_ident = excluded;
|
||||
|
@ -1008,6 +1031,7 @@ namespace data
|
|||
if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
|
||||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
|
||||
{
|
||||
// try to find router
|
||||
auto router = FindRouter (ident);
|
||||
if (router && !router->IsUnreachable ())
|
||||
{
|
||||
|
@ -1020,17 +1044,26 @@ namespace data
|
|||
if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP ||
|
||||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
|
||||
{
|
||||
auto leaseSet = FindLeaseSet (ident);
|
||||
if (!leaseSet)
|
||||
// try to find leaseset
|
||||
if (context.IsFloodfill ())
|
||||
{
|
||||
auto leaseSet = FindLeaseSet (ident);
|
||||
if (!leaseSet)
|
||||
{
|
||||
// no leaseset found
|
||||
LogPrint(eLogDebug, "NetDb: Requested LeaseSet not found for ", ident.ToBase32());
|
||||
}
|
||||
else if (!leaseSet->IsExpired ()) // we don't send back expired leasesets
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDb: Requested LeaseSet ", key, " found");
|
||||
replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
|
||||
}
|
||||
}
|
||||
else if (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP)
|
||||
{
|
||||
// no lease set found
|
||||
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");
|
||||
replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
|
||||
}
|
||||
LogPrint (eLogWarning, "NetDb: Explicit LeaseSet lookup to non-floodfill dropped");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replyMsg)
|
||||
|
@ -1104,7 +1137,7 @@ namespace data
|
|||
for (int i = 0; i < numDestinations; i++)
|
||||
{
|
||||
RAND_bytes (randomHash, 32);
|
||||
auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
|
||||
auto dest = m_Requests.CreateRequest (randomHash, true, !throughTunnels); // exploratory
|
||||
if (!dest)
|
||||
{
|
||||
LogPrint (eLogWarning, "NetDb: Exploratory destination is requested already");
|
||||
|
@ -1169,15 +1202,17 @@ namespace data
|
|||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
|
||||
bool reverse, bool endpoint) const
|
||||
{
|
||||
return GetRandomRouter (
|
||||
[compatibleWith, reverse](std::shared_ptr<const RouterInfo> router)->bool
|
||||
[compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
return !router->IsHidden () && router != compatibleWith &&
|
||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
||||
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)):
|
||||
router->IsReachableFrom (*compatibleWith)) &&
|
||||
router->IsECIES ();
|
||||
router->IsECIES () && !router->IsHighCongestion (false) &&
|
||||
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1201,17 +1236,20 @@ namespace data
|
|||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const
|
||||
std::shared_ptr<const RouterInfo> NetDb::GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith,
|
||||
bool reverse, bool endpoint) const
|
||||
{
|
||||
return GetRandomRouter (
|
||||
[compatibleWith, reverse](std::shared_ptr<const RouterInfo> router)->bool
|
||||
[compatibleWith, reverse, endpoint](std::shared_ptr<const RouterInfo> router)->bool
|
||||
{
|
||||
return !router->IsHidden () && router != compatibleWith &&
|
||||
(reverse ? compatibleWith->IsReachableFrom (*router) :
|
||||
(reverse ? (compatibleWith->IsReachableFrom (*router) && router->GetCompatibleTransports (true)) :
|
||||
router->IsReachableFrom (*compatibleWith)) &&
|
||||
(router->GetCaps () & RouterInfo::eHighBandwidth) &&
|
||||
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
|
||||
router->IsECIES () && !router->IsHighCongestion ();
|
||||
router->IsECIES () && !router->IsHighCongestion (true) &&
|
||||
(!endpoint || (router->IsV4 () && (!reverse || router->IsPublished (true)))); // endpoint must be ipv4 and published if inbound(reverse)
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1219,11 +1257,13 @@ namespace data
|
|||
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter (Filter filter) const
|
||||
{
|
||||
if (m_RouterInfos.empty())
|
||||
return 0;
|
||||
return nullptr;
|
||||
uint16_t inds[3];
|
||||
RAND_bytes ((uint8_t *)inds, sizeof (inds));
|
||||
std::unique_lock<std::mutex> l(m_RouterInfosMutex);
|
||||
inds[0] %= m_RouterInfos.size ();
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
auto count = m_RouterInfos.size ();
|
||||
if(count == 0) return nullptr;
|
||||
inds[0] %= count;
|
||||
auto it = m_RouterInfos.begin ();
|
||||
std::advance (it, inds[0]);
|
||||
// try random router
|
||||
|
@ -1282,7 +1322,7 @@ namespace data
|
|||
const std::set<IdentHash>& excluded) const
|
||||
{
|
||||
IdentHash destKey = CreateRoutingKey (destination);
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||
return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
|
||||
{
|
||||
return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
|
||||
|
@ -1297,22 +1337,22 @@ namespace data
|
|||
IdentHash destKey = CreateRoutingKey (destination);
|
||||
std::vector<std::shared_ptr<RouterInfo> > v;
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||
std::lock_guard<std::mutex> l(m_FloodfillsMutex);
|
||||
v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
|
||||
{
|
||||
return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
|
||||
!excluded.count (r->GetIdentHash ());
|
||||
});
|
||||
}
|
||||
}
|
||||
if (v.empty ()) return res;
|
||||
|
||||
|
||||
XORMetric ourMetric;
|
||||
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
|
||||
for (auto& it: v)
|
||||
{
|
||||
if (closeThanUsOnly && ourMetric < (destKey ^ it->GetIdentHash ())) break;
|
||||
res.push_back (it->GetIdentHash ());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -1348,6 +1388,17 @@ namespace data
|
|||
return r;
|
||||
}
|
||||
|
||||
void NetDb::ManageRouterInfos ()
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_RouterInfosMutex);
|
||||
for (auto& it: m_RouterInfos)
|
||||
it.second->UpdateIntroducers (ts);
|
||||
}
|
||||
SaveUpdated ();
|
||||
}
|
||||
|
||||
void NetDb::ManageLeaseSets ()
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
|
|
|
@ -38,9 +38,9 @@ namespace data
|
|||
{
|
||||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_MIN_FLOODFILLS = 5;
|
||||
const int NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE = 8; // in percents
|
||||
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1500;
|
||||
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
|
||||
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
|
||||
|
@ -85,8 +85,8 @@ namespace data
|
|||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
|
@ -95,6 +95,7 @@ namespace data
|
|||
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||
void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
|
||||
|
||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
|
@ -128,6 +129,7 @@ namespace data
|
|||
};
|
||||
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
|
||||
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) { return m_IdentitiesPool.AcquireSharedMt (buf, len); };
|
||||
std::shared_ptr<RouterProfile> NewRouterProfile () { return m_RouterProfilesPool.AcquireSharedMt (); };
|
||||
|
||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||
|
||||
|
@ -139,6 +141,7 @@ namespace data
|
|||
void Run (); // exploratory thread
|
||||
void Explore (int numDestinations);
|
||||
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
|
||||
void ManageRouterInfos ();
|
||||
void ManageLeaseSets ();
|
||||
void ManageRequests ();
|
||||
|
||||
|
@ -184,6 +187,7 @@ namespace data
|
|||
i2p::util::MemoryPoolMt<RouterInfo::Addresses> m_RouterInfoAddressVectorsPool;
|
||||
i2p::util::MemoryPoolMt<Lease> m_LeasesPool;
|
||||
i2p::util::MemoryPoolMt<IdentityEx> m_IdentitiesPool;
|
||||
i2p::util::MemoryPoolMt<RouterProfile> m_RouterProfilesPool;
|
||||
};
|
||||
|
||||
extern NetDb netdb;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -11,11 +11,23 @@
|
|||
#include "Transports.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "NetDbRequests.h"
|
||||
#include "ECIESX25519AEADRatchetSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct):
|
||||
m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct),
|
||||
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0)
|
||||
{
|
||||
}
|
||||
|
||||
RequestedDestination::~RequestedDestination ()
|
||||
{
|
||||
if (m_RequestComplete) m_RequestComplete (nullptr);
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||
{
|
||||
|
@ -28,7 +40,7 @@ namespace data
|
|||
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
|
||||
if(router)
|
||||
m_ExcludedPeers.insert (router->GetIdentHash ());
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -37,7 +49,7 @@ namespace data
|
|||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||
m_ExcludedPeers.insert (floodfill);
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -74,15 +86,36 @@ namespace data
|
|||
}
|
||||
|
||||
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination,
|
||||
bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete)
|
||||
{
|
||||
// request RouterInfo directly
|
||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
|
||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory, direct);
|
||||
dest->SetRequestComplete (requestComplete);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
auto ret = m_RequestedDestinations.emplace (destination, dest);
|
||||
if (!ret.second) // not inserted
|
||||
{
|
||||
dest->SetRequestComplete (nullptr); // don't call requestComplete in destructor
|
||||
if (requestComplete)
|
||||
{
|
||||
auto prev = ret.first->second->GetRequestComplete ();
|
||||
if (prev) // if already set
|
||||
ret.first->second->SetRequestComplete (
|
||||
[requestComplete, prev](std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
prev (r); // call previous
|
||||
requestComplete (r); // then new
|
||||
});
|
||||
else
|
||||
ret.first->second->SetRequestComplete (requestComplete);
|
||||
}
|
||||
if (i2p::util::GetSecondsSinceEpoch () > ret.first->second->GetLastRequestTime () + MIN_REQUEST_TIME)
|
||||
if (!SendNextRequest (ret.first->second)) // try next floodfill
|
||||
m_RequestedDestinations.erase (ret.first); // delete request if failed
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
@ -125,35 +158,10 @@ namespace data
|
|||
{
|
||||
auto& dest = it->second;
|
||||
bool done = false;
|
||||
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
|
||||
if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME) // request becomes worthless
|
||||
{
|
||||
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
|
||||
{
|
||||
auto count = dest->GetExcludedPeers ().size ();
|
||||
if (!dest->IsExploratory () && count < 7)
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool->GetNextOutboundTunnel ();
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||
else
|
||||
{
|
||||
done = true;
|
||||
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
|
||||
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
||||
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval
|
||||
done = !SendNextRequest (dest);
|
||||
}
|
||||
else // delete obsolete request
|
||||
done = true;
|
||||
|
@ -164,5 +172,62 @@ namespace data
|
|||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
bool NetDbRequests::SendNextRequest (std::shared_ptr<RequestedDestination> dest)
|
||||
{
|
||||
if (!dest) return false;
|
||||
bool ret = true;
|
||||
auto count = dest->GetExcludedPeers ().size ();
|
||||
if (!dest->IsExploratory () && count < MAX_NUM_REQUEST_ATTEMPTS)
|
||||
{
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill)
|
||||
{
|
||||
bool direct = dest->IsDirect ();
|
||||
if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
|
||||
!i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ()))
|
||||
direct = false; // floodfill can't be reached directly
|
||||
if (direct)
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly");
|
||||
auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ());
|
||||
msg->onDrop = [this, dest]() { this->SendNextRequest (dest); };
|
||||
i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool->GetNextOutboundTunnel ();
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
{
|
||||
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels");
|
||||
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
|
||||
msg->onDrop = [this, dest]() { this->SendNextRequest (dest); };
|
||||
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
|
||||
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = false;
|
||||
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2020, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -9,9 +9,10 @@
|
|||
#ifndef NETDB_REQUESTS_H__
|
||||
#define NETDB_REQUESTS_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
|
||||
|
@ -19,27 +20,34 @@ namespace i2p
|
|||
{
|
||||
namespace data
|
||||
{
|
||||
const size_t MAX_NUM_REQUEST_ATTEMPTS = 7;
|
||||
const uint64_t MANAGE_REQUESTS_INTERVAL = 15; // in seconds
|
||||
const uint64_t MIN_REQUEST_TIME = 5; // in seconds
|
||||
const uint64_t MAX_REQUEST_TIME = MAX_NUM_REQUEST_ATTEMPTS*MANAGE_REQUESTS_INTERVAL;
|
||||
|
||||
class RequestedDestination
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
|
||||
|
||||
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
|
||||
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
|
||||
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
|
||||
RequestedDestination (const IdentHash& destination, bool isExploratory = false, bool direct = true);
|
||||
~RequestedDestination ();
|
||||
|
||||
const IdentHash& GetDestination () const { return m_Destination; };
|
||||
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
||||
const std::set<IdentHash>& GetExcludedPeers () { return m_ExcludedPeers; };
|
||||
void ClearExcludedPeers ();
|
||||
bool IsExploratory () const { return m_IsExploratory; };
|
||||
bool IsDirect () const { return m_IsDirect; };
|
||||
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
|
||||
uint64_t GetCreationTime () const { return m_CreationTime; };
|
||||
uint64_t GetLastRequestTime () const { return m_LastRequestTime; };
|
||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
|
||||
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
|
||||
|
||||
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
||||
RequestComplete GetRequestComplete () const { return m_RequestComplete; };
|
||||
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
||||
void Success (std::shared_ptr<RouterInfo> r);
|
||||
void Fail ();
|
||||
|
@ -47,9 +55,9 @@ namespace data
|
|||
private:
|
||||
|
||||
IdentHash m_Destination;
|
||||
bool m_IsExploratory;
|
||||
bool m_IsExploratory, m_IsDirect;
|
||||
std::set<IdentHash> m_ExcludedPeers;
|
||||
uint64_t m_CreationTime;
|
||||
uint64_t m_CreationTime, m_LastRequestTime; // in seconds
|
||||
RequestComplete m_RequestComplete;
|
||||
};
|
||||
|
||||
|
@ -60,15 +68,17 @@ namespace data
|
|||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory,
|
||||
bool direct = false, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
|
||||
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
|
||||
void ManageRequests ();
|
||||
|
||||
bool SendNextRequest (std::shared_ptr<RequestedDestination> dest);
|
||||
|
||||
private:
|
||||
|
||||
mutable std::mutex m_RequestedDestinationsMutex;
|
||||
std::map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||
std::unordered_map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "FS.h"
|
||||
#include "Log.h"
|
||||
#include "Timestamp.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "Profiling.h"
|
||||
|
||||
namespace i2p
|
||||
|
@ -30,12 +31,12 @@ namespace data
|
|||
{
|
||||
return boost::posix_time::second_clock::local_time();
|
||||
}
|
||||
|
||||
|
||||
RouterProfile::RouterProfile ():
|
||||
m_LastUpdateTime (GetTime ()), m_IsUpdated (false),
|
||||
m_LastDeclineTime (0), m_LastUnreachableTime (0),
|
||||
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
|
||||
m_NumTimesTaken (0), m_NumTimesRejected (0)
|
||||
m_NumTimesTaken (0), m_NumTimesRejected (0), m_HasConnected (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -55,6 +56,7 @@ namespace data
|
|||
boost::property_tree::ptree usage;
|
||||
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||
usage.put (PEER_PROFILE_USAGE_CONNECTED, m_HasConnected);
|
||||
// fill property tree
|
||||
boost::property_tree::ptree pt;
|
||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
||||
|
@ -123,6 +125,7 @@ namespace data
|
|||
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
|
||||
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
|
||||
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
|
||||
m_HasConnected = usage.get (PEER_PROFILE_USAGE_CONNECTED, false);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path& ex)
|
||||
{
|
||||
|
@ -148,22 +151,30 @@ namespace data
|
|||
}
|
||||
else
|
||||
{
|
||||
m_NumTunnelsAgreed++;
|
||||
m_NumTunnelsAgreed++;
|
||||
m_LastDeclineTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelNonReplied ()
|
||||
{
|
||||
m_NumTunnelsNonReplied++;
|
||||
m_NumTunnelsNonReplied++;
|
||||
UpdateTime ();
|
||||
if (m_NumTunnelsNonReplied > 2*m_NumTunnelsAgreed && m_NumTunnelsNonReplied > 3)
|
||||
{
|
||||
m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::Unreachable ()
|
||||
void RouterProfile::Unreachable (bool unreachable)
|
||||
{
|
||||
m_LastUnreachableTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_LastUnreachableTime = unreachable ? i2p::util::GetSecondsSinceEpoch () : 0;
|
||||
UpdateTime ();
|
||||
}
|
||||
|
||||
void RouterProfile::Connected ()
|
||||
{
|
||||
m_HasConnected = true;
|
||||
UpdateTime ();
|
||||
}
|
||||
|
||||
|
@ -214,6 +225,11 @@ namespace data
|
|||
return (bool)m_LastUnreachableTime;
|
||||
}
|
||||
|
||||
bool RouterProfile::IsUseful() const
|
||||
{
|
||||
return IsReal () || m_NumTunnelsNonReplied >= PEER_PROFILE_USEFUL_THRESHOLD;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
||||
{
|
||||
{
|
||||
|
@ -221,8 +237,8 @@ namespace data
|
|||
auto it = g_Profiles.find (identHash);
|
||||
if (it != g_Profiles.end ())
|
||||
return it->second;
|
||||
}
|
||||
auto profile = std::make_shared<RouterProfile> ();
|
||||
}
|
||||
auto profile = netdb.NewRouterProfile ();
|
||||
profile->Load (identHash); // if possible
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
g_Profiles.emplace (identHash, profile);
|
||||
|
@ -242,7 +258,7 @@ namespace data
|
|||
{
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||
{
|
||||
{
|
||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL)
|
||||
{
|
||||
if (it->second->IsUpdated ())
|
||||
|
@ -251,11 +267,11 @@ namespace data
|
|||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto& it: tmp)
|
||||
if (it.second) it.second->Save (it.first);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveProfiles ()
|
||||
{
|
||||
|
@ -267,24 +283,24 @@ namespace data
|
|||
}
|
||||
auto ts = GetTime ();
|
||||
for (auto& it: tmp)
|
||||
if (it.second->IsUpdated () && (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
|
||||
if (it.second->IsUseful() && (it.second->IsUpdated () || (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600))
|
||||
it.second->Save (it.first);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DeleteObsoleteProfiles ()
|
||||
{
|
||||
{
|
||||
auto ts = GetTime ();
|
||||
std::unique_lock<std::mutex> l(g_ProfilesMutex);
|
||||
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
|
||||
{
|
||||
{
|
||||
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
|
||||
it = g_Profiles.erase (it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct stat st;
|
||||
std::time_t now = std::time(nullptr);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -28,35 +28,40 @@ namespace data
|
|||
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
|
||||
const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
|
||||
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
|
||||
|
||||
const char PEER_PROFILE_USAGE_CONNECTED[] = "connected";
|
||||
|
||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days)
|
||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 6 * 3600; // in seconds (6 hours)
|
||||
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 3 * 3600; // in seconds (3 hours)
|
||||
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour)
|
||||
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
|
||||
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
|
||||
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours)
|
||||
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
|
||||
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
|
||||
|
||||
class RouterProfile
|
||||
{
|
||||
public:
|
||||
|
||||
RouterProfile ();
|
||||
RouterProfile& operator= (const RouterProfile& ) = default;
|
||||
|
||||
void Save (const IdentHash& identHash);
|
||||
void Load (const IdentHash& identHash);
|
||||
|
||||
bool IsBad ();
|
||||
bool IsUnreachable ();
|
||||
bool IsReal () const { return m_HasConnected || m_NumTunnelsAgreed > 0 || m_NumTunnelsDeclined > 0; }
|
||||
|
||||
void TunnelBuildResponse (uint8_t ret);
|
||||
void TunnelNonReplied ();
|
||||
|
||||
void Unreachable ();
|
||||
void Unreachable (bool unreachable);
|
||||
void Connected ();
|
||||
|
||||
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
bool IsUpdated () const { return m_IsUpdated; };
|
||||
|
||||
bool IsUseful() const;
|
||||
|
||||
private:
|
||||
|
||||
void UpdateTime ();
|
||||
|
@ -78,6 +83,7 @@ namespace data
|
|||
// usage
|
||||
uint32_t m_NumTimesTaken;
|
||||
uint32_t m_NumTimesRejected;
|
||||
bool m_HasConnected; // successful trusted(incoming or NTCP2) connection
|
||||
};
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -26,6 +26,7 @@
|
|||
#include "HTTP.h"
|
||||
#include "util.h"
|
||||
#include "Config.h"
|
||||
#include "Socks5.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -615,62 +616,21 @@ namespace data
|
|||
{
|
||||
// assume socks if not http, is checked before this for other types
|
||||
// TODO: support username/password auth etc
|
||||
uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00};
|
||||
uint8_t hs_readbuf[2];
|
||||
boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode);
|
||||
if(ecode)
|
||||
bool success = false;
|
||||
i2p::transport::Socks5Handshake (sock, std::make_pair(url.host, url.port),
|
||||
[&success](const boost::system::error_code& ec)
|
||||
{
|
||||
if (!ec)
|
||||
success = true;
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SOCKS handshake failed: ", ec.message());
|
||||
});
|
||||
service.run (); // execute all async operations
|
||||
if (!success)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
size_t sz = 0;
|
||||
uint8_t buf[256];
|
||||
|
||||
buf[0] = 0x05;
|
||||
buf[1] = 0x01;
|
||||
buf[2] = 0x00;
|
||||
buf[3] = 0x03;
|
||||
sz += 4;
|
||||
size_t hostsz = url.host.size();
|
||||
if(1 + 2 + hostsz + sz > sizeof(buf))
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host);
|
||||
return "";
|
||||
}
|
||||
buf[4] = (uint8_t) hostsz;
|
||||
memcpy(buf+5, url.host.c_str(), hostsz);
|
||||
sz += hostsz + 1;
|
||||
htobe16buf(buf+sz, url.port);
|
||||
sz += 2;
|
||||
boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
if(buf[1] != 0x00)
|
||||
{
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1]));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -687,18 +647,16 @@ namespace data
|
|||
while (it != end)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
if (
|
||||
(
|
||||
!i2p::util::net::IsInReservedRange(ep.address ()) && (
|
||||
(ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
|
||||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())
|
||||
)
|
||||
) ||
|
||||
(
|
||||
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
|
||||
i2p::context.SupportsMesh ()
|
||||
)
|
||||
)
|
||||
bool supported = false;
|
||||
if (!ep.address ().is_unspecified ())
|
||||
{
|
||||
if (ep.address ().is_v4 ())
|
||||
supported = i2p::context.SupportsV4 ();
|
||||
else if (ep.address ().is_v6 ())
|
||||
supported = i2p::util::net::IsYggdrasilAddress (ep.address ()) ?
|
||||
i2p::context.SupportsMesh () : i2p::context.SupportsV6 ();
|
||||
}
|
||||
if (supported)
|
||||
{
|
||||
s.lowest_layer().connect (ep, ecode);
|
||||
if (!ecode)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -31,7 +31,8 @@ namespace i2p
|
|||
RouterContext::RouterContext ():
|
||||
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
|
||||
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
|
||||
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID),
|
||||
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone),
|
||||
m_Testing (false), m_TestingV6 (false), m_NetID (I2PD_NET_ID),
|
||||
m_PublishReplyToken (0), m_IsHiddenMode (false)
|
||||
{
|
||||
}
|
||||
|
@ -60,9 +61,11 @@ namespace i2p
|
|||
{
|
||||
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleInitialPublish ();
|
||||
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCongestionUpdate ();
|
||||
}
|
||||
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCongestionUpdate ();
|
||||
m_CleanupTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
|
||||
ScheduleCleanupTimer ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,10 +280,33 @@ namespace i2p
|
|||
fk.write ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
|
||||
}
|
||||
|
||||
void RouterContext::SetTesting (bool testing)
|
||||
{
|
||||
if (testing != m_Testing)
|
||||
{
|
||||
m_Testing = testing;
|
||||
if (m_Testing)
|
||||
m_Error = eRouterErrorNone;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetTestingV6 (bool testing)
|
||||
{
|
||||
if (testing != m_TestingV6)
|
||||
{
|
||||
m_TestingV6 = testing;
|
||||
if (m_TestingV6)
|
||||
m_ErrorV6 = eRouterErrorNone;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetStatus (RouterStatus status)
|
||||
{
|
||||
SetTesting (false);
|
||||
if (status != m_Status)
|
||||
{
|
||||
LogPrint(eLogInfo, "Router: network status v4 changed ",
|
||||
ROUTER_STATUS_NAMES[m_Status], " -> ", ROUTER_STATUS_NAMES[status]);
|
||||
m_Status = status;
|
||||
switch (m_Status)
|
||||
{
|
||||
|
@ -290,9 +316,6 @@ namespace i2p
|
|||
case eRouterStatusFirewalled:
|
||||
SetUnreachable (true, false); // ipv4
|
||||
break;
|
||||
case eRouterStatusTesting:
|
||||
m_Error = eRouterErrorNone;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
@ -301,8 +324,11 @@ namespace i2p
|
|||
|
||||
void RouterContext::SetStatusV6 (RouterStatus status)
|
||||
{
|
||||
SetTestingV6 (false);
|
||||
if (status != m_StatusV6)
|
||||
{
|
||||
LogPrint(eLogInfo, "Router: network status v6 changed ",
|
||||
ROUTER_STATUS_NAMES[m_StatusV6], " -> ", ROUTER_STATUS_NAMES[status]);
|
||||
m_StatusV6 = status;
|
||||
switch (m_StatusV6)
|
||||
{
|
||||
|
@ -312,9 +338,6 @@ namespace i2p
|
|||
case eRouterStatusFirewalled:
|
||||
SetUnreachable (false, true); // ipv6
|
||||
break;
|
||||
case eRouterStatusTesting:
|
||||
m_ErrorV6 = eRouterErrorNone;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
@ -577,15 +600,15 @@ namespace i2p
|
|||
/* detect parameters */
|
||||
switch (L)
|
||||
{
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = 48; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 64; type = high; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = 128; type = high; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH3 : limit = 256; type = high; break;
|
||||
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = 2048; type = extra; break;
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH1 : limit = 12; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH2 : limit = i2p::data::LOW_BANDWIDTH_LIMIT; type = low; break; // 48
|
||||
case i2p::data::CAPS_FLAG_LOW_BANDWIDTH3 : limit = 64; type = low; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH1 : limit = 128; type = high; break;
|
||||
case i2p::data::CAPS_FLAG_HIGH_BANDWIDTH2 : limit = i2p::data::HIGH_BANDWIDTH_LIMIT; type = high; break; // 256
|
||||
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH1 : limit = i2p::data::EXTRA_BANDWIDTH_LIMIT; type = extra; break; // 2048
|
||||
case i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2 : limit = 1000000; type = unlim; break; // 1Gbyte/s
|
||||
default:
|
||||
limit = 48; type = low;
|
||||
limit = i2p::data::LOW_BANDWIDTH_LIMIT; type = low; // 48
|
||||
}
|
||||
/* update caps & flags in RI */
|
||||
auto caps = m_RouterInfo.GetCaps ();
|
||||
|
@ -1114,13 +1137,14 @@ namespace i2p
|
|||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
}
|
||||
|
||||
bool RouterContext::IsHighCongestion () const
|
||||
int RouterContext::GetCongestionLevel (bool longTerm) const
|
||||
{
|
||||
return i2p::tunnel::tunnels.IsTooManyTransitTunnels () ||
|
||||
i2p::transport::transports.IsBandwidthExceeded () ||
|
||||
i2p::transport::transports.IsTransitBandwidthExceeded ();
|
||||
}
|
||||
|
||||
return std::max (
|
||||
i2p::tunnel::tunnels.GetCongestionLevel (),
|
||||
i2p::transport::transports.GetCongestionLevel (longTerm)
|
||||
);
|
||||
}
|
||||
|
||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||
{
|
||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
||||
|
@ -1128,6 +1152,13 @@ namespace i2p
|
|||
|
||||
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID)
|
||||
{
|
||||
if (typeID == eI2NPDeliveryStatus)
|
||||
{
|
||||
// try tunnel test
|
||||
auto pool = GetTunnelPool ();
|
||||
if (pool && pool->ProcessDeliveryStatus (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET), bufbe64toh (payload + DELIVERY_STATUS_TIMESTAMP_OFFSET)))
|
||||
return true;
|
||||
}
|
||||
auto msg = CreateI2NPMessage (typeID, payload, len, msgID);
|
||||
if (!msg) return false;
|
||||
i2p::HandleI2NPMessage (msg);
|
||||
|
@ -1182,17 +1213,26 @@ namespace i2p
|
|||
else
|
||||
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
||||
}
|
||||
|
||||
void RouterContext::CleanupDestination ()
|
||||
|
||||
void RouterContext::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post ([this]()
|
||||
{
|
||||
this->i2p::garlic::GarlicDestination::CleanupExpiredTags ();
|
||||
});
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t k[32];
|
||||
uint64_t t;
|
||||
} data;
|
||||
memcpy (data.k, key, 32);
|
||||
data.t = tag;
|
||||
m_Service->GetService ().post ([this,data](void)
|
||||
{
|
||||
AddECIESx25519Key (data.k, data.t);
|
||||
});
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: service is NULL");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RouterContext::GetUptime () const
|
||||
{
|
||||
|
@ -1337,10 +1377,19 @@ namespace i2p
|
|||
uint32_t replyToken;
|
||||
RAND_bytes ((uint8_t *)&replyToken, 4);
|
||||
LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||
auto onDrop = [this]()
|
||||
{
|
||||
if (m_Service)
|
||||
m_Service->GetService ().post ([this]() { HandlePublishResendTimer (boost::system::error_code ()); });
|
||||
};
|
||||
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
|
||||
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
|
||||
{
|
||||
// send directly
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken);
|
||||
msg->onDrop = onDrop;
|
||||
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise through exploratory
|
||||
|
@ -1348,8 +1397,13 @@ namespace i2p
|
|||
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
|
||||
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
|
||||
if (inbound && outbound)
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
||||
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
|
||||
{
|
||||
// encrypt for floodfill
|
||||
auto msg = CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound);
|
||||
msg->onDrop = onDrop;
|
||||
outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0,
|
||||
i2p::garlic::WrapECIESX25519MessageForRouter (msg, floodfill->GetIdentity ()->GetEncryptionPublicKey ()));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds");
|
||||
}
|
||||
|
@ -1401,13 +1455,41 @@ namespace i2p
|
|||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
auto c = i2p::data::RouterInfo::eLowCongestion;
|
||||
if (!AcceptsTunnels ())
|
||||
if (!AcceptsTunnels () || !m_ShareRatio)
|
||||
c = i2p::data::RouterInfo::eRejectAll;
|
||||
else if (IsHighCongestion ())
|
||||
c = i2p::data::RouterInfo::eHighCongestion;
|
||||
else
|
||||
{
|
||||
int congestionLevel = GetCongestionLevel (true);
|
||||
if (congestionLevel > CONGESTION_LEVEL_HIGH)
|
||||
c = i2p::data::RouterInfo::eHighCongestion;
|
||||
else if (congestionLevel > CONGESTION_LEVEL_MEDIUM)
|
||||
c = i2p::data::RouterInfo::eMediumCongestion;
|
||||
}
|
||||
if (m_RouterInfo.UpdateCongestion (c))
|
||||
UpdateRouterInfo ();
|
||||
ScheduleCongestionUpdate ();
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::ScheduleCleanupTimer ()
|
||||
{
|
||||
if (m_CleanupTimer)
|
||||
{
|
||||
m_CleanupTimer->cancel ();
|
||||
m_CleanupTimer->expires_from_now (boost::posix_time::minutes(ROUTER_INFO_CLEANUP_INTERVAL));
|
||||
m_CleanupTimer->async_wait (std::bind (&RouterContext::HandleCleanupTimer,
|
||||
this, std::placeholders::_1));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Router: Cleanup timer is NULL");
|
||||
}
|
||||
|
||||
void RouterContext::HandleCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
CleanupExpiredTags ();
|
||||
ScheduleCleanupTimer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -38,15 +38,24 @@ namespace garlic
|
|||
const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||
const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||
const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
|
||||
const int ROUTER_INFO_CLEANUP_INTERVAL = 5; // in minutes
|
||||
|
||||
enum RouterStatus
|
||||
{
|
||||
eRouterStatusOK = 0,
|
||||
eRouterStatusTesting = 1,
|
||||
eRouterStatusFirewalled = 2,
|
||||
eRouterStatusUnknown = 3,
|
||||
eRouterStatusProxy = 4,
|
||||
eRouterStatusMesh = 5
|
||||
eRouterStatusFirewalled = 1,
|
||||
eRouterStatusUnknown = 2,
|
||||
eRouterStatusProxy = 3,
|
||||
eRouterStatusMesh = 4
|
||||
};
|
||||
|
||||
const char* const ROUTER_STATUS_NAMES[] =
|
||||
{
|
||||
"OK", // 0
|
||||
"Firewalled", // 1
|
||||
"Unknown", // 2
|
||||
"Proxy", // 3
|
||||
"Mesh" // 4
|
||||
};
|
||||
|
||||
enum RouterError
|
||||
|
@ -121,10 +130,14 @@ namespace garlic
|
|||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
uint64_t GetBandwidthLimit () const { return m_BandwidthLimit; };
|
||||
uint64_t GetTransitBandwidthLimit () const { return (m_BandwidthLimit*m_ShareRatio)/100LL; };
|
||||
bool GetTesting () const { return m_Testing; };
|
||||
void SetTesting (bool testing);
|
||||
RouterStatus GetStatus () const { return m_Status; };
|
||||
void SetStatus (RouterStatus status);
|
||||
RouterError GetError () const { return m_Error; };
|
||||
void SetError (RouterError error) { m_Error = error; };
|
||||
bool GetTestingV6 () const { return m_TestingV6; };
|
||||
void SetTestingV6 (bool testing);
|
||||
RouterStatus GetStatusV6 () const { return m_StatusV6; };
|
||||
void SetStatusV6 (RouterStatus status);
|
||||
RouterError GetErrorV6 () const { return m_ErrorV6; };
|
||||
|
@ -133,6 +146,7 @@ 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 SubmitECIESx25519Key (const uint8_t * key, uint64_t tag);
|
||||
|
||||
void UpdatePort (int port); // called from Daemon
|
||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon
|
||||
|
@ -153,7 +167,7 @@ namespace garlic
|
|||
void SetShareRatio (int percents); // 0 - 100
|
||||
bool AcceptsTunnels () const { return m_AcceptsTunnels; };
|
||||
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
bool IsHighCongestion () const;
|
||||
int GetCongestionLevel (bool longTerm) const;
|
||||
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
|
||||
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
|
||||
bool SupportsMesh () const { return m_RouterInfo.IsMesh (); };
|
||||
|
@ -168,7 +182,6 @@ namespace garlic
|
|||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||
void UpdateStats ();
|
||||
void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing
|
||||
void CleanupDestination (); // garlic destination
|
||||
|
||||
// implements LocalDestination
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||
|
@ -217,6 +230,8 @@ namespace garlic
|
|||
void HandlePublishResendTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleCongestionUpdate ();
|
||||
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleCleanupTimer ();
|
||||
void HandleCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -231,6 +246,7 @@ namespace garlic
|
|||
int m_ShareRatio;
|
||||
RouterStatus m_Status, m_StatusV6;
|
||||
RouterError m_Error, m_ErrorV6;
|
||||
bool m_Testing, m_TestingV6;
|
||||
int m_NetID;
|
||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
|
||||
|
@ -239,7 +255,7 @@ namespace garlic
|
|||
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
|
||||
// publish
|
||||
std::unique_ptr<RouterService> m_Service;
|
||||
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer;
|
||||
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer, m_CleanupTimer;
|
||||
std::set<i2p::data::IdentHash> m_PublishExcluded;
|
||||
uint32_t m_PublishReplyToken;
|
||||
bool m_IsHiddenMode; // not publish
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -21,6 +21,7 @@
|
|||
#include "Base.h"
|
||||
#include "Timestamp.h"
|
||||
#include "Log.h"
|
||||
#include "Transports.h"
|
||||
#include "NetDb.hpp"
|
||||
#include "RouterContext.h"
|
||||
#include "RouterInfo.h"
|
||||
|
@ -130,7 +131,7 @@ namespace data
|
|||
m_BufferLen = s.tellg ();
|
||||
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
|
||||
{
|
||||
LogPrint(eLogError, "RouterInfo: File", fullPath, " is malformed");
|
||||
LogPrint(eLogError, "RouterInfo: File ", fullPath, " is malformed");
|
||||
return false;
|
||||
}
|
||||
s.seekg(0, std::ios::beg);
|
||||
|
@ -253,7 +254,7 @@ namespace data
|
|||
address->host = boost::asio::ip::address::from_string (value, ecode);
|
||||
if (!ecode && !address->host.is_unspecified ())
|
||||
{
|
||||
if (!i2p::util::net::IsInReservedRange (address->host) ||
|
||||
if (!i2p::transport::transports.IsInReservedRange (address->host) ||
|
||||
i2p::util::net::IsYggdrasilAddress (address->host))
|
||||
isHost = true;
|
||||
else
|
||||
|
@ -293,7 +294,8 @@ namespace data
|
|||
else if (!strcmp (key, "s")) // ntcp2 or ssu2 static key
|
||||
{
|
||||
Base64ToByteStream (value, strlen (value), address->s, 32);
|
||||
isStaticKey = true;
|
||||
if (!(address->s[31] & 0x80)) // check if x25519 public key
|
||||
isStaticKey = true;
|
||||
}
|
||||
else if (!strcmp (key, "i")) // ntcp2 iv or ssu2 intro
|
||||
{
|
||||
|
@ -362,11 +364,12 @@ namespace data
|
|||
}
|
||||
if (!s) return;
|
||||
}
|
||||
|
||||
if (address->transportStyle == eTransportNTCP2)
|
||||
{
|
||||
if (isStaticKey)
|
||||
{
|
||||
if (isHost)
|
||||
if (isHost && address->port)
|
||||
{
|
||||
if (address->host.is_v6 ())
|
||||
supportedTransports |= (i2p::util::net::IsYggdrasilAddress (address->host) ? eNTCP2V6Mesh : eNTCP2V6);
|
||||
|
@ -374,8 +377,9 @@ namespace data
|
|||
supportedTransports |= eNTCP2V4;
|
||||
m_ReachableTransports |= supportedTransports;
|
||||
}
|
||||
else if (!address->published)
|
||||
else
|
||||
{
|
||||
address->published = false;
|
||||
if (address->caps)
|
||||
{
|
||||
if (address->caps & AddressCaps::eV4) supportedTransports |= eNTCP2V4;
|
||||
|
@ -386,7 +390,7 @@ namespace data
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (address->transportStyle == eTransportSSU2 && isV2)
|
||||
else if (address->transportStyle == eTransportSSU2 && isV2 && isStaticKey)
|
||||
{
|
||||
if (address->IsV4 ()) supportedTransports |= eSSU2V4;
|
||||
if (address->IsV6 ()) supportedTransports |= eSSU2V6;
|
||||
|
@ -400,18 +404,9 @@ namespace data
|
|||
{
|
||||
// exclude invalid introducers
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
int numValid = 0;
|
||||
for (auto& it: address->ssu->introducers)
|
||||
{
|
||||
if (it.iTag && ts < it.iExp)
|
||||
numValid++;
|
||||
else
|
||||
it.iTag = 0;
|
||||
}
|
||||
if (numValid)
|
||||
UpdateIntroducers (address, ts);
|
||||
if (!address->ssu->introducers.empty ()) // still has something
|
||||
m_ReachableTransports |= supportedTransports;
|
||||
else
|
||||
address->ssu->introducers.resize (0);
|
||||
}
|
||||
}
|
||||
if (supportedTransports)
|
||||
|
@ -491,7 +486,10 @@ namespace data
|
|||
if (netdb.GetFamilies ().VerifyFamily (family, GetIdentHash (), value))
|
||||
m_FamilyID = netdb.GetFamilies ().GetFamilyID (family);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "RouterInfo: Family ", family, " signature verification failed");
|
||||
SetUnreachable (true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!s) return;
|
||||
|
@ -518,7 +516,6 @@ namespace data
|
|||
break;
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH1:
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH2:
|
||||
case CAPS_FLAG_HIGH_BANDWIDTH3:
|
||||
m_Caps |= Caps::eHighBandwidth;
|
||||
break;
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
||||
|
@ -576,6 +573,21 @@ namespace data
|
|||
return caps;
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts)
|
||||
{
|
||||
if (!address || !address->ssu) return;
|
||||
int numValid = 0;
|
||||
for (auto& it: address->ssu->introducers)
|
||||
{
|
||||
if (it.iTag && ts < it.iExp && !it.iH.IsZero ())
|
||||
numValid++;
|
||||
else
|
||||
it.iTag = 0;
|
||||
}
|
||||
if (!numValid)
|
||||
address->ssu->introducers.resize (0);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
if (!m_RouterIdentity) return false;
|
||||
|
@ -976,11 +988,23 @@ namespace data
|
|||
|
||||
bool RouterInfo::IsEligibleFloodfill () const
|
||||
{
|
||||
// floodfill must be reachable by ipv4, >= 0.9.38 and not DSA
|
||||
return IsReachableBy (eNTCP2V4 | eSSU2V4) && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
||||
// floodfill must have published ipv4, >= 0.9.38 and not DSA
|
||||
return m_Version >= NETDB_MIN_FLOODFILL_VERSION && IsPublished (true) &&
|
||||
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||
}
|
||||
|
||||
bool RouterInfo::IsPublished (bool v4) const
|
||||
{
|
||||
if (m_Caps & (eUnreachable | eHidden)) return false; // if router sets U or H we assume that all addresses are not published
|
||||
auto addr = GetAddresses ();
|
||||
if (v4)
|
||||
return ((*addr)[eNTCP2V4Idx] && ((*addr)[eNTCP2V4Idx])->published) ||
|
||||
((*addr)[eSSU2V4Idx] && ((*addr)[eSSU2V4Idx])->published);
|
||||
else
|
||||
return ((*addr)[eNTCP2V6Idx] && ((*addr)[eNTCP2V6Idx])->published) ||
|
||||
((*addr)[eSSU2V6Idx] && ((*addr)[eSSU2V6Idx])->published);
|
||||
}
|
||||
|
||||
bool RouterInfo::IsSSU2PeerTesting (bool v4) const
|
||||
{
|
||||
if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false;
|
||||
|
@ -1036,6 +1060,31 @@ namespace data
|
|||
}
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateIntroducers (uint64_t ts)
|
||||
{
|
||||
if (ts*1000 < m_Timestamp + INTRODUCER_UPDATE_INTERVAL) return;
|
||||
if (m_ReachableTransports & eSSU2V4)
|
||||
{
|
||||
auto addr = (*GetAddresses ())[eSSU2V4Idx];
|
||||
if (addr && addr->UsesIntroducer ())
|
||||
{
|
||||
UpdateIntroducers (addr, ts);
|
||||
if (!addr->UsesIntroducer ()) // no more valid introducers
|
||||
m_ReachableTransports &= ~eSSU2V4;
|
||||
}
|
||||
}
|
||||
if (m_ReachableTransports & eSSU2V6)
|
||||
{
|
||||
auto addr = (*GetAddresses ())[eSSU2V6Idx];
|
||||
if (addr && addr->UsesIntroducer ())
|
||||
{
|
||||
UpdateIntroducers (addr, ts);
|
||||
if (!addr->UsesIntroducer ()) // no more valid introducers
|
||||
m_ReachableTransports &= ~eSSU2V6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateBuffer (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (!m_Buffer)
|
||||
|
@ -1070,13 +1119,25 @@ namespace data
|
|||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
bool RouterInfo::IsHighCongestion () const
|
||||
bool RouterInfo::IsHighCongestion (bool highBandwidth) const
|
||||
{
|
||||
if (m_Congestion == eLowCongestion || m_Congestion == eMediumCongestion) return false;
|
||||
if (m_Congestion == eRejectAll) return true;
|
||||
if (m_Congestion == eHighCongestion)
|
||||
return (i2p::util::GetMillisecondsSinceEpoch () < m_Timestamp + HIGH_CONGESTION_INTERVAL*1000LL) ? true : false;
|
||||
return false;
|
||||
switch (m_Congestion)
|
||||
{
|
||||
case eLowCongestion:
|
||||
return false;
|
||||
break;
|
||||
case eMediumCongestion:
|
||||
return highBandwidth;
|
||||
break;
|
||||
case eHighCongestion:
|
||||
return i2p::util::GetMillisecondsSinceEpoch () < m_Timestamp + HIGH_CONGESTION_INTERVAL*1000LL;
|
||||
break;
|
||||
case eRejectAll:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
|
||||
|
@ -1116,7 +1177,7 @@ namespace data
|
|||
CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
|
||||
CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
|
||||
else
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH2; // 'O'
|
||||
caps += CAPS_FLAG_FLOODFILL; // floodfill
|
||||
}
|
||||
else
|
||||
|
@ -1124,7 +1185,7 @@ namespace data
|
|||
if (c & eExtraBandwidth)
|
||||
caps += (c & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
|
||||
else
|
||||
caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
|
||||
caps += (c & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH2 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
|
||||
}
|
||||
if (c & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
|
||||
if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
|
||||
|
@ -1260,6 +1321,7 @@ namespace data
|
|||
int i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
if (!introducer.iTag) continue;
|
||||
if (introducer.iExp) // expiration is specified
|
||||
{
|
||||
WriteString ("iexp" + boost::lexical_cast<std::string>(i), properties);
|
||||
|
@ -1272,6 +1334,7 @@ namespace data
|
|||
i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
if (!introducer.iTag) continue;
|
||||
WriteString ("ih" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
char value[64];
|
||||
|
@ -1284,6 +1347,7 @@ namespace data
|
|||
i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
if (!introducer.iTag) continue;
|
||||
WriteString ("itag" + boost::lexical_cast<std::string>(i), properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -39,11 +39,15 @@ namespace data
|
|||
/* bandwidth flags */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'M'; /* 48-64 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'N'; /* 64-128 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH3 = 'M'; /* 48-64 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH1 = 'N'; /* 64-128 KBps */
|
||||
const char CAPS_FLAG_HIGH_BANDWIDTH2 = 'O'; /* 128-256 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2048 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2048 KBps */
|
||||
// bandwidth limits in kBps
|
||||
const uint32_t LOW_BANDWIDTH_LIMIT = 48;
|
||||
const uint32_t HIGH_BANDWIDTH_LIMIT = 256;
|
||||
const uint32_t EXTRA_BANDWIDTH_LIMIT = 2048;
|
||||
// congesion flags
|
||||
const char CAPS_FLAG_MEDIUM_CONGESTION = 'D';
|
||||
const char CAPS_FLAG_HIGH_CONGESTION = 'E';
|
||||
|
@ -61,6 +65,7 @@ namespace data
|
|||
|
||||
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
|
||||
const int HIGH_CONGESTION_INTERVAL = 15*60; // in seconds, 15 minutes
|
||||
const int INTRODUCER_UPDATE_INTERVAL = 20*60*1000; // in milliseconds, 20 minutes
|
||||
|
||||
class RouterInfo: public RoutingDestination
|
||||
{
|
||||
|
@ -124,7 +129,7 @@ namespace data
|
|||
|
||||
struct Introducer
|
||||
{
|
||||
Introducer (): iTag (0), iExp (0) {};
|
||||
Introducer (): iTag (0), iExp (0) { iH.Fill(0); };
|
||||
IdentHash iH;
|
||||
uint32_t iTag;
|
||||
uint32_t iExp;
|
||||
|
@ -221,8 +226,9 @@ namespace data
|
|||
void RemoveSSU2Address (bool v4);
|
||||
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
|
||||
void UpdateSupportedTransports ();
|
||||
void UpdateIntroducers (uint64_t ts); // ts in seconds
|
||||
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
|
||||
bool IsReachable () const { return m_Caps & Caps::eReachable; };
|
||||
void ResetFlooldFill () { m_Caps &= ~Caps::eFloodfill; };
|
||||
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||
bool IsNTCP2 (bool v4only = true) const;
|
||||
bool IsNTCP2V6 () const { return m_SupportedTransports & eNTCP2V6; };
|
||||
|
@ -246,9 +252,10 @@ namespace data
|
|||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
bool IsEligibleFloodfill () const;
|
||||
bool IsPublished (bool v4) const;
|
||||
bool IsSSU2PeerTesting (bool v4) const;
|
||||
bool IsSSU2Introducer (bool v4) const;
|
||||
bool IsHighCongestion () const;
|
||||
bool IsHighCongestion (bool highBandwidth) const;
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||
|
@ -257,6 +264,7 @@ namespace data
|
|||
|
||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||
void ExcludeReachableTransports (CompatibleTransports transports) { m_ReachableTransports &= ~transports; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; };
|
||||
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
|
||||
|
@ -302,6 +310,7 @@ namespace data
|
|||
size_t ReadString (char* str, size_t len, std::istream& s) const;
|
||||
void ExtractCaps (const char * value);
|
||||
uint8_t ExtractAddressCaps (const char * value) const;
|
||||
void UpdateIntroducers (std::shared_ptr<Address> address, uint64_t ts);
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const Address> GetAddress (Filter filter) const;
|
||||
virtual std::shared_ptr<Buffer> NewBuffer () const;
|
||||
|
@ -315,7 +324,7 @@ namespace data
|
|||
std::shared_ptr<const IdentityEx> m_RouterIdentity;
|
||||
std::shared_ptr<Buffer> m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
uint64_t m_Timestamp;
|
||||
uint64_t m_Timestamp; // in milliseconds
|
||||
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||
bool m_IsUpdated, m_IsUnreachable;
|
||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
|
||||
|
|
138
libi2pd/SSU2.cpp
138
libi2pd/SSU2.cpp
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -24,7 +24,8 @@ namespace transport
|
|||
m_AddressV4 (boost::asio::ip::address_v4()), m_AddressV6 (boost::asio::ip::address_v6()),
|
||||
m_TerminationTimer (GetService ()), m_CleanupTimer (GetService ()), m_ResendTimer (GetService ()),
|
||||
m_IntroducersUpdateTimer (GetService ()), m_IntroducersUpdateTimerV6 (GetService ()),
|
||||
m_IsPublished (true), m_IsSyncClockFromPeers (true), m_IsThroughProxy (false)
|
||||
m_IsPublished (true), m_IsSyncClockFromPeers (true), m_PendingTimeOffset (0),
|
||||
m_IsThroughProxy (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -78,6 +79,7 @@ namespace transport
|
|||
if (address->IsV4 ())
|
||||
{
|
||||
found = true;
|
||||
LogPrint (eLogDebug, "SSU2: Opening IPv4 socket at Start");
|
||||
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV4, port));
|
||||
m_ReceiveService.GetService ().post(
|
||||
[this]()
|
||||
|
@ -89,6 +91,7 @@ namespace transport
|
|||
if (address->IsV6 ())
|
||||
{
|
||||
found = true;
|
||||
LogPrint (eLogDebug, "SSU2: Opening IPv6 socket at Start");
|
||||
OpenSocket (boost::asio::ip::udp::endpoint (m_AddressV6, port));
|
||||
m_ReceiveService.GetService ().post(
|
||||
[this]()
|
||||
|
@ -207,6 +210,42 @@ namespace transport
|
|||
return ep.port ();
|
||||
}
|
||||
|
||||
void SSU2Server::AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
if (m_PendingTimeOffset) // one more
|
||||
{
|
||||
if (m_PendingTimeOffsetFrom && from &&
|
||||
m_PendingTimeOffsetFrom->GetIdentHash ().GetLL()[0] != from->GetIdentHash ().GetLL()[0]) // from different routers
|
||||
{
|
||||
if (std::abs (m_PendingTimeOffset - offset) < SSU2_CLOCK_SKEW)
|
||||
{
|
||||
offset = (m_PendingTimeOffset + offset)/2; // average
|
||||
LogPrint (eLogWarning, "SSU2: Clock adjusted by ", offset, " seconds");
|
||||
i2p::util::AdjustTimeOffset (offset);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU2: Time offsets are too different. Clock not adjusted");
|
||||
m_PendingTimeOffset = 0;
|
||||
m_PendingTimeOffsetFrom = nullptr;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU2: Time offsets from same router. Clock not adjusted");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PendingTimeOffset = offset; // first
|
||||
m_PendingTimeOffsetFrom = from;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PendingTimeOffset = 0; // reset
|
||||
m_PendingTimeOffsetFrom = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
boost::asio::ip::udp::socket& SSU2Server::OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint)
|
||||
{
|
||||
boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4;
|
||||
|
@ -219,13 +258,22 @@ namespace transport
|
|||
socket.set_option (boost::asio::ip::v6_only (true));
|
||||
socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU2_SOCKET_RECEIVE_BUFFER_SIZE));
|
||||
socket.set_option (boost::asio::socket_base::send_buffer_size (SSU2_SOCKET_SEND_BUFFER_SIZE));
|
||||
}
|
||||
catch (std::exception& ex )
|
||||
{
|
||||
LogPrint (eLogCritical, "SSU2: Failed to open socket on ", localEndpoint.address (), ": ", ex.what());
|
||||
ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint.address (), ": ", ex.what ());
|
||||
return socket;
|
||||
}
|
||||
try
|
||||
{
|
||||
socket.bind (localEndpoint);
|
||||
LogPrint (eLogInfo, "SSU2: Start listening on ", localEndpoint);
|
||||
}
|
||||
catch (std::exception& ex )
|
||||
{
|
||||
LogPrint (eLogCritical, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
|
||||
ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ());
|
||||
LogPrint (eLogWarning, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what(), ". Actual endpoint is ", socket.local_endpoint ());
|
||||
// we can continue without binding being firewalled
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
@ -243,10 +291,12 @@ namespace transport
|
|||
if (!ecode
|
||||
|| ecode == boost::asio::error::connection_refused
|
||||
|| ecode == boost::asio::error::connection_reset
|
||||
|| ecode == boost::asio::error::network_reset
|
||||
|| ecode == boost::asio::error::network_unreachable
|
||||
|| ecode == boost::asio::error::host_unreachable
|
||||
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|
||||
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|
||||
|| ecode.value() == boost::winapi::WSAENETRESET_ // 10052
|
||||
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|
||||
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|
||||
#endif
|
||||
|
@ -255,8 +305,15 @@ namespace transport
|
|||
// but better to find out which host were sent it and mark that router as unreachable
|
||||
{
|
||||
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
|
||||
if (bytes_transferred < SSU2_MIN_RECEIVED_PACKET_SIZE)
|
||||
{
|
||||
// drop too short packets
|
||||
m_PacketsPool.ReleaseMt (packet);
|
||||
Receive (socket);
|
||||
return;
|
||||
}
|
||||
packet->len = bytes_transferred;
|
||||
|
||||
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = socket.available (ec);
|
||||
if (!ec && moreBytes)
|
||||
|
@ -303,7 +360,7 @@ namespace transport
|
|||
else
|
||||
{
|
||||
auto ep = socket.local_endpoint ();
|
||||
socket.close ();
|
||||
LogPrint (eLogCritical, "SSU2: Reopening socket in HandleReceivedFrom: code ", ecode.value(), ": ", ecode.message ());
|
||||
OpenSocket (ep);
|
||||
Receive (socket);
|
||||
}
|
||||
|
@ -538,7 +595,7 @@ namespace transport
|
|||
else
|
||||
it1->second->ProcessRetry (buf, len);
|
||||
}
|
||||
else if (!i2p::util::net::IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port ())
|
||||
else if (!i2p::transport::transports.IsInReservedRange(senderEndpoint.address ()) && senderEndpoint.port ())
|
||||
{
|
||||
// assume new incoming session
|
||||
auto session = std::make_shared<SSU2Session> (*this);
|
||||
|
@ -558,16 +615,25 @@ namespace transport
|
|||
SendThroughProxy (header, headerLen, nullptr, 0, payload, payloadLen, to);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> bufs
|
||||
{
|
||||
boost::asio::buffer (header, headerLen),
|
||||
boost::asio::buffer (payload, payloadLen)
|
||||
};
|
||||
|
||||
boost::system::error_code ec;
|
||||
if (to.address ().is_v6 ())
|
||||
{
|
||||
if (!m_SocketV6.is_open ()) return;
|
||||
m_SocketV6.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_SocketV4.is_open ()) return;
|
||||
m_SocketV4.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
|
||||
if (!ec)
|
||||
i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen);
|
||||
else
|
||||
|
@ -582,17 +648,25 @@ namespace transport
|
|||
SendThroughProxy (header, headerLen, headerX, headerXLen, payload, payloadLen, to);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<boost::asio::const_buffer> bufs
|
||||
{
|
||||
boost::asio::buffer (header, headerLen),
|
||||
boost::asio::buffer (headerX, headerXLen),
|
||||
boost::asio::buffer (payload, payloadLen)
|
||||
};
|
||||
|
||||
boost::system::error_code ec;
|
||||
if (to.address ().is_v6 ())
|
||||
{
|
||||
if (!m_SocketV6.is_open ()) return;
|
||||
m_SocketV6.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_SocketV4.is_open ()) return;
|
||||
m_SocketV4.send_to (bufs, to, 0, ec);
|
||||
}
|
||||
|
||||
if (!ec)
|
||||
i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen);
|
||||
|
@ -621,7 +695,7 @@ namespace transport
|
|||
bool isValidEndpoint = !address->host.is_unspecified () && address->port;
|
||||
if (isValidEndpoint)
|
||||
{
|
||||
if (i2p::util::net::IsInReservedRange(address->host)) return false;
|
||||
if (i2p::transport::transports.IsInReservedRange(address->host)) return false;
|
||||
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (address->host, address->port));
|
||||
if (s)
|
||||
{
|
||||
|
@ -708,7 +782,7 @@ namespace transport
|
|||
if (addr)
|
||||
{
|
||||
bool isValidEndpoint = !addr->host.is_unspecified () && addr->port &&
|
||||
!i2p::util::net::IsInReservedRange(addr->host);
|
||||
!i2p::transport::transports.IsInReservedRange(addr->host);
|
||||
if (isValidEndpoint)
|
||||
{
|
||||
auto s = FindPendingOutgoingSession (boost::asio::ip::udp::endpoint (addr->host, addr->port));
|
||||
|
@ -962,7 +1036,7 @@ namespace transport
|
|||
void SSU2Server::UpdateIntroducers (bool v4)
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::list<i2p::data::IdentHash> newList;
|
||||
std::list<i2p::data::IdentHash> newList, impliedList;
|
||||
auto& introducers = v4 ? m_Introducers : m_IntroducersV6;
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
for (const auto& it : introducers)
|
||||
|
@ -974,12 +1048,19 @@ namespace transport
|
|||
session = it1->second;
|
||||
excluded.insert (it);
|
||||
}
|
||||
if (session && session->IsEstablished ())
|
||||
if (session && session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ()) // still session with introducer?
|
||||
{
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION)
|
||||
{
|
||||
session->SendKeepAlive ();
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||
newList.push_back (it);
|
||||
if (ts < session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION)
|
||||
newList.push_back (it);
|
||||
else
|
||||
{
|
||||
impliedList.push_back (it); // keep in introducers list, but not publish
|
||||
session = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
session = nullptr;
|
||||
}
|
||||
|
@ -993,20 +1074,18 @@ namespace transport
|
|||
{
|
||||
// bump creation time for previous introducers if no new sessions found
|
||||
LogPrint (eLogDebug, "SSU2: No new introducers found. Trying to reuse existing");
|
||||
impliedList.clear ();
|
||||
for (auto& it : introducers)
|
||||
{
|
||||
auto it1 = m_SessionsByRouterHash.find (it);
|
||||
if (it1 != m_SessionsByRouterHash.end ())
|
||||
{
|
||||
auto session = it1->second;
|
||||
if (session->IsEstablished ())
|
||||
if (session->IsEstablished () && session->GetRelayTag () && session->IsOutgoing ())
|
||||
{
|
||||
session->SetCreationTime (session->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_DURATION);
|
||||
if (std::find (newList.begin (), newList.end (), it) == newList.end ())
|
||||
{
|
||||
newList.push_back (it);
|
||||
sessions.push_back (session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1014,10 +1093,14 @@ namespace transport
|
|||
|
||||
for (const auto& it : sessions)
|
||||
{
|
||||
uint32_t tag = it->GetRelayTag ();
|
||||
uint32_t exp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
||||
if (!tag || ts + SSU2_TO_INTRODUCER_SESSION_DURATION/2 > exp)
|
||||
continue; // don't pick too old session for introducer
|
||||
i2p::data::RouterInfo::Introducer introducer;
|
||||
introducer.iTag = it->GetRelayTag ();
|
||||
introducer.iTag = tag;
|
||||
introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
|
||||
introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
|
||||
introducer.iExp = exp;
|
||||
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
|
||||
if (i2p::context.AddSSU2Introducer (introducer, v4))
|
||||
{
|
||||
|
@ -1051,13 +1134,15 @@ namespace transport
|
|||
}
|
||||
}
|
||||
}
|
||||
introducers.splice (introducers.end (), impliedList); // insert non-published, but non-expired introducers back
|
||||
}
|
||||
|
||||
void SSU2Server::ScheduleIntroducersUpdateTimer ()
|
||||
{
|
||||
if (m_IsPublished)
|
||||
{
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
||||
SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, true));
|
||||
}
|
||||
|
@ -1070,7 +1155,8 @@ namespace transport
|
|||
m_IntroducersUpdateTimer.cancel ();
|
||||
i2p::context.ClearSSU2Introducers (true);
|
||||
m_Introducers.clear ();
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(
|
||||
(SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
||||
m_IntroducersUpdateTimer.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, true));
|
||||
}
|
||||
|
@ -1080,7 +1166,8 @@ namespace transport
|
|||
{
|
||||
if (m_IsPublished)
|
||||
{
|
||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL));
|
||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
||||
SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE));
|
||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, false));
|
||||
}
|
||||
|
@ -1093,7 +1180,8 @@ namespace transport
|
|||
m_IntroducersUpdateTimerV6.cancel ();
|
||||
i2p::context.ClearSSU2Introducers (false);
|
||||
m_IntroducersV6.clear ();
|
||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(SSU2_KEEP_ALIVE_INTERVAL/2));
|
||||
m_IntroducersUpdateTimerV6.expires_from_now (boost::posix_time::seconds(
|
||||
(SSU2_KEEP_ALIVE_INTERVAL + rand () % SSU2_KEEP_ALIVE_INTERVAL_VARIANCE)/2));
|
||||
m_IntroducersUpdateTimerV6.async_wait (std::bind (&SSU2Server::HandleIntroducersUpdateTimer,
|
||||
this, std::placeholders::_1, false));
|
||||
}
|
||||
|
@ -1106,7 +1194,7 @@ namespace transport
|
|||
// timeout expired
|
||||
if (v4)
|
||||
{
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
if (i2p::context.GetTesting ())
|
||||
{
|
||||
// we still don't know if we need introducers
|
||||
ScheduleIntroducersUpdateTimer ();
|
||||
|
@ -1129,7 +1217,7 @@ namespace transport
|
|||
}
|
||||
else
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
||||
if (i2p::context.GetTestingV6 ())
|
||||
{
|
||||
// we still don't know if we need introducers
|
||||
ScheduleIntroducersUpdateTimerV6 ();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -13,6 +13,7 @@
|
|||
#include <mutex>
|
||||
#include "util.h"
|
||||
#include "SSU2Session.h"
|
||||
#include "Socks5.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
|
@ -27,9 +28,11 @@ namespace transport
|
|||
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
const size_t SSU2_MAX_NUM_INTRODUCERS = 3;
|
||||
const size_t SSU2_MIN_RECEIVED_PACKET_SIZE = 40; // 16 byte short header + 8 byte minimum payload + 16 byte MAC
|
||||
const int SSU2_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
||||
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
|
||||
const int SSU2_KEEP_ALIVE_INTERVAL = 30; // in seconds
|
||||
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
|
||||
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
|
||||
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
|
||||
|
||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||
|
@ -65,6 +68,7 @@ namespace transport
|
|||
bool IsSupported (const boost::asio::ip::address& addr) const;
|
||||
uint16_t GetPort (bool v4) const;
|
||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
|
||||
|
||||
void AddSession (std::shared_ptr<SSU2Session> session);
|
||||
void RemoveSession (uint64_t connID);
|
||||
|
@ -160,6 +164,8 @@ namespace transport
|
|||
std::shared_ptr<SSU2Session> m_LastSession;
|
||||
bool m_IsPublished; // if we maintain introducers
|
||||
bool m_IsSyncClockFromPeers;
|
||||
int64_t m_PendingTimeOffset; // during peer test
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
|
||||
|
||||
// proxy
|
||||
bool m_IsThroughProxy;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -114,6 +114,8 @@ namespace transport
|
|||
{
|
||||
if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived)
|
||||
{
|
||||
LogPrint(eLogDebug, "SSU2: Connecting to ", GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ")");
|
||||
ScheduleConnectTimer ();
|
||||
auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint);
|
||||
if (token)
|
||||
|
@ -243,7 +245,7 @@ namespace transport
|
|||
if (IsEstablished ())
|
||||
{
|
||||
uint8_t payload[20];
|
||||
size_t payloadSize = CreatePaddingBlock (payload, 20, 5);
|
||||
size_t payloadSize = CreatePaddingBlock (payload, 20, 8);
|
||||
SendData (payload, payloadSize);
|
||||
}
|
||||
}
|
||||
|
@ -260,8 +262,10 @@ namespace transport
|
|||
m_SentHandshakePacket.reset (nullptr);
|
||||
m_SessionConfirmedFragment.reset (nullptr);
|
||||
m_PathChallenge.reset (nullptr);
|
||||
for (auto& it: m_SendQueue)
|
||||
it->Drop ();
|
||||
m_SendQueue.clear ();
|
||||
m_SendQueueSize = 0;
|
||||
SetSendQueueSize (0);
|
||||
m_SentPackets.clear ();
|
||||
m_IncompleteMessages.clear ();
|
||||
m_RelaySessions.clear ();
|
||||
|
@ -269,7 +273,16 @@ namespace transport
|
|||
m_ReceivedI2NPMsgIDs.clear ();
|
||||
m_Server.RemoveSession (m_SourceConnID);
|
||||
transports.PeerDisconnected (shared_from_this ());
|
||||
LogPrint (eLogDebug, "SSU2: Session terminated");
|
||||
auto remoteIdentity = GetRemoteIdentity ();
|
||||
if (remoteIdentity)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,6 +311,8 @@ namespace transport
|
|||
m_OnEstablished ();
|
||||
m_OnEstablished = nullptr;
|
||||
}
|
||||
LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
|
||||
" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established");
|
||||
}
|
||||
|
||||
void SSU2Session::Done ()
|
||||
|
@ -336,8 +351,12 @@ namespace transport
|
|||
void SSU2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
|
||||
{
|
||||
if (m_State == eSSU2SessionStateTerminated) return;
|
||||
bool isSemiFull = m_SendQueue.size () > SSU2_MAX_OUTGOING_QUEUE_SIZE/2;
|
||||
for (auto it: msgs)
|
||||
m_SendQueue.push_back (std::move (it));
|
||||
if (isSemiFull && it->onDrop)
|
||||
it->Drop (); // drop earlier because we can handle it
|
||||
else
|
||||
m_SendQueue.push_back (std::move (it));
|
||||
SendQueue ();
|
||||
|
||||
if (m_SendQueue.size () > 0) // windows is full
|
||||
|
@ -351,7 +370,7 @@ namespace transport
|
|||
RequestTermination (eSSU2TerminationReasonTimeout);
|
||||
}
|
||||
}
|
||||
m_SendQueueSize = m_SendQueue.size ();
|
||||
SetSendQueueSize (m_SendQueue.size ());
|
||||
}
|
||||
|
||||
bool SSU2Session::SendQueue ()
|
||||
|
@ -366,8 +385,10 @@ namespace transport
|
|||
while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize)
|
||||
{
|
||||
auto msg = m_SendQueue.front ();
|
||||
if (!msg)
|
||||
if (!msg || msg->IsExpired (ts))
|
||||
{
|
||||
// drop null or expired message
|
||||
if (msg) msg->Drop ();
|
||||
m_SendQueue.pop_front ();
|
||||
continue;
|
||||
}
|
||||
|
@ -511,7 +532,7 @@ namespace transport
|
|||
LogPrint (eLogInfo, "SSU2: Packet was not Acked after ", it->second->numResends, " attempts. Terminate session");
|
||||
m_SentPackets.clear ();
|
||||
m_SendQueue.clear ();
|
||||
m_SendQueueSize = 0;
|
||||
SetSendQueueSize (0);
|
||||
RequestTermination (eSSU2TerminationReasonTimeout);
|
||||
return resentPackets.size ();
|
||||
}
|
||||
|
@ -809,6 +830,8 @@ namespace transport
|
|||
m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: SessionCreated AEAD verification failed ");
|
||||
if (GetRemoteIdentity ())
|
||||
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
|
||||
return false;
|
||||
}
|
||||
m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed
|
||||
|
@ -1051,6 +1074,17 @@ namespace transport
|
|||
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
|
||||
return false;
|
||||
}
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
if (ts > ri->GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is too old for ", (ts - ri->GetTimestamp ())/1000LL, " seconds");
|
||||
return false;
|
||||
}
|
||||
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri->GetTimestamp ()) // 2 minutes
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds");
|
||||
return false;
|
||||
}
|
||||
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
|
||||
if (!m_Address || memcmp (S, m_Address->s, 32))
|
||||
{
|
||||
|
@ -1426,8 +1460,7 @@ namespace transport
|
|||
header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4));
|
||||
m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint);
|
||||
m_SendPacketNum++;
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumSentBytes += len + 32;
|
||||
UpdateNumSentBytes (len + 32);
|
||||
return m_SendPacketNum - 1;
|
||||
}
|
||||
|
||||
|
@ -1446,7 +1479,7 @@ namespace transport
|
|||
ResendHandshakePacket (); // assume we receive
|
||||
return;
|
||||
}
|
||||
if (from != m_RemoteEndpoint && !i2p::util::net::IsInReservedRange (from.address ()))
|
||||
if (from != m_RemoteEndpoint && !i2p::transport::transports.IsInReservedRange (from.address ()))
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from);
|
||||
m_RemoteEndpoint = from;
|
||||
|
@ -1468,8 +1501,7 @@ namespace transport
|
|||
LogPrint (eLogWarning, "SSU2: Data AEAD verification failed ");
|
||||
return;
|
||||
}
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumReceivedBytes += len;
|
||||
UpdateNumReceivedBytes (len);
|
||||
if (!packetNum || UpdateReceivePacketNum (packetNum))
|
||||
HandlePayload (payload, payloadSize);
|
||||
}
|
||||
|
@ -1484,7 +1516,7 @@ namespace transport
|
|||
auto size = bufbe16toh (buf + offset);
|
||||
offset += 2;
|
||||
LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size);
|
||||
if (size > len)
|
||||
if (offset + size > len)
|
||||
{
|
||||
LogPrint (eLogError, "SSU2: Unexpected block length ", size);
|
||||
break;
|
||||
|
@ -1530,16 +1562,21 @@ namespace transport
|
|||
break;
|
||||
case eSSU2BlkTermination:
|
||||
{
|
||||
uint8_t rsn = buf[11]; // reason
|
||||
LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn);
|
||||
if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived)
|
||||
RequestTermination (eSSU2TerminationReasonTerminationReceived);
|
||||
else if (m_State != eSSU2SessionStateTerminated)
|
||||
if (size >= 9)
|
||||
{
|
||||
if (m_State == eSSU2SessionStateClosing && rsn == eSSU2TerminationReasonTerminationReceived)
|
||||
m_State = eSSU2SessionStateClosingConfirmed;
|
||||
Done ();
|
||||
uint8_t rsn = buf[offset + 8]; // reason
|
||||
LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn);
|
||||
if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived)
|
||||
RequestTermination (eSSU2TerminationReasonTerminationReceived);
|
||||
else if (m_State != eSSU2SessionStateTerminated)
|
||||
{
|
||||
if (m_State == eSSU2SessionStateClosing && rsn == eSSU2TerminationReasonTerminationReceived)
|
||||
m_State = eSSU2SessionStateClosingConfirmed;
|
||||
Done ();
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "SSU2: Unexpected termination block size ", size);
|
||||
break;
|
||||
}
|
||||
case eSSU2BlkRelayRequest:
|
||||
|
@ -1633,16 +1670,18 @@ namespace transport
|
|||
break;
|
||||
case eSSU2SessionStateSessionCreatedReceived:
|
||||
case eSSU2SessionStateTokenReceived:
|
||||
if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetStatus () == eRouterStatusTesting) ||
|
||||
(m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetStatusV6 () == eRouterStatusTesting))
|
||||
if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetTesting ()) ||
|
||||
(m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetTestingV6 ()))
|
||||
{
|
||||
if (m_Server.IsSyncClockFromPeers ())
|
||||
{
|
||||
if (std::abs (offset) > SSU2_CLOCK_THRESHOLD)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Clock adjusted by ", -offset, " seconds");
|
||||
i2p::util::AdjustTimeOffset (-offset);
|
||||
}
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Time offset ", offset, " from ", m_RemoteEndpoint);
|
||||
m_Server.AdjustTimeOffset (-offset, GetRemoteIdentity ());
|
||||
}
|
||||
else
|
||||
m_Server.AdjustTimeOffset (0, nullptr);
|
||||
}
|
||||
else if (std::abs (offset) > SSU2_CLOCK_SKEW)
|
||||
{
|
||||
|
@ -1722,7 +1761,7 @@ namespace transport
|
|||
if (ExtractEndpoint (buf, len, ep))
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU2: Our external address is ", ep);
|
||||
if (!i2p::util::net::IsInReservedRange (ep.address ()))
|
||||
if (!i2p::transport::transports.IsInReservedRange (ep.address ()))
|
||||
{
|
||||
i2p::context.UpdateAddress (ep.address ());
|
||||
// check our port
|
||||
|
@ -1732,14 +1771,14 @@ namespace transport
|
|||
LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4));
|
||||
if (isV4)
|
||||
{
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
if (i2p::context.GetTesting ())
|
||||
i2p::context.SetError (eRouterErrorSymmetricNAT);
|
||||
else if (m_State == eSSU2SessionStatePeerTest)
|
||||
i2p::context.SetError (eRouterErrorFullConeNAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i2p::context.GetStatusV6 () == eRouterStatusTesting)
|
||||
if (i2p::context.GetTestingV6 ())
|
||||
i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
|
||||
else if (m_State == eSSU2SessionStatePeerTest)
|
||||
i2p::context.SetErrorV6 (eRouterErrorFullConeNAT);
|
||||
|
@ -2212,7 +2251,7 @@ namespace transport
|
|||
if (buf[1] == eSSU2PeerTestCodeAccept)
|
||||
{
|
||||
if (GetRouterStatus () == eRouterStatusUnknown)
|
||||
SetRouterStatus (eRouterStatusTesting);
|
||||
SetTestingState (true);
|
||||
auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
|
||||
if (r && it->second.first)
|
||||
{
|
||||
|
@ -2238,13 +2277,17 @@ namespace transport
|
|||
}
|
||||
else
|
||||
{
|
||||
if (GetRouterStatus () == eRouterStatusTesting)
|
||||
if (GetTestingState ())
|
||||
{
|
||||
SetRouterStatus (eRouterStatusFirewalled);
|
||||
if (m_Address->IsV4 ())
|
||||
m_Server.RescheduleIntroducersUpdateTimer ();
|
||||
else
|
||||
m_Server.RescheduleIntroducersUpdateTimerV6 ();
|
||||
SetTestingState (false);
|
||||
if (GetRouterStatus () != eRouterStatusFirewalled)
|
||||
{
|
||||
SetRouterStatus (eRouterStatusFirewalled);
|
||||
if (m_Address->IsV4 ())
|
||||
m_Server.RescheduleIntroducersUpdateTimer ();
|
||||
else
|
||||
m_Server.RescheduleIntroducersUpdateTimerV6 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()),
|
||||
|
@ -2273,7 +2316,7 @@ namespace transport
|
|||
{
|
||||
LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ",
|
||||
i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3)));
|
||||
if (GetRouterStatus () == eRouterStatusTesting)
|
||||
if (GetTestingState ())
|
||||
SetRouterStatus (eRouterStatusUnknown);
|
||||
it->second.first->Done ();
|
||||
}
|
||||
|
@ -2322,7 +2365,7 @@ namespace transport
|
|||
if (!msg->IsExpired ())
|
||||
{
|
||||
// m_LastActivityTimestamp is updated in ProcessData before
|
||||
if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)m_LastActivityTimestamp).second)
|
||||
if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)GetLastActivityTimestamp ()).second)
|
||||
m_Handler.PutNextMessage (std::move (msg));
|
||||
else
|
||||
LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received");
|
||||
|
@ -2427,6 +2470,31 @@ namespace transport
|
|||
}
|
||||
}
|
||||
|
||||
bool SSU2Session::GetTestingState () const
|
||||
{
|
||||
if (m_Address)
|
||||
{
|
||||
if (m_Address->IsV4 ())
|
||||
return i2p::context.GetTesting ();
|
||||
if (m_Address->IsV6 ())
|
||||
return i2p::context.GetTestingV6 ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SSU2Session::SetTestingState (bool testing) const
|
||||
{
|
||||
if (m_Address)
|
||||
{
|
||||
if (m_Address->IsV4 ())
|
||||
i2p::context.SetTesting (testing);
|
||||
else if (m_Address->IsV6 ())
|
||||
i2p::context.SetTestingV6 (testing);
|
||||
}
|
||||
if (!testing)
|
||||
m_Server.AdjustTimeOffset (0, nullptr); // reset time offset when testing is over
|
||||
}
|
||||
|
||||
size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep)
|
||||
{
|
||||
if (len < 9) return 0;
|
||||
|
@ -2839,7 +2907,7 @@ namespace transport
|
|||
|
||||
void SSU2Session::SendPathResponse (const uint8_t * data, size_t len)
|
||||
{
|
||||
if (len < 8 || len > m_MaxPayloadSize - 3)
|
||||
if (len > m_MaxPayloadSize - 3)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len);
|
||||
return;
|
||||
|
@ -2848,7 +2916,10 @@ namespace transport
|
|||
payload[0] = eSSU2BlkPathResponse;
|
||||
htobe16buf (payload + 1, len);
|
||||
memcpy (payload + 3, data, len);
|
||||
SendData (payload, len + 3);
|
||||
size_t payloadSize = len + 3;
|
||||
if (payloadSize < m_MaxPayloadSize)
|
||||
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, payloadSize < 8 ? 8 : 0);
|
||||
SendData (payload, payloadSize);
|
||||
}
|
||||
|
||||
void SSU2Session::SendPathChallenge ()
|
||||
|
@ -2866,7 +2937,7 @@ namespace transport
|
|||
}
|
||||
len += 3;
|
||||
if (len < m_MaxPayloadSize)
|
||||
len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len);
|
||||
len += CreatePaddingBlock (payload + len, m_MaxPayloadSize - len, len < 8 ? 8 : 0);
|
||||
SendData (payload, len);
|
||||
}
|
||||
|
||||
|
@ -2882,7 +2953,7 @@ namespace transport
|
|||
else
|
||||
++it;
|
||||
}
|
||||
if (m_ReceivedI2NPMsgIDs.size () > SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS || ts > m_LastActivityTimestamp + SSU2_DECAY_INTERVAL)
|
||||
if (m_ReceivedI2NPMsgIDs.size () > SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS || ts > GetLastActivityTimestamp () + SSU2_DECAY_INTERVAL)
|
||||
// decay
|
||||
m_ReceivedI2NPMsgIDs.clear ();
|
||||
else
|
||||
|
@ -2954,7 +3025,7 @@ namespace transport
|
|||
{
|
||||
bool sent = SendQueue (); // if we have something to send
|
||||
if (sent)
|
||||
m_SendQueueSize = m_SendQueue.size ();
|
||||
SetSendQueueSize (m_SendQueue.size ());
|
||||
if (m_IsDataReceived)
|
||||
{
|
||||
if (!sent) SendQuickAck ();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2022-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -25,7 +25,7 @@ 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_TIMEOUT = 165; // in seconds
|
||||
const int SSU2_CLOCK_SKEW = 60; // in seconds
|
||||
const int SSU2_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust
|
||||
const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds
|
||||
|
@ -308,6 +308,8 @@ namespace transport
|
|||
void AdjustMaxPayloadSize ();
|
||||
RouterStatus GetRouterStatus () const;
|
||||
void SetRouterStatus (RouterStatus status) const;
|
||||
bool GetTestingState () const;
|
||||
void SetTestingState(bool testing) const;
|
||||
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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -15,26 +15,35 @@ namespace i2p
|
|||
namespace crypto
|
||||
{
|
||||
#if OPENSSL_EDDSA
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ():
|
||||
m_Pkey (nullptr)
|
||||
{
|
||||
m_MDCtx = EVP_MD_CTX_create ();
|
||||
}
|
||||
|
||||
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
||||
{
|
||||
EVP_MD_CTX_destroy (m_MDCtx);
|
||||
EVP_PKEY_free (m_Pkey);
|
||||
}
|
||||
|
||||
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey)
|
||||
{
|
||||
EVP_PKEY * pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
|
||||
EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, pkey);
|
||||
EVP_PKEY_free (pkey);
|
||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||
m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
|
||||
}
|
||||
|
||||
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len);
|
||||
if (m_Pkey)
|
||||
{
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, m_Pkey);
|
||||
auto ret = EVP_DigestVerify (ctx, signature, 64, buf, len);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "EdDSA verification key is not set");
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -99,41 +108,45 @@ namespace crypto
|
|||
|
||||
#if OPENSSL_EDDSA
|
||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey):
|
||||
m_MDCtx (nullptr), m_Fallback (nullptr)
|
||||
m_Pkey (nullptr), m_Fallback (nullptr)
|
||||
{
|
||||
EVP_PKEY * pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32);
|
||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32);
|
||||
uint8_t publicKey[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
size_t len = EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
EVP_PKEY_get_raw_public_key (pkey, publicKey, &len);
|
||||
EVP_PKEY_get_raw_public_key (m_Pkey, publicKey, &len);
|
||||
if (signingPublicKey && memcmp (publicKey, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
|
||||
{
|
||||
LogPrint (eLogWarning, "EdDSA public key mismatch. Fallback");
|
||||
m_Fallback = new EDDSA25519SignerCompat (signingPrivateKey, signingPublicKey);
|
||||
EVP_PKEY_free (m_Pkey);
|
||||
m_Pkey = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_MDCtx = EVP_MD_CTX_create ();
|
||||
EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, pkey);
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
}
|
||||
|
||||
EDDSA25519Signer::~EDDSA25519Signer ()
|
||||
{
|
||||
if (m_Fallback) delete m_Fallback;
|
||||
EVP_MD_CTX_destroy (m_MDCtx);
|
||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||
}
|
||||
|
||||
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
if (m_Fallback) return m_Fallback->Sign (buf, len, signature);
|
||||
else
|
||||
if (m_Fallback)
|
||||
return m_Fallback->Sign (buf, len, signature);
|
||||
else if (m_Pkey)
|
||||
{
|
||||
|
||||
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
|
||||
size_t l = 64;
|
||||
uint8_t sig[64]; // temporary buffer for signature. openssl issue #7232
|
||||
EVP_DigestSign (m_MDCtx, sig, &l, buf, len);
|
||||
EVP_DigestSignInit (ctx, NULL, NULL, NULL, m_Pkey);
|
||||
if (!EVP_DigestSign (ctx, sig, &l, buf, len))
|
||||
LogPrint (eLogError, "EdDSA signing failed");
|
||||
memcpy (signature, sig, 64);
|
||||
EVP_MD_CTX_destroy (ctx);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "EdDSA signing key is not set");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2021, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -304,7 +304,7 @@ namespace crypto
|
|||
private:
|
||||
|
||||
#if OPENSSL_EDDSA
|
||||
EVP_MD_CTX * m_MDCtx;
|
||||
EVP_PKEY * m_Pkey;
|
||||
#else
|
||||
EDDSAPoint m_PublicKey;
|
||||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
|
@ -341,7 +341,7 @@ namespace crypto
|
|||
|
||||
private:
|
||||
|
||||
EVP_MD_CTX * m_MDCtx;
|
||||
EVP_PKEY * m_Pkey;
|
||||
EDDSA25519SignerCompat * m_Fallback;
|
||||
};
|
||||
#else
|
||||
|
|
210
libi2pd/Socks5.h
Normal file
210
libi2pd/Socks5.h
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 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 SOCKS5_H__
|
||||
#define SOCKS5_H__
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <boost/asio.hpp>
|
||||
#include "I2PEndian.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
// SOCKS5 constants
|
||||
const uint8_t SOCKS5_VER = 0x05;
|
||||
const uint8_t SOCKS5_CMD_CONNECT = 0x01;
|
||||
const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03;
|
||||
const uint8_t SOCKS5_ATYP_IPV4 = 0x01;
|
||||
const uint8_t SOCKS5_ATYP_IPV6 = 0x04;
|
||||
const uint8_t SOCKS5_ATYP_NAME = 0x03;
|
||||
const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10;
|
||||
const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22;
|
||||
|
||||
const uint8_t SOCKS5_REPLY_SUCCESS = 0x00;
|
||||
const uint8_t SOCKS5_REPLY_SERVER_FAILURE = 0x01;
|
||||
const uint8_t SOCKS5_REPLY_CONNECTION_NOT_ALLOWED = 0x02;
|
||||
const uint8_t SOCKS5_REPLY_NETWORK_UNREACHABLE = 0x03;
|
||||
const uint8_t SOCKS5_REPLY_HOST_UNREACHABLE = 0x04;
|
||||
const uint8_t SOCKS5_REPLY_CONNECTION_REFUSED = 0x05;
|
||||
const uint8_t SOCKS5_REPLY_TTL_EXPIRED = 0x06;
|
||||
const uint8_t SOCKS5_REPLY_COMMAND_NOT_SUPPORTED = 0x07;
|
||||
const uint8_t SOCKS5_REPLY_ADDRESS_TYPE_NOT_SUPPORTED = 0x08;
|
||||
|
||||
// SOCKS5 handshake
|
||||
template<typename Socket, typename Handler>
|
||||
void Socks5ReadReply (Socket& s, Handler handler)
|
||||
{
|
||||
auto readbuff = std::make_shared<std::vector<int8_t> >(258); // max possible
|
||||
boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), 5), boost::asio::transfer_all(), // read 4 bytes of header + first byte of address
|
||||
[readbuff, &s, handler](const boost::system::error_code& ec, std::size_t transferred)
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
if ((*readbuff)[1] == SOCKS5_REPLY_SUCCESS)
|
||||
{
|
||||
size_t len = 0;
|
||||
switch ((*readbuff)[3]) // ATYP
|
||||
{
|
||||
case SOCKS5_ATYP_IPV4: len = 3; break; // address length 4 bytes
|
||||
case SOCKS5_ATYP_IPV6: len = 15; break; // address length 16 bytes
|
||||
case SOCKS5_ATYP_NAME: len += (*readbuff)[4]; break; // first byte of address is length
|
||||
default: ;
|
||||
}
|
||||
if (len)
|
||||
{
|
||||
len += 2; // port
|
||||
boost::asio::async_read(s, boost::asio::buffer(readbuff->data (), len), boost::asio::transfer_all(),
|
||||
[readbuff, handler](const boost::system::error_code& ec, std::size_t transferred)
|
||||
{
|
||||
if (!ec)
|
||||
handler (boost::system::error_code ()); // success
|
||||
else
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::connection_aborted));
|
||||
});
|
||||
}
|
||||
else
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::fault)); // unknown address type
|
||||
}
|
||||
else
|
||||
switch ((*readbuff)[1]) // REP
|
||||
{
|
||||
case SOCKS5_REPLY_SERVER_FAILURE:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::access_denied ));
|
||||
break;
|
||||
case SOCKS5_REPLY_CONNECTION_NOT_ALLOWED:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::no_permission));
|
||||
break;
|
||||
case SOCKS5_REPLY_HOST_UNREACHABLE:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::host_unreachable));
|
||||
break;
|
||||
case SOCKS5_REPLY_NETWORK_UNREACHABLE:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::network_unreachable));
|
||||
break;
|
||||
case SOCKS5_REPLY_CONNECTION_REFUSED:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::connection_refused));
|
||||
break;
|
||||
case SOCKS5_REPLY_TTL_EXPIRED:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out));
|
||||
break;
|
||||
case SOCKS5_REPLY_COMMAND_NOT_SUPPORTED:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::operation_not_supported));
|
||||
break;
|
||||
case SOCKS5_REPLY_ADDRESS_TYPE_NOT_SUPPORTED:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::no_protocol_option));
|
||||
break;
|
||||
default:
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::connection_aborted));
|
||||
}
|
||||
}
|
||||
else
|
||||
handler (ec);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Socket, typename Handler>
|
||||
void Socks5Connect (Socket& s, Handler handler, std::shared_ptr<std::vector<uint8_t> > buff, uint16_t port)
|
||||
{
|
||||
if (buff && buff->size () >= 6)
|
||||
{
|
||||
(*buff)[0] = SOCKS5_VER;
|
||||
(*buff)[1] = SOCKS5_CMD_CONNECT;
|
||||
(*buff)[2] = 0x00;
|
||||
htobe16buf(buff->data () + buff->size () - 2, port);
|
||||
boost::asio::async_write(s, boost::asio::buffer(*buff), boost::asio::transfer_all(),
|
||||
[buff, &s, handler](const boost::system::error_code& ec, std::size_t transferred)
|
||||
{
|
||||
(void) transferred;
|
||||
if (!ec)
|
||||
Socks5ReadReply (s, handler);
|
||||
else
|
||||
handler (ec);
|
||||
});
|
||||
}
|
||||
else
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::no_buffer_space));
|
||||
}
|
||||
|
||||
template<typename Socket, typename Handler>
|
||||
void Socks5Connect (Socket& s, const boost::asio::ip::tcp::endpoint& ep, Handler handler)
|
||||
{
|
||||
std::shared_ptr<std::vector<uint8_t> > buff;
|
||||
if(ep.address ().is_v4 ())
|
||||
{
|
||||
buff = std::make_shared<std::vector<uint8_t> >(10);
|
||||
(*buff)[3] = SOCKS5_ATYP_IPV4;
|
||||
auto addrbytes = ep.address ().to_v4().to_bytes();
|
||||
memcpy(buff->data () + 4, addrbytes.data(), 4);
|
||||
}
|
||||
else if (ep.address ().is_v6 ())
|
||||
{
|
||||
buff = std::make_shared<std::vector<uint8_t> >(22);
|
||||
(*buff)[3] = SOCKS5_ATYP_IPV6;
|
||||
auto addrbytes = ep.address ().to_v6().to_bytes();
|
||||
memcpy(buff->data () + 4, addrbytes.data(), 16);
|
||||
}
|
||||
if (buff)
|
||||
Socks5Connect (s, handler, buff, ep.port ());
|
||||
else
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::fault));
|
||||
}
|
||||
|
||||
template<typename Socket, typename Handler>
|
||||
void Socks5Connect (Socket& s, const std::pair<std::string, uint16_t>& ep, Handler handler)
|
||||
{
|
||||
auto& addr = ep.first;
|
||||
if (addr.length () <= 255)
|
||||
{
|
||||
auto buff = std::make_shared<std::vector<uint8_t> >(addr.length () + 7);
|
||||
(*buff)[3] = SOCKS5_ATYP_NAME;
|
||||
(*buff)[4] = addr.length ();
|
||||
memcpy (buff->data () + 5, addr.c_str (), addr.length ());
|
||||
Socks5Connect (s, handler, buff, ep.second);
|
||||
}
|
||||
else
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::name_too_long));
|
||||
}
|
||||
|
||||
|
||||
template<typename Socket, typename Endpoint, typename Handler>
|
||||
void Socks5Handshake (Socket& s, Endpoint ep, Handler handler)
|
||||
{
|
||||
static const uint8_t methodSelection[3] = { SOCKS5_VER, 0x01, 0x00 }; // 1 method, no auth
|
||||
boost::asio::async_write(s, boost::asio::buffer(methodSelection, 3), boost::asio::transfer_all(),
|
||||
[&s, ep, handler] (const boost::system::error_code& ec, std::size_t transferred)
|
||||
{
|
||||
(void) transferred;
|
||||
if (!ec)
|
||||
{
|
||||
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
|
||||
boost::asio::async_read(s, boost::asio::buffer(*readbuff), boost::asio::transfer_all(),
|
||||
[&s, ep, handler, readbuff] (const boost::system::error_code& ec, std::size_t transferred)
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
if (transferred == 2 && (*readbuff)[1] == 0x00) // no auth
|
||||
Socks5Connect (s, ep, handler);
|
||||
else
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::invalid_argument));
|
||||
}
|
||||
else
|
||||
handler (ec);
|
||||
});
|
||||
}
|
||||
else
|
||||
handler (ec);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -19,11 +19,6 @@ namespace i2p
|
|||
{
|
||||
namespace stream
|
||||
{
|
||||
void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
|
||||
{
|
||||
Add (std::make_shared<SendBuffer>(buf, len, handler));
|
||||
}
|
||||
|
||||
void SendBufferQueue::Add (std::shared_ptr<SendBuffer> buf)
|
||||
{
|
||||
if (buf)
|
||||
|
@ -115,10 +110,7 @@ namespace stream
|
|||
|
||||
void Stream::CleanUp ()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SendBufferMutex);
|
||||
m_SendBuffer.CleanUp ();
|
||||
}
|
||||
m_SendBuffer.CleanUp ();
|
||||
while (!m_ReceiveQueue.empty ())
|
||||
{
|
||||
auto packet = m_ReceiveQueue.front ();
|
||||
|
@ -137,6 +129,11 @@ namespace stream
|
|||
|
||||
void Stream::HandleNextPacket (Packet * packet)
|
||||
{
|
||||
if (m_Status == eStreamStatusTerminated)
|
||||
{
|
||||
m_LocalDestination.DeletePacket (packet);
|
||||
return;
|
||||
}
|
||||
m_NumReceivedBytes += packet->GetLength ();
|
||||
if (!m_SendStreamID)
|
||||
{
|
||||
|
@ -167,7 +164,8 @@ namespace stream
|
|||
{
|
||||
// we have received next in sequence message
|
||||
ProcessPacket (packet);
|
||||
|
||||
if (m_Status == eStreamStatusTerminated) return;
|
||||
|
||||
// we should also try stored messages if any
|
||||
for (auto it = m_SavedPackets.begin (); it != m_SavedPackets.end ();)
|
||||
{
|
||||
|
@ -177,6 +175,7 @@ namespace stream
|
|||
m_SavedPackets.erase (it++);
|
||||
|
||||
ProcessPacket (savedPacket);
|
||||
if (m_Status == eStreamStatusTerminated) return;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -187,13 +186,9 @@ namespace stream
|
|||
{
|
||||
if (!m_IsAckSendScheduled)
|
||||
{
|
||||
m_IsAckSendScheduled = true;
|
||||
auto ackTimeout = m_RTT/10;
|
||||
if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay;
|
||||
else if (ackTimeout < MIN_SEND_ACK_TIMEOUT) ackTimeout = MIN_SEND_ACK_TIMEOUT;
|
||||
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(ackTimeout));
|
||||
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
ScheduleAck (ackTimeout);
|
||||
}
|
||||
}
|
||||
else if (packet->IsSYN ())
|
||||
|
@ -216,22 +211,17 @@ namespace stream
|
|||
SavePacket (packet);
|
||||
if (m_LastReceivedSequenceNumber >= 0)
|
||||
{
|
||||
// send NACKs for missing messages ASAP
|
||||
if (m_IsAckSendScheduled)
|
||||
{
|
||||
m_IsAckSendScheduled = false;
|
||||
m_AckSendTimer.cancel ();
|
||||
}
|
||||
SendQuickAck ();
|
||||
}
|
||||
if (!m_IsAckSendScheduled)
|
||||
{
|
||||
// send NACKs for missing messages
|
||||
int ackTimeout = MIN_SEND_ACK_TIMEOUT*m_SavedPackets.size ();
|
||||
if (ackTimeout > m_AckDelay) ackTimeout = m_AckDelay;
|
||||
ScheduleAck (ackTimeout);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// wait for SYN
|
||||
m_IsAckSendScheduled = true;
|
||||
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(SYN_TIMEOUT));
|
||||
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
ScheduleAck (SYN_TIMEOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,14 +522,18 @@ namespace stream
|
|||
|
||||
void Stream::AsyncSend (const uint8_t * buf, size_t len, SendHandler handler)
|
||||
{
|
||||
std::shared_ptr<i2p::stream::SendBuffer> buffer;
|
||||
if (len > 0 && buf)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SendBufferMutex);
|
||||
m_SendBuffer.Add (buf, len, handler);
|
||||
}
|
||||
buffer = std::make_shared<i2p::stream::SendBuffer>(buf, len, handler);
|
||||
else if (handler)
|
||||
handler(boost::system::error_code ());
|
||||
m_Service.post (std::bind (&Stream::SendBuffer, shared_from_this ()));
|
||||
auto s = shared_from_this ();
|
||||
m_Service.post ([s, buffer]()
|
||||
{
|
||||
if (buffer)
|
||||
s->m_SendBuffer.Add (buffer);
|
||||
s->SendBuffer ();
|
||||
});
|
||||
}
|
||||
|
||||
void Stream::SendBuffer ()
|
||||
|
@ -549,91 +543,88 @@ namespace stream
|
|||
|
||||
bool isNoAck = m_LastReceivedSequenceNumber < 0; // first packet
|
||||
std::vector<Packet *> packets;
|
||||
while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0))
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SendBufferMutex);
|
||||
while ((m_Status == eStreamStatusNew) || (IsEstablished () && !m_SendBuffer.IsEmpty () && numMsgs > 0))
|
||||
Packet * p = m_LocalDestination.NewPacket ();
|
||||
uint8_t * packet = p->GetBuffer ();
|
||||
// TODO: implement setters
|
||||
size_t size = 0;
|
||||
htobe32buf (packet + size, m_SendStreamID);
|
||||
size += 4; // sendStreamID
|
||||
htobe32buf (packet + size, m_RecvStreamID);
|
||||
size += 4; // receiveStreamID
|
||||
htobe32buf (packet + size, m_SequenceNumber++);
|
||||
size += 4; // sequenceNum
|
||||
if (isNoAck)
|
||||
htobuf32 (packet + size, 0);
|
||||
else
|
||||
htobe32buf (packet + size, m_LastReceivedSequenceNumber);
|
||||
size += 4; // ack Through
|
||||
if (m_Status == eStreamStatusNew && !m_SendStreamID && m_RemoteIdentity)
|
||||
{
|
||||
Packet * p = m_LocalDestination.NewPacket ();
|
||||
uint8_t * packet = p->GetBuffer ();
|
||||
// TODO: implement setters
|
||||
size_t size = 0;
|
||||
htobe32buf (packet + size, m_SendStreamID);
|
||||
size += 4; // sendStreamID
|
||||
htobe32buf (packet + size, m_RecvStreamID);
|
||||
size += 4; // receiveStreamID
|
||||
htobe32buf (packet + size, m_SequenceNumber++);
|
||||
size += 4; // sequenceNum
|
||||
if (isNoAck)
|
||||
htobuf32 (packet + size, 0);
|
||||
else
|
||||
htobe32buf (packet + size, m_LastReceivedSequenceNumber);
|
||||
size += 4; // ack Through
|
||||
if (m_Status == eStreamStatusNew && !m_SendStreamID && m_RemoteIdentity)
|
||||
{
|
||||
// first SYN packet
|
||||
packet[size] = 8;
|
||||
size++; // NACK count
|
||||
memcpy (packet + size, m_RemoteIdentity->GetIdentHash (), 32);
|
||||
size += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[size] = 0;
|
||||
size++; // NACK count
|
||||
}
|
||||
packet[size] = m_RTO/1000;
|
||||
size++; // resend delay
|
||||
if (m_Status == eStreamStatusNew)
|
||||
{
|
||||
// initial packet
|
||||
m_Status = eStreamStatusOpen;
|
||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
|
||||
m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
|
||||
}
|
||||
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
|
||||
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
|
||||
if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
|
||||
bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
|
||||
if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
|
||||
htobe16buf (packet + size, flags);
|
||||
size += 2; // flags
|
||||
size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
|
||||
size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
|
||||
uint8_t * optionsSize = packet + size; // set options size later
|
||||
size += 2; // options size
|
||||
m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
|
||||
size += identityLen; // from
|
||||
htobe16buf (packet + size, m_MTU);
|
||||
size += 2; // max packet size
|
||||
if (isOfflineSignature)
|
||||
{
|
||||
const auto& offlineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetOfflineSignature ();
|
||||
memcpy (packet + size, offlineSignature.data (), offlineSignature.size ());
|
||||
size += offlineSignature.size (); // offline signature
|
||||
}
|
||||
uint8_t * signature = packet + size; // set it later
|
||||
memset (signature, 0, signatureLen); // zeroes for now
|
||||
size += signatureLen; // signature
|
||||
htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
|
||||
size += m_SendBuffer.Get (packet + size, m_MTU); // payload
|
||||
m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
// follow on packet
|
||||
htobuf16 (packet + size, 0);
|
||||
size += 2; // flags
|
||||
htobuf16 (packet + size, 0); // no options
|
||||
size += 2; // options size
|
||||
size += m_SendBuffer.Get(packet + size, m_MTU); // payload
|
||||
}
|
||||
p->len = size;
|
||||
packets.push_back (p);
|
||||
numMsgs--;
|
||||
// first SYN packet
|
||||
packet[size] = 8;
|
||||
size++; // NACK count
|
||||
memcpy (packet + size, m_RemoteIdentity->GetIdentHash (), 32);
|
||||
size += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
packet[size] = 0;
|
||||
size++; // NACK count
|
||||
}
|
||||
packet[size] = m_RTO/1000;
|
||||
size++; // resend delay
|
||||
if (m_Status == eStreamStatusNew)
|
||||
{
|
||||
// initial packet
|
||||
m_Status = eStreamStatusOpen;
|
||||
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
|
||||
m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
|
||||
}
|
||||
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
|
||||
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
|
||||
if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
|
||||
bool isOfflineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().IsOfflineSignature ();
|
||||
if (isOfflineSignature) flags |= PACKET_FLAG_OFFLINE_SIGNATURE;
|
||||
htobe16buf (packet + size, flags);
|
||||
size += 2; // flags
|
||||
size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
|
||||
size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
|
||||
uint8_t * optionsSize = packet + size; // set options size later
|
||||
size += 2; // options size
|
||||
m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
|
||||
size += identityLen; // from
|
||||
htobe16buf (packet + size, m_MTU);
|
||||
size += 2; // max packet size
|
||||
if (isOfflineSignature)
|
||||
{
|
||||
const auto& offlineSignature = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetOfflineSignature ();
|
||||
memcpy (packet + size, offlineSignature.data (), offlineSignature.size ());
|
||||
size += offlineSignature.size (); // offline signature
|
||||
}
|
||||
uint8_t * signature = packet + size; // set it later
|
||||
memset (signature, 0, signatureLen); // zeroes for now
|
||||
size += signatureLen; // signature
|
||||
htobe16buf (optionsSize, packet + size - 2 - optionsSize); // actual options size
|
||||
size += m_SendBuffer.Get (packet + size, m_MTU); // payload
|
||||
m_LocalDestination.GetOwner ()->Sign (packet, size, signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
// follow on packet
|
||||
htobuf16 (packet + size, 0);
|
||||
size += 2; // flags
|
||||
htobuf16 (packet + size, 0); // no options
|
||||
size += 2; // options size
|
||||
size += m_SendBuffer.Get(packet + size, m_MTU); // payload
|
||||
}
|
||||
p->len = size;
|
||||
packets.push_back (p);
|
||||
numMsgs--;
|
||||
}
|
||||
if (packets.size () > 0)
|
||||
{
|
||||
|
@ -1036,6 +1027,17 @@ namespace stream
|
|||
}
|
||||
}
|
||||
|
||||
void Stream::ScheduleAck (int timeout)
|
||||
{
|
||||
if (m_IsAckSendScheduled)
|
||||
m_AckSendTimer.cancel ();
|
||||
m_IsAckSendScheduled = true;
|
||||
if (timeout < MIN_SEND_ACK_TIMEOUT) timeout = MIN_SEND_ACK_TIMEOUT;
|
||||
m_AckSendTimer.expires_from_now (boost::posix_time::milliseconds(timeout));
|
||||
m_AckSendTimer.async_wait (std::bind (&Stream::HandleAckSendTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void Stream::HandleAckSendTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (m_IsAckSendScheduled)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -135,7 +135,6 @@ namespace stream
|
|||
SendBufferQueue (): m_Size (0) {};
|
||||
~SendBufferQueue () { CleanUp (); };
|
||||
|
||||
void Add (const uint8_t * buf, size_t len, SendHandler handler);
|
||||
void Add (std::shared_ptr<SendBuffer> buf);
|
||||
size_t Get (uint8_t * buf, size_t len);
|
||||
size_t GetSize () const { return m_Size; };
|
||||
|
@ -228,6 +227,7 @@ namespace stream
|
|||
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleAck (int timeout);
|
||||
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
private:
|
||||
|
@ -251,7 +251,6 @@ namespace stream
|
|||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||
uint16_t m_Port;
|
||||
|
||||
std::mutex m_SendBufferMutex;
|
||||
SendBufferQueue m_SendBuffer;
|
||||
int m_WindowSize, m_RTT, m_RTO, m_AckDelay;
|
||||
uint64_t m_LastWindowSizeIncreaseTime;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2023, The PurpleI2P Project
|
||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
||||
*
|
||||
* This file is part of Purple i2pd project and licensed under BSD3
|
||||
*
|
||||
|
@ -71,15 +71,17 @@ namespace transport
|
|||
|
||||
const int64_t TRANSPORT_SESSION_SLOWNESS_THRESHOLD = 500; // in milliseconds
|
||||
const int64_t TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL = 10000; // in milliseconds
|
||||
const uint64_t TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL = 5; // in seconds
|
||||
class TransportSession
|
||||
{
|
||||
public:
|
||||
|
||||
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
|
||||
m_NumSentBytes (0), m_NumReceivedBytes (0), m_SendQueueSize (0),
|
||||
m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
|
||||
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()),
|
||||
m_HandshakeInterval (0)
|
||||
m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_HandshakeInterval (0),
|
||||
m_SendQueueSize (0), m_NumSentBytes (0), m_NumReceivedBytes (0),
|
||||
m_LastBandWidthUpdateNumSentBytes (0), m_LastBandWidthUpdateNumReceivedBytes (0),
|
||||
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()),
|
||||
m_LastBandwidthUpdateTimestamp (m_LastActivityTimestamp), m_InBandwidth (0), m_OutBandwidth (0)
|
||||
{
|
||||
if (router)
|
||||
m_RemoteIdentity = router->GetRouterIdentity ();
|
||||
|
@ -103,11 +105,29 @@ namespace transport
|
|||
}
|
||||
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
void UpdateNumSentBytes (size_t len)
|
||||
{
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumSentBytes += len;
|
||||
UpdateBandwidth ();
|
||||
}
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
void UpdateNumReceivedBytes (size_t len)
|
||||
{
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
m_NumReceivedBytes += len;
|
||||
UpdateBandwidth ();
|
||||
}
|
||||
size_t GetSendQueueSize () const { return m_SendQueueSize; };
|
||||
void SetSendQueueSize (size_t s) { m_SendQueueSize = s; };
|
||||
bool IsOutgoing () const { return m_IsOutgoing; };
|
||||
bool IsSlow () const { return m_HandshakeInterval > TRANSPORT_SESSION_SLOWNESS_THRESHOLD &&
|
||||
m_HandshakeInterval < TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL; };
|
||||
bool IsBandwidthExceeded (bool isHighBandwidth) const
|
||||
{
|
||||
auto limit = isHighBandwidth ? i2p::data::HIGH_BANDWIDTH_LIMIT*1024 : i2p::data::LOW_BANDWIDTH_LIMIT*1024; // convert to bytes
|
||||
return std::max (m_InBandwidth, m_OutBandwidth) > limit;
|
||||
}
|
||||
|
||||
int GetTerminationTimeout () const { return m_TerminationTimeout; };
|
||||
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
|
||||
|
@ -120,31 +140,53 @@ namespace transport
|
|||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
|
||||
|
||||
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
||||
void SetLastActivityTimestamp (uint64_t ts) { m_LastActivityTimestamp = ts; };
|
||||
|
||||
virtual uint32_t GetRelayTag () const { return 0; };
|
||||
virtual void SendLocalRouterInfo (bool update = false) { SendI2NPMessages ({ CreateDatabaseStoreMsg () }); };
|
||||
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
||||
virtual bool IsEstablished () const = 0;
|
||||
|
||||
private:
|
||||
|
||||
void UpdateBandwidth ()
|
||||
{
|
||||
int64_t interval = m_LastActivityTimestamp - m_LastBandwidthUpdateTimestamp;
|
||||
if (interval < 0 || interval > 60*10) // 10 minutes
|
||||
{
|
||||
// clock was adjusted, copy new values
|
||||
m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes;
|
||||
m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes;
|
||||
m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp;
|
||||
return;
|
||||
}
|
||||
if ((uint64_t)interval > TRANSPORT_SESSION_BANDWIDTH_UPDATE_MIN_INTERVAL)
|
||||
{
|
||||
m_OutBandwidth = (m_NumSentBytes - m_LastBandWidthUpdateNumSentBytes)/interval;
|
||||
m_LastBandWidthUpdateNumSentBytes = m_NumSentBytes;
|
||||
m_InBandwidth = (m_NumReceivedBytes - m_LastBandWidthUpdateNumReceivedBytes)/interval;
|
||||
m_LastBandWidthUpdateNumReceivedBytes = m_NumReceivedBytes;
|
||||
m_LastBandwidthUpdateTimestamp = m_LastActivityTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||
mutable std::mutex m_RemoteIdentityMutex;
|
||||
size_t m_NumSentBytes, m_NumReceivedBytes, m_SendQueueSize;
|
||||
bool m_IsOutgoing;
|
||||
int m_TerminationTimeout;
|
||||
uint64_t m_LastActivityTimestamp;
|
||||
uint32_t m_CreationTime; // seconds since epoch
|
||||
int64_t m_HandshakeInterval; // in milliseconds between SessionRequest->SessionCreated or SessionCreated->SessionConfirmed
|
||||
};
|
||||
|
||||
// SOCKS5 proxy
|
||||
const uint8_t SOCKS5_VER = 0x05;
|
||||
const uint8_t SOCKS5_CMD_CONNECT = 0x01;
|
||||
const uint8_t SOCKS5_CMD_UDP_ASSOCIATE = 0x03;
|
||||
const uint8_t SOCKS5_ATYP_IPV4 = 0x01;
|
||||
const uint8_t SOCKS5_ATYP_IPV6 = 0x04;
|
||||
const size_t SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE = 10;
|
||||
const size_t SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE = 22;
|
||||
private:
|
||||
|
||||
size_t m_SendQueueSize, m_NumSentBytes, m_NumReceivedBytes,
|
||||
m_LastBandWidthUpdateNumSentBytes, m_LastBandWidthUpdateNumReceivedBytes;
|
||||
uint64_t m_LastActivityTimestamp, m_LastBandwidthUpdateTimestamp;
|
||||
uint32_t m_InBandwidth, m_OutBandwidth;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue