Browse Source

Merge pull request #1911 from PurpleI2P/openssl

recents changes
pull/1939/head
orignal 2 years ago committed by GitHub
parent
commit
245e6b6efd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .editorconfig
  2. 25
      .github/workflows/build-deb.yml
  3. 8
      .github/workflows/build-freebsd.yml
  4. 7
      .github/workflows/build-osx.yml
  5. 52
      .github/workflows/build-windows-msvc.yml
  6. 86
      .github/workflows/build-windows.yml
  7. 25
      .github/workflows/build.yml
  8. 7
      .github/workflows/docker.yml
  9. 15
      ChangeLog
  10. 12
      Makefile
  11. 3
      Makefile.bsd
  12. 5
      Makefile.linux
  13. 16
      Makefile.mingw
  14. 13
      Makefile.osx
  15. 4
      Win32/DaemonWin32.cpp
  16. 4
      Win32/Resource.rc2
  17. 9
      Win32/Win32App.cpp
  18. 2
      Win32/Win32App.h
  19. 13
      Win32/Win32NetState.cpp
  20. 7
      Win32/Win32NetState.h
  21. 20
      Win32/Win32Service.cpp
  22. 11
      build/.gitignore
  23. 185
      build/CMakeLists.txt
  24. 2
      build/cmake_modules/TargetArch.cmake
  25. 16
      build/cmake_modules/Version.cmake
  26. 34
      contrib/certificates/reseed/arnavbhatt288_at_mail.i2p.crt
  27. 50
      contrib/certificates/reseed/igor_at_novg.net.crt
  28. 8
      contrib/dinit/i2pd
  29. 5
      contrib/i2pd.conf
  30. 5
      contrib/rpm/i2pd-git.spec
  31. 7
      contrib/rpm/i2pd.spec
  32. 16
      daemon/Daemon.cpp
  33. 8
      daemon/HTTPServer.cpp
  34. 2
      daemon/UnixDaemon.cpp
  35. 6
      debian/changelog
  36. 14
      i18n/German.cpp
  37. 6
      i18n/I18N.h
  38. 10
      i18n/Italian.cpp
  39. 8
      i18n/Portuguese.cpp
  40. 8
      libi2pd/Config.cpp
  41. 4
      libi2pd/Datagram.cpp
  42. 20
      libi2pd/Destination.cpp
  43. 4
      libi2pd/ECIESX25519AEADRatchetSession.cpp
  44. 4
      libi2pd/Ed25519.cpp
  45. 4
      libi2pd/Family.cpp
  46. 6
      libi2pd/Garlic.cpp
  47. 2
      libi2pd/Gzip.cpp
  48. 28
      libi2pd/HTTP.cpp
  49. 3
      libi2pd/HTTP.h
  50. 39
      libi2pd/I2NPProtocol.cpp
  51. 8
      libi2pd/I2NPProtocol.h
  52. 18
      libi2pd/I2PEndian.h
  53. 46
      libi2pd/Identity.cpp
  54. 11
      libi2pd/Identity.h
  55. 14
      libi2pd/KadDHT.cpp
  56. 12
      libi2pd/KadDHT.h
  57. 6
      libi2pd/LeaseSet.cpp
  58. 10
      libi2pd/Log.cpp
  59. 1
      libi2pd/Log.h
  60. 10
      libi2pd/NTCP2.cpp
  61. 206
      libi2pd/NetDb.cpp
  62. 19
      libi2pd/NetDb.hpp
  63. 4
      libi2pd/NetDbRequests.cpp
  64. 73
      libi2pd/Reseed.cpp
  65. 229
      libi2pd/RouterContext.cpp
  66. 45
      libi2pd/RouterContext.h
  67. 92
      libi2pd/RouterInfo.cpp
  68. 26
      libi2pd/RouterInfo.h
  69. 9
      libi2pd/SSU2.cpp
  70. 30
      libi2pd/SSU2Session.cpp
  71. 4
      libi2pd/SSU2Session.h
  72. 37
      libi2pd/Streaming.cpp
  73. 5
      libi2pd/Streaming.h
  74. 26
      libi2pd/TransitTunnel.h
  75. 8
      libi2pd/TransportSession.h
  76. 13
      libi2pd/Transports.cpp
  77. 10
      libi2pd/Transports.h
  78. 28
      libi2pd/Tunnel.cpp
  79. 32
      libi2pd/Tunnel.h
  80. 6
      libi2pd/TunnelEndpoint.cpp
  81. 2
      libi2pd/TunnelPool.cpp
  82. 6
      libi2pd/api.cpp
  83. 102
      libi2pd/util.cpp
  84. 10
      libi2pd/version.h
  85. 2
      libi2pd_client/AddressBook.cpp
  86. 29
      libi2pd_client/ClientContext.cpp
  87. 2
      libi2pd_client/HTTPProxy.cpp
  88. 4
      libi2pd_client/I2CP.cpp
  89. 7
      libi2pd_client/I2PTunnel.cpp
  90. 6
      libi2pd_client/SAM.cpp
  91. 2
      libi2pd_client/SAM.h

4
.editorconfig

@ -30,3 +30,7 @@ indent_size = 4
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.yml]
indent_style = space
indent_size = 2

25
.github/workflows/build-deb.yml

@ -6,27 +6,34 @@ jobs:
build: build:
name: ${{ matrix.dist }} name: ${{ matrix.dist }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false
matrix: matrix:
dist: ['buster', 'bullseye', 'bookworm'] dist: ['buster', 'bullseye', 'bookworm']
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: change debian changelog
run: | - name: Build package
sudo apt-get update uses: jtdor/build-deb-action@v1
sudo apt-get install devscripts
debchange -v "`git describe --tags`-${{ matrix.dist }}" -b -M --distribution ${{ matrix.dist }} "trunk build"
- uses: jtdor/build-deb-action@v1
with: with:
docker-image: debian:${{ matrix.dist }}-slim docker-image: debian:${{ matrix.dist }}-slim
buildpackage-opts: --build=binary --no-sign buildpackage-opts: --build=binary --no-sign
- uses: actions/upload-artifact@v3 before-build-hook: debchange --controlmaint --local "+${{ github.sha }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
extra-build-deps: devscripts git
- name: Upload package
uses: actions/upload-artifact@v3
with: with:
name: i2pd_${{ matrix.dist }} name: i2pd_${{ matrix.dist }}
path: debian/artifacts/i2pd_*.deb path: debian/artifacts/i2pd_*.deb
- uses: actions/upload-artifact@v3
- name: Upload debugging symbols
uses: actions/upload-artifact@v3
with: with:
name: i2pd-dbgsym_${{ matrix.dist }} name: i2pd-dbgsym_${{ matrix.dist }}
path: debian/artifacts/i2pd-dbgsym_*.deb path: debian/artifacts/i2pd-dbgsym_*.deb

8
.github/workflows/build-freebsd.yml

@ -6,8 +6,11 @@ jobs:
build: build:
runs-on: macos-12 runs-on: macos-12
name: with UPnP name: with UPnP
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
- name: Test in FreeBSD - name: Test in FreeBSD
id: test id: test
uses: vmactions/freebsd-vm@v0.3.0 uses: vmactions/freebsd-vm@v0.3.0
@ -21,8 +24,9 @@ jobs:
cd build cd build
cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release . cmake -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
gmake -j2 gmake -j2
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: i2pd-freebsd name: i2pd-freebsd
path: build/i2pd path: build/i2pd

7
.github/workflows/build-osx.yml

@ -6,16 +6,21 @@ jobs:
build: build:
name: With USE_UPNP=${{ matrix.with_upnp }} name: With USE_UPNP=${{ matrix.with_upnp }}
runs-on: macOS-latest runs-on: macOS-latest
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
with_upnp: ['yes', 'no'] with_upnp: ['yes', 'no']
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew update brew update
brew install boost miniupnpc openssl@1.1 brew install boost miniupnpc openssl@1.1
- name: build application - name: build application
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3 run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3

52
.github/workflows/build-windows-msvc.yml

@ -0,0 +1,52 @@
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.*

86
.github/workflows/build-windows.yml

@ -8,44 +8,106 @@ defaults:
jobs: jobs:
build: build:
name: Building using ${{ matrix.arch }} toolchain name: ${{ matrix.arch }}
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
fail-fast: true fail-fast: false
matrix: matrix:
include: [ include: [
{ msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt }, { msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt, compiler: gcc },
{ msystem: MINGW64, arch: x86_64, arch_short: x64 }, { msystem: CLANG64, arch: clang-x86_64, arch_short: x64-clang, compiler: clang },
{ msystem: MINGW32, arch: i686, arch_short: x86 } { msystem: MINGW64, arch: x86_64, arch_short: x64, compiler: gcc },
{ msystem: MINGW32, arch: i686, arch_short: x86, compiler: gcc }
] ]
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup MSYS2 - name: Setup MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
msystem: ${{ matrix.msystem }} msystem: ${{ matrix.msystem }}
install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc install: base-devel git mingw-w64-${{ matrix.arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
update: true update: true
- name: Install additional clang packages
if: ${{ matrix.msystem == 'CLANG64' }}
run: pacman --noconfirm -S mingw-w64-${{ matrix.arch }}-gcc-compat
- name: Build application - name: Build application
run: | run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3 make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: i2pd-${{ matrix.arch_short }}.exe name: i2pd-${{ matrix.arch_short }}.exe
path: i2pd.exe path: i2pd.exe
build-cmake:
name: CMake ${{ matrix.arch }}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include: [
{ msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt, compiler: gcc },
{ msystem: CLANG64, arch: clang-x86_64, arch_short: x64-clang, compiler: clang },
{ msystem: MINGW64, arch: x86_64, arch_short: x64, compiler: gcc },
{ msystem: MINGW32, arch: i686, arch_short: x86, compiler: gcc }
]
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
install: base-devel git mingw-w64-${{ matrix.arch }}-cmake mingw-w64-${{ matrix.arch }}-ninja mingw-w64-${{ matrix.arch }}-${{ matrix.compiler }} mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
update: true
- name: Build application
run: |
cd build
cmake -DWITH_GIT_VERSION=ON -DWITH_STATIC=ON -DWITH_UPNP=ON -DCMAKE_BUILD_TYPE=Release .
cmake --build . -- -j3
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: i2pd-cmake-${{ matrix.arch_short }}.exe
path: build/i2pd.exe
build-xp: build-xp:
name: Building for Windows XP name: XP
runs-on: windows-latest runs-on: windows-latest
strategy:
fail-fast: false
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup MSYS2 - name: Setup MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
msystem: MINGW32 msystem: MINGW32
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
update: true update: true
- name: Build WinXP-capable CRT packages - name: Build WinXP-capable CRT packages
run: | run: |
git clone https://github.com/msys2/MINGW-packages git clone https://github.com/msys2/MINGW-packages
@ -64,12 +126,14 @@ jobs:
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
popd popd
popd popd
- name: Build application - name: Build application
run: | run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3 make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: i2pd-xp.exe name: i2pd-xp.exe
path: i2pd.exe path: i2pd.exe

25
.github/workflows/build.yml

@ -5,34 +5,43 @@ on: [push, pull_request]
jobs: jobs:
build-make: build-make:
name: Make with USE_UPNP=${{ matrix.with_upnp }} name: Make with USE_UPNP=${{ matrix.with_upnp }}
runs-on: ubuntu-18.04 runs-on: ubuntu-latest
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
with_upnp: ['yes', 'no'] with_upnp: ['yes', 'no']
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |
sudo add-apt-repository ppa:mhier/libboost-latest
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application - name: build application
run: make USE_UPNP=${{ matrix.with_upnp }} -j3 run: make USE_UPNP=${{ matrix.with_upnp }} -j3
build-cmake: build-cmake:
name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }} name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }}
runs-on: ubuntu-18.04 runs-on: ubuntu-latest
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
with_upnp: ['ON', 'OFF'] with_upnp: ['ON', 'OFF']
steps: steps:
- uses: actions/checkout@v2 - name: Checkout
uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |
sudo add-apt-repository ppa:mhier/libboost-latest
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential cmake libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev sudo apt-get install build-essential cmake libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application - name: build application
run: | run: |
cd build cd build

7
.github/workflows/docker.yml

@ -10,6 +10,7 @@ on:
jobs: jobs:
build: build:
name: Building container for ${{ matrix.platform }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
packages: write packages: write
@ -26,7 +27,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
@ -60,7 +61,9 @@ jobs:
provenance: false provenance: false
push: push:
name: Pushing merged manifest
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
packages: write packages: write
contents: read contents: read
@ -69,7 +72,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2

15
ChangeLog

@ -1,6 +1,21 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.47.0] - 2023-03-11
### Added
- Congestion caps
- SAM UDP port parameter
- Support domain addresses for yggdrasil reseeds
### Changed
- DHT for floodfills instead plain list
- Process router's messages in separate thread
- Don't publish non-reachable router
- Send and check target destination in first streaming SYN packet
- Reseeds list
### Fixed
- Memory leak in windows network state detection
- Reseed attempts from invalid address
## [2.46.1] - 2023-02-20 ## [2.46.1] - 2023-02-20
### Fixed ### Fixed
- Race condition while getting router's peer profile - Race condition while getting router's peer profile

12
Makefile

@ -71,13 +71,15 @@ else # not supported
$(error Not supported platform) $(error Not supported platform)
endif endif
INCFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR)
DEFINES += -DOPENSSL_SUPPRESS_DEPRECATED
NEEDED_CXXFLAGS += -MMD -MP
ifeq ($(USE_GIT_VERSION),yes) ifeq ($(USE_GIT_VERSION),yes)
GIT_VERSION := $(shell git describe --tags) GIT_VERSION := $(shell git describe --tags)
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\" DEFINES += -DGITVER=$(GIT_VERSION)
endif endif
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) -DOPENSSL_SUPPRESS_DEPRECATED
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
LANG_OBJS += $(patsubst %.cpp,obj/%.o,$(LANG_SRC)) LANG_OBJS += $(patsubst %.cpp,obj/%.o,$(LANG_SRC))
@ -110,13 +112,13 @@ wrapper: api_client $(SHLIB_WRAP) $(ARLIB_WRAP)
## custom FLAGS to work at build-time. ## custom FLAGS to work at build-time.
obj/%.o: %.cpp | mk_obj_dir obj/%.o: %.cpp | mk_obj_dir
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(DEFINES) $(INCFLAGS) -c -o $@ $<
# '-' is 'ignore if missing' on first run # '-' is 'ignore if missing' on first run
-include $(DEPS) -include $(DEPS)
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) $(CXX) -o $@ $(DEFINES) $(LDFLAGS) $^ $(LDLIBS)
$(SHLIB): $(LIB_OBJS) $(SHLIB): $(LIB_OBJS)
ifneq ($(USE_STATIC),yes) ifneq ($(USE_STATIC),yes)

3
Makefile.bsd

@ -6,7 +6,8 @@ CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misl
## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove ## (e.g. -fstack-protector-strong -Wformat -Werror=format-security), we do not want to remove
## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## -std=c++11. If you want to remove this variable please do so in a way that allows setting
## custom FLAGS to work at build-time. ## custom FLAGS to work at build-time.
NEEDED_CXXFLAGS = -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 NEEDED_CXXFLAGS = -std=c++11
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1
INCFLAGS = -I/usr/include/ -I/usr/local/include/ INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib LDFLAGS = ${LD_DEBUG} -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread

5
Makefile.linux

@ -58,12 +58,13 @@ endif
# UPNP Support (miniupnpc 1.5 and higher) # UPNP Support (miniupnpc 1.5 and higher)
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
NEEDED_CXXFLAGS += -DUSE_UPNP DEFINES += -DUSE_UPNP
endif endif
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
NEEDED_CXXFLAGS += -D__AES__ -maes NEEDED_CXXFLAGS += -maes
DEFINES += -D__AES__
endif endif
endif endif

16
Makefile.mingw

@ -4,17 +4,18 @@ USE_WIN32_APP := yes
WINDRES = windres WINDRES = windres
CXXFLAGS := $(CXX_DEBUG) -fPIC -msse CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32 INCFLAGS := -I$(DAEMON_SRC_DIR) -IWin32
LDFLAGS := ${LD_DEBUG} -static LDFLAGS := ${LD_DEBUG} -static
NEEDED_CXXFLAGS += -std=c++17 -DWIN32_LEAN_AND_MEAN NEEDED_CXXFLAGS += -std=c++17
DEFINES += -DWIN32_LEAN_AND_MEAN
# Boost libraries suffix # Boost libraries suffix
BOOST_SUFFIX = -mt BOOST_SUFFIX = -mt
# UPNP Support # UPNP Support
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB DEFINES += -DUSE_UPNP -DMINIUPNP_STATICLIB
LDLIBS = -lminiupnpc LDLIBS = -lminiupnpc
endif endif
@ -35,18 +36,19 @@ LDLIBS += \
-lpthread -lpthread
ifeq ($(USE_WIN32_APP), yes) ifeq ($(USE_WIN32_APP), yes)
NEEDED_CXXFLAGS += -DWIN32_APP DEFINES += -DWIN32_APP
LDFLAGS += -mwindows LDFLAGS += -mwindows
DAEMON_RC += Win32/Resource.rc DAEMON_RC += Win32/Resource.rc
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
endif endif
ifeq ($(USE_WINXP_FLAGS), yes) ifeq ($(USE_WINXP_FLAGS), yes)
NEEDED_CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 DEFINES += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
endif endif
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
NEEDED_CXXFLAGS += -D__AES__ -maes NEEDED_CXXFLAGS += -maes
DEFINES += -D__AES__
endif endif
ifeq ($(USE_ASLR),yes) ifeq ($(USE_ASLR),yes)
@ -54,4 +56,4 @@ ifeq ($(USE_ASLR),yes)
endif endif
obj/%.o : %.rc | mk_obj_dir obj/%.o : %.rc | mk_obj_dir
$(WINDRES) -i $< -o $@ $(WINDRES) $(DEFINES) $(INCFLAGS) --preprocessor-arg=-MMD --preprocessor-arg=-MP --preprocessor-arg=-MF$@.d -i $< -o $@

13
Makefile.osx vendored

@ -1,6 +1,7 @@
CXX = clang++ CXX = clang++
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11
INCFLAGS = -I/usr/local/include INCFLAGS = -I/usr/local/include
DEFINES := -DMAC_OSX
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
LDFLAGS += -Wl,-dead_strip LDFLAGS += -Wl,-dead_strip
LDFLAGS += -Wl,-dead_strip_dylibs LDFLAGS += -Wl,-dead_strip_dylibs
@ -14,7 +15,7 @@ endif
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
LDFLAGS += -ldl LDFLAGS += -ldl
CXXFLAGS += -DUSE_UPNP DEFINES += -DUSE_UPNP
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)
LDLIBS += /usr/local/lib/libminiupnpc.a LDLIBS += /usr/local/lib/libminiupnpc.a
else else
@ -22,8 +23,12 @@ ifeq ($(USE_UPNP),yes)
endif endif
endif endif
ifeq ($(USE_AESNI),yes) OSARCH = $(shell uname -p)
ifneq ($(OSARCH),powerpc)
ifeq ($(USE_AESNI),yes)
CXXFLAGS += -D__AES__ -maes CXXFLAGS += -D__AES__ -maes
else else
CXXFLAGS += -msse CXXFLAGS += -msse
endif
endif endif

4
Win32/DaemonWin32.cpp

@ -47,7 +47,7 @@ namespace util
I2PService service((PSTR)SERVICE_NAME); I2PService service((PSTR)SERVICE_NAME);
if (!I2PService::Run(service)) if (!I2PService::Run(service))
{ {
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); LogPrint(eLogCritical, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
return false; return false;
} }
return false; return false;
@ -64,7 +64,7 @@ namespace util
//setlocale(LC_ALL, "Russian"); //setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C"); setlocale(LC_TIME, "C");
#ifdef WIN32_APP #ifdef WIN32_APP
if (!i2p::win32::StartWin32App ()) return false; if (!i2p::win32::StartWin32App (isDaemon)) return false;
#endif #endif
bool ret = Daemon_Singleton::start(); bool ret = Daemon_Singleton::start();
if (ret && i2p::log::Logger().GetLogType() == eLogFile) if (ret && i2p::log::Logger().GetLogType() == eLogFile)

4
Win32/Resource.rc2

@ -2,7 +2,7 @@
#error this file is not editable by Microsoft Visual C++ #error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED #endif //APSTUDIO_INVOKED
#include "../libi2pd/version.h" #include "version.h"
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH FILEVERSION I2PD_VERSION_MAJOR,I2PD_VERSION_MINOR,I2PD_VERSION_MICRO,I2PD_VERSION_PATCH
@ -25,7 +25,7 @@ BEGIN
VALUE "FileDescription", "C++ I2P daemon" VALUE "FileDescription", "C++ I2P daemon"
VALUE "FileVersion", I2PD_VERSION VALUE "FileVersion", I2PD_VERSION
VALUE "InternalName", CODENAME VALUE "InternalName", CODENAME
VALUE "LegalCopyright", "Copyright (C) 2013-2022, The PurpleI2P Project" VALUE "LegalCopyright", "Copyright (C) 2013-2023, The PurpleI2P Project"
VALUE "OriginalFilename", "i2pd" VALUE "OriginalFilename", "i2pd"
VALUE "ProductName", "Purple I2P" VALUE "ProductName", "Purple I2P"
VALUE "ProductVersion", I2P_VERSION VALUE "ProductVersion", I2P_VERSION

9
Win32/Win32App.cpp

@ -45,6 +45,7 @@ namespace i2p
namespace win32 namespace win32
{ {
DWORD g_GracefulShutdownEndtime = 0; DWORD g_GracefulShutdownEndtime = 0;
bool g_isWinService;
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem) static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
{ {
@ -416,8 +417,9 @@ namespace win32
return DefWindowProc( hWnd, uMsg, wParam, lParam); return DefWindowProc( hWnd, uMsg, wParam, lParam);
} }
bool StartWin32App () bool StartWin32App (bool isWinService)
{ {
g_isWinService = isWinService;
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"))) if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
{ {
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK); MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
@ -446,6 +448,8 @@ namespace win32
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
return false; return false;
} }
// COM requires message loop to work, which is not implemented in service mode
if (!g_isWinService)
SubscribeToEvents(); SubscribeToEvents();
return true; return true;
} }
@ -466,7 +470,8 @@ namespace win32
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd) if (hWnd)
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0); PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0);
// UnSubscribeFromEvents(); // TODO: understand why unsubscribing crashes app else if(!g_isWinService)
UnSubscribeFromEvents();
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL)); UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
} }

2
Win32/Win32App.h

@ -17,7 +17,7 @@ namespace win32
{ {
extern DWORD g_GracefulShutdownEndtime; extern DWORD g_GracefulShutdownEndtime;
bool StartWin32App (); bool StartWin32App (bool isWinService);
void StopWin32App (); void StopWin32App ();
int RunWin32App (); int RunWin32App ();
bool GracefulShutdown (); bool GracefulShutdown ();

13
Win32/Win32NetState.cpp

@ -15,6 +15,7 @@ IUnknown *pUnknown = nullptr;
INetworkListManager *pNetworkListManager = nullptr; INetworkListManager *pNetworkListManager = nullptr;
IConnectionPointContainer *pCPContainer = nullptr; IConnectionPointContainer *pCPContainer = nullptr;
IConnectionPoint *pConnectPoint = nullptr; IConnectionPoint *pConnectPoint = nullptr;
CNetworkListManagerEvent *pNetEvent = nullptr;
DWORD Cookie = 0; DWORD Cookie = 0;
void SubscribeToEvents() void SubscribeToEvents()
@ -29,7 +30,11 @@ void SubscribeToEvents()
if (SUCCEEDED(Result)) if (SUCCEEDED(Result))
{ {
VARIANT_BOOL IsConnect = VARIANT_FALSE; VARIANT_BOOL IsConnect = VARIANT_FALSE;
#if defined(_MSC_VER)
Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect);
#else
Result = pNetworkListManager->IsConnectedToInternet(&IsConnect); Result = pNetworkListManager->IsConnectedToInternet(&IsConnect);
#endif
if (SUCCEEDED(Result)) { if (SUCCEEDED(Result)) {
i2p::transport::transports.SetOnline (true); i2p::transport::transports.SetOnline (true);
LogPrint(eLogInfo, "NetState: Current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected"); LogPrint(eLogInfo, "NetState: Current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
@ -41,8 +46,8 @@ void SubscribeToEvents()
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint); Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
if(SUCCEEDED(Result)) if(SUCCEEDED(Result))
{ {
CNetworkListManagerEvent *NetEvent = new CNetworkListManagerEvent; pNetEvent = new CNetworkListManagerEvent;
Result = pConnectPoint->Advise((IUnknown *)NetEvent, &Cookie); Result = pConnectPoint->Advise((IUnknown *)pNetEvent, &Cookie);
if (SUCCEEDED(Result)) if (SUCCEEDED(Result))
LogPrint(eLogInfo, "NetState: Successfully subscribed to NetworkListManagerEvent messages"); LogPrint(eLogInfo, "NetState: Successfully subscribed to NetworkListManagerEvent messages");
else else
@ -59,6 +64,7 @@ void SubscribeToEvents()
void UnSubscribeFromEvents() void UnSubscribeFromEvents()
{ {
LogPrint(eLogInfo, "NetState: Unsubscribing from NetworkListManagerEvents");
try try
{ {
if (pConnectPoint) { if (pConnectPoint) {
@ -66,6 +72,9 @@ void UnSubscribeFromEvents()
pConnectPoint->Release(); pConnectPoint->Release();
} }
if (pNetEvent)
pNetEvent->Release();
if (pCPContainer) if (pCPContainer)
pCPContainer->Release(); pCPContainer->Release();

7
Win32/Win32NetState.h

@ -19,21 +19,18 @@ class CNetworkListManagerEvent : public INetworkListManagerEvents
{ {
public: public:
CNetworkListManagerEvent() : m_ref(1) { } CNetworkListManagerEvent() : m_ref(1) { }
~CNetworkListManagerEvent() { }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{ {
HRESULT Result = S_OK;
if (IsEqualIID(riid, IID_IUnknown)) { if (IsEqualIID(riid, IID_IUnknown)) {
*ppvObject = (IUnknown *)this; *ppvObject = (IUnknown *)this;
} else if (IsEqualIID(riid ,IID_INetworkListManagerEvents)) { } else if (IsEqualIID(riid ,IID_INetworkListManagerEvents)) {
*ppvObject = (INetworkListManagerEvents *)this; *ppvObject = (INetworkListManagerEvents *)this;
} else { } else {
Result = E_NOINTERFACE; return E_NOINTERFACE;
} }
AddRef(); AddRef();
return S_OK;
return Result;
} }
ULONG STDMETHODCALLTYPE AddRef() ULONG STDMETHODCALLTYPE AddRef()

20
Win32/Win32Service.cpp

@ -21,7 +21,7 @@ BOOL I2PService::isService()
HWINSTA hWinStation = GetProcessWindowStation(); HWINSTA hWinStation = GetProcessWindowStation();
if (hWinStation != NULL) if (hWinStation != NULL)
{ {
USEROBJECTFLAGS uof = { 0 }; USEROBJECTFLAGS uof = { FALSE, FALSE, 0 };
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0)) if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
{ {
bIsService = TRUE; bIsService = TRUE;
@ -119,12 +119,12 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
} }
catch (DWORD dwError) catch (DWORD dwError)
{ {
LogPrint(eLogError, "Win32Service: Start error: ", dwError); LogPrint(eLogCritical, "Win32Service: Start error: ", dwError);
SetServiceStatus(SERVICE_STOPPED, dwError); SetServiceStatus(SERVICE_STOPPED, dwError);
} }
catch (...) catch (...)
{ {
LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogCritical, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_STOPPED); SetServiceStatus(SERVICE_STOPPED);
} }
} }
@ -162,7 +162,7 @@ void I2PService::Stop()
} }
catch (...) catch (...)
{ {
LogPrint(eLogError, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogCritical, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(dwOriginalState); SetServiceStatus(dwOriginalState);
} }
} }
@ -191,12 +191,12 @@ void I2PService::Pause()
} }
catch (DWORD dwError) catch (DWORD dwError)
{ {
LogPrint(eLogError, "Win32Service: Pause error: ", dwError); LogPrint(eLogCritical, "Win32Service: Pause error: ", dwError);
SetServiceStatus(SERVICE_RUNNING); SetServiceStatus(SERVICE_RUNNING);
} }
catch (...) catch (...)
{ {
LogPrint(eLogError, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogCritical, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_RUNNING); SetServiceStatus(SERVICE_RUNNING);
} }
} }
@ -215,12 +215,12 @@ void I2PService::Continue()
} }
catch (DWORD dwError) catch (DWORD dwError)
{ {
LogPrint(eLogError, "Win32Service: Continue error: ", dwError); LogPrint(eLogCritical, "Win32Service: Continue error: ", dwError);
SetServiceStatus(SERVICE_PAUSED); SetServiceStatus(SERVICE_PAUSED);
} }
catch (...) catch (...)
{ {
LogPrint(eLogError, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogCritical, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_PAUSED); SetServiceStatus(SERVICE_PAUSED);
} }
} }
@ -238,11 +238,11 @@ void I2PService::Shutdown()
} }
catch (DWORD dwError) catch (DWORD dwError)
{ {
LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError); LogPrint(eLogCritical, "Win32Service: Shutdown error: ", dwError);
} }
catch (...) catch (...)
{ {
LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogCritical, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
} }
} }

11
build/.gitignore vendored

@ -2,7 +2,12 @@
/CMakeFiles/ /CMakeFiles/
/Testing/ /Testing/
/tests/ /tests/
/.ninja_*
/arch.c
/build.ninja
/i2pd /i2pd
/i2pd.exe
/i2pd.exe.debug
/libi2pd.a /libi2pd.a
/libi2pdclient.a /libi2pdclient.a
/libi2pdlang.a /libi2pdlang.a
@ -12,7 +17,11 @@
/CPackSourceConfig.cmake /CPackSourceConfig.cmake
/CTestTestfile.cmake /CTestTestfile.cmake
/install_manifest.txt /install_manifest.txt
/arch.c /Makefile
# windows build script # windows build script
i2pd*.zip i2pd*.zip
build*.log build*.log
# MVS project files
*.vcxproj
*.vcxproj.filters
*.sln

185
build/CMakeLists.txt

@ -1,14 +1,32 @@
cmake_minimum_required(VERSION 3.7) cmake_minimum_required(VERSION 3.7)
cmake_policy(VERSION 3.7)
project("i2pd") if(${CMAKE_VERSION} VERSION_LESS 3.22)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.22)
endif()
# for debugging # for debugging
#set(CMAKE_VERBOSE_MAKEFILE on) #set(CMAKE_VERBOSE_MAKEFILE on)
# Win32 build with cmake is not supported # paths
if(WIN32 OR MSVC OR MSYS OR MINGW) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.") set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
endif()
set(LIBI2PD_SRC_DIR ${CMAKE_SOURCE_DIR}/libi2pd)
set(LIBI2PD_CLIENT_SRC_DIR ${CMAKE_SOURCE_DIR}/libi2pd_client)
set(LANG_SRC_DIR ${CMAKE_SOURCE_DIR}/i18n)
set(DAEMON_SRC_DIR ${CMAKE_SOURCE_DIR}/daemon)
include(Version)
set_version("${LIBI2PD_SRC_DIR}/version.h" PROJECT_VERSION)
project(
i2pd
VERSION ${PROJECT_VERSION}
HOMEPAGE_URL "https://i2pd.website/"
LANGUAGES CXX
)
# configurable options # configurable options
option(WITH_AESNI "Use AES-NI instructions set" ON) option(WITH_AESNI "Use AES-NI instructions set" ON)
@ -26,27 +44,22 @@ IF(BUILD_TESTING)
enable_testing() enable_testing()
ENDIF() ENDIF()
# paths
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
# Handle paths nicely # Handle paths nicely
include(GNUInstallDirs) include(GNUInstallDirs)
# architecture # Architecture
include(TargetArch) include(TargetArch)
target_architecture(ARCHITECTURE) target_architecture(ARCHITECTURE)
set(LIBI2PD_SRC_DIR ../libi2pd) include(CheckAtomic)
set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client)
set(LANG_SRC_DIR ../i18n)
set(DAEMON_SRC_DIR ../daemon)
include_directories(${LIBI2PD_SRC_DIR}) if(WITH_STATIC)
include_directories(${LIBI2PD_CLIENT_SRC_DIR}) if(MSVC)
include_directories(${LANG_SRC_DIR}) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
include_directories(${DAEMON_SRC_DIR}) endif()
endif()
include_directories(${LIBI2PD_SRC_DIR})
FILE(GLOB LIBI2PD_SRC ${LIBI2PD_SRC_DIR}/*.cpp) FILE(GLOB LIBI2PD_SRC ${LIBI2PD_SRC_DIR}/*.cpp)
add_library(libi2pd ${LIBI2PD_SRC}) add_library(libi2pd ${LIBI2PD_SRC})
set_target_properties(libi2pd PROPERTIES PREFIX "") set_target_properties(libi2pd PROPERTIES PREFIX "")
@ -57,11 +70,9 @@ if(WITH_LIBRARY)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT Libraries) COMPONENT Libraries)
# TODO Make libi2pd available to 3rd party projects via CMake as imported target
# FIXME This pulls stdafx
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif() endif()
include_directories(${LIBI2PD_CLIENT_SRC_DIR})
FILE(GLOB CLIENT_SRC ${LIBI2PD_CLIENT_SRC_DIR}/*.cpp) FILE(GLOB CLIENT_SRC ${LIBI2PD_CLIENT_SRC_DIR}/*.cpp)
add_library(libi2pdclient ${CLIENT_SRC}) add_library(libi2pdclient ${CLIENT_SRC})
set_target_properties(libi2pdclient PROPERTIES PREFIX "") set_target_properties(libi2pdclient PROPERTIES PREFIX "")
@ -74,6 +85,7 @@ if(WITH_LIBRARY)
COMPONENT Libraries) COMPONENT Libraries)
endif() endif()
include_directories(${LANG_SRC_DIR})
FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp) FILE(GLOB LANG_SRC ${LANG_SRC_DIR}/*.cpp)
add_library(libi2pdlang ${LANG_SRC}) add_library(libi2pdlang ${LANG_SRC})
set_target_properties(libi2pdlang PROPERTIES PREFIX "") set_target_properties(libi2pdlang PROPERTIES PREFIX "")
@ -86,6 +98,8 @@ if(WITH_LIBRARY)
COMPONENT Libraries) COMPONENT Libraries)
endif() endif()
include_directories(${DAEMON_SRC_DIR})
set(DAEMON_SRC set(DAEMON_SRC
"${DAEMON_SRC_DIR}/Daemon.cpp" "${DAEMON_SRC_DIR}/Daemon.cpp"
"${DAEMON_SRC_DIR}/HTTPServer.cpp" "${DAEMON_SRC_DIR}/HTTPServer.cpp"
@ -95,6 +109,22 @@ set(DAEMON_SRC
"${DAEMON_SRC_DIR}/UPnP.cpp" "${DAEMON_SRC_DIR}/UPnP.cpp"
) )
if(WIN32)
set(WIN32_SRC_DIR ${CMAKE_SOURCE_DIR}/Win32)
include_directories(${WIN32_SRC_DIR})
list(APPEND DAEMON_SRC
"${WIN32_SRC_DIR}/DaemonWin32.cpp"
"${WIN32_SRC_DIR}/Win32App.cpp"
"${WIN32_SRC_DIR}/Win32Service.cpp"
"${WIN32_SRC_DIR}/Win32NetState.cpp"
)
file(GLOB WIN32_RC ${WIN32_SRC_DIR}/*.rc)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN")
endif()
if(WITH_UPNP) if(WITH_UPNP)
add_definitions(-DUSE_UPNP) add_definitions(-DUSE_UPNP)
endif() endif()
@ -102,30 +132,40 @@ endif()
if(WITH_GIT_VERSION) if(WITH_GIT_VERSION)
include(GetGitRevisionDescription) include(GetGitRevisionDescription)
git_describe(GIT_VERSION) git_describe(GIT_VERSION)
add_definitions(-DGITVER="${GIT_VERSION}") add_definitions(-DGITVER=${GIT_VERSION})
endif() endif()
if(APPLE) if(APPLE)
add_definitions(-DMAC_OSX) add_definitions(-DMAC_OSX)
endif() endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter") if(MSVC)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic") add_definitions(-DWINVER=0x0600)
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT. add_definitions(-D_WIN32_WINNT=0x0600)
# Multiple definitions of __stack_chk_fail(libssp & libc) else()
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter -Wno-uninitialized")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
# check for c++17 & c++11 support # Multiple definitions of __stack_chk_fail(libssp & libc)
include(CheckCXXCompilerFlag) if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED) set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s")
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED) endif()
if(CXX17_SUPPORTED) set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -ffunction-sections -fdata-sections")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
# check for c++17 & c++11 support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++17" CXX17_SUPPORTED)
CHECK_CXX_COMPILER_FLAG("-std=c++11" CXX11_SUPPORTED)
if(CXX17_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
elseif(CXX11_SUPPORTED) elseif(CXX11_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
else() else()
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
endif()
endif() endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
@ -157,6 +197,12 @@ endif()
# Note: AES-NI and AVX is available on x86-based CPU's. # Note: AES-NI and AVX is available on x86-based CPU's.
# Here also ARM64 implementation, but currently we don't support it. # 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()
if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386")) if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386"))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
add_definitions(-D__AES__) add_definitions(-D__AES__)
@ -188,10 +234,36 @@ set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
if(WITH_STATIC) if(WITH_STATIC)
if(NOT MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
endif()
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
if(MSVC)
set(Boost_USE_STATIC_RUNTIME ON) set(Boost_USE_STATIC_RUNTIME ON)
else()
set(Boost_USE_STATIC_RUNTIME OFF)
endif()
if(MSVC)
set(OPENSSL_MSVC_STATIC_RT ON)
endif()
set(OPENSSL_USE_STATIC_LIBS ON) set(OPENSSL_USE_STATIC_LIBS ON)
set(ZLIB_USE_STATIC_LIBS ON)
if(MSVC)
set(ZLIB_NAMES zlibstatic zlibstat)
else()
set(ZLIB_NAMES libz zlibstatic zlibstat zlib z)
endif()
if(WITH_UPNP)
set(MINIUPNPC_USE_STATIC_LIBS ON)
add_definitions(-DMINIUPNP_STATICLIB)
endif()
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*") if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
# set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive") # set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
@ -201,17 +273,23 @@ else()
# TODO: Consider separate compilation for LIBI2PD_SRC for library. # TODO: Consider separate compilation for LIBI2PD_SRC for library.
# No need in -fPIC overhead for binary if not interested in library # No need in -fPIC overhead for binary if not interested in library
# HINT: revert c266cff CMakeLists.txt: compilation speed up # HINT: revert c266cff CMakeLists.txt: compilation speed up
if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK) endif()
add_definitions(-DBOOST_ATOMIC_DYN_LINK -DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
if(WIN32)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_STATIC_RUNTIME OFF)
endif()
endif() endif()
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED) find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic)
if(NOT DEFINED Boost_INCLUDE_DIRS) if(NOT DEFINED Boost_FOUND)
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
endif() endif()
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
if(NOT DEFINED OPENSSL_INCLUDE_DIR) if(NOT DEFINED OPENSSL_FOUND)
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
endif() endif()
@ -236,8 +314,6 @@ endif()
# load includes # load includes
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
include(CheckAtomic)
# show summary # show summary
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
message(STATUS "Build type : ${CMAKE_BUILD_TYPE}") message(STATUS "Build type : ${CMAKE_BUILD_TYPE}")
@ -259,11 +335,25 @@ message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
if(WITH_BINARY) if(WITH_BINARY)
if(WIN32)
add_executable("${PROJECT_NAME}" WIN32 ${DAEMON_SRC} ${WIN32_RC})
else()
add_executable("${PROJECT_NAME}" ${DAEMON_SRC}) add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
endif()
if(WIN32)
list(APPEND MINGW_EXTRA "wsock32" "ws2_32" "iphlpapi")
# OpenSSL may require Crypt32 library on MSVC build, which is not added by CMake lesser than 3.21
if(MSVC AND ${CMAKE_VERSION} VERSION_LESS 3.21)
list(APPEND MINGW_EXTRA "crypt32")
endif()
endif()
if(WITH_STATIC) if(WITH_STATIC)
if(NOT MSVC)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static") set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
endif() endif()
endif()
if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now") set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now")
@ -275,11 +365,18 @@ if(WITH_BINARY)
list(REMOVE_AT Boost_LIBRARIES -1) list(REMOVE_AT Boost_LIBRARIES -1)
endif() endif()
# synchronization library is incompatible with Windows 7
if(WIN32)
get_target_property(BOOSTFSLIBS Boost::filesystem INTERFACE_LINK_LIBRARIES)
list(REMOVE_ITEM BOOSTFSLIBS synchronization)
set_target_properties(Boost::filesystem PROPERTIES INTERFACE_LINK_LIBRARIES "${BOOSTFSLIBS}")
endif()
if(WITH_STATIC) if(WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS}) set(DL_LIB ${CMAKE_DL_LIBS})
endif() endif()
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES}) target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}") set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

2
build/cmake_modules/TargetArch.cmake

@ -18,7 +18,7 @@ set(archdetect_c_code "
|| defined(_M_ARM64) \\ || defined(_M_ARM64) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8) || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8)
#error cmake_ARCH arm64 #error cmake_ARCH arm64
#if defined(__ARM_ARCH_7__) \\ #elif defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\ || defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\ || defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\ || defined(__ARM_ARCH_7M__) \\

16
build/cmake_modules/Version.cmake

@ -0,0 +1,16 @@
# read version
function(set_version version_file output_var)
file(READ "${version_file}" version_data)
string(REGEX MATCH "I2PD_VERSION_MAJOR ([0-9]*)" _ ${version_data})
set(version_major ${CMAKE_MATCH_1})
string(REGEX MATCH "I2PD_VERSION_MINOR ([0-9]*)" _ ${version_data})
set(version_minor ${CMAKE_MATCH_1})
string(REGEX MATCH "I2PD_VERSION_MICRO ([0-9]*)" _ ${version_data})
set(version_micro ${CMAKE_MATCH_1})
set(${output_var} "${version_major}.${version_minor}.${version_micro}" PARENT_SCOPE)
endfunction()

34
contrib/certificates/reseed/arnavbhatt288_at_mail.i2p.crt

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF2TCCA8GgAwIBAgIQIHQPtSoFU+cUpYD8PZaWZjANBgkqhkiG9w0BAQsFADB2
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEfMB0GA1UEAwwW
YXJuYXZiaGF0dDI4OEBtYWlsLmkycDAeFw0yMzAxMjUxODUzNDFaFw0zMzAxMjUx
ODUzNDFaMHYxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx
HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR8w
HQYDVQQDDBZhcm5hdmJoYXR0Mjg4QG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEAtwG73sC0jYd3fgEzZh0SveAdUd5yD35nINJRrdPSrSwY
n3i1qGe3fNLj877PvUDU+qiHH0fFZfyFkXTaq3TUp1u4YkmvaoPHy6FZlojB08lK
FBm+iJ1hifQ7MFmvIKUGv+cjlN6xSoQ0U6B2QOy6iZnBgFZ/7jbRY4iZOIj7VJtY
aodeHfy0bWe447VJovbkUi7NJPFZQS65LMcAIWcWTxrC0Gj8SmdxL3a5+hxpmmg0
+KCQvWQDdxAQjsc16sgUCdUc6cWYO4yw9H6fgdq9GJX+LnXR9OB58GsAjjlLlFoI
CZxdARDpoqcIj6AoKIanALf8yfbIyrqqJE47cuaqV9bht5MWKnXbwHplEkT4ZNkh
PnRDia7B5HY3uwbt39CBm264PEWXvWG2sozTWKQqBjmMN2cj/NFDUEqKv6BggMY1
HcqxWFKRcgKCtRvrmTmfp5l0/ou+OtUaFUg0a6Qhtb93Hj10vK6wZzidBqj0ggzB
eJDI95b89u8JgzRoOBriuMKTc91WTkOvBLkB3dgUbUpx2p8KHjvf/pppBH9u0oxp
qJFFK840DbnJydEvjKezeVe5Ax6YRSRxyEdKzRoWdvKVxb3qBBKMdCKTYEPxHPBu
JMEQVUCXJMti++1KEiQGhcfWvLyT7OewbcIZNk9XWNrxlKcGrTp9AOwaaNC5m1kC
AwEAAaNjMGEwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggr
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB8GA1UdDgQYBBZhcm5hdmJoYXR0Mjg4
QG1haWwuaTJwMA0GCSqGSIb3DQEBCwUAA4ICAQAHiK0ld/1PF9DIhutD660/bzBg
mF2Z76hcBqDZ8tnQai/u/RXYrH9wso9BYyrVsvk3fr6tpGT49Ian0MVpPOxMoTU2
oBEmQlYrfclQLFsOLmA0y2r1ggXzIrt69jB710Vhwdnz09oOE8rS4E2T5oDD8Wvy
Kony+AarRceqtkOlzyquc42KjzdrbHsosF7G2iGhNI6t+T3BfWJ+Q+d5sj3OIh6e
gSfvHL44E4vZt6dtofRN3MAZ60kNLF5YWyaUo3Snv9Lso1IwIz3AVr5ehv+8sFL/
KxaXdkZ5Yn2YUX7p1t4VQd+eXVPYjf1befg4PvrwSkylu3Jpee3fllZSKXeSVx9x
jpJiq5vIakqk22pnWb1Vn7xzSW1vtEG7QLjobOr1WrcGiwdv+HKiWcXJXDzKoWXs
h3VEfr51Kap8cIJv+D6lJIG9IcIhiQ6CXWBmtjWJvbdVwFBy1/3Fhaou9liHi+gK
4Yh5a5OGCzc7xjtpGaTmoLEz7NzDNOdd/r840qRDOh70izzmFZd5Gwq4hoVcPJcS
EAySwtgqK0/4d0zDd2Wg9ASJV9DnDf8QuSmHZgZ9Efs47XcWz9TvkWUS1E66AJsN
mmI1NDQ3mv3dv5+WPq+dqqYFsnx3xWL1g5Z3buk0opeuXMzoHwM7UfN8h7Q1M5+t
+XBgkaYA4iEwYKqlCQ==
-----END CERTIFICATE-----

50
contrib/certificates/reseed/igor_at_novg.net.crt

@ -1,33 +1,33 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIFvjCCA6agAwIBAgIQIDtv8tGMh0FyB2w5XjfZxTANBgkqhkiG9w0BAQsFADBt MIIFvjCCA6agAwIBAgIQBnsUOmOu2oZZIwHBmQc1BDANBgkqhkiG9w0BAQsFADBt
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwN ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwN
aWdvckBub3ZnLm5ldDAeFw0xNzA3MjQxODI4NThaFw0yNzA3MjQxODI4NThaMG0x aWdvckBub3ZnLm5ldDAeFw0yMzAxMjgxNDM4MzFaFw0zMzAxMjgxNDM4MzFaMG0x
CzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNVBAoT CzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNVBAoT
FUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1p FUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1p
Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxst4 Z29yQG5vdmcubmV0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvLkf
cam3YibBtQHGPCPX13uRQti56U3XZytSZntaKrUFmJxjt41Q/mOy3KYo+lBvhfDF bM3uiYfp9m0vgdoftyXtk2/9bHf3u5iaM0WfoJIsw1iizo/mxJl+Iy7SxLC16nV0
x3tWKjgP9LJOJ28zvddFhZVNxqZRjcnAoPuSOVCw88g01D9OAasKF11hCfdxZP6h v5FpncVv+Z8x9dgoAYVuLq9zKfsAbpj6kuxAqw6vJMlD1TiIL3nSODV9BJLk47X5
vGm8WCnjD8KPcYFxJC4HJUiFeProAwuTzEAESTRk4CAQe3Ie91JspuqoLUc5Qxlm tmvoOSj9BgvemYThTE3nj+DbuJRW5q90KyBV/LdLrQJX3k5R3FFL5tTad2LKFNZ4
w5QpjnjfZY4kaVHmZDKGIZDgNIt5v85bu4pWwZ6O+o90xQqjxvjyz/xccIec3sHw vEOcYwwx6mvrkJ2lly6bAQUCtfc648Jyq+NO3Rba1fmn7gcP9zXXc5KYsj/ovyY2
MHJ8h8ZKMokCKEJTaRWBvdeNXki7nf3gUy/3GjYQlzo0Nxk/Hw4svPcA+eL0AYiy OaocSF5wMhzBuPxO+M2HqbYLMAkc6/GesGds8Rm8wofuhJoI5YtqJuLKZm6nQXSc
Jn83bIB5VToW2zYUdV4u3qHeAhEg8Y7HI0kKcSUGm9AQXzbzP8YCHxi0sbb0GAJy fx6PKgbKcTIUWNFMsxyfghz9hpbg0rkvC7PtfAjtV0yaDtUum1eZeNEx1HbRWN2n
f1Xf3XzoPfT64giD8ReUHhwKpyMB6uvG/NfWSZAzeAO/NT7DAwXpKIVQdkVdqy8b TQNCVuv0yaKC41qxqzhEybkdjL9JlgUh7VuskaCelB0lz+kgYjGu8ezOa0ua2iKq
mvHvjf9/kWKOirA2Nygf3r79Vbg2mqbYC/b63XI9hheU689+O7qyhTEhNz+11X0d 4FC/1MbPulxN8NOt4pmbGqqoxmCdShp38wdnOBM3DsAS9f0JaQZd4CDyY4DCSfVn
Zax7UPrLrwOeB9TNfEnztsmrHNdv2n+KcOO2o11Wvz2nHP9g+dgwoZSD1ZEpFzWP xPdWk31+VXVt3Ixh1EUqZWYTRSsZApkCyYzkiZ/qPGG6FR9Hq2SuhC5o4P44k7eo
0sD5knKLwAL/64qLlAQ1feqW7hMr80IADcKjLSODkIDIIGm0ksXqEzTjz1JzbRDq 6wwBWD8a5RjsZhvr05E5yBrKXh/PjLwmtG73QC+ouR54/5xtedvdTwNS94FnNctX
jUjq7EAlkw3G69rv1gHxIntllJRQidAqecyWHOMCAwEAAaNaMFgwDgYDVR0PAQH/ FT6QGZnRwCkhPaRe1oQMzP+88pGoCfO33GBAuwUCAwEAAaNaMFgwDgYDVR0PAQH/
BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8E BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNVHRMBAf8E
BTADAQH/MBYGA1UdDgQPBA1pZ29yQG5vdmcubmV0MA0GCSqGSIb3DQEBCwUAA4IC BTADAQH/MBYGA1UdDgQPBA1pZ29yQG5vdmcubmV0MA0GCSqGSIb3DQEBCwUAA4IC
AQADyPaec28qc1HQtAV5dscJr47k92RTfvan+GEgIwyQDHZQm38eyTb05xipQCdk AQCteAb5/bqhHr/i5CJbDzlofprXFC826c19GxQ/9Hw0kA52l0J9Q8Vz8Vy7VQyP
5ruUDFXLB5qXXFJKUbQM6IpaktmWDJqk4Zn+1nGbtFEbKgrF55pd63+NQer5QW9o QNa8MCv6FeNy8a/wXp6cafyFsBtvehVQO8lFlpCgMEl2Bma43+GaCwkrM6bFNXeW
3+dGj0eZJa3HX5EBkd2r7j2LFuB6uxv3r/xiTeHaaflCnsmyDLfb7axvYhyEzHQS iQ9h4e1KjsUZ8cQDNEcamiJ80+xbMhBrj5bAZwKmZs8MoGEMyXKEZmcmwA+/fy1c
AUi1bR+ln+dXewdtuojqc1+YmVGDgzWZK2T0oOz2E21CpZUDiP3wv9QfMaotLEal cx4izsOsmRXmEHXsvB9ydJHZZeKW8+r0DAtgPslwXuXHG6MuBQo7dKCqn+iMxHXV
zECnbhS++q889inN3GB4kIoN6WpPpeYtTV+/r7FLv9+KUOV1s2z6mxIqC5wBFhZs Jxriq3yvNffdGx4maSLJrjQ1ealt/UMzql7huVSItnVFWoYf7GAELXNJ/PmqVyaK
0Sr1kVo8hB/EW/YYhDp99LoAOjIO6nn1h+qttfzBYr6C16j+8lGK2A12REJ4LiUQ q11LQ8W/Aud6s/bblaJrFJnK8PbPpaw4RvHoWVLYaZYmQnV2msWs5EuESBlEADbv
cQI/0zTjt2C8Ns6ueNzMLQN1Mvmlg1Z8wIB7Az7jsIbY2zFJ0M5qR5VJveTj33K4 UklQXLMc2f9HKWPA5678nvYPrmu8IL5pMkAxgGRqmd+7vCz4lU9M5z3HObU+WRBt
4WSbC/zMWOBYHTVBvGmc6JGhu5ZUTZ+mWP7QfimGu+tdhvtrybFjE9ROIE/4yFr6 qEMYyXywV8o3tbmnlDS5S5Xxf+tLZn1cxz3ZrmcHPHDbLBNdvszF3CTJH/R2sQvD
GkxEyt0UY87TeKXJ/3KygvkMwdvqGWiZhItb807iy99+cySujtbGfF2ZXYGjBXVW bizvYJM+p5F+GWM5mt6w0HrOut5MRlpOws/NRrkbijuVA/A45nzTtKplIFYE3qe8
dJOVRbyGQkHh6lrWHQM4ntBv4x+5QA+OAan5PBF3tcDx1vefPx+asYslbOXpzII5 q5SAbwYLc8cJcZCN3PxtWwbEv81V33abMt5QcjnWGLH5t2+1Z2KLCgKLSCQTxM8s
qhvoQxuRs6j5jsVFG6RdsKNeQAt87Mb2u2zK2ZakMdyD1w== zBPHtUe8qtSQaElnNLILYbtJ1w67dPnGYTphHihC+CXjBg==
-----END CERTIFICATE----- -----END CERTIFICATE-----

8
contrib/dinit/i2pd

@ -0,0 +1,8 @@
type = bgprocess
run-as = i2pd
command = /usr/bin/i2pd --conf=/var/lib/i2pd/i2pd.conf --pidfile=/var/lib/i2pd/i2pd.pid --daemon --service
smooth-recovery = true
depends-on = ntpd
# uncomment if you want to use i2pd with yggdrasil
# depends-on = yggdrasil
pid-file = /var/lib/i2pd/i2pd.pid

5
contrib/i2pd.conf

@ -33,7 +33,7 @@
# log = file # log = file
## Path to logfile (default - autodetect) ## Path to logfile (default - autodetect)
# logfile = /var/log/i2pd/i2pd.log # logfile = /var/log/i2pd/i2pd.log
## Log messages above this level (debug, info, *warn, error, none) ## Log messages above this level (debug, info, *warn, error, critical, none)
## If you set it to none, logging will be disabled ## If you set it to none, logging will be disabled
# loglevel = warn # loglevel = warn
## Write full CLF-formatted date and time to log (default: write only time) ## Write full CLF-formatted date and time to log (default: write only time)
@ -168,9 +168,10 @@ port = 4447
[sam] [sam]
## Comment or set to 'false' to disable SAM Bridge ## Comment or set to 'false' to disable SAM Bridge
enabled = true enabled = true
## Address and port service will listen on ## Address and ports service will listen on
# address = 127.0.0.1 # address = 127.0.0.1
# port = 7656 # port = 7656
# portudp = 7655
[bob] [bob]
## Uncomment and set to 'true' to enable BOB command channel ## Uncomment and set to 'true' to enable BOB command channel

5
contrib/rpm/i2pd-git.spec

@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7) %define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git Name: i2pd-git
Version: 2.46.1 Version: 2.47.0
Release: git%{git_hash}%{?dist} Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd Conflicts: i2pd
@ -158,6 +158,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
- update to 2.47.0
* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1 * Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
- update to 2.46.1 - update to 2.46.1

7
contrib/rpm/i2pd.spec

@ -1,6 +1,6 @@
Name: i2pd Name: i2pd
Version: 2.46.1 Version: 2.47.0
Release: 2%{?dist} Release: 1%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@ -155,6 +155,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
- update to 2.47.0
* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1 * Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
- update to 2.46.1 - update to 2.46.1

16
daemon/Daemon.cpp

@ -179,7 +179,7 @@ namespace util
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels")) if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels"))
transitTunnels *= 2; // double default number of transit tunnels for floodfill transitTunnels *= 2; // double default number of transit tunnels for floodfill
SetMaxNumTransitTunnels (transitTunnels); i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels);
/* this section also honors 'floodfill' flag, if set above */ /* this section also honors 'floodfill' flag, if set above */
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth); std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
@ -269,7 +269,7 @@ namespace util
if (hidden) if (hidden)
{ {
LogPrint(eLogInfo, "Daemon: Hidden mode enabled"); LogPrint(eLogInfo, "Daemon: Hidden mode enabled");
i2p::data::netdb.SetHidden(true); i2p::context.SetHidden(true);
} }
std::string httpLang; i2p::config::GetOption("http.lang", httpLang); std::string httpLang; i2p::config::GetOption("http.lang", httpLang);
@ -310,7 +310,7 @@ namespace util
LogPrint(eLogInfo, "Daemon: Transports started"); LogPrint(eLogInfo, "Daemon: Transports started");
else else
{ {
LogPrint(eLogError, "Daemon: Failed to start Transports"); LogPrint(eLogCritical, "Daemon: Failed to start Transports");
/** shut down netdb right away */ /** shut down netdb right away */
i2p::transport::transports.Stop(); i2p::transport::transports.Stop();
i2p::data::netdb.Stop(); i2p::data::netdb.Stop();
@ -329,15 +329,17 @@ namespace util
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Daemon: Failed to start Webconsole: ", ex.what ()); LogPrint (eLogCritical, "Daemon: Failed to start Webconsole: ", ex.what ());
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ()); ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
} }
} }
LogPrint(eLogInfo, "Daemon: Starting Tunnels"); LogPrint(eLogInfo, "Daemon: Starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
LogPrint(eLogInfo, "Daemon: Starting Router context");
i2p::context.Start();
LogPrint(eLogInfo, "Daemon: Starting Client"); LogPrint(eLogInfo, "Daemon: Starting Client");
i2p::client::context.Start (); i2p::client::context.Start ();
@ -354,7 +356,7 @@ namespace util
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Daemon: Failed to start I2PControl: ", ex.what ()); LogPrint (eLogCritical, "Daemon: Failed to start I2PControl: ", ex.what ());
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ()); ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
} }
} }
@ -366,6 +368,8 @@ namespace util
LogPrint(eLogInfo, "Daemon: Shutting down"); LogPrint(eLogInfo, "Daemon: Shutting down");
LogPrint(eLogInfo, "Daemon: Stopping Client"); LogPrint(eLogInfo, "Daemon: Stopping Client");
i2p::client::context.Stop(); i2p::client::context.Stop();
LogPrint(eLogInfo, "Daemon: Stopping Router context");
i2p::context.Stop();
LogPrint(eLogInfo, "Daemon: Stopping Tunnels"); LogPrint(eLogInfo, "Daemon: Stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();

8
daemon/HTTPServer.cpp

@ -156,7 +156,7 @@ namespace http {
static void SetLogLevel (const std::string& level) static void SetLogLevel (const std::string& level)
{ {
if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug") if (level == "none" || level == "critical" || level == "error" || level == "warn" || level == "info" || level == "debug")
i2p::log::Logger().SetLogLevel(level); i2p::log::Logger().SetLogLevel(level);
else { else {
LogPrint(eLogError, "HTTPServer: Unknown loglevel set attempted"); LogPrint(eLogError, "HTTPServer: Unknown loglevel set attempted");
@ -749,12 +749,13 @@ namespace http {
auto loglevel = i2p::log::Logger().GetLogLevel(); auto loglevel = i2p::log::Logger().GetLogLevel();
s << "<b>" << tr("Logging level") << "</b><br>\r\n"; s << "<b>" << tr("Logging level") << "</b><br>\r\n";
s << " <a class=\"button" << (loglevel == eLogNone ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n"; s << " <a class=\"button" << (loglevel == eLogNone ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
s << " <a class=\"button" << (loglevel == eLogCritical ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=critical&token=" << token << "\"> critical </a> \r\n";
s << " <a class=\"button" << (loglevel == eLogError ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n"; s << " <a class=\"button" << (loglevel == eLogError ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n";
s << " <a class=\"button" << (loglevel == eLogWarning ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n"; s << " <a class=\"button" << (loglevel == eLogWarning ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n";
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 == 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"; 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 = GetMaxNumTransitTunnels (); uint16_t maxTunnels = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
s << "<b>" << tr("Transit tunnels limit") << "</b><br>\r\n"; s << "<b>" << tr("Transit tunnels limit") << "</b><br>\r\n";
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n"; s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n"; s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n";
@ -838,6 +839,7 @@ namespace http {
tmp_s << " [itag:" << it->GetRelayTag () << "]"; tmp_s << " [itag:" << it->GetRelayTag () << "]";
if (it->GetSendQueueSize () > 0) if (it->GetSendQueueSize () > 0)
tmp_s << " [queue:" << it->GetSendQueueSize () << "]"; tmp_s << " [queue:" << it->GetSendQueueSize () << "]";
if (it->IsSlow ()) tmp_s << " [slow]";
tmp_s << "</div>\r\n" << std::endl; tmp_s << "</div>\r\n" << std::endl;
cnt++; cnt++;
} }
@ -1314,7 +1316,7 @@ namespace http {
{ {
uint32_t limit = std::stoul(params["limit"], nullptr); uint32_t limit = std::stoul(params["limit"], nullptr);
if (limit > 0 && limit <= TRANSIT_TUNNELS_LIMIT) if (limit > 0 && limit <= TRANSIT_TUNNELS_LIMIT)
SetMaxNumTransitTunnels (limit); i2p::tunnel::tunnels.SetMaxNumTransitTunnels (limit);
else { else {
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Transit tunnels count must not exceed %d", TRANSIT_TUNNELS_LIMIT) << "\r\n<br>\r\n<br>\r\n"; s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Transit tunnels count must not exceed %d", TRANSIT_TUNNELS_LIMIT) << "\r\n<br>\r\n<br>\r\n";
s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n"; s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n";

2
daemon/UnixDaemon.cpp

@ -173,7 +173,7 @@ namespace i2p
ftruncate(pidFH, 0); ftruncate(pidFH, 0);
if (write(pidFH, pid, strlen(pid)) < 0) if (write(pidFH, pid, strlen(pid)) < 0)
{ {
LogPrint(eLogError, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno)); LogPrint(eLogCritical, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl; std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
return false; return false;
} }

6
debian/changelog vendored

@ -1,3 +1,9 @@
i2pd (2.47.0-1) unstable; urgency=high
* updated to version 2.47.0/0.9.58
-- orignal <orignal@i2pmail.org> Sat, 11 Mar 2023 16:00:00 +0000
i2pd (2.46.1-2) unstable; urgency=critical i2pd (2.46.1-2) unstable; urgency=critical
* re-pushed release due to new critical bug * re-pushed release due to new critical bug

14
i18n/German.cpp

@ -61,6 +61,7 @@ namespace german // language namespace
{"Clock skew", "Zeitabweichung"}, {"Clock skew", "Zeitabweichung"},
{"Offline", "Offline"}, {"Offline", "Offline"},
{"Symmetric NAT", "Symmetrisches NAT"}, {"Symmetric NAT", "Symmetrisches NAT"},
{"No Descriptors", "Keine Beschreibungen"},
{"Uptime", "Laufzeit"}, {"Uptime", "Laufzeit"},
{"Network status", "Netzwerkstatus"}, {"Network status", "Netzwerkstatus"},
{"Network status v6", "Netzwerkstatus v6"}, {"Network status v6", "Netzwerkstatus v6"},
@ -116,8 +117,10 @@ namespace german // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Enddatum"}, {"EndDate", "Enddatum"},
{"floodfill mode is disabled", "Floodfill Modus ist deaktiviert"},
{"Queue size", "Größe der Warteschlange"}, {"Queue size", "Größe der Warteschlange"},
{"Run peer test", "Peer-Test durchführen"}, {"Run peer test", "Peer-Test durchführen"},
{"Reload tunnels configuration", "Tunnel Konfiguration neu laden"},
{"Decline transit tunnels", "Transittunnel ablehnen"}, {"Decline transit tunnels", "Transittunnel ablehnen"},
{"Accept transit tunnels", "Transittunnel akzeptieren"}, {"Accept transit tunnels", "Transittunnel akzeptieren"},
{"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"}, {"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"},
@ -145,6 +148,8 @@ namespace german // language namespace
{"Destination not found", "Ziel nicht gefunden"}, {"Destination not found", "Ziel nicht gefunden"},
{"StreamID can't be null", "StreamID kann nicht null sein"}, {"StreamID can't be null", "StreamID kann nicht null sein"},
{"Return to destination page", "Zurück zur Ziel-Seite"}, {"Return to destination page", "Zurück zur Ziel-Seite"},
{"You will be redirected in %d seconds", "Du wirst umgeleitet in %d Sekunden"},
{"Transit tunnels count must not exceed %d", "Die Anzahl der Transittunnel darf nicht über %d gehen"},
{"Back to commands list", "Zurück zur Befehlsliste"}, {"Back to commands list", "Zurück zur Befehlsliste"},
{"Register at reg.i2p", "Auf reg.i2p registrieren"}, {"Register at reg.i2p", "Auf reg.i2p registrieren"},
{"Description", "Beschreibung"}, {"Description", "Beschreibung"},
@ -162,6 +167,15 @@ namespace german // language namespace
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"}, {"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"},
{"Invalid request", "Ungültige Anfrage"}, {"Invalid request", "Ungültige Anfrage"},
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"}, {"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"},
{"Addresshelper is not supported", "Adresshelfer wird nicht unterstützt"},
{"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>.", "Host %s ist <font color=red>bereits im Adressbuch des Routers</font>. <b>Vorsicht: Die Quelle dieser URL kann schädlich sein!</b> Klicken Sie hier, um den Datensatz zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."},
{"Addresshelper forced update rejected", "Adresshelfer gezwungene Aktualisierung abgelehnt"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Um den Host <b>%s</b> im Adressbuch des Routers hinzuzufügen, klicken Sie hier: <a href=\"%s%s%s\">Weiter</a>."},
{"Addresshelper request", "Adresshelfer gefunden"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s wurde vom Helfer zum Adressbuch des Routers hinzugefügt. Klicken Sie hier, um fortzufahren: <a href=\"%s\">Weiter</a>."},
{"Addresshelper adding", "Adresshelfer hinzufügen"},
{"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>.", "Host %s ist <font color=red>bereits im Adressbuch des Routers</font>. Klicken Sie hier, um den Eintrag zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."},
{"Addresshelper update", "Adresshelfer aktualisieren"},
{"Invalid request URI", "Ungültige Anfrage-URI"}, {"Invalid request URI", "Ungültige Anfrage-URI"},
{"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"}, {"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"},
{"Outproxy failure", "Outproxy-Fehler"}, {"Outproxy failure", "Outproxy-Fehler"},

6
i18n/I18N.h

@ -95,9 +95,8 @@ std::string tr (TValue&& arg, TArgs&&... args)
std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg)); std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg));
size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...); size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...);
size = size + 1;
std::string str(size, 0); std::string str(size, 0);
std::snprintf(&str.front(), size, tr_str.c_str(), std::forward<TArgs>(args)...); std::snprintf(&str.front(), size + 1, tr_str.c_str(), std::forward<TArgs>(args)...);
return str; return str;
} }
@ -127,9 +126,8 @@ std::string ntr (TValue&& arg, TValue2&& arg2, int& n, TArgs&&... args)
std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg), std::forward<TValue2>(arg2), std::forward<int>(n)); std::string tr_str = i2p::i18n::translate(std::forward<TValue>(arg), std::forward<TValue2>(arg2), std::forward<int>(n));
size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...); size_t size = std::snprintf(NULL, 0, tr_str.c_str(), std::forward<TArgs>(args)...);
size = size + 1;
std::string str(size, 0); std::string str(size, 0);
std::snprintf(&str.front(), size, tr_str.c_str(), std::forward<TArgs>(args)...); std::snprintf(&str.front(), size + 1, tr_str.c_str(), std::forward<TArgs>(args)...);
return str; return str;
} }

10
i18n/Italian.cpp

@ -61,6 +61,8 @@ namespace italian // language namespace
{"Clock skew", "Orologio disallineato"}, {"Clock skew", "Orologio disallineato"},
{"Offline", "Disconnesso"}, {"Offline", "Disconnesso"},
{"Symmetric NAT", "NAT simmetrico"}, {"Symmetric NAT", "NAT simmetrico"},
{"Full cone NAT", "Cono completo NAT"},
{"No Descriptors", "Nessun descrittore"},
{"Uptime", "In funzione da"}, {"Uptime", "In funzione da"},
{"Network status", "Stato della rete"}, {"Network status", "Stato della rete"},
{"Network status v6", "Stato della rete v6"}, {"Network status v6", "Stato della rete v6"},
@ -116,6 +118,7 @@ namespace italian // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Data di fine"}, {"EndDate", "Data di fine"},
{"floodfill mode is disabled", "la modalità floodfill è disabilitata"},
{"Queue size", "Dimensione della coda"}, {"Queue size", "Dimensione della coda"},
{"Run peer test", "Esegui il test dei peer"}, {"Run peer test", "Esegui il test dei peer"},
{"Reload tunnels configuration", "Ricarica la configurazione dei tunnel"}, {"Reload tunnels configuration", "Ricarica la configurazione dei tunnel"},
@ -165,8 +168,15 @@ namespace italian // language namespace
{"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"}, {"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"},
{"Invalid request", "Richiesta non valida"}, {"Invalid request", "Richiesta non valida"},
{"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"}, {"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"},
{"Addresshelper is not supported", "Addresshelper non è supportato"},
{"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'host %s è <font color=red>già nella rubrica del router</font>. <b>Attenzione: la fonte di questo URL potrebbe essere dannosa!</b> Fai clic qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."},
{"Addresshelper forced update rejected", "Aggiornamento forzato dell'helper degli indirizzi rifiutato"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Per aggiungere host <b>%s</b> nella rubrica del router, clicca qui: <a href=\"%s%s%s\">Continua</a>."}, {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Per aggiungere host <b>%s</b> nella rubrica del router, clicca qui: <a href=\"%s%s%s\">Continua</a>."},
{"Addresshelper request", "Richiesta di indirizzo helper"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'host %s viene aggiunto alla rubrica del router dall'helper. Fai clic qui per procedere: <a href=\"%s\">Continua</a>."},
{"Addresshelper adding", "Aggiunta di Addresshelper"},
{"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'host %s è <font color=red>già nella rubrica del router</font>. Clicca qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</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'host %s è <font color=red>già nella rubrica del router</font>. Clicca qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."},
{"Addresshelper update", "Aggiornamento dell'helper degli indirizzi"},
{"Invalid request URI", "URI della richiesta non valido"}, {"Invalid request URI", "URI della richiesta non valido"},
{"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"}, {"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"},
{"Outproxy failure", "Fallimento del proxy di uscita"}, {"Outproxy failure", "Fallimento del proxy di uscita"},

8
i18n/Portuguese.cpp

@ -73,7 +73,7 @@ namespace portuguese // language namespace
{"%.2f KiB/s", "%.2f KiB/s"}, {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Enviado"}, {"Sent", "Enviado"},
{"Transit", "Trânsito"}, {"Transit", "Trânsito"},
{"Data path", "Caminho dos dados"}, {"Data path", "Diretório dos dados"},
{"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."}, {"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
{"Router Ident", "Identidade do Roteador"}, {"Router Ident", "Identidade do Roteador"},
{"Router Family", "Família do Roteador"}, {"Router Family", "Família do Roteador"},
@ -122,15 +122,15 @@ namespace portuguese // language namespace
{"Queue size", "Tamanho da fila"}, {"Queue size", "Tamanho da fila"},
{"Run peer test", "Executar teste de peers"}, {"Run peer test", "Executar teste de peers"},
{"Reload tunnels configuration", "Recarregar a configuração dos túneis"}, {"Reload tunnels configuration", "Recarregar a configuração dos túneis"},
{"Decline transit tunnels", "Negar túnel de trânsito"}, {"Decline transit tunnels", "Negar túneis de trânsito"},
{"Accept transit tunnels", "Aceitar túnel de trânsito"}, {"Accept transit tunnels", "Aceitar túneis de trânsito"},
{"Cancel graceful shutdown", "Cancelar desligamento gracioso"}, {"Cancel graceful shutdown", "Cancelar desligamento gracioso"},
{"Start graceful shutdown", "Iniciar desligamento gracioso"}, {"Start graceful shutdown", "Iniciar desligamento gracioso"},
{"Force shutdown", "Forçar desligamento"}, {"Force shutdown", "Forçar desligamento"},
{"Reload external CSS styles", "Recarregar estilos CSS externos"}, {"Reload external CSS styles", "Recarregar estilos CSS externos"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Nota: </b> Qualquer ação feita aqui não será permanente e não altera os seus arquivos de configuração."}, {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Nota: </b> Qualquer ação feita aqui não será permanente e não altera os seus arquivos de configuração."},
{"Logging level", "Nível de registro"}, {"Logging level", "Nível de registro"},
{"Transit tunnels limit", "Limite nos túneis de trânsito"}, {"Transit tunnels limit", "Limite de túneis de trânsito"},
{"Change", "Mudar"}, {"Change", "Mudar"},
{"Change language", "Trocar idioma"}, {"Change language", "Trocar idioma"},
{"no transit tunnels currently built", "Nenhum túnel de trânsito construido no momento"}, {"no transit tunnels currently built", "Nenhum túnel de trânsito construido no momento"},

8
libi2pd/Config.cpp

@ -149,7 +149,8 @@ namespace config {
sam.add_options() sam.add_options()
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge") ("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address") ("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port") ("sam.port", value<uint16_t>()->default_value(7656), "SAM listen TCP port")
("sam.portudp", value<uint16_t>()->default_value(0), "SAM listen UDP port")
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread") ("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread")
; ;
@ -215,10 +216,11 @@ namespace config {
"https://reseed.onion.im/," "https://reseed.onion.im/,"
"https://i2pseed.creativecowpat.net:8443/," "https://i2pseed.creativecowpat.net:8443/,"
"https://reseed.i2pgit.org/," "https://reseed.i2pgit.org/,"
"https://i2p.novg.net/,"
"https://banana.incognet.io/," "https://banana.incognet.io/,"
"https://reseed-pl.i2pd.xyz/," "https://reseed-pl.i2pd.xyz/,"
"https://www2.mk16.de/" "https://www2.mk16.de/,"
"https://i2p.ghativega.in/,"
"https://i2p.novg.net/"
), "Reseed URLs, separated by comma") ), "Reseed URLs, separated by comma")
("reseed.yggurls", value<std::string>()->default_value( ("reseed.yggurls", value<std::string>()->default_value(
"http://[324:71e:281a:9ed3::ace]:7070/," "http://[324:71e:281a:9ed3::ace]:7070/,"

4
libi2pd/Datagram.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -425,7 +425,7 @@ namespace datagram
if (m) if (m)
send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m}); send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m});
} }
routingPath->outboundTunnel->SendTunnelDataMsg(send); routingPath->outboundTunnel->SendTunnelDataMsgs(send);
} }
m_SendQueue.clear(); m_SendQueue.clear();
} }

20
libi2pd/Destination.cpp

@ -108,7 +108,7 @@ namespace client
if (authType >= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE && authType <= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK) if (authType >= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE && authType <= i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
m_AuthType = authType; m_AuthType = authType;
else else
LogPrint (eLogError, "Destination: Unknown auth type ", authType); LogPrint (eLogError, "Destination: Unknown auth type: ", authType);
} }
} }
it = params->find (I2CP_PARAM_LEASESET_PRIV_KEY); it = params->find (I2CP_PARAM_LEASESET_PRIV_KEY);
@ -117,7 +117,7 @@ namespace client
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>()); m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32) if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
{ {
LogPrint(eLogError, "Destination: Invalid value i2cp.leaseSetPrivKey ", it->second); LogPrint(eLogCritical, "Destination: Invalid value i2cp.leaseSetPrivKey: ", it->second);
m_LeaseSetPrivKey.reset (nullptr); m_LeaseSetPrivKey.reset (nullptr);
} }
} }
@ -635,7 +635,7 @@ namespace client
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, msg);
m_LastSubmissionTime = ts; m_LastSubmissionTime = ts;
} }
@ -835,7 +835,7 @@ namespace client
AddSessionKey (replyKey, replyTag); AddSessionKey (replyKey, replyTag);
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
request->outboundTunnel->SendTunnelDataMsg ( request->outboundTunnel->SendTunnelDataMsgs (
{ {
i2p::tunnel::TunnelMessageBlock i2p::tunnel::TunnelMessageBlock
{ {
@ -1000,7 +1000,7 @@ namespace client
m_StreamingAckDelay = std::stoi(it->second); m_StreamingAckDelay = std::stoi(it->second);
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS); it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ()) if (it != params->end ())
m_IsStreamingAnswerPings = (it->second == "true"); m_IsStreamingAnswerPings = std::stoi (it->second); // 1 for true
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{ {
@ -1014,12 +1014,12 @@ namespace client
else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK) else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params); ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params);
else else
LogPrint (eLogError, "Destination: Unexpected auth type ", authType); LogPrint (eLogError, "Destination: Unexpected auth type: ", authType);
if (m_AuthKeys->size ()) if (m_AuthKeys->size ())
LogPrint (eLogInfo, "Destination: ", m_AuthKeys->size (), " auth keys read"); LogPrint (eLogInfo, "Destination: ", m_AuthKeys->size (), " auth keys read");
else else
{ {
LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType); LogPrint (eLogCritical, "Destination: No auth keys read for auth type: ", authType);
m_AuthKeys = nullptr; m_AuthKeys = nullptr;
} }
} }
@ -1028,7 +1028,7 @@ namespace client
} }
catch (std::exception & ex) catch (std::exception & ex)
{ {
LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what()); LogPrint(eLogCritical, "Destination: Unable to parse parameters for destination: ", ex.what());
} }
} }
@ -1336,7 +1336,7 @@ namespace client
f1.write ((char *)keys->priv, 256); f1.write ((char *)keys->priv, 256);
return; return;
} }
LogPrint(eLogError, "Destinations: Can't save keys to ", path); LogPrint(eLogCritical, "Destinations: Can't save keys to ", path);
} }
void ClientDestination::CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) void ClientDestination::CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels)
@ -1413,7 +1413,7 @@ namespace client
if (pubKey.FromBase64 (it.second.substr (pos+1))) if (pubKey.FromBase64 (it.second.substr (pos+1)))
m_AuthKeys->push_back (pubKey); m_AuthKeys->push_back (pubKey);
else else
LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1)); LogPrint (eLogCritical, "Destination: Unexpected auth key: ", it.second.substr (pos+1));
} }
} }
} }

4
libi2pd/ECIESX25519AEADRatchetSession.cpp

@ -1150,7 +1150,7 @@ namespace garlic
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<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
{ {
auto m = NewI2NPMessage (); auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
m->Align (12); // in order to get buf aligned to 16 (12 + 4) m->Align (12); // in order to get buf aligned to 16 (12 + 4)
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
size_t offset = 0; size_t offset = 0;
@ -1176,7 +1176,7 @@ namespace garlic
// Noise_N, we are Alice, routerPublicKey is Bob's // Noise_N, we are Alice, routerPublicKey is Bob's
i2p::crypto::NoiseSymmetricState noiseState; i2p::crypto::NoiseSymmetricState noiseState;
i2p::crypto::InitNoiseNState (noiseState, routerPublicKey); i2p::crypto::InitNoiseNState (noiseState, routerPublicKey);
auto m = NewI2NPMessage (); auto m = NewI2NPMessage ((msg ? msg->GetPayloadLength () : 0) + 128);
m->Align (12); // in order to get buf aligned to 16 (12 + 4) m->Align (12); // in order to get buf aligned to 16 (12 + 4)
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
size_t offset = 0; size_t offset = 0;

4
libi2pd/Ed25519.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -413,7 +413,7 @@ namespace crypto
BIGNUM * y = BN_new (); BIGNUM * y = BN_new ();
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
BIGNUM * x = RecoverX (y, ctx); BIGNUM * x = RecoverX (y, ctx);
if (BN_is_bit_set (x, 0) != isHighestBitSet) if ((bool)BN_is_bit_set (x, 0) != isHighestBitSet)
BN_sub (x, q, x); // x = q - x BN_sub (x, q, x); // x = q - x
BIGNUM * z = BN_new (), * t = BN_new (); BIGNUM * z = BN_new (), * t = BN_new ();
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t

4
libi2pd/Family.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -88,7 +88,7 @@ namespace data
} }
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
if (verifier && cn) if (verifier && cn)
m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1)); m_SigningKeys.emplace (cn, std::make_pair(verifier, (int)m_SigningKeys.size () + 1));
} }
SSL_free (ssl); SSL_free (ssl);
} }

6
libi2pd/Garlic.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -709,7 +709,7 @@ namespace garlic
else else
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel"); LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
if (tunnel) // we have sent it through an outbound tunnel if (tunnel) // we have sent it through an outbound tunnel
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, msg); tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, msg);
else else
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
} }
@ -1075,7 +1075,7 @@ namespace garlic
{ {
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel (); auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
if (tunnel) if (tunnel)
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID)); tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID));
else else
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
} }

2
libi2pd/Gzip.cpp

@ -139,7 +139,7 @@ namespace data
if (m_IsDirty) deflateReset (&m_Deflator); if (m_IsDirty) deflateReset (&m_Deflator);
m_IsDirty = true; m_IsDirty = true;
size_t offset = 0; size_t offset = 0;
int err; int err = 0;
for (const auto& it: bufs) for (const auto& it: bufs)
{ {
m_Deflator.next_in = const_cast<uint8_t *>(it.first); m_Deflator.next_in = const_cast<uint8_t *>(it.first);

28
libi2pd/HTTP.cpp

@ -93,15 +93,18 @@ namespace http
std::size_t pos_c = 0; /* < work position */ std::size_t pos_c = 0; /* < work position */
if(url.at(0) != '/' || pos_p > 0) { if(url.at(0) != '/' || pos_p > 0) {
std::size_t pos_s = 0; std::size_t pos_s = 0;
/* schema */ /* schema */
pos_c = url.find("://"); pos_c = url.find("://");
if (pos_c != std::string::npos) { if (pos_c != std::string::npos) {
schema = url.substr(0, pos_c); schema = url.substr(0, pos_c);
pos_p = pos_c + 3; pos_p = pos_c + 3;
} }
/* user[:pass] */ /* user[:pass] */
pos_s = url.find('/', pos_p); /* find first slash */ pos_s = url.find('/', pos_p); /* find first slash */
pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */ pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */
if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) { if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) {
std::size_t delim = url.find(':', pos_p); std::size_t delim = url.find(':', pos_p);
if (delim && delim != std::string::npos && delim < pos_c) { if (delim && delim != std::string::npos && delim < pos_c) {
@ -113,21 +116,28 @@ namespace http
} }
pos_p = pos_c + 1; pos_p = pos_c + 1;
} }
/* hostname[:port][/path] */ /* hostname[:port][/path] */
if (url[pos_p] == '[') // ipv6 if (url.at(pos_p) == '[') // ipv6
{ {
auto pos_b = url.find(']', pos_p); auto pos_b = url.find(']', pos_p);
if (pos_b == std::string::npos) return false; if (pos_b == std::string::npos) return false;
ipv6 = true;
pos_c = url.find_first_of(":/", pos_b); pos_c = url.find_first_of(":/", pos_b);
} }
else else
pos_c = url.find_first_of(":/", pos_p); pos_c = url.find_first_of(":/", pos_p);
if (pos_c == std::string::npos) { if (pos_c == std::string::npos) {
/* only hostname, without post and path */ /* only hostname, without post and path */
host = url.substr(pos_p, std::string::npos); host = ipv6 ?
url.substr(pos_p + 1, url.length() - 1) :
url.substr(pos_p, std::string::npos);
return true; return true;
} else if (url.at(pos_c) == ':') { } else if (url.at(pos_c) == ':') {
host = url.substr(pos_p, pos_c - pos_p); host = ipv6 ?
url.substr(pos_p + 1, pos_c - pos_p - 2) :
url.substr(pos_p, pos_c - pos_p);
/* port[/path] */ /* port[/path] */
pos_p = pos_c + 1; pos_p = pos_c + 1;
pos_c = url.find('/', pos_p); pos_c = url.find('/', pos_p);
@ -147,7 +157,9 @@ namespace http
pos_p = pos_c; pos_p = pos_c;
} else { } else {
/* start of path part found */ /* start of path part found */
host = url.substr(pos_p, pos_c - pos_p); host = ipv6 ?
url.substr(pos_p + 1, pos_c - pos_p - 2) :
url.substr(pos_p, pos_c - pos_p);
pos_p = pos_c; pos_p = pos_c;
} }
} }
@ -212,12 +224,20 @@ namespace http
} else if (user != "") { } else if (user != "") {
out += user + "@"; out += user + "@";
} }
if (ipv6) {
if (port) {
out += "[" + host + "]:" + std::to_string(port);
} else {
out += "[" + host + "]";
}
} else {
if (port) { if (port) {
out += host + ":" + std::to_string(port); out += host + ":" + std::to_string(port);
} else { } else {
out += host; out += host;
} }
} }
}
out += path; out += path;
if (hasquery) // add query even if it was empty if (hasquery) // add query even if it was empty
out += "?"; out += "?";

3
libi2pd/HTTP.h

@ -36,8 +36,9 @@ namespace http
bool hasquery; bool hasquery;
std::string query; std::string query;
std::string frag; std::string frag;
bool ipv6;
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag("") {}; URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag(""), ipv6(false) {};
/** /**
* @brief Tries to parse url from string * @brief Tries to parse url from string

39
libi2pd/I2NPProtocol.cpp

@ -36,6 +36,11 @@ namespace i2p
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >(); return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
} }
std::shared_ptr<I2NPMessage> NewI2NPMediumMessage ()
{
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MEDIUM_MESSAGE_SIZE> >();
}
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint) std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
{ {
return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint); return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint);
@ -43,7 +48,10 @@ namespace i2p
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len) std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
{ {
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE - I2NP_HEADER_SIZE - 2) ? NewI2NPShortMessage () : NewI2NPMessage (); 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 ();
} }
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum) void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum)
@ -126,7 +134,8 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers) uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{ {
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage (); int cnt = excludedPeers ? excludedPeers->size () : 0;
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload (); uint8_t * buf = m->GetPayload ();
memcpy (buf, key, 32); // key memcpy (buf, key, 32); // key
buf += 32; buf += 32;
@ -147,7 +156,6 @@ namespace i2p
if (excludedPeers) if (excludedPeers)
{ {
int cnt = excludedPeers->size ();
htobe16buf (buf, cnt); htobe16buf (buf, cnt);
buf += 2; buf += 2;
for (auto& it: *excludedPeers) for (auto& it: *excludedPeers)
@ -353,21 +361,6 @@ namespace i2p
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
} }
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{
if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
{
LogPrint (eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
g_MaxNumTransitTunnels = maxNumTransitTunnels;
}
}
uint16_t GetMaxNumTransitTunnels ()
{
return g_MaxNumTransitTunnels;
}
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{ {
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
@ -379,10 +372,7 @@ namespace i2p
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false; if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
uint8_t retCode = 0; uint8_t retCode = 0;
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ())
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded () &&
!i2p::transport::transports.IsTransitBandwidthExceeded ())
{ {
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
@ -576,10 +566,7 @@ namespace i2p
// check if we accept this tunnel // check if we accept this tunnel
uint8_t retCode = 0; uint8_t retCode = 0;
if (!i2p::context.AcceptsTunnels () || if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ())
i2p::tunnel::tunnels.GetTransitTunnels ().size () > g_MaxNumTransitTunnels ||
i2p::transport::transports.IsBandwidthExceeded () ||
i2p::transport::transports.IsTransitBandwidthExceeded ())
retCode = 30; retCode = 30;
if (!retCode) if (!retCode)
{ {

8
libi2pd/I2NPProtocol.h

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -140,6 +140,7 @@ namespace tunnel
const size_t I2NP_MAX_MESSAGE_SIZE = 62708; const size_t I2NP_MAX_MESSAGE_SIZE = 62708;
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096; const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
const size_t I2NP_MAX_MEDIUM_MESSAGE_SIZE = 16384;
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT) const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
@ -262,6 +263,7 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPMessage (); std::shared_ptr<I2NPMessage> NewI2NPMessage ();
std::shared_ptr<I2NPMessage> NewI2NPShortMessage (); std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
std::shared_ptr<I2NPMessage> NewI2NPMediumMessage ();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len); std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
@ -308,10 +310,6 @@ namespace tunnel
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs; std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
}; };
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
uint16_t GetMaxNumTransitTunnels ();
} }
#endif #endif

18
libi2pd/I2PEndian.h

@ -36,6 +36,23 @@
#define le64toh(x) OSSwapLittleToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x)
#elif defined(_WIN32) #elif defined(_WIN32)
#if defined(_MSC_VER)
#include <stdlib.h>
#define htobe16(x) _byteswap_ushort(x)
#define htole16(x) (x)
#define be16toh(x) _byteswap_ushort(x)
#define le16toh(x) (x)
#define htobe32(x) _byteswap_ulong(x)
#define htole32(x) (x)
#define be32toh(x) _byteswap_ulong(x)
#define le32toh(x) (x)
#define htobe64(x) _byteswap_uint64(x)
#define htole64(x) (x)
#define be64toh(x) _byteswap_uint64(x)
#define le64toh(x) (x)
#else
#define htobe16(x) __builtin_bswap16(x) #define htobe16(x) __builtin_bswap16(x)
#define htole16(x) (x) #define htole16(x) (x)
#define be16toh(x) __builtin_bswap16(x) #define be16toh(x) __builtin_bswap16(x)
@ -50,6 +67,7 @@
#define htole64(x) (x) #define htole64(x) (x)
#define be64toh(x) __builtin_bswap64(x) #define be64toh(x) __builtin_bswap64(x)
#define le64toh(x) (x) #define le64toh(x) (x)
#endif
#else #else
#define NEEDS_LOCAL_ENDIAN #define NEEDS_LOCAL_ENDIAN

46
libi2pd/Identity.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -187,7 +187,6 @@ namespace data
IdentityEx::~IdentityEx () IdentityEx::~IdentityEx ()
{ {
delete m_Verifier;
} }
IdentityEx& IdentityEx::operator=(const IdentityEx& other) IdentityEx& IdentityEx::operator=(const IdentityEx& other)
@ -201,9 +200,8 @@ namespace data
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE; if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen); memcpy (m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen);
} }
delete m_Verifier;
m_Verifier = nullptr; m_Verifier = nullptr;
CreateVerifier ();
return *this; return *this;
} }
@ -212,11 +210,10 @@ namespace data
{ {
m_StandardIdentity = standard; m_StandardIdentity = standard;
m_IdentHash = m_StandardIdentity.Hash (); m_IdentHash = m_StandardIdentity.Hash ();
m_ExtendedLen = 0; m_ExtendedLen = 0;
delete m_Verifier;
m_Verifier = nullptr; m_Verifier = nullptr;
CreateVerifier ();
return *this; return *this;
} }
@ -249,8 +246,8 @@ namespace data
m_ExtendedLen = 0; m_ExtendedLen = 0;
SHA256(buf, GetFullLen (), m_IdentHash); SHA256(buf, GetFullLen (), m_IdentHash);
delete m_Verifier;
m_Verifier = nullptr; m_Verifier = nullptr;
CreateVerifier ();
return GetFullLen (); return GetFullLen ();
} }
@ -286,7 +283,6 @@ namespace data
size_t IdentityEx::GetSigningPublicKeyLen () const size_t IdentityEx::GetSigningPublicKeyLen () const
{ {
if (!m_Verifier) CreateVerifier ();
if (m_Verifier) if (m_Verifier)
return m_Verifier->GetPublicKeyLen (); return m_Verifier->GetPublicKeyLen ();
return 128; return 128;
@ -301,7 +297,6 @@ namespace data
size_t IdentityEx::GetSigningPrivateKeyLen () const size_t IdentityEx::GetSigningPrivateKeyLen () const
{ {
if (!m_Verifier) CreateVerifier ();
if (m_Verifier) if (m_Verifier)
return m_Verifier->GetPrivateKeyLen (); return m_Verifier->GetPrivateKeyLen ();
return GetSignatureLen ()/2; return GetSignatureLen ()/2;
@ -309,14 +304,12 @@ namespace data
size_t IdentityEx::GetSignatureLen () const size_t IdentityEx::GetSignatureLen () const
{ {
if (!m_Verifier) CreateVerifier ();
if (m_Verifier) if (m_Verifier)
return m_Verifier->GetSignatureLen (); return m_Verifier->GetSignatureLen ();
return i2p::crypto::DSA_SIGNATURE_LENGTH; return i2p::crypto::DSA_SIGNATURE_LENGTH;
} }
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
if (!m_Verifier) CreateVerifier ();
if (m_Verifier) if (m_Verifier)
return m_Verifier->Verify (buf, len, signature); return m_Verifier->Verify (buf, len, signature);
return false; return false;
@ -373,9 +366,10 @@ namespace data
return nullptr; return nullptr;
} }
void IdentityEx::CreateVerifier () const void IdentityEx::CreateVerifier ()
{
if (!m_Verifier)
{ {
if (m_Verifier) return; // don't create again
auto verifier = CreateVerifier (GetSigningKeyType ()); auto verifier = CreateVerifier (GetSigningKeyType ());
if (verifier) if (verifier)
{ {
@ -393,32 +387,8 @@ namespace data
delete[] signingKey; delete[] signingKey;
} }
} }
UpdateVerifier (verifier); m_Verifier.reset (verifier);
}
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
{
bool del = false;
{
std::lock_guard<std::mutex> l(m_VerifierMutex);
if (!m_Verifier)
m_Verifier = verifier;
else
del = true;
}
if (del)
delete verifier;
}
void IdentityEx::DropVerifier () const
{
i2p::crypto::Verifier * verifier;
{
std::lock_guard<std::mutex> l(m_VerifierMutex);
verifier = m_Verifier;
m_Verifier = nullptr;
} }
delete verifier;
} }
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key) std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)

11
libi2pd/Identity.h

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -13,9 +13,7 @@
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <atomic>
#include <vector> #include <vector>
#include <mutex>
#include "Base.h" #include "Base.h"
#include "Signature.h" #include "Signature.h"
#include "CryptoKey.h" #include "CryptoKey.h"
@ -118,7 +116,6 @@ namespace data
SigningKeyType GetSigningKeyType () const; SigningKeyType GetSigningKeyType () const;
bool IsRSA () const; // signing key type bool IsRSA () const; // signing key type
CryptoKeyType GetCryptoKeyType () const; CryptoKeyType GetCryptoKeyType () const;
void DropVerifier () const; // to save memory
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); } bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
void RecalculateIdentHash(uint8_t * buff=nullptr); void RecalculateIdentHash(uint8_t * buff=nullptr);
@ -128,15 +125,13 @@ namespace data
private: private:
void CreateVerifier () const; void CreateVerifier ();
void UpdateVerifier (i2p::crypto::Verifier * verifier) const;
private: private:
Identity m_StandardIdentity; Identity m_StandardIdentity;
IdentHash m_IdentHash; IdentHash m_IdentHash;
mutable i2p::crypto::Verifier * m_Verifier = nullptr; std::unique_ptr<i2p::crypto::Verifier> m_Verifier;
mutable std::mutex m_VerifierMutex;
size_t m_ExtendedLen; size_t m_ExtendedLen;
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
}; };

14
libi2pd/KadDHT.cpp

@ -81,13 +81,13 @@ namespace data
{ {
if (bit1) if (bit1)
{ {
if (root->one) return; // someting wrong if (root->one) return; // something wrong
root->one = new DHTNode; root->one = new DHTNode;
root = root->one; root = root->one;
} }
else else
{ {
if (root->zero) return; // someting wrong if (root->zero) return; // something wrong
root->zero = new DHTNode; root->zero = new DHTNode;
root = root->zero; root = root->zero;
} }
@ -186,7 +186,7 @@ namespace data
return false; return false;
} }
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) const
{ {
if (filter) m_Filter = filter; if (filter) m_Filter = filter;
auto r = FindClosest (h, m_Root, 0); auto r = FindClosest (h, m_Root, 0);
@ -194,7 +194,7 @@ namespace data
return r; return r;
} }
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) const
{ {
bool split = false; bool split = false;
do do
@ -241,7 +241,7 @@ namespace data
return nullptr; return nullptr;
} }
std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) const
{ {
std::vector<std::shared_ptr<RouterInfo> > vec; std::vector<std::shared_ptr<RouterInfo> > vec;
if (num > 0) if (num > 0)
@ -253,7 +253,7 @@ namespace data
return vec; return vec;
} }
void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const
{ {
if (hashes.size () >= num) return; if (hashes.size () >= num) return;
bool split = false; bool split = false;
@ -292,7 +292,7 @@ namespace data
} }
} }
void DHTTable::Cleanup (Filter filter) void DHTTable::Cleanup (const Filter& filter)
{ {
if (filter) if (filter)
{ {

12
libi2pd/KadDHT.h

@ -44,20 +44,20 @@ namespace data
void Insert (const std::shared_ptr<RouterInfo>& r); void Insert (const std::shared_ptr<RouterInfo>& r);
bool Remove (const IdentHash& h); bool Remove (const IdentHash& h);
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr); std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr) const;
std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr); std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr) const;
void Print (std::stringstream& s); void Print (std::stringstream& s);
size_t GetSize () const { return m_Size; }; size_t GetSize () const { return m_Size; };
void Clear (); void Clear ();
void Cleanup (Filter filter); void Cleanup (const Filter& filter);
private: private:
void Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level); // recursive void Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level); // recursive
bool Remove (const IdentHash& h, DHTNode * root, int level); bool Remove (const IdentHash& h, DHTNode * root, int level);
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level); std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level) const;
void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes); void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const;
void Cleanup (DHTNode * root); void Cleanup (DHTNode * root);
void Print (std::stringstream& s, DHTNode * root, int level); void Print (std::stringstream& s, DHTNode * root, int level);
@ -66,7 +66,7 @@ namespace data
DHTNode * m_Root; DHTNode * m_Root;
size_t m_Size; size_t m_Size;
// transient // transient
Filter m_Filter; mutable Filter m_Filter;
}; };
} }
} }

6
libi2pd/LeaseSet.cpp

@ -50,7 +50,7 @@ namespace data
void LeaseSet::ReadFromBuffer (bool readIdentity, bool verifySignature) void LeaseSet::ReadFromBuffer (bool readIdentity, bool verifySignature)
{ {
if (readIdentity || !m_Identity) if (readIdentity || !m_Identity)
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen); m_Identity = netdb.NewIdentity (m_Buffer, m_BufferLen);
size_t size = m_Identity->GetFullLen (); size_t size = m_Identity->GetFullLen ();
if (size + 256 > m_BufferLen) if (size + 256 > m_BufferLen)
{ {
@ -76,7 +76,7 @@ namespace data
LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num); LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num);
if (!num || num > MAX_NUM_LEASES) if (!num || num > MAX_NUM_LEASES)
{ {
LogPrint (eLogError, "LeaseSet: Rncorrect number of leases", (int)num); LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)num);
m_IsValid = false; m_IsValid = false;
return; return;
} }
@ -317,7 +317,7 @@ namespace data
std::shared_ptr<const IdentityEx> identity; std::shared_ptr<const IdentityEx> identity;
if (readIdentity || !GetIdentity ()) if (readIdentity || !GetIdentity ())
{ {
identity = std::make_shared<IdentityEx>(buf, len); identity = netdb.NewIdentity (buf, len);
SetIdentity (identity); SetIdentity (identity);
} }
else else

10
libi2pd/Log.cpp

@ -21,6 +21,7 @@ namespace log {
static const char *g_LogLevelStr[eNumLogLevels] = static const char *g_LogLevelStr[eNumLogLevels] =
{ {
"none", // eLogNone "none", // eLogNone
"critical", // eLogCritical
"error", // eLogError "error", // eLogError
"warn", // eLogWarning "warn", // eLogWarning
"info", // eLogInfo "info", // eLogInfo
@ -32,10 +33,11 @@ namespace log {
* @note Using ISO 6429 (ANSI) color sequences * @note Using ISO 6429 (ANSI) color sequences
*/ */
#ifdef _WIN32 #ifdef _WIN32
static const char *LogMsgColors[] = { "", "", "", "", "", "" }; static const char *LogMsgColors[] = { "", "", "", "", "", "", "" };
#else /* UNIX */ #else /* UNIX */
static const char *LogMsgColors[] = { static const char *LogMsgColors[] = {
"\033[1;32m", /* none: green */ "\033[1;32m", /* none: green */
"\033[1;41m", /* critical: red background */
"\033[1;31m", /* error: red */ "\033[1;31m", /* error: red */
"\033[1;33m", /* warning: yellow */ "\033[1;33m", /* warning: yellow */
"\033[1;36m", /* info: cyan */ "\033[1;36m", /* info: cyan */
@ -53,6 +55,7 @@ namespace log {
int priority = LOG_DEBUG; int priority = LOG_DEBUG;
switch (l) { switch (l) {
case eLogNone : priority = LOG_CRIT; break; case eLogNone : priority = LOG_CRIT; break;
case eLogCritical: priority = LOG_CRIT; break;
case eLogError : priority = LOG_ERR; break; case eLogError : priority = LOG_ERR; break;
case eLogWarning : priority = LOG_WARNING; break; case eLogWarning : priority = LOG_WARNING; break;
case eLogInfo : priority = LOG_INFO; break; case eLogInfo : priority = LOG_INFO; break;
@ -124,12 +127,13 @@ namespace log {
void Log::SetLogLevel (const std::string& level_) { void Log::SetLogLevel (const std::string& level_) {
std::string level=str_tolower(level_); std::string level=str_tolower(level_);
if (level == "none") { m_MinLevel = eLogNone; } if (level == "none") { m_MinLevel = eLogNone; }
else if (level == "critical") { m_MinLevel = eLogCritical; }
else if (level == "error") { m_MinLevel = eLogError; } else if (level == "error") { m_MinLevel = eLogError; }
else if (level == "warn") { m_MinLevel = eLogWarning; } else if (level == "warn") { m_MinLevel = eLogWarning; }
else if (level == "info") { m_MinLevel = eLogInfo; } else if (level == "info") { m_MinLevel = eLogInfo; }
else if (level == "debug") { m_MinLevel = eLogDebug; } else if (level == "debug") { m_MinLevel = eLogDebug; }
else { else {
LogPrint(eLogError, "Log: Unknown loglevel: ", level); LogPrint(eLogCritical, "Log: Unknown loglevel: ", level);
return; return;
} }
LogPrint(eLogInfo, "Log: Logging level set to ", level); LogPrint(eLogInfo, "Log: Logging level set to ", level);
@ -212,7 +216,7 @@ namespace log {
m_LogStream = os; m_LogStream = os;
return; return;
} }
LogPrint(eLogError, "Log: Can't open file ", path); LogPrint(eLogCritical, "Log: Can't open file ", path);
} }
void Log::SendTo (std::shared_ptr<std::ostream> os) { void Log::SendTo (std::shared_ptr<std::ostream> os) {

1
libi2pd/Log.h

@ -27,6 +27,7 @@
enum LogLevel enum LogLevel
{ {
eLogNone = 0, eLogNone = 0,
eLogCritical,
eLogError, eLogError,
eLogWarning, eLogWarning,
eLogInfo, eLogInfo,

10
libi2pd/NTCP2.cpp

@ -452,6 +452,7 @@ namespace transport
{ {
m_Establisher->CreateSessionRequestMessage (); m_Establisher->CreateSessionRequestMessage ();
// send message // send message
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionRequestBuffer, m_Establisher->m_SessionRequestBufferLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
@ -529,6 +530,7 @@ namespace transport
{ {
m_Establisher->CreateSessionCreatedMessage (); m_Establisher->CreateSessionCreatedMessage ();
// send message // send message
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionCreatedBuffer, m_Establisher->m_SessionCreatedBufferLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
@ -542,6 +544,7 @@ namespace transport
} }
else else
{ {
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
uint16_t paddingLen = 0; uint16_t paddingLen = 0;
if (m_Establisher->ProcessSessionCreatedMessage (paddingLen)) if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
@ -646,6 +649,7 @@ namespace transport
} }
else else
{ {
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
// part 1 // part 1
uint8_t nonce[12]; uint8_t nonce[12];
@ -1238,7 +1242,7 @@ namespace transport
boost::system::error_code e; boost::system::error_code e;
auto itr = m_Resolver.resolve(q, e); auto itr = m_Resolver.resolve(q, e);
if(e) if(e)
LogPrint(eLogError, "NTCP2: Failed to resolve proxy ", e.message()); LogPrint(eLogCritical, "NTCP2: Failed to resolve proxy ", e.message());
else else
{ {
m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr)); m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr));
@ -1266,7 +1270,7 @@ namespace transport
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogError, "NTCP2: Failed to bind to v4 port ", address->port, ex.what()); LogPrint(eLogCritical, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
ThrowFatal ("Unable to start IPv4 NTCP2 transport at port ", address->port, ": ", ex.what ()); ThrowFatal ("Unable to start IPv4 NTCP2 transport at port ", address->port, ": ", ex.what ());
continue; continue;
} }
@ -1309,7 +1313,7 @@ namespace transport
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what()); LogPrint(eLogCritical, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ()); ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
continue; continue;
} }

206
libi2pd/NetDb.cpp

@ -36,7 +36,7 @@ namespace data
{ {
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false) NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true)
{ {
} }
@ -55,7 +55,7 @@ namespace data
Load (); Load ();
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils if (m_RouterInfos.size () < threshold || m_Floodfills.GetSize () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
{ {
Reseed (); Reseed ();
} }
@ -66,13 +66,13 @@ namespace data
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
{ {
// remove own router // remove own router
m_Floodfills.remove (it->second); m_Floodfills.Remove (it->second->GetIdentHash ());
m_RouterInfos.erase (it); m_RouterInfos.erase (it);
} }
// insert own router // insert own router
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ()); m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ()); m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles); i2p::config::GetOption("persist.profiles", m_PersistProfiles);
@ -88,7 +88,7 @@ namespace data
SaveProfiles (); SaveProfiles ();
DeleteObsoleteProfiles (); DeleteObsoleteProfiles ();
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.clear (); m_Floodfills.Clear ();
if (m_Thread) if (m_Thread)
{ {
m_IsRunning = false; m_IsRunning = false;
@ -106,7 +106,7 @@ namespace data
{ {
i2p::util::SetThreadName("NetDB"); i2p::util::SetThreadName("NetDB");
uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; uint64_t lastSave = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch (); uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
int16_t profilesCleanupVariance = 0; int16_t profilesCleanupVariance = 0;
@ -132,9 +132,6 @@ namespace data
case eI2NPDatabaseLookup: case eI2NPDatabaseLookup:
HandleDatabaseLookupMsg (msg); HandleDatabaseLookupMsg (msg);
break; break;
case eI2NPDeliveryStatus:
HandleDeliveryStatusMsg (msg);
break;
case eI2NPDummyMsg: case eI2NPDummyMsg:
// plain RouterInfo from NTCP2 with flags for now // plain RouterInfo from NTCP2 with flags for now
HandleNTCP2RouterInfoMsg (msg); HandleNTCP2RouterInfoMsg (msg);
@ -184,33 +181,6 @@ namespace data
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE); profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
} }
// publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{
bool publish = false;
if (m_PublishReplyToken)
{
// next publishing attempt
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
}
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL ||
ts + NETDB_PUBLISH_INTERVAL < lastPublish)
{
// new publish
m_PublishExcluded.clear ();
if (i2p::context.IsFloodfill ())
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
publish = true;
}
if (publish) // update timestamp and publish
{
i2p::context.UpdateTimestamp (ts);
Publish ();
lastPublish = ts;
}
}
if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds
{ {
auto numRouters = m_RouterInfos.size (); auto numRouters = m_RouterInfos.size ();
@ -224,7 +194,7 @@ namespace data
if (numRouters < 1) numRouters = 1; if (numRouters < 1) numRouters = 1;
if (numRouters > 9) numRouters = 9; if (numRouters > 9) numRouters = 9;
m_Requests.ManageRequests (); m_Requests.ManageRequests ();
if(!m_HiddenMode) if(!i2p::context.IsHidden ())
Explore (numRouters); Explore (numRouters);
lastExploratory = ts; lastExploratory = ts;
} }
@ -237,12 +207,6 @@ namespace data
} }
} }
void NetDb::SetHidden(bool hide)
{
// TODO: remove reachable addresses from router info
m_HiddenMode = hide;
}
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len) std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len)
{ {
bool updated; bool updated;
@ -289,7 +253,7 @@ namespace data
if (wasFloodfill) if (wasFloodfill)
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.remove (r); m_Floodfills.Remove (r->GetIdentHash ());
} }
m_Requests.RequestComplete (ident, nullptr); m_Requests.RequestComplete (ident, nullptr);
return nullptr; return nullptr;
@ -301,9 +265,9 @@ namespace data
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
if (wasFloodfill) if (wasFloodfill)
m_Floodfills.remove (r); m_Floodfills.Remove (r->GetIdentHash ());
else if (r->IsEligibleFloodfill ()) else if (r->IsEligibleFloodfill ())
m_Floodfills.push_back (r); m_Floodfills.Insert (r);
} }
} }
else else
@ -329,7 +293,7 @@ namespace data
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.Insert (r);
} }
} }
else else
@ -467,8 +431,8 @@ namespace data
} }
// try reseeding from floodfill first if specified // try reseeding from floodfill first if specified
std::string riPath; std::string riPath; i2p::config::GetOption("reseed.floodfill", riPath);
if(i2p::config::GetOption("reseed.floodfill", riPath)) if (!riPath.empty())
{ {
auto ri = std::make_shared<RouterInfo>(riPath); auto ri = std::make_shared<RouterInfo>(riPath);
if (ri->IsFloodfill()) if (ri->IsFloodfill())
@ -530,7 +494,7 @@ namespace data
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second) if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{ {
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
m_Floodfills.push_back (r); m_Floodfills.Insert (r);
} }
} }
else else
@ -614,7 +578,7 @@ namespace data
{ {
// make sure we cleanup netDb from previous attempts // make sure we cleanup netDb from previous attempts
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.clear (); m_Floodfills.Clear ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
std::vector<std::string> files; std::vector<std::string> files;
@ -622,14 +586,14 @@ namespace data
for (const auto& path : files) for (const auto& path : files)
LoadRouterInfo (path, ts); LoadRouterInfo (path, ts);
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)"); LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.GetSize (), " floodfils)");
} }
void NetDb::SaveUpdated () void NetDb::SaveUpdated ()
{ {
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0; int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
auto totalFloodfills = m_Floodfills.size (); auto totalFloodfills = m_Floodfills.GetSize ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
auto uptime = i2p::context.GetUptime (); auto uptime = i2p::context.GetUptime ();
@ -698,6 +662,7 @@ namespace data
m_RouterInfoBuffersPool.CleanUpMt (); m_RouterInfoBuffersPool.CleanUpMt ();
m_RouterInfoAddressesPool.CleanUpMt (); m_RouterInfoAddressesPool.CleanUpMt ();
m_RouterInfoAddressVectorsPool.CleanUpMt (); m_RouterInfoAddressVectorsPool.CleanUpMt ();
m_IdentitiesPool.CleanUpMt ();
if (updatedCount > 0) if (updatedCount > 0)
LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers"); LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
@ -721,11 +686,10 @@ namespace data
// clean up expired floodfills or not floodfills anymore // clean up expired floodfills or not floodfills anymore
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();) m_Floodfills.Cleanup ([](const std::shared_ptr<RouterInfo>& r)->bool
if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ()) {
it = m_Floodfills.erase (it); return r && r->IsFloodfill () && !r->IsUnreachable ();
else });
it++;
} }
} }
} }
@ -753,7 +717,7 @@ namespace data
auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr; auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr; auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (outbound && inbound) if (outbound && inbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound)); outbound->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound));
else else
{ {
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found"); LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
@ -828,7 +792,7 @@ namespace data
auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr; auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr;
if (outbound) if (outbound)
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus); outbound->SendTunnelDataMsgTo (buf + offset, tunnelID, deliveryStatus);
else else
LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found"); LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
} }
@ -937,7 +901,7 @@ namespace data
{ {
// request destination // request destination
LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ()); LogPrint (eLogDebug, "NetDb: Try ", key, " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 ());
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0, outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (nextFloodfill, inbound)); dest->CreateRequestMessage (nextFloodfill, inbound));
deleteDest = false; deleteDest = false;
} }
@ -1117,7 +1081,7 @@ namespace data
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr; auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
if (outbound) if (outbound)
outbound->SendTunnelDataMsg (replyIdent, replyTunnelID, replyMsg); outbound->SendTunnelDataMsgTo (replyIdent, replyTunnelID, replyMsg);
else else
transports.SendMessage (replyIdent, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg)); transports.SendMessage (replyIdent, i2p::CreateTunnelGatewayMsg (replyTunnelID, replyMsg));
} }
@ -1126,16 +1090,6 @@ namespace data
} }
} }
void NetDb::HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg)
{
if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
{
LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken);
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
}
}
void NetDb::Explore (int numDestinations) void NetDb::Explore (int numDestinations)
{ {
// new requests // new requests
@ -1183,42 +1137,7 @@ namespace data
m_Requests.RequestComplete (randomHash, nullptr); m_Requests.RequestComplete (randomHash, nullptr);
} }
if (throughTunnels && msgs.size () > 0) if (throughTunnels && msgs.size () > 0)
outbound->SendTunnelDataMsg (msgs); outbound->SendTunnelDataMsgs (msgs);
}
void NetDb::Publish ()
{
i2p::context.UpdateStats (); // for floodfill
if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
{
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
m_PublishExcluded.clear ();
}
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill)
{
uint32_t replyToken;
RAND_bytes ((uint8_t *)&replyToken, 4);
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken;
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
// send directly
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else
{
// otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (inbound && outbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
}
}
} }
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg) void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
@ -1292,7 +1211,7 @@ namespace data
router->IsReachableFrom (*compatibleWith)) && router->IsReachableFrom (*compatibleWith)) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) && (router->GetCaps () & RouterInfo::eHighBandwidth) &&
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
router->IsECIES (); router->IsECIES () && !router->IsHighCongestion ();
}); });
} }
@ -1362,74 +1281,37 @@ namespace data
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const const std::set<IdentHash>& excluded) const
{ {
std::shared_ptr<const RouterInfo> r;
XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
{
if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ())
{ {
XORMetric m = destKey ^ it->GetIdentHash (); return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
if (m < minMetric && !excluded.count (it->GetIdentHash ())) !excluded.count (r->GetIdentHash ());
{ });
minMetric = m;
r = it;
}
}
}
return r;
} }
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly) const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{ {
struct Sorted std::vector<IdentHash> res;
{
std::shared_ptr<const RouterInfo> r;
XORMetric metric;
bool operator< (const Sorted& other) const { return metric < other.metric; };
};
std::set<Sorted> sorted;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
XORMetric ourMetric; std::vector<std::shared_ptr<RouterInfo> > v;
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool
{
if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ())
{ {
XORMetric m = destKey ^ it->GetIdentHash (); return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () &&
if (closeThanUsOnly && ourMetric < m) continue; !excluded.count (r->GetIdentHash ());
if (sorted.size () < num) });
sorted.insert ({it, m});
else if (m < sorted.rbegin ()->metric)
{
sorted.insert ({it, m});
sorted.erase (std::prev (sorted.end ()));
}
}
}
} }
if (v.empty ()) return res;
std::vector<IdentHash> res; XORMetric ourMetric;
size_t i = 0; if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
for (const auto& it: sorted) for (auto& it: v)
{
if (i < num)
{
const auto& ident = it.r->GetIdentHash ();
if (!excluded.count (ident))
{ {
res.push_back (ident); if (closeThanUsOnly && ourMetric < (destKey ^ it->GetIdentHash ())) break;
i++; res.push_back (it->GetIdentHash ());
}
}
else
break;
} }
return res; return res;
} }

19
libi2pd/NetDb.hpp

@ -12,7 +12,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <unordered_map> #include <unordered_map>
#include <list>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@ -31,6 +30,7 @@
#include "Family.h" #include "Family.h"
#include "version.h" #include "version.h"
#include "util.h" #include "util.h"
#include "KadDHT.h"
namespace i2p namespace i2p
{ {
@ -45,9 +45,6 @@ namespace data
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes
const int NETDB_PUBLISH_INTERVAL = 60 * 40;
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
@ -86,7 +83,6 @@ namespace data
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m); void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
void HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; 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> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
@ -102,15 +98,12 @@ namespace data
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide);
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; };
// for web interface // for web interface
int GetNumRouters () const { return m_RouterInfos.size (); }; int GetNumRouters () const { return m_RouterInfos.size (); };
int GetNumFloodfills () const { return m_Floodfills.size (); }; int GetNumFloodfills () const { return m_Floodfills.GetSize (); };
int GetNumLeaseSets () const { return m_LeaseSets.size (); }; int GetNumLeaseSets () const { return m_LeaseSets.size (); };
/** visit all lease sets we currently store */ /** visit all lease sets we currently store */
@ -134,6 +127,7 @@ namespace data
&m_RouterInfoAddressVectorsPool, std::placeholders::_1)); &m_RouterInfoAddressVectorsPool, std::placeholders::_1));
}; };
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); }; 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); };
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; }; uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
@ -144,7 +138,6 @@ namespace data
void SaveUpdated (); void SaveUpdated ();
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish ();
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg); void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
@ -164,7 +157,7 @@ namespace data
mutable std::mutex m_RouterInfosMutex; mutable std::mutex m_RouterInfosMutex;
std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos; std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
std::list<std::shared_ptr<RouterInfo> > m_Floodfills; DHTTable m_Floodfills;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
@ -183,9 +176,6 @@ namespace data
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/ /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
/** true if in hidden mode */
bool m_HiddenMode;
std::set<IdentHash> m_PublishExcluded; std::set<IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken = 0; uint32_t m_PublishReplyToken = 0;
@ -193,6 +183,7 @@ namespace data
i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool; i2p::util::MemoryPoolMt<RouterInfo::Address> m_RouterInfoAddressesPool;
i2p::util::MemoryPoolMt<RouterInfo::Addresses> m_RouterInfoAddressVectorsPool; i2p::util::MemoryPoolMt<RouterInfo::Addresses> m_RouterInfoAddressVectorsPool;
i2p::util::MemoryPoolMt<Lease> m_LeasesPool; i2p::util::MemoryPoolMt<Lease> m_LeasesPool;
i2p::util::MemoryPoolMt<IdentityEx> m_IdentitiesPool;
}; };
extern NetDb netdb; extern NetDb netdb;

4
libi2pd/NetDbRequests.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -137,7 +137,7 @@ namespace data
auto inbound = pool->GetNextInboundTunnel (); auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound) if (nextFloodfill && outbound && inbound)
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0, outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (nextFloodfill, inbound)); dest->CreateRequestMessage (nextFloodfill, inbound));
else else
{ {

73
libi2pd/Reseed.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -153,7 +153,7 @@ namespace data
return ProcessSU3Stream (s); return ProcessSU3Stream (s);
else else
{ {
LogPrint (eLogError, "Reseed: Can't open file ", filename); LogPrint (eLogCritical, "Reseed: Can't open file ", filename);
return 0; return 0;
} }
} }
@ -170,7 +170,7 @@ namespace data
} }
else else
{ {
LogPrint (eLogError, "Reseed: Can't open file ", filename); LogPrint (eLogCritical, "Reseed: Can't open file ", filename);
return 0; return 0;
} }
} }
@ -278,7 +278,7 @@ namespace data
if (verify) // not verified if (verify) // not verified
{ {
LogPrint (eLogError, "Reseed: SU3 verification failed"); LogPrint (eLogCritical, "Reseed: SU3 verification failed");
return 0; return 0;
} }
@ -320,7 +320,7 @@ namespace data
uint16_t fileNameLength, extraFieldLength; uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2); s.read ((char *)&fileNameLength, 2);
fileNameLength = le16toh (fileNameLength); fileNameLength = le16toh (fileNameLength);
if ( fileNameLength > 255 ) { if ( fileNameLength >= 255 ) {
// too big // too big
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength); LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
return numFiles; return numFiles;
@ -492,7 +492,7 @@ namespace data
SSL_free (ssl); SSL_free (ssl);
} }
else else
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename); LogPrint (eLogCritical, "Reseed: Can't open certificate file ", filename);
SSL_CTX_free (ctx); SSL_CTX_free (ctx);
} }
@ -534,17 +534,17 @@ namespace data
} }
// check for valid proxy url schema // check for valid proxy url schema
if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") { if (proxyUrl.schema != "http" && proxyUrl.schema != "socks") {
LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy); LogPrint(eLogCritical, "Reseed: Bad proxy url: ", proxy);
return ""; return "";
} }
} else { } else {
LogPrint(eLogError, "Reseed: Bad proxy url: ", proxy); LogPrint(eLogCritical, "Reseed: Bad proxy url: ", proxy);
return ""; return "";
} }
} }
i2p::http::URL url; i2p::http::URL url;
if (!url.parse(address)) { if (!url.parse(address)) {
LogPrint(eLogError, "Reseed: Failed to parse url: ", address); LogPrint(eLogCritical, "Reseed: Failed to parse url: ", address);
return ""; return "";
} }
url.schema = "https"; url.schema = "https";
@ -687,12 +687,23 @@ namespace data
while (it != end) while (it != end)
{ {
boost::asio::ip::tcp::endpoint ep = *it; boost::asio::ip::tcp::endpoint ep = *it;
if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) || if (
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())) (
!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 ()
)
)
{ {
s.lowest_layer().connect (ep, ecode); s.lowest_layer().connect (ep, ecode);
if (!ecode) if (!ecode)
{ {
LogPrint (eLogDebug, "Reseed: Resolved to ", ep.address ());
connected = true; connected = true;
break; break;
} }
@ -780,17 +791,45 @@ namespace data
boost::asio::io_service service; boost::asio::io_service service;
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6()); boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
if (url.host.length () < 2) return ""; // assume [] auto it = boost::asio::ip::tcp::resolver(service).resolve (
auto host = url.host.substr (1, url.host.length () - 2); boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode);
LogPrint (eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port);
s.connect (boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v6::from_string (host), url.port), ecode); if (!ecode)
{
bool connected = false;
boost::asio::ip::tcp::resolver::iterator end;
while (it != end)
{
boost::asio::ip::tcp::endpoint ep = *it;
if (
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
i2p::context.SupportsMesh ()
)
{
LogPrint (eLogDebug, "Reseed: Yggdrasil: Resolved to ", ep.address ());
s.connect (ep, ecode);
if (!ecode)
{
connected = true;
break;
}
}
it++;
}
if (!connected)
{
LogPrint(eLogError, "Reseed: Yggdrasil: Failed to connect to ", url.host);
return "";
}
}
if (!ecode) if (!ecode)
{ {
LogPrint (eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port); LogPrint (eLogDebug, "Reseed: Yggdrasil: Connected to ", url.host, ":", url.port);
return ReseedRequest (s, url.to_string()); return ReseedRequest (s, url.to_string());
} }
else else
LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ()); LogPrint (eLogError, "Reseed: Yggdrasil: Couldn't connect to ", url.host, ": ", ecode.message ());
return ""; return "";
} }

229
libi2pd/RouterContext.cpp

@ -20,6 +20,8 @@
#include "Log.h" #include "Log.h"
#include "Family.h" #include "Family.h"
#include "ECIESX25519AEADRatchetSession.h" #include "ECIESX25519AEADRatchetSession.h"
#include "Transports.h"
#include "Tunnel.h"
#include "RouterContext.h" #include "RouterContext.h"
namespace i2p namespace i2p
@ -29,7 +31,8 @@ namespace i2p
RouterContext::RouterContext (): RouterContext::RouterContext ():
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), 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_NetID (I2PD_NET_ID),
m_PublishReplyToken (0), m_IsHiddenMode (false)
{ {
} }
@ -47,6 +50,34 @@ namespace i2p
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState); m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState);
} }
void RouterContext::Start ()
{
if (!m_Service)
{
m_Service.reset (new RouterService);
m_Service->Start ();
if (!m_IsHiddenMode)
{
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
ScheduleInitialPublish ();
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
ScheduleCongestionUpdate ();
}
}
}
void RouterContext::Stop ()
{
if (m_Service)
{
if (m_PublishTimer)
m_PublishTimer->cancel ();
if (m_CongestionUpdateTimer)
m_CongestionUpdateTimer->cancel ();
m_Service->Stop ();
}
}
void RouterContext::CreateNewRouter () void RouterContext::CreateNewRouter ()
{ {
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
@ -198,6 +229,7 @@ namespace i2p
routerInfo.CreateBuffer (m_Keys); routerInfo.CreateBuffer (m_Keys);
m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.SetRouterIdentity (GetIdentity ());
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
m_RouterInfo.SetUnreachable (false);
} }
uint16_t RouterContext::SelectRandomPort () const uint16_t RouterContext::SelectRandomPort () const
@ -1058,6 +1090,8 @@ namespace i2p
UpdateSSU2Keys (); UpdateSSU2Keys ();
updated = true; updated = true;
} }
if (m_RouterInfo.UpdateCongestion (i2p::data::RouterInfo::eLowCongestion))
updated = true;
if (updated) if (updated)
UpdateRouterInfo (); UpdateRouterInfo ();
@ -1080,6 +1114,13 @@ namespace i2p
return i2p::tunnel::tunnels.GetExploratoryPool (); return i2p::tunnel::tunnels.GetExploratoryPool ();
} }
bool RouterContext::IsHighCongestion () const
{
return i2p::tunnel::tunnels.IsTooManyTransitTunnels () ||
i2p::transport::transports.IsBandwidthExceeded () ||
i2p::transport::transports.IsTransitBandwidthExceeded ();
}
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len) void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
{ {
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
@ -1087,12 +1128,6 @@ namespace i2p
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID)
{ {
if (typeID == eI2NPGarlic)
{
// TODO: implement
LogPrint (eLogWarning, "Router: garlic message in garlic clove. Dropped");
return false;
}
auto msg = CreateI2NPMessage (typeID, payload, len, msgID); auto msg = CreateI2NPMessage (typeID, payload, len, msgID);
if (!msg) return false; if (!msg) return false;
i2p::HandleI2NPMessage (msg); i2p::HandleI2NPMessage (msg);
@ -1101,7 +1136,14 @@ namespace i2p
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
std::unique_lock<std::mutex> l(m_GarlicMutex); if (m_Service)
m_Service->GetService ().post (std::bind (&RouterContext::PostGarlicMessage, this, msg));
else
LogPrint (eLogError, "Router: service is NULL");
}
void RouterContext::PostGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
uint32_t len = bufbe32toh (buf); uint32_t len = bufbe32toh (buf);
if (len > msg->GetLength ()) if (len > msg->GetLength ())
@ -1122,19 +1164,34 @@ namespace i2p
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) if (m_Service)
i2p::data::netdb.PostI2NPMsg (msg); m_Service->GetService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg));
else else
LogPrint (eLogError, "Router: service is NULL");
}
void RouterContext::PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
std::unique_lock<std::mutex> l(m_GarlicMutex); if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); {
LogPrint (eLogInfo, "Router: Publishing confirmed. reply token=", m_PublishReplyToken);
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
SchedulePublish ();
} }
else
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
} }
void RouterContext::CleanupDestination () void RouterContext::CleanupDestination ()
{ {
std::unique_lock<std::mutex> l(m_GarlicMutex); if (m_Service)
i2p::garlic::GarlicDestination::CleanupExpiredTags (); m_Service->GetService ().post ([this]()
{
this->i2p::garlic::GarlicDestination::CleanupExpiredTags ();
});
else
LogPrint (eLogError, "Router: service is NULL");
} }
uint32_t RouterContext::GetUptime () const uint32_t RouterContext::GetUptime () const
@ -1209,4 +1266,148 @@ namespace i2p
} }
return *m_SSU2StaticKeys; return *m_SSU2StaticKeys;
} }
void RouterContext::ScheduleInitialPublish ()
{
if (m_PublishTimer)
{
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_INITIAL_PUBLISH_INTERVAL));
m_PublishTimer->async_wait (std::bind (&RouterContext::HandleInitialPublishTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Publish timer is NULL");
}
void RouterContext::HandleInitialPublishTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
HandlePublishTimer (ecode);
else
ScheduleInitialPublish ();
}
}
void RouterContext::SchedulePublish ()
{
if (m_PublishTimer)
{
m_PublishTimer->cancel ();
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_PUBLISH_INTERVAL +
rand () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE));
m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Publish timer is NULL");
}
void RouterContext::HandlePublishTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
if (IsFloodfill ())
{
UpdateStats (); // for floodfill
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
}
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
Publish ();
SchedulePublishResend ();
}
}
void RouterContext::Publish ()
{
if (!i2p::transport::transports.IsOnline ()) return;
if (m_PublishExcluded.size () > ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
{
LogPrint (eLogError, "Router: Couldn't publish our RouterInfo to ", ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
m_PublishExcluded.clear ();
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
}
auto floodfill = i2p::data::netdb.GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill)
{
uint32_t replyToken;
RAND_bytes ((uint8_t *)&replyToken, 4);
LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
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));
else
{
// otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
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));
else
LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds");
}
m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken;
}
else
LogPrint (eLogInfo, "Router: Can't find floodfill to publish our RouterInfo");
}
void RouterContext::SchedulePublishResend ()
{
if (m_PublishTimer)
{
m_PublishTimer->cancel ();
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONFIRMATION_TIMEOUT));
m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishResendTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Publish timer is NULL");
}
void RouterContext::HandlePublishResendTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
i2p::context.UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
Publish ();
SchedulePublishResend ();
}
}
void RouterContext::ScheduleCongestionUpdate ()
{
if (m_CongestionUpdateTimer)
{
m_CongestionUpdateTimer->cancel ();
m_CongestionUpdateTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONGESTION_UPDATE_INTERVAL));
m_CongestionUpdateTimer->async_wait (std::bind (&RouterContext::HandleCongestionUpdateTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Congestion update timer is NULL");
}
void RouterContext::HandleCongestionUpdateTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto c = i2p::data::RouterInfo::eLowCongestion;
if (!AcceptsTunnels ())
c = i2p::data::RouterInfo::eRejectAll;
else if (IsHighCongestion ())
c = i2p::data::RouterInfo::eHighCongestion;
if (m_RouterInfo.UpdateCongestion (c))
UpdateRouterInfo ();
ScheduleCongestionUpdate ();
}
}
} }

45
libi2pd/RouterContext.h

@ -12,12 +12,13 @@
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <mutex>
#include <chrono> #include <chrono>
#include <set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "Garlic.h" #include "Garlic.h"
#include "util.h"
namespace i2p namespace i2p
{ {
@ -30,7 +31,13 @@ namespace garlic
const char ROUTER_KEYS[] = "router.keys"; const char ROUTER_KEYS[] = "router.keys";
const char NTCP2_KEYS[] = "ntcp2.keys"; const char NTCP2_KEYS[] = "ntcp2.keys";
const char SSU2_KEYS[] = "ssu2.keys"; const char SSU2_KEYS[] = "ssu2.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes const int ROUTER_INFO_UPDATE_INTERVAL = 30*60; // 30 minutes
const int ROUTER_INFO_PUBLISH_INTERVAL = 39*60; // in seconds
const int ROUTER_INFO_INITIAL_PUBLISH_INTERVAL = 10; // in seconds
const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds
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
enum RouterStatus enum RouterStatus
{ {
@ -70,10 +77,22 @@ namespace garlic
uint8_t intro[32]; uint8_t intro[32];
}; };
class RouterService: public i2p::util::RunnableServiceWithWork
{
public:
RouterService (): RunnableServiceWithWork ("Router") {};
boost::asio::io_service& GetService () { return GetIOService (); };
void Start () { StartIOService (); };
void Stop () { StopIOService (); };
};
public: public:
RouterContext (); RouterContext ();
void Init (); void Init ();
void Start ();
void Stop ();
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; }; i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; };
@ -134,6 +153,7 @@ namespace garlic
void SetShareRatio (int percents); // 0 - 100 void SetShareRatio (int percents); // 0 - 100
bool AcceptsTunnels () const { return m_AcceptsTunnels; }; bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
bool IsHighCongestion () const;
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
bool SupportsMesh () const { return m_RouterInfo.IsMesh (); }; bool SupportsMesh () const { return m_RouterInfo.IsMesh (); };
@ -141,6 +161,8 @@ namespace garlic
void SetSupportsV4 (bool supportsV4); void SetSupportsV4 (bool supportsV4);
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host); void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
void SetMTU (int mtu, bool v4); void SetMTU (int mtu, bool v4);
void SetHidden(bool hide) { m_IsHiddenMode = hide; };
bool IsHidden() const { return m_IsHiddenMode; };
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
@ -183,6 +205,18 @@ namespace garlic
void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const; void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const;
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize); bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
void PostGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void ScheduleInitialPublish ();
void HandleInitialPublishTimer (const boost::system::error_code& ecode);
void SchedulePublish ();
void HandlePublishTimer (const boost::system::error_code& ecode);
void Publish ();
void SchedulePublishResend ();
void HandlePublishResendTimer (const boost::system::error_code& ecode);
void ScheduleCongestionUpdate ();
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
private: private:
@ -198,12 +232,17 @@ namespace garlic
RouterStatus m_Status, m_StatusV6; RouterStatus m_Status, m_StatusV6;
RouterError m_Error, m_ErrorV6; RouterError m_Error, m_ErrorV6;
int m_NetID; int m_NetID;
std::mutex m_GarlicMutex;
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys; std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys; std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys; std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys;
// for ECIESx25519 // for ECIESx25519
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState; 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::set<i2p::data::IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken;
bool m_IsHiddenMode; // not publish
}; };
extern RouterContext context; extern RouterContext context;

92
libi2pd/RouterInfo.cpp

@ -43,7 +43,7 @@ namespace data
RouterInfo::RouterInfo (const std::string& fullPath): RouterInfo::RouterInfo (const std::string& fullPath):
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false), m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0),m_ReachableTransports (0), m_SupportedTransports (0),m_ReachableTransports (0),
m_Caps (0), m_Version (0) m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
{ {
m_Addresses = boost::make_shared<Addresses>(); // create empty list m_Addresses = boost::make_shared<Addresses>(); // create empty list
m_Buffer = NewBuffer (); // always RouterInfo's m_Buffer = NewBuffer (); // always RouterInfo's
@ -53,7 +53,7 @@ namespace data
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len): RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false), m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
m_SupportedTransports (0), m_ReachableTransports (0), m_SupportedTransports (0), m_ReachableTransports (0),
m_Caps (0), m_Version (0) m_Caps (0), m_Version (0), m_Congestion (eLowCongestion)
{ {
if (len <= MAX_RI_BUFFER_SIZE) if (len <= MAX_RI_BUFFER_SIZE)
{ {
@ -161,7 +161,7 @@ namespace data
m_IsUnreachable = true; m_IsUnreachable = true;
return; return;
} }
m_RouterIdentity = std::make_shared<IdentityEx>(m_Buffer->data (), m_BufferLen); m_RouterIdentity = NewIdentity (m_Buffer->data (), m_BufferLen);
size_t identityLen = m_RouterIdentity->GetFullLen (); size_t identityLen = m_RouterIdentity->GetFullLen ();
if (identityLen >= m_BufferLen) if (identityLen >= m_BufferLen)
{ {
@ -186,7 +186,6 @@ namespace data
m_IsUnreachable = true; m_IsUnreachable = true;
return; return;
} }
m_RouterIdentity->DropVerifier ();
} }
// parse RI // parse RI
std::stringstream str; std::stringstream str;
@ -202,7 +201,7 @@ namespace data
void RouterInfo::ReadFromStream (std::istream& s) void RouterInfo::ReadFromStream (std::istream& s)
{ {
if (!s) return; if (!s) return;
m_Caps = 0; m_Caps = 0; m_Congestion = eLowCongestion;
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp)); s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
m_Timestamp = be64toh (m_Timestamp); m_Timestamp = be64toh (m_Timestamp);
// read addresses // read addresses
@ -336,11 +335,7 @@ namespace data
address->ssu->introducers.resize (index + 1); address->ssu->introducers.resize (index + 1);
} }
Introducer& introducer = address->ssu->introducers.at (index); Introducer& introducer = address->ssu->introducers.at (index);
if (!strcmp (key, "ihost")) if (!strcmp (key, "itag"))
introducer.isH = false; // SSU1
else if (!strcmp (key, "iport"))
introducer.isH = false; // SSU1
else if (!strcmp (key, "itag"))
{ {
try try
{ {
@ -352,10 +347,7 @@ namespace data
} }
} }
else if (!strcmp (key, "ih")) else if (!strcmp (key, "ih"))
{
Base64ToByteStream (value, strlen (value), introducer.iH, 32); Base64ToByteStream (value, strlen (value), introducer.iH, 32);
introducer.isH = true;
}
else if (!strcmp (key, "iexp")) else if (!strcmp (key, "iexp"))
{ {
try try
@ -411,7 +403,7 @@ namespace data
int numValid = 0; int numValid = 0;
for (auto& it: address->ssu->introducers) for (auto& it: address->ssu->introducers)
{ {
if (it.iTag && ts < it.iExp && it.isH) if (it.iTag && ts < it.iExp)
numValid++; numValid++;
else else
it.iTag = 0; it.iTag = 0;
@ -542,6 +534,15 @@ namespace data
case CAPS_FLAG_UNREACHABLE: case CAPS_FLAG_UNREACHABLE:
m_Caps |= Caps::eUnreachable; m_Caps |= Caps::eUnreachable;
break; break;
case CAPS_FLAG_MEDIUM_CONGESTION:
m_Congestion = eMediumCongestion;
break;
case CAPS_FLAG_HIGH_CONGESTION:
m_Congestion = eHighCongestion;
break;
case CAPS_FLAG_REJECT_ALL_CONGESTION:
m_Congestion = eRejectAll;
break;
default: ; default: ;
} }
cap++; cap++;
@ -1059,11 +1060,25 @@ namespace data
return netdb.NewRouterInfoAddresses (); return netdb.NewRouterInfoAddresses ();
} }
std::shared_ptr<IdentityEx> RouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
{
return netdb.NewIdentity (buf, len);
}
void RouterInfo::RefreshTimestamp () void RouterInfo::RefreshTimestamp ()
{ {
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
} }
bool RouterInfo::IsHighCongestion () 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;
}
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys) void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
{ {
RefreshTimestamp (); RefreshTimestamp ();
@ -1115,9 +1130,34 @@ namespace data
if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
switch (GetCongestion ())
{
case eMediumCongestion:
caps += CAPS_FLAG_MEDIUM_CONGESTION;
break;
case eHighCongestion:
caps += CAPS_FLAG_HIGH_CONGESTION;
break;
case eRejectAll:
caps += CAPS_FLAG_REJECT_ALL_CONGESTION;
break;
default: ;
};
SetProperty ("caps", caps); SetProperty ("caps", caps);
} }
bool LocalRouterInfo::UpdateCongestion (Congestion c)
{
if (c != GetCongestion ())
{
SetCongestion (c);
UpdateCapsProperty ();
return true;
}
return false;
}
void LocalRouterInfo::WriteToStream (std::ostream& s) const void LocalRouterInfo::WriteToStream (std::ostream& s) const
{ {
auto addresses = GetAddresses (); auto addresses = GetAddresses ();
@ -1154,44 +1194,37 @@ namespace data
s.write ((const char *)&cost, sizeof (cost)); s.write ((const char *)&cost, sizeof (cost));
s.write ((const char *)&address.date, sizeof (address.date)); s.write ((const char *)&address.date, sizeof (address.date));
std::stringstream properties; std::stringstream properties;
bool isPublished = false; bool isPublished = address.published && !address.host.is_unspecified () && address.port;
if (address.transportStyle == eTransportNTCP2) if (address.transportStyle == eTransportNTCP2)
{
if (address.IsNTCP2 ())
{ {
WriteString ("NTCP2", s); WriteString ("NTCP2", s);
if (address.IsPublishedNTCP2 () && !address.host.is_unspecified () && address.port) // caps
isPublished = true; if (!isPublished)
else
{ {
WriteString ("caps", properties); WriteString ("caps", properties);
properties << '='; properties << '=';
std::string caps; std::string caps;
if (address.IsV4 ()) caps += CAPS_FLAG_V4; if (address.IsV4 ()) caps += CAPS_FLAG_V4;
if (address.IsV6 ()) caps += CAPS_FLAG_V6; if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
if (caps.empty ()) caps += CAPS_FLAG_V4; if (caps.empty ()) caps += CAPS_FLAG_V4;
WriteString (caps, properties); WriteString (caps, properties);
properties << ';'; properties << ';';
} }
} }
else
continue; // don't write NTCP address
}
else if (address.transportStyle == eTransportSSU2) else if (address.transportStyle == eTransportSSU2)
{ {
WriteString ("SSU2", s); WriteString ("SSU2", s);
// caps // caps
std::string caps; std::string caps;
if (address.published) if (isPublished)
{ {
isPublished = true;
if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU2_TESTING; if (address.IsPeerTesting ()) caps += CAPS_FLAG_SSU2_TESTING;
if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU2_INTRODUCER; if (address.IsIntroducer ()) caps += CAPS_FLAG_SSU2_INTRODUCER;
} }
else else
{ {
if (address.IsV4 ()) caps += CAPS_FLAG_V4; if (address.IsV4 ()) caps += CAPS_FLAG_V4;
if (address.IsV6 ()) caps += CAPS_FLAG_V6; if (address.IsV6 () || address.host.is_v6 ()) caps += CAPS_FLAG_V6; // we set 6 for unspecified ipv6
if (caps.empty ()) caps += CAPS_FLAG_V4; if (caps.empty ()) caps += CAPS_FLAG_V4;
} }
if (!caps.empty ()) if (!caps.empty ())
@ -1350,6 +1383,11 @@ namespace data
return boost::make_shared<Addresses> (); return boost::make_shared<Addresses> ();
} }
std::shared_ptr<IdentityEx> LocalRouterInfo::NewIdentity (const uint8_t * buf, size_t len) const
{
return std::make_shared<IdentityEx> (buf, len);
}
bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4) bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
{ {
auto addresses = GetAddresses (); auto addresses = GetAddresses ();

26
libi2pd/RouterInfo.h

@ -44,6 +44,10 @@ namespace data
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 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_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
// congesion flags
const char CAPS_FLAG_MEDIUM_CONGESTION = 'D';
const char CAPS_FLAG_HIGH_CONGESTION = 'E';
const char CAPS_FLAG_REJECT_ALL_CONGESTION = 'G';
const char CAPS_FLAG_V4 = '4'; const char CAPS_FLAG_V4 = '4';
const char CAPS_FLAG_V6 = '6'; const char CAPS_FLAG_V6 = '6';
@ -56,6 +60,8 @@ namespace data
const uint8_t COST_SSU2_NON_PUBLISHED = 15; const uint8_t COST_SSU2_NON_PUBLISHED = 15;
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later 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
class RouterInfo: public RoutingDestination class RouterInfo: public RoutingDestination
{ {
public: public:
@ -93,6 +99,14 @@ namespace data
eUnreachable = 0x20 eUnreachable = 0x20
}; };
enum Congestion
{
eLowCongestion = 0,
eMediumCongestion,
eHighCongestion,
eRejectAll
};
enum AddressCaps enum AddressCaps
{ {
eV4 = 0x01, eV4 = 0x01,
@ -110,11 +124,10 @@ namespace data
struct Introducer struct Introducer
{ {
Introducer (): iTag (0), iExp (0), isH (false) {}; Introducer (): iTag (0), iExp (0) {};
IdentHash iH; IdentHash iH;
uint32_t iTag; uint32_t iTag;
uint32_t iExp; uint32_t iExp;
bool isH; // TODO: remove later
}; };
struct SSUExt struct SSUExt
@ -235,10 +248,13 @@ namespace data
bool IsEligibleFloodfill () const; bool IsEligibleFloodfill () const;
bool IsSSU2PeerTesting (bool v4) const; bool IsSSU2PeerTesting (bool v4) const;
bool IsSSU2Introducer (bool v4) const; bool IsSSU2Introducer (bool v4) const;
bool IsHighCongestion () const;
uint8_t GetCaps () const { return m_Caps; }; uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps) { m_Caps = caps; }; void SetCaps (uint8_t caps) { m_Caps = caps; };
Congestion GetCongestion () const { return m_Congestion; };
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; }; bool IsUnreachable () const { return m_IsUnreachable; };
@ -275,6 +291,7 @@ namespace data
void RefreshTimestamp (); void RefreshTimestamp ();
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; }; CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; }; void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
void SetCongestion (Congestion c) { m_Congestion = c; };
private: private:
@ -290,6 +307,7 @@ namespace data
virtual std::shared_ptr<Buffer> NewBuffer () const; virtual std::shared_ptr<Buffer> NewBuffer () const;
virtual std::shared_ptr<Address> NewAddress () const; virtual std::shared_ptr<Address> NewAddress () const;
virtual boost::shared_ptr<Addresses> NewAddresses () const; virtual boost::shared_ptr<Addresses> NewAddresses () const;
virtual std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const;
private: private:
@ -303,6 +321,7 @@ namespace data
CompatibleTransports m_SupportedTransports, m_ReachableTransports; CompatibleTransports m_SupportedTransports, m_ReachableTransports;
uint8_t m_Caps; uint8_t m_Caps;
int m_Version; int m_Version;
Congestion m_Congestion;
mutable std::shared_ptr<RouterProfile> m_Profile; mutable std::shared_ptr<RouterProfile> m_Profile;
}; };
@ -311,9 +330,9 @@ namespace data
public: public:
LocalRouterInfo () = default; LocalRouterInfo () = default;
LocalRouterInfo (const std::string& fullPath): RouterInfo (fullPath) {};
void CreateBuffer (const PrivateKeys& privateKeys); void CreateBuffer (const PrivateKeys& privateKeys);
void UpdateCaps (uint8_t caps); void UpdateCaps (uint8_t caps);
bool UpdateCongestion (Congestion c); // returns true if updated
void SetProperty (const std::string& key, const std::string& value) override; void SetProperty (const std::string& key, const std::string& value) override;
void DeleteProperty (const std::string& key); void DeleteProperty (const std::string& key);
@ -331,6 +350,7 @@ namespace data
std::shared_ptr<Buffer> NewBuffer () const override; std::shared_ptr<Buffer> NewBuffer () const override;
std::shared_ptr<Address> NewAddress () const override; std::shared_ptr<Address> NewAddress () const override;
boost::shared_ptr<Addresses> NewAddresses () const override; boost::shared_ptr<Addresses> NewAddresses () const override;
std::shared_ptr<IdentityEx> NewIdentity (const uint8_t * buf, size_t len) const override;
private: private:

9
libi2pd/SSU2.cpp

@ -99,7 +99,7 @@ namespace transport
} }
} }
else else
LogPrint (eLogError, "SSU2: Can't start server because port not specified"); LogPrint (eLogCritical, "SSU2: Can't start server because port not specified");
} }
} }
if (found) if (found)
@ -224,7 +224,7 @@ namespace transport
} }
catch (std::exception& ex ) catch (std::exception& ex )
{ {
LogPrint (eLogError, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what()); LogPrint (eLogCritical, "SSU2: Failed to bind to ", localEndpoint, ": ", ex.what());
ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ()); ThrowFatal ("Unable to start SSU2 transport on ", localEndpoint, ": ", ex.what ());
} }
return socket; return socket;
@ -918,7 +918,7 @@ namespace transport
} }
uint64_t token; uint64_t token;
RAND_bytes ((uint8_t *)&token, 8); RAND_bytes ((uint8_t *)&token, 8);
m_IncomingTokens.emplace (ep, std::make_pair (token, ts + SSU2_TOKEN_EXPIRATION_TIMEOUT)); m_IncomingTokens.emplace (ep, std::make_pair (token, uint32_t(ts + SSU2_TOKEN_EXPIRATION_TIMEOUT)));
return token; return token;
} }
@ -927,7 +927,7 @@ namespace transport
m_IncomingTokens.erase (ep); // drop previous m_IncomingTokens.erase (ep); // drop previous
uint64_t token; uint64_t token;
RAND_bytes ((uint8_t *)&token, 8); RAND_bytes ((uint8_t *)&token, 8);
auto ret = std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT); auto ret = std::make_pair (token, uint32_t(i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT));
m_IncomingTokens.emplace (ep, ret); m_IncomingTokens.emplace (ep, ret);
return ret; return ret;
} }
@ -1017,7 +1017,6 @@ namespace transport
i2p::data::RouterInfo::Introducer introducer; i2p::data::RouterInfo::Introducer introducer;
introducer.iTag = it->GetRelayTag (); introducer.iTag = it->GetRelayTag ();
introducer.iH = it->GetRemoteIdentity ()->GetIdentHash (); introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
introducer.isH = true;
introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION; introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
if (i2p::context.AddSSU2Introducer (introducer, v4)) if (i2p::context.AddSSU2Introducer (introducer, v4))

30
libi2pd/SSU2Session.cpp

@ -23,7 +23,7 @@ namespace transport
if (msg->len + fragmentSize > msg->maxLen) if (msg->len + fragmentSize > msg->maxLen)
{ {
LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough"); LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough");
auto newMsg = NewI2NPMessage (); auto newMsg = NewI2NPMessage (msg->len + fragmentSize);
*newMsg = *msg; *newMsg = *msg;
msg = newMsg; msg = newMsg;
} }
@ -608,7 +608,7 @@ namespace transport
* payload = m_SentHandshakePacket->payload; * payload = m_SentHandshakePacket->payload;
// fill packet // fill packet
header.h.connID = m_DestConnID; // dest id header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0; RAND_bytes (header.buf + 8, 4); // random packet num
header.h.type = eSSU2SessionRequest; header.h.type = eSSU2SessionRequest;
header.h.flags[0] = 2; // ver header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
@ -636,7 +636,7 @@ namespace transport
m_EphemeralKeys->Agree (m_Address->s, sharedSecret); m_EphemeralKeys->Agree (m_Address->s, sharedSecret);
m_NoiseState->MixKey (sharedSecret); m_NoiseState->MixKey (sharedSecret);
// encrypt // encrypt
const uint8_t nonce[12] = {0}; const uint8_t nonce[12] = {0}; // always 0
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16; payloadSize += 16;
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24)); header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
@ -648,6 +648,7 @@ namespace transport
if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ())) if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ()))
{ {
m_State = eSSU2SessionStateSessionRequestSent; m_State = eSSU2SessionStateSessionRequestSent;
m_HandshakeInterval = ts;
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
} }
else else
@ -721,7 +722,7 @@ namespace transport
uint8_t * headerX = m_SentHandshakePacket->headerX, uint8_t * headerX = m_SentHandshakePacket->headerX,
* payload = m_SentHandshakePacket->payload; * payload = m_SentHandshakePacket->payload;
header.h.connID = m_DestConnID; // dest id header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0; RAND_bytes (header.buf + 8, 4); // random packet num
header.h.type = eSSU2SessionCreated; header.h.type = eSSU2SessionCreated;
header.h.flags[0] = 2; // ver header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
@ -760,7 +761,7 @@ namespace transport
m_EphemeralKeys->Agree (X, sharedSecret); m_EphemeralKeys->Agree (X, sharedSecret);
m_NoiseState->MixKey (sharedSecret); m_NoiseState->MixKey (sharedSecret);
// encrypt // encrypt
const uint8_t nonce[12] = {0}; const uint8_t nonce[12] = {0}; // always zero
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16; payloadSize += 16;
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created) m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created)
@ -770,6 +771,7 @@ namespace transport
m_State = eSSU2SessionStateSessionCreatedSent; m_State = eSSU2SessionStateSessionCreatedSent;
m_SentHandshakePacket->payloadSize = payloadSize; m_SentHandshakePacket->payloadSize = payloadSize;
// send // send
m_HandshakeInterval = ts;
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
} }
@ -790,6 +792,7 @@ namespace transport
LogPrint (eLogWarning, "SSU2: SessionCreated message too short ", len); LogPrint (eLogWarning, "SSU2: SessionCreated message too short ", len);
return false; return false;
} }
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
const uint8_t nonce[12] = {0}; const uint8_t nonce[12] = {0};
uint8_t headerX[48]; uint8_t headerX[48];
i2p::crypto::ChaCha20 (buf + 16, 48, kh2, nonce, headerX); i2p::crypto::ChaCha20 (buf + 16, 48, kh2, nonce, headerX);
@ -832,7 +835,7 @@ namespace transport
// fill packet // fill packet
Header& header = m_SentHandshakePacket->header; Header& header = m_SentHandshakePacket->header;
header.h.connID = m_DestConnID; // dest id header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0; header.h.packetNum = 0; // always zero
header.h.type = eSSU2SessionConfirmed; header.h.type = eSSU2SessionConfirmed;
memset (header.h.flags, 0, 3); memset (header.h.flags, 0, 3);
header.h.flags[0] = 1; // frag, total fragments always 1 header.h.flags[0] = 1; // frag, total fragments always 1
@ -855,7 +858,7 @@ namespace transport
// Encrypt part 1 // Encrypt part 1
uint8_t * part1 = m_SentHandshakePacket->headerX; uint8_t * part1 = m_SentHandshakePacket->headerX;
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (1, nonce); CreateNonce (1, nonce); // always one
i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetSSU2StaticPublicKey (), 32, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, part1, 48, true); i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetSSU2StaticPublicKey (), 32, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, part1, 48, true);
m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext); m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext);
// KDF for Session Confirmed part 2 // KDF for Session Confirmed part 2
@ -863,7 +866,7 @@ namespace transport
i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret); i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret);
m_NoiseState->MixKey (sharedSecret); m_NoiseState->MixKey (sharedSecret);
// Encrypt part2 // Encrypt part2
memset (nonce, 0, 12); memset (nonce, 0, 12); // always zero
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true); i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16; payloadSize += 16;
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext); m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext);
@ -920,6 +923,12 @@ namespace transport
// TODO: queue up // TODO: queue up
return true; return true;
} }
// packet num must be always zero
if (header.h.packetNum)
{
LogPrint (eLogError, "SSU2: Non zero packet number in SessionConfirmed");
return false;
}
// check if fragmented // check if fragmented
uint8_t numFragments = header.h.flags[0] & 0x0F; uint8_t numFragments = header.h.flags[0] & 0x0F;
if (numFragments > 1) if (numFragments > 1)
@ -989,6 +998,7 @@ namespace transport
if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr); if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
return false; return false;
} }
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
// KDF for Session Confirmed part 1 // KDF for Session Confirmed part 1
m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header) m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header)
// decrypt part1 // decrypt part1
@ -1661,7 +1671,7 @@ namespace transport
// ranges // ranges
len -= 5; len -= 5;
const uint8_t * ranges = buf + 5; const uint8_t * ranges = buf + 5;
while (len > 0 && firstPacketNum) while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS)
{ {
uint32_t lastPacketNum = firstPacketNum - 1; uint32_t lastPacketNum = firstPacketNum - 1;
if (*ranges > lastPacketNum) break; if (*ranges > lastPacketNum) break;
@ -1766,8 +1776,8 @@ namespace transport
void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len) void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len)
{ {
auto msg = (buf[0] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
uint32_t msgID; memcpy (&msgID, buf + 1, 4); uint32_t msgID; memcpy (&msgID, buf + 1, 4);
auto msg = NewI2NPShortMessage ();
// same format as I2NP message block // same format as I2NP message block
msg->len = msg->offset + len + 7; msg->len = msg->offset + len + 7;
memcpy (msg->GetNTCP2Header (), buf, len); memcpy (msg->GetNTCP2Header (), buf, len);

4
libi2pd/SSU2Session.h

@ -49,10 +49,10 @@ namespace transport
const float SSU2_kAPPA = 1.8; const float SSU2_kAPPA = 1.8;
const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages
const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks
const int SSU2_MAX_NUM_ACK_PACKETS = 510; // 2*255 ack + nack const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
const int SSU2_SEND_DATETIME_NUM_PACKETS = 250; const int SSU2_SEND_DATETIME_NUM_PACKETS = 256;
// flags // flags
const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;

37
libi2pd/Streaming.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -51,8 +51,8 @@ namespace stream
{ {
// partially // partially
rem = len - offset; rem = len - offset;
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset); memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem);
nextBuffer->offset += (len - offset); nextBuffer->offset += rem;
offset = len; // break offset = len; // break
} }
} }
@ -139,14 +139,22 @@ namespace stream
{ {
m_NumReceivedBytes += packet->GetLength (); m_NumReceivedBytes += packet->GetLength ();
if (!m_SendStreamID) if (!m_SendStreamID)
{
m_SendStreamID = packet->GetReceiveStreamID (); m_SendStreamID = packet->GetReceiveStreamID ();
if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet
memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32))
{
LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ());
m_LocalDestination.DeletePacket (packet);
return;
}
}
if (!packet->IsNoAck ()) // ack received if (!packet->IsNoAck ()) // ack received
ProcessAck (packet); ProcessAck (packet);
int32_t receivedSeqn = packet->GetSeqn (); int32_t receivedSeqn = packet->GetSeqn ();
bool isSyn = packet->IsSYN (); if (!receivedSeqn && !packet->GetFlags ())
if (!receivedSeqn && !isSyn)
{ {
// plain ack // plain ack
LogPrint (eLogDebug, "Streaming: Plain ACK received"); LogPrint (eLogDebug, "Streaming: Plain ACK received");
@ -188,7 +196,7 @@ namespace stream
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
} }
else if (isSyn) else if (packet->IsSYN ())
// we have to send SYN back to incoming connection // we have to send SYN back to incoming connection
SendBuffer (); // also sets m_IsOpen SendBuffer (); // also sets m_IsOpen
} }
@ -384,7 +392,7 @@ namespace stream
memset (p.buf, 0, 22); // minimal header all zeroes memset (p.buf, 0, 22); // minimal header all zeroes
memcpy (p.buf + 4, packet->buf, 4); // but receiveStreamID is the sendStreamID from the ping memcpy (p.buf + 4, packet->buf, 4); // but receiveStreamID is the sendStreamID from the ping
htobe16buf (p.buf + 18, PACKET_FLAG_ECHO); // and echo flag htobe16buf (p.buf + 18, PACKET_FLAG_ECHO); // and echo flag
ssize_t payloadLen = packet->len - (packet->GetPayload () - packet->buf); auto payloadLen = int(packet->len) - (packet->GetPayload () - packet->buf);
if (payloadLen > 0) if (payloadLen > 0)
memcpy (p.buf + 22, packet->GetPayload (), payloadLen); memcpy (p.buf + 22, packet->GetPayload (), payloadLen);
else else
@ -560,8 +568,19 @@ namespace stream
else else
htobe32buf (packet + size, m_LastReceivedSequenceNumber); htobe32buf (packet + size, m_LastReceivedSequenceNumber);
size += 4; // ack Through 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; packet[size] = 0;
size++; // NACK count size++; // NACK count
}
packet[size] = m_RTO/1000; packet[size] = m_RTO/1000;
size++; // resend delay size++; // resend delay
if (m_Status == eStreamStatusNew) if (m_Status == eStreamStatusNew)
@ -906,7 +925,7 @@ namespace stream
}); });
m_NumSentBytes += it->GetLength (); m_NumSentBytes += it->GetLength ();
} }
m_CurrentOutboundTunnel->SendTunnelDataMsg (msgs); m_CurrentOutboundTunnel->SendTunnelDataMsgs (msgs);
} }
else else
{ {
@ -1428,7 +1447,7 @@ namespace stream
const uint8_t * payload, size_t len, uint16_t toPort, bool checksum, bool gzip) const uint8_t * payload, size_t len, uint16_t toPort, bool checksum, bool gzip)
{ {
size_t size; size_t size;
auto msg = m_I2NPMsgsPool.AcquireShared (); auto msg = (len <= STREAMING_MTU_RATCHETS) ? m_I2NPMsgsPool.AcquireShared () : NewI2NPMessage ();
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for lengthlength buf += 4; // reserve for lengthlength
msg->len += 4; msg->len += 4;

5
libi2pd/Streaming.h

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -80,6 +80,7 @@ namespace stream
uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); }; uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); };
uint8_t GetNACKCount () const { return buf[16]; }; uint8_t GetNACKCount () const { return buf[16]; };
uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); }; uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); };
const uint8_t * GetNACKs () const { return buf + 17; };
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); }; uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); };
uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); }; uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); };
@ -312,7 +313,7 @@ namespace stream
std::unordered_map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN std::unordered_map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
i2p::util::MemoryPool<Packet> m_PacketsPool; i2p::util::MemoryPool<Packet> m_PacketsPool;
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool; i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> > m_I2NPMsgsPool;
public: public:

26
libi2pd/TransitTunnel.h

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -34,9 +34,9 @@ namespace tunnel
virtual size_t GetNumTransmittedBytes () const { return 0; }; virtual size_t GetNumTransmittedBytes () const { return 0; };
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out); void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
private: private:
i2p::crypto::AESKey m_LayerKey, m_IVKey; i2p::crypto::AESKey m_LayerKey, m_IVKey;
@ -54,9 +54,9 @@ namespace tunnel
layerKey, ivKey), m_NumTransmittedBytes (0) {}; layerKey, ivKey), m_NumTransmittedBytes (0) {};
~TransitTunnelParticipant (); ~TransitTunnelParticipant ();
size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; size_t GetNumTransmittedBytes () const override { return m_NumTransmittedBytes; };
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
void FlushTunnelDataMsgs (); void FlushTunnelDataMsgs () override;
private: private:
@ -74,9 +74,9 @@ namespace tunnel
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {}; layerKey, ivKey), m_Gateway(this) {};
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void FlushTunnelDataMsgs (); void FlushTunnelDataMsgs () override;
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; size_t GetNumTransmittedBytes () const override { return m_Gateway.GetNumSentBytes (); };
private: private:
@ -94,10 +94,10 @@ namespace tunnel
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
m_Endpoint (false) {}; // transit endpoint is always outbound m_Endpoint (false) {}; // transit endpoint is always outbound
void Cleanup () { m_Endpoint.Cleanup (); } void Cleanup () override { m_Endpoint.Cleanup (); }
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); } size_t GetNumTransmittedBytes () const override { return m_Endpoint.GetNumReceivedBytes (); }
private: private:

8
libi2pd/TransportSession.h

@ -69,6 +69,8 @@ namespace transport
std::stringstream m_Stream; std::stringstream m_Stream;
}; };
const int64_t TRANSPORT_SESSION_SLOWNESS_THRESHOLD = 500; // in milliseconds
const int64_t TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL = 10000; // in milliseconds
class TransportSession class TransportSession
{ {
public: public:
@ -76,7 +78,8 @@ namespace transport
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout): TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
m_NumSentBytes (0), m_NumReceivedBytes (0), m_SendQueueSize (0), m_NumSentBytes (0), m_NumReceivedBytes (0), m_SendQueueSize (0),
m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()) m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()),
m_HandshakeInterval (0)
{ {
if (router) if (router)
m_RemoteIdentity = router->GetRouterIdentity (); m_RemoteIdentity = router->GetRouterIdentity ();
@ -103,6 +106,8 @@ namespace transport
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
size_t GetSendQueueSize () const { return m_SendQueueSize; }; size_t GetSendQueueSize () const { return m_SendQueueSize; };
bool IsOutgoing () const { return m_IsOutgoing; }; bool IsOutgoing () const { return m_IsOutgoing; };
bool IsSlow () const { return m_HandshakeInterval > TRANSPORT_SESSION_SLOWNESS_THRESHOLD &&
m_HandshakeInterval < TRANSPORT_SESSION_MAX_HANDSHAKE_INTERVAL; };
int GetTerminationTimeout () const { return m_TerminationTimeout; }; int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; }; void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
@ -129,6 +134,7 @@ namespace transport
int m_TerminationTimeout; int m_TerminationTimeout;
uint64_t m_LastActivityTimestamp; uint64_t m_LastActivityTimestamp;
uint32_t m_CreationTime; // seconds since epoch uint32_t m_CreationTime; // seconds since epoch
int64_t m_HandshakeInterval; // in milliseconds between SessionRequest->SessionCreated or SessionCreated->SessionConfirmed
}; };
// SOCKS5 proxy // SOCKS5 proxy

13
libi2pd/Transports.cpp

@ -200,10 +200,10 @@ namespace transport
i2p::context.SetStatusV6 (eRouterStatusProxy); i2p::context.SetStatusV6 (eRouterStatusProxy);
} }
else else
LogPrint(eLogError, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy); LogPrint(eLogCritical, "Transports: Unsupported NTCP2 proxy URL ", ntcp2proxy);
} }
else else
LogPrint(eLogError, "Transports: Invalid NTCP2 proxy URL ", ntcp2proxy); LogPrint(eLogCritical, "Transports: Invalid NTCP2 proxy URL ", ntcp2proxy);
} }
else else
m_NTCP2Server = new NTCP2Server (); m_NTCP2Server = new NTCP2Server ();
@ -225,10 +225,10 @@ namespace transport
i2p::context.SetStatusV6 (eRouterStatusProxy); i2p::context.SetStatusV6 (eRouterStatusProxy);
} }
else else
LogPrint(eLogError, "Transports: Can't set SSU2 proxy ", ssu2proxy); LogPrint(eLogCritical, "Transports: Can't set SSU2 proxy ", ssu2proxy);
} }
else else
LogPrint(eLogError, "Transports: Invalid SSU2 proxy URL ", ssu2proxy); LogPrint(eLogCritical, "Transports: Invalid SSU2 proxy URL ", ssu2proxy);
} }
} }
@ -906,9 +906,10 @@ namespace transport
return GetRandomPeer ( return GetRandomPeer (
[isHighBandwidth](const Peer& peer)->bool [isHighBandwidth](const Peer& peer)->bool
{ {
// connected and not overloaded // connected, not overloaded and not slow
return !peer.router && !peer.sessions.empty () && return !peer.router && !peer.sessions.empty () && peer.isReachable &&
peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE && peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
!peer.sessions.front ()->IsSlow () &&
(!isHighBandwidth || peer.isHighBandwidth); (!isHighBandwidth || peer.isHighBandwidth);
}); });
} }

10
libi2pd/Transports.h

@ -72,15 +72,18 @@ namespace transport
uint64_t creationTime, nextRouterInfoUpdateTime; uint64_t creationTime, nextRouterInfoUpdateTime;
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages; std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
std::vector<i2p::data::RouterInfo::SupportedTransports> priority; std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
bool isHighBandwidth; bool isHighBandwidth, isReachable;
Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts): Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts):
numAttempts (0), router (r), creationTime (ts), numAttempts (0), router (r), creationTime (ts),
nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL), nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL),
isHighBandwidth (false) isHighBandwidth (false), isReachable (false)
{ {
if (router) if (router)
{
isHighBandwidth = router->IsHighBandwidth (); isHighBandwidth = router->IsHighBandwidth ();
isReachable = (bool)router->GetCompatibleTransports (true);
}
} }
void Done () void Done ()
@ -93,7 +96,10 @@ namespace transport
{ {
router = r; router = r;
if (router) if (router)
{
isHighBandwidth = router->IsHighBandwidth (); isHighBandwidth = router->IsHighBandwidth ();
isReachable = (bool)router->GetCompatibleTransports (true);
}
} }
}; };

28
libi2pd/Tunnel.cpp

@ -103,7 +103,7 @@ namespace tunnel
if (msg1) msg = msg1; if (msg1) msg = msg1;
} }
} }
outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); outboundTunnel->SendTunnelDataMsgTo (GetNextIdentHash (), 0, msg);
} }
else else
{ {
@ -266,7 +266,7 @@ namespace tunnel
} }
} }
void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg) void OutboundTunnel::SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg)
{ {
TunnelMessageBlock block; TunnelMessageBlock block;
if (gwHash) if (gwHash)
@ -284,10 +284,10 @@ namespace tunnel
block.deliveryType = eDeliveryTypeLocal; block.deliveryType = eDeliveryTypeLocal;
block.data = msg; block.data = msg;
SendTunnelDataMsg ({block}); SendTunnelDataMsgs ({block});
} }
void OutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs) void OutboundTunnel::SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs)
{ {
std::unique_lock<std::mutex> l(m_SendMutex); std::unique_lock<std::mutex> l(m_SendMutex);
for (auto& it : msgs) for (auto& it : msgs)
@ -306,7 +306,7 @@ namespace tunnel
{ {
} }
void ZeroHopsOutboundTunnel::SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs) void ZeroHopsOutboundTunnel::SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs)
{ {
for (auto& msg : msgs) for (auto& msg : msgs)
{ {
@ -331,14 +331,15 @@ namespace tunnel
Tunnels tunnels; Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), m_MaxNumTransitTunnels (DEFAULT_MAX_NUM_TRANSIT_TUNNELS),
m_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal avarage m_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal average
m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0) m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0)
{ {
} }
Tunnels::~Tunnels () Tunnels::~Tunnels ()
{ {
DeleteTunnelPool(m_ExploratoryPool);
} }
std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID) std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID)
@ -543,7 +544,7 @@ namespace tunnel
ManageTunnels (ts); ManageTunnels (ts);
lastTs = ts; lastTs = ts;
} }
if (ts - lastPoolsTs >= TUNNEL_POOLS_MANAGE_INTERVAL || // manage pools every 5 secondsts if (ts - lastPoolsTs >= TUNNEL_POOLS_MANAGE_INTERVAL || // manage pools every 5 seconds
ts + TUNNEL_POOLS_MANAGE_INTERVAL < lastPoolsTs) ts + TUNNEL_POOLS_MANAGE_INTERVAL < lastPoolsTs)
{ {
ManageTunnelPools (ts); ManageTunnelPools (ts);
@ -697,7 +698,7 @@ namespace tunnel
if (m_OutboundTunnels.size () < 3) if (m_OutboundTunnels.size () < 3)
{ {
// trying to create one more oubound tunnel // trying to create one more outbound tunnel
auto inboundTunnel = GetNextInboundTunnel (); auto inboundTunnel = GetNextInboundTunnel ();
auto router = i2p::transport::transports.RoutesRestricted() ? auto router = i2p::transport::transports.RoutesRestricted() ?
i2p::transport::transports.GetRestrictedPeer() : i2p::transport::transports.GetRestrictedPeer() :
@ -970,5 +971,14 @@ namespace tunnel
// TODO: locking // TODO: locking
return m_OutboundTunnels.size(); return m_OutboundTunnels.size();
} }
void Tunnels::SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{
if (maxNumTransitTunnels > 0 && m_MaxNumTransitTunnels != maxNumTransitTunnels)
{
LogPrint (eLogDebug, "Tunnel: Max number of transit tunnels set to ", maxNumTransitTunnels);
m_MaxNumTransitTunnels = maxNumTransitTunnels;
}
}
} }
} }

32
libi2pd/Tunnel.h

@ -41,6 +41,7 @@ namespace tunnel
const int MAX_NUM_RECORDS = 8; const int MAX_NUM_RECORDS = 8;
const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds
const int MAX_TUNNEL_MSGS_BATCH_SIZE = 100; // handle messages without interrupt const int MAX_TUNNEL_MSGS_BATCH_SIZE = 100; // handle messages without interrupt
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
const int TUNNEL_MANAGE_INTERVAL = 15; // in seconds const int TUNNEL_MANAGE_INTERVAL = 15; // in seconds
const int TUNNEL_POOLS_MANAGE_INTERVAL = 5; // in seconds const int TUNNEL_POOLS_MANAGE_INTERVAL = 5; // in seconds
const int TUNNEL_MEMORY_POOL_MANAGE_INTERVAL = 120; // in seconds const int TUNNEL_MEMORY_POOL_MANAGE_INTERVAL = 120; // in seconds
@ -102,8 +103,8 @@ namespace tunnel
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out); void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) override;
/** @brief add latency sample */ /** @brief add latency sample */
void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; } void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; }
@ -137,15 +138,15 @@ namespace tunnel
OutboundTunnel (std::shared_ptr<const TunnelConfig> config): OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsgTo (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages virtual void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; }; const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; };
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
// implements TunnelBase // implements TunnelBase
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) override;
bool IsInbound() const { return false; } bool IsInbound() const override { return false; }
private: private:
@ -159,12 +160,12 @@ namespace tunnel
public: public:
InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {}; InboundTunnel (std::shared_ptr<const TunnelConfig> config): Tunnel (config), m_Endpoint (true) {};
void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg); void HandleTunnelDataMsg (std::shared_ptr<I2NPMessage>&& msg) override;
virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; virtual size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); };
bool IsInbound() const { return true; } bool IsInbound() const override { return true; }
// override TunnelBase // override TunnelBase
void Cleanup () { m_Endpoint.Cleanup (); }; void Cleanup () override { m_Endpoint.Cleanup (); };
private: private:
@ -176,8 +177,8 @@ namespace tunnel
public: public:
ZeroHopsInboundTunnel (); ZeroHopsInboundTunnel ();
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) override;
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const override { return m_NumReceivedBytes; };
private: private:
@ -189,8 +190,8 @@ namespace tunnel
public: public:
ZeroHopsOutboundTunnel (); ZeroHopsOutboundTunnel ();
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); void SendTunnelDataMsgs (const std::vector<TunnelMessageBlock>& msgs) override;
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const override { return m_NumSentBytes; };
private: private:
@ -229,6 +230,10 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
uint16_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
bool IsTooManyTransitTunnels () const { return m_TransitTunnels.size () >= m_MaxNumTransitTunnels; };
private: private:
template<class TTunnel> template<class TTunnel>
@ -287,6 +292,7 @@ namespace tunnel
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool; i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool; i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
uint16_t m_MaxNumTransitTunnels;
// count of tunnels for total TCSR algorithm // count of tunnels for total TCSR algorithm
int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations;
double m_TunnelCreationSuccessRate; double m_TunnelCreationSuccessRate;

6
libi2pd/TunnelEndpoint.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -208,7 +208,7 @@ namespace tunnel
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
// LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough"); // LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough");
auto newMsg = NewI2NPMessage (); auto newMsg = NewI2NPMessage (msg.data->len + size);
*newMsg = *(msg.data); *newMsg = *(msg.data);
msg.data = newMsg; msg.data = newMsg;
} }
@ -297,7 +297,7 @@ namespace tunnel
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough"); LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
auto newMsg = NewI2NPMessage (); auto newMsg = NewI2NPMessage (msg.data->len + size);
*newMsg = *(msg.data); *newMsg = *(msg.data);
msg.data = newMsg; msg.data = newMsg;
} }

2
libi2pd/TunnelPool.cpp

@ -383,7 +383,7 @@ namespace tunnel
std::unique_lock<std::mutex> l(m_TestsMutex); std::unique_lock<std::mutex> l(m_TestsMutex);
m_Tests[msgID] = std::make_pair (*it1, *it2); m_Tests[msgID] = std::make_pair (*it1, *it2);
} }
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), (*it1)->SendTunnelDataMsgTo ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID)); CreateDeliveryStatusMsg (msgID));
++it1; ++it2; ++it1; ++it2;
} }

6
libi2pd/api.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -67,11 +67,15 @@ namespace api
i2p::transport::transports.Start(); i2p::transport::transports.Start();
LogPrint(eLogInfo, "API: Starting Tunnels"); LogPrint(eLogInfo, "API: Starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
LogPrint(eLogInfo, "API: Starting Router context");
i2p::context.Start();
} }
void StopI2P () void StopI2P ()
{ {
LogPrint(eLogInfo, "API: Shutting down"); LogPrint(eLogInfo, "API: Shutting down");
LogPrint(eLogInfo, "API: Stopping Router context");
i2p::context.Stop();
LogPrint(eLogInfo, "API: Stopping Tunnels"); LogPrint(eLogInfo, "API: Stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();
LogPrint(eLogInfo, "API: Stopping Transports"); LogPrint(eLogInfo, "API: Stopping Transports");

102
libi2pd/util.cpp

@ -15,7 +15,7 @@
#include "Log.h" #include "Log.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#if not defined (__FreeBSD__) #if !defined (__FreeBSD__) && !defined(_MSC_VER)
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -37,6 +37,19 @@
#include <iphlpapi.h> #include <iphlpapi.h>
#include <shlobj.h> #include <shlobj.h>
#if defined(_MSC_VER)
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
} THREADNAME_INFO;
#pragma pack(pop)
#endif
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
@ -75,7 +88,8 @@ const char *inet_ntop_xp(int af, const void *src, char *dst, socklen_t size)
ZeroMemory(&ss, sizeof(ss)); ZeroMemory(&ss, sizeof(ss));
ss.ss_family = af; ss.ss_family = af;
switch(af) { switch (af)
{
case AF_INET: case AF_INET:
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
break; break;
@ -161,7 +175,23 @@ namespace util
#elif defined(__NetBSD__) #elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void *)name); pthread_setname_np(pthread_self(), "%s", (void *)name);
#elif !defined(__gnu_hurd__) #elif !defined(__gnu_hurd__)
#if defined(_MSC_VER)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = -1;
info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
}
#pragma warning(pop)
#else
pthread_setname_np(pthread_self(), name); pthread_setname_np(pthread_self(), name);
#endif
#endif #endif
} }
@ -179,7 +209,7 @@ namespace net
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) if (GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW) == ERROR_BUFFER_OVERFLOW)
{ {
FREE(pAddresses); FREE(pAddresses);
@ -190,7 +220,7 @@ namespace net
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
); );
if(dwRetVal != NO_ERROR) if (dwRetVal != NO_ERROR)
{ {
LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed"); LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses); FREE(pAddresses);
@ -198,19 +228,17 @@ namespace net
} }
pCurrAddresses = pAddresses; pCurrAddresses = pAddresses;
while(pCurrAddresses) while (pCurrAddresses)
{ {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress;
if(pUnicast == nullptr) if (pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported"); LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported");
for(int i = 0; pUnicast != nullptr; ++i) while (pUnicast != nullptr)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr; sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) if (localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
{ {
char addr[INET_ADDRSTRLEN]; char addr[INET_ADDRSTRLEN];
inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN); inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN);
@ -264,12 +292,11 @@ namespace net
pCurrAddresses = pAddresses; pCurrAddresses = pAddresses;
while (pCurrAddresses) while (pCurrAddresses)
{ {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress;
if (pUnicast == nullptr) if (pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported"); LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported");
for (int i = 0; pUnicast != nullptr; ++i) while (pUnicast != nullptr)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
@ -317,13 +344,13 @@ namespace net
IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton"); IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found
if(localAddress.is_v4()) if (localAddress.is_v4())
{ {
sockaddr_in inputAddress; sockaddr_in inputAddress;
inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr)); inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
return GetMTUWindowsIpv4(inputAddress, fallback); return GetMTUWindowsIpv4(inputAddress, fallback);
} }
else if(localAddress.is_v6()) else if (localAddress.is_v6())
{ {
sockaddr_in6 inputAddress; sockaddr_in6 inputAddress;
inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr)); inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
@ -339,7 +366,7 @@ namespace net
int GetMTUUnix (const boost::asio::ip::address& localAddress, int fallback) int GetMTUUnix (const boost::asio::ip::address& localAddress, int fallback)
{ {
ifaddrs* ifaddr, *ifa = nullptr; ifaddrs* ifaddr, *ifa = nullptr;
if(getifaddrs(&ifaddr) == -1) if (getifaddrs(&ifaddr) == -1)
{ {
LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno)); LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno));
return fallback; return fallback;
@ -347,34 +374,34 @@ namespace net
int family = 0; int family = 0;
// look for interface matching local address // look for interface matching local address
for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{ {
if(!ifa->ifa_addr) if (!ifa->ifa_addr)
continue; continue;
family = ifa->ifa_addr->sa_family; family = ifa->ifa_addr->sa_family;
if(family == AF_INET && localAddress.is_v4()) if (family == AF_INET && localAddress.is_v4())
{ {
sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr; sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr;
if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4)) if (!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
break; // address matches break; // address matches
} }
else if(family == AF_INET6 && localAddress.is_v6()) else if (family == AF_INET6 && localAddress.is_v6())
{ {
sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr; sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr;
if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16)) if (!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
break; // address matches break; // address matches
} }
} }
int mtu = fallback; int mtu = fallback;
if(ifa && family) if (ifa && family)
{ // interface found? { // interface found?
int fd = socket(family, SOCK_DGRAM, 0); int fd = socket(family, SOCK_DGRAM, 0);
if(fd > 0) if (fd > 0)
{ {
ifreq ifr; ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ-1); // set interface for query strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ-1); // set interface for query
if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0) if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU mtu = ifr.ifr_mtu; // MTU
else else
LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno)); LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno));
@ -407,7 +434,7 @@ namespace net
{ {
#ifdef _WIN32 #ifdef _WIN32
LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32"); LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32");
if(ipv6) if (ipv6)
return boost::asio::ip::address::from_string("::1"); return boost::asio::ip::address::from_string("::1");
else else
return boost::asio::ip::address::from_string("127.0.0.1"); return boost::asio::ip::address::from_string("127.0.0.1");
@ -426,7 +453,7 @@ namespace net
// match // match
char addr[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
memset (addr, 0, INET6_ADDRSTRLEN); memset (addr, 0, INET6_ADDRSTRLEN);
if(af == AF_INET) if (af == AF_INET)
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN); inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
else else
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN); inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
@ -442,9 +469,9 @@ namespace net
LogPrint(eLogError, "NetIface: Exception while searching address using ifaddr: ", ex.what()); LogPrint(eLogError, "NetIface: Exception while searching address using ifaddr: ", ex.what());
} }
if(addrs) freeifaddrs(addrs); if (addrs) freeifaddrs(addrs);
std::string fallback; std::string fallback;
if(ipv6) if (ipv6)
{ {
fallback = "::1"; fallback = "::1";
LogPrint(eLogWarning, "NetIface: Cannot find IPv6 address for interface ", ifname); LogPrint(eLogWarning, "NetIface: Cannot find IPv6 address for interface ", ifname);
@ -512,7 +539,7 @@ namespace net
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) if (GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW) == ERROR_BUFFER_OVERFLOW)
{ {
FREE(pAddresses); FREE(pAddresses);
@ -523,7 +550,7 @@ namespace net
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
); );
if(dwRetVal != NO_ERROR) if (dwRetVal != NO_ERROR)
{ {
LogPrint(eLogError, "NetIface: GetYggdrasilAddress(): enclosed GetAdaptersAddresses() call has failed"); LogPrint(eLogError, "NetIface: GetYggdrasilAddress(): enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses); FREE(pAddresses);
@ -531,12 +558,11 @@ namespace net
} }
pCurrAddresses = pAddresses; pCurrAddresses = pAddresses;
while(pCurrAddresses) while (pCurrAddresses)
{ {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress;
for(int i = 0; pUnicast != nullptr; ++i) while (pUnicast != nullptr)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
@ -580,7 +606,7 @@ namespace net
LogPrint(eLogError, "NetIface: Exception while searching Yggdrasill address using ifaddr: ", ex.what()); LogPrint(eLogError, "NetIface: Exception while searching Yggdrasill address using ifaddr: ", ex.what());
} }
LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found"); LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found");
if(addrs) freeifaddrs(addrs); if (addrs) freeifaddrs(addrs);
return boost::asio::ip::address_v6 (); return boost::asio::ip::address_v6 ();
#endif #endif
} }
@ -600,7 +626,7 @@ namespace net
{ {
// https://en.wikipedia.org/wiki/Reserved_IP_addresses // https://en.wikipedia.org/wiki/Reserved_IP_addresses
if (host.is_unspecified ()) return false; if (host.is_unspecified ()) return false;
if(host.is_v4()) if (host.is_v4())
{ {
static const std::vector< std::pair<uint32_t, uint32_t> > reservedIPv4Ranges { static const std::vector< std::pair<uint32_t, uint32_t> > reservedIPv4Ranges {
address_pair_v4("0.0.0.0", "0.255.255.255"), address_pair_v4("0.0.0.0", "0.255.255.255"),
@ -620,12 +646,12 @@ namespace net
}; };
uint32_t ipv4_address = host.to_v4 ().to_ulong (); uint32_t ipv4_address = host.to_v4 ().to_ulong ();
for(const auto& it : reservedIPv4Ranges) { for (const auto& it : reservedIPv4Ranges) {
if (ipv4_address >= it.first && ipv4_address <= it.second) if (ipv4_address >= it.first && ipv4_address <= it.second)
return true; return true;
} }
} }
if(host.is_v6()) if (host.is_v6())
{ {
static const std::vector< std::pair<boost::asio::ip::address_v6::bytes_type, boost::asio::ip::address_v6::bytes_type> > reservedIPv6Ranges { static const std::vector< std::pair<boost::asio::ip::address_v6::bytes_type, boost::asio::ip::address_v6::bytes_type> > reservedIPv6Ranges {
address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"), address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"),
@ -637,7 +663,7 @@ namespace net
}; };
boost::asio::ip::address_v6::bytes_type ipv6_address = host.to_v6 ().to_bytes (); boost::asio::ip::address_v6::bytes_type ipv6_address = host.to_v6 ().to_bytes ();
for(const auto& it : reservedIPv6Ranges) { for (const auto& it : reservedIPv6Ranges) {
if (ipv6_address >= it.first && ipv6_address <= it.second) if (ipv6_address >= it.first && ipv6_address <= it.second)
return true; return true;
} }

10
libi2pd/version.h

@ -11,16 +11,18 @@
#define CODENAME "Purple" #define CODENAME "Purple"
#define XSTRINGIZE(x) STRINGIZE(x)
#define STRINGIZE(x) #x #define STRINGIZE(x) #x
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 46 #define I2PD_VERSION_MINOR 47
#define I2PD_VERSION_MICRO 1 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#ifdef GITVER #ifdef GITVER
#define I2PD_VERSION GITVER #define I2PD_VERSION XSTRINGIZE(GITVER)
#else #else
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
#endif #endif
@ -31,7 +33,7 @@
#define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9 #define I2P_VERSION_MINOR 9
#define I2P_VERSION_MICRO 57 #define I2P_VERSION_MICRO 58
#define I2P_VERSION_PATCH 0 #define I2P_VERSION_PATCH 0
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)

2
libi2pd_client/AddressBook.cpp

@ -661,7 +661,7 @@ namespace client
this, std::placeholders::_1)); this, std::placeholders::_1));
} }
else else
LogPrint (eLogError, "Addressbook: Can't start subscriptions: missing shared local destination"); LogPrint (eLogCritical, "Addressbook: Can't start subscriptions: missing shared local destination");
} }
void AddressBook::StopSubscriptions () void AddressBook::StopSubscriptions ()

29
libi2pd_client/ClientContext.cpp

@ -63,18 +63,19 @@ namespace client
if (sam) if (sam)
{ {
std::string samAddr; i2p::config::GetOption("sam.address", samAddr); std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
uint16_t samPort; i2p::config::GetOption("sam.port", samPort); uint16_t samPortTCP; i2p::config::GetOption("sam.port", samPortTCP);
uint16_t samPortUDP; i2p::config::GetOption("sam.portudp", samPortUDP);
bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread); bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread);
LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":", samPort); LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP, "]");
try try
{ {
m_SamBridge = new SAMBridge (samAddr, samPort, singleThread); m_SamBridge = new SAMBridge (samAddr, samPortTCP, samPortUDP, singleThread);
m_SamBridge->Start (); m_SamBridge->Start ();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what()); LogPrint(eLogCritical, "Clients: Exception in SAM bridge: ", e.what());
ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ()); ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP,"]: ", e.what ());
} }
} }
@ -91,7 +92,7 @@ namespace client
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what()); LogPrint(eLogCritical, "Clients: Exception in BOB bridge: ", e.what());
ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ()); ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ());
} }
} }
@ -111,7 +112,7 @@ namespace client
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what()); LogPrint(eLogCritical, "Clients: Exception in I2CP: ", e.what());
ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ()); ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ());
} }
} }
@ -278,7 +279,7 @@ namespace client
s.read ((char *)buf, len); s.read ((char *)buf, len);
if(!keys.FromBuffer (buf, len)) if(!keys.FromBuffer (buf, len))
{ {
LogPrint (eLogError, "Clients: Failed to load keyfile ", filename); LogPrint (eLogCritical, "Clients: Failed to load keyfile ", filename);
success = false; success = false;
} }
else else
@ -287,7 +288,7 @@ namespace client
} }
else else
{ {
LogPrint (eLogError, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType); LogPrint (eLogCritical, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType);
keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true);
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
size_t len = keys.GetFullLen (); size_t len = keys.GetFullLen ();
@ -850,7 +851,7 @@ namespace client
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Clients: Can't read tunnel ", name, " params: ", ex.what ()); LogPrint (eLogCritical, "Clients: Can't read tunnel ", name, " params: ", ex.what ());
ThrowFatal ("Unable to start tunnel ", name, ": ", ex.what ()); ThrowFatal ("Unable to start tunnel ", name, ": ", ex.what ());
} }
} }
@ -882,7 +883,7 @@ namespace client
if (localDestination) localDestination->Acquire (); if (localDestination) localDestination->Acquire ();
} }
else else
LogPrint(eLogError, "Clients: Failed to load HTTP Proxy key"); LogPrint(eLogCritical, "Clients: Failed to load HTTP Proxy key");
} }
try try
{ {
@ -891,7 +892,7 @@ namespace client
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); LogPrint(eLogCritical, "Clients: Exception in HTTP Proxy: ", e.what());
ThrowFatal ("Unable to start HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort, ": ", e.what ()); ThrowFatal ("Unable to start HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort, ": ", e.what ());
} }
} }
@ -929,7 +930,7 @@ namespace client
if (localDestination) localDestination->Acquire (); if (localDestination) localDestination->Acquire ();
} }
else else
LogPrint(eLogError, "Clients: Failed to load SOCKS Proxy key"); LogPrint(eLogCritical, "Clients: Failed to load SOCKS Proxy key");
} }
try try
{ {
@ -939,7 +940,7 @@ namespace client
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what()); LogPrint(eLogCritical, "Clients: Exception in SOCKS Proxy: ", e.what());
ThrowFatal ("Unable to start SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort, ": ", e.what ()); ThrowFatal ("Unable to start SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort, ": ", e.what ());
} }
} }

2
libi2pd_client/HTTPProxy.cpp

@ -113,7 +113,7 @@ namespace proxy {
i2p::http::URL m_ProxyURL; i2p::http::URL m_ProxyURL;
i2p::http::URL m_RequestURL; i2p::http::URL m_RequestURL;
uint8_t m_socks_buf[255+8]; // for socks request/response uint8_t m_socks_buf[255+8]; // for socks request/response
ssize_t m_req_len; int m_req_len;
i2p::http::URL m_ClientRequestURL; i2p::http::URL m_ClientRequestURL;
i2p::http::HTTPReq m_ClientRequest; i2p::http::HTTPReq m_ClientRequest;
i2p::http::HTTPRes m_ClientResponse; i2p::http::HTTPRes m_ClientResponse;

4
libi2pd_client/I2CP.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -230,7 +230,7 @@ namespace client
remoteLease->tunnelGateway, remoteLease->tunnelID, remoteLease->tunnelGateway, remoteLease->tunnelID,
garlic garlic
}); });
outboundTunnel->SendTunnelDataMsg (msgs); outboundTunnel->SendTunnelDataMsgs (msgs);
return true; return true;
} }
else else

7
libi2pd_client/I2PTunnel.cpp

@ -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 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -691,7 +691,10 @@ namespace client
int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip): int port, std::shared_ptr<ClientDestination> localDestination, int inport, bool gzip):
I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false) I2PService (localDestination), m_IsUniqueLocal(true), m_Name (name), m_Address (address), m_Port (port), m_IsAccessList (false)
{ {
m_PortDestination = localDestination->CreateStreamingDestination (inport > 0 ? inport : port, gzip); if (!inport) inport = port;
m_PortDestination = localDestination->GetStreamingDestination (inport);
if (!m_PortDestination)
m_PortDestination = localDestination->CreateStreamingDestination (inport, gzip);
} }
void I2PServerTunnel::Start () void I2PServerTunnel::Start ()

6
libi2pd_client/SAM.cpp

@ -1244,10 +1244,10 @@ namespace client
// TODO: implement datagrams // TODO: implement datagrams
} }
SAMBridge::SAMBridge (const std::string& address, int port, bool singleThread): SAMBridge::SAMBridge (const std::string& address, int portTCP, int portUDP, bool singleThread):
RunnableService ("SAM"), m_IsSingleThread (singleThread), RunnableService ("SAM"), m_IsSingleThread (singleThread),
m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)), m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), portTCP)),
m_DatagramEndpoint (boost::asio::ip::address::from_string(address), port-1), m_DatagramSocket (GetIOService (), m_DatagramEndpoint), m_DatagramEndpoint (boost::asio::ip::address::from_string(address), (!portUDP) ? portTCP-1 : portUDP), m_DatagramSocket (GetIOService (), m_DatagramEndpoint),
m_SignatureTypes m_SignatureTypes
{ {
{"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1}, {"DSA_SHA1", i2p::data::SIGNING_KEY_TYPE_DSA_SHA1},

2
libi2pd_client/SAM.h

@ -233,7 +233,7 @@ namespace client
{ {
public: public:
SAMBridge (const std::string& address, int port, bool singleThread); SAMBridge (const std::string& address, int portTCP, int portUDP, bool singleThread);
~SAMBridge (); ~SAMBridge ();
void Start (); void Start ();

Loading…
Cancel
Save