Compare commits

..

No commits in common. 'openssl' and '2.47.0' have entirely different histories.

@ -34,6 +34,3 @@ trim_trailing_whitespace = false
[*.yml] [*.yml]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
[*.patch]
trim_trailing_whitespace = false

@ -1,24 +1,6 @@
name: Build Debian packages name: Build Debian packages
on: on: [push, pull_request]
push:
branches:
- '*'
paths:
- .github/workflows/build-deb.yml
- contrib/**
- daemon/**
- debian/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Makefile
- Makefile.linux
tags:
- '*'
pull_request:
branches:
- '*'
jobs: jobs:
build: build:
@ -32,30 +14,26 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Commit Hash
id: commit
uses: prompt/actions-commit-hash@v3.0.0
- name: Build package - name: Build package
uses: jtdor/build-deb-action@v1 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
before-build-hook: debchange --controlmaint --local "+${{ steps.commit.outputs.short }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build" before-build-hook: debchange --controlmaint --local "+${{ github.sha }}~${{ matrix.dist }}" -b --distribution ${{ matrix.dist }} "CI build"
extra-build-deps: devscripts git extra-build-deps: devscripts git
- name: Upload package - name: Upload package
uses: actions/upload-artifact@v4 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
- name: Upload debugging symbols - name: Upload debugging symbols
uses: actions/upload-artifact@v4 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

@ -1,37 +1,19 @@
name: Build on FreeBSD name: Build on FreeBSD
on: on: [push, pull_request]
push:
branches:
- '*'
paths:
- .github/workflows/build-freebsd.yml
- build/CMakeLists.txt
- build/cmake_modules/**
- daemon/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Makefile
- Makefile.bsd
tags:
- '*'
pull_request:
branches:
- '*'
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: macos-12
name: with UPnP name: with UPnP
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Test in FreeBSD - name: Test in FreeBSD
id: test id: test
uses: vmactions/freebsd-vm@v1 uses: vmactions/freebsd-vm@v0.3.0
with: with:
usesh: true usesh: true
mem: 2048 mem: 2048
@ -44,7 +26,7 @@ jobs:
gmake -j2 gmake -j2
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: i2pd-freebsd name: i2pd-freebsd
path: build/i2pd path: build/i2pd

@ -1,22 +1,6 @@
name: Build on OSX name: Build on OSX
on: on: [push, pull_request]
push:
branches:
- '*'
paths:
- .github/workflows/build-osx.yml
- daemon/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Makefile
- Makefile.homebrew
tags:
- '*'
pull_request:
branches:
- '*'
jobs: jobs:
build: build:
@ -30,16 +14,13 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Install required formulae - 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: List installed formulae - name: build application
run: brew list
- 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

@ -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.*

@ -1,80 +0,0 @@
name: Build on Windows with MSVC
on:
push:
branches:
- '*'
paths:
- .github/workflows/build-windows-msvc.yml
- build/CMakeLists.txt
- build/cmake_modules/**
- daemon/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Win32/**
tags:
- '*'
pull_request:
branches:
- '*'
jobs:
build:
name: Build
runs-on: windows-latest
env:
boost_path: ${{ github.workspace }}\boost_1_83_0
openssl_path: ${{ github.workspace }}\openssl_3_2_1
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build and install zlib
run: |
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
set BUILD_TYPE=Debug
./install_zlib.bat
set BUILD_TYPE=Release
./install_zlib.bat
del install_zlib.bat
- name: Install Boost
run: |
powershell -Command "(Start-BitsTransfer -Source https://sourceforge.net/projects/boost/files/boost-binaries/1.83.0/boost_1_83_0-msvc-14.3-64.exe/download -Destination boost_1_83_0-msvc-14.3-64.exe)"
./boost_1_83_0-msvc-14.3-64.exe /DIR="${{env.boost_path}}" /VERYSILENT /SUPPRESSMSGBOXES /SP-
- name: Install OpenSSL
run: |
powershell -Command "(Start-BitsTransfer -Source https://slproweb.com/download/Win64OpenSSL-3_2_1.exe -Destination Win64OpenSSL-3_2_1.exe)"
./Win64OpenSSL-3_2_1.exe /DIR="${{env.openssl_path}}" /TASKS="copytobin" /VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-
- name: Make copy of the OpenSSL libraries for CMake
run: |
dir ${{ github.workspace }}
dir ${{env.openssl_path}}\lib\VC
dir ${{env.openssl_path}}\lib\VC\x64\
dir ${{env.openssl_path}}\lib\VC\x64\MTd\
xcopy /s /y "${{env.openssl_path}}\lib\VC\x64\MTd" "${{env.openssl_path}}\lib"
- name: Configure
working-directory: build
run: cmake -DBoost_ROOT="${{env.boost_path}}" -DOPENSSL_ROOT_DIR="${{env.openssl_path}}" -DWITH_STATIC=ON .
- name: Build
working-directory: build
run: cmake --build . --config Debug -- -m
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: i2pd-msvc
path: build/Debug/i2pd.*

@ -1,25 +1,6 @@
name: Build on Windows name: Build on Windows
on: on: [push, pull_request]
push:
branches:
- '*'
paths:
- .github/workflows/build-windows.yml
- build/CMakeLists.txt
- build/cmake_modules/**
- daemon/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Win32/**
- Makefile
- Makefile.mingw
tags:
- '*'
pull_request:
branches:
- '*'
defaults: defaults:
run: run:
@ -42,7 +23,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
@ -63,7 +44,7 @@ jobs:
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@v4 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
@ -84,7 +65,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
@ -102,7 +83,7 @@ jobs:
cmake --build . -- -j3 cmake --build . -- -j3
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: i2pd-cmake-${{ matrix.arch_short }}.exe name: i2pd-cmake-${{ matrix.arch_short }}.exe
path: build/i2pd.exe path: build/i2pd.exe
@ -116,7 +97,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
fetch-depth: 0 fetch-depth: 0
@ -125,117 +106,34 @@ jobs:
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
cache: true
update: true update: true
- name: Clone MinGW packages repository - name: Build WinXP-capable CRT packages
run: git clone https://github.com/msys2/MINGW-packages
# headers
- name: Get headers package version
id: version-headers
run: |
echo "version=$(pacman -Si mingw-w64-i686-headers-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
- name: Cache headers package
uses: actions/cache@v4
id: cache-headers
with:
path: MINGW-packages/mingw-w64-headers-git/*.zst
key: winxp-headers-${{ steps.version-headers.outputs.version }}
- name: Build WinXP-capable headers package
if: steps.cache-headers.outputs.cache-hit != 'true'
run: | run: |
cd MINGW-packages/mingw-w64-headers-git git clone https://github.com/msys2/MINGW-packages
pushd MINGW-packages
pushd mingw-w64-headers-git
sed -i 's/0x601/0x501/' PKGBUILD sed -i 's/0x601/0x501/' PKGBUILD
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
- name: Install headers package pacman --noconfirm -U mingw-w64-i686-headers-git-*-any.pkg.tar.zst
run: pacman --noconfirm -U MINGW-packages/mingw-w64-headers-git/mingw-w64-i686-*-any.pkg.tar.zst popd
pushd mingw-w64-crt-git
# CRT MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
- name: Get crt package version pacman --noconfirm -U mingw-w64-i686-crt-git-*-any.pkg.tar.zst
id: version-crt popd
run: | pushd mingw-w64-winpthreads-git
echo "version=$(pacman -Si mingw-w64-i686-crt-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
- name: Cache crt package pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
uses: actions/cache@v4 popd
id: cache-crt popd
with:
path: MINGW-packages/mingw-w64-crt-git/*.zst
key: winxp-crt-${{ steps.version-crt.outputs.version }}
- name: Build WinXP-capable crt package
if: steps.cache-crt.outputs.cache-hit != 'true'
run: |
cd MINGW-packages/mingw-w64-crt-git
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- name: Install crt package
run: pacman --noconfirm -U MINGW-packages/mingw-w64-crt-git/mingw-w64-i686-*-any.pkg.tar.zst
# winpthreads
- name: Get winpthreads package version
id: version-winpthreads
run: |
echo "version=$(pacman -Si mingw-w64-i686-winpthreads-git | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
- name: Cache winpthreads package
uses: actions/cache@v4
id: cache-winpthreads
with:
path: MINGW-packages/mingw-w64-winpthreads-git/*.zst
key: winxp-winpthreads-${{ steps.version-winpthreads.outputs.version }}
- name: Build WinXP-capable winpthreads package
if: steps.cache-winpthreads.outputs.cache-hit != 'true'
run: |
cd MINGW-packages/mingw-w64-winpthreads-git
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- name: Install winpthreads package
run: pacman --noconfirm -U MINGW-packages/mingw-w64-winpthreads-git/mingw-w64-i686-*-any.pkg.tar.zst
# OpenSSL
- name: Get openssl package version
id: version-openssl
run: |
echo "version=$(pacman -Si mingw-w64-i686-openssl | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
- name: Cache openssl package
uses: actions/cache@v4
id: cache-openssl
with:
path: MINGW-packages/mingw-w64-openssl/*.zst
key: winxp-openssl-${{ steps.version-openssl.outputs.version }}
- name: Build WinXP-capable openssl package
if: steps.cache-openssl.outputs.cache-hit != 'true'
run: |
cd MINGW-packages/mingw-w64-openssl
gpg --recv-keys D894E2CE8B3D79F5
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- name: Install openssl package
run: pacman --noconfirm -U MINGW-packages/mingw-w64-openssl/mingw-w64-i686-*-any.pkg.tar.zst
# Boost
- name: Get boost package version
id: version-boost
run: |
echo "version=$(pacman -Si mingw-w64-i686-boost | grep -Po '^Version\s*: \K.+')" >> $GITHUB_OUTPUT
- name: Cache boost package
uses: actions/cache@v4
id: cache-boost
with:
path: MINGW-packages/mingw-w64-boost/*.zst
key: winxp-winpthreads-${{ steps.version-boost.outputs.version }}
- name: Build WinXP-capable boost package
if: steps.cache-boost.outputs.cache-hit != 'true'
run: |
cd MINGW-packages/mingw-w64-boost
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- name: Install boost package
run: pacman --noconfirm -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst
# Building i2pd
- 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@v4 uses: actions/upload-artifact@v3
with: with:
name: i2pd-xp.exe name: i2pd-xp.exe
path: i2pd.exe path: i2pd.exe

@ -1,24 +1,6 @@
name: Build on Ubuntu name: Build on Ubuntu
on: on: [push, pull_request]
push:
branches:
- '*'
paths:
- .github/workflows/build.yml
- build/CMakeLists.txt
- build/cmake_modules/**
- daemon/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Makefile
- Makefile.linux
tags:
- '*'
pull_request:
branches:
- '*'
jobs: jobs:
build-make: build-make:
@ -32,7 +14,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |
@ -53,7 +35,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |

@ -5,16 +5,6 @@ on:
branches: branches:
- openssl - openssl
- docker - docker
paths:
- .github/workflows/docker.yml
- contrib/docker/**
- contrib/certificates/**
- daemon/**
- i18n/**
- libi2pd/**
- libi2pd_client/**
- Makefile
- Makefile.linux
tags: tags:
- '*' - '*'
@ -37,29 +27,29 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container registry - name: Login to GitHub Container registry
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build container for ${{ matrix.archname }} - name: Build container for ${{ matrix.archname }}
uses: docker/build-push-action@v5 uses: docker/build-push-action@v3
with: with:
context: ./contrib/docker context: ./contrib/docker
file: ./contrib/docker/Dockerfile file: ./contrib/docker/Dockerfile
@ -82,22 +72,22 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v2
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
username: ${{ secrets.DOCKERHUB_USERNAME }} username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container registry - name: Login to GitHub Container registry
uses: docker/login-action@v3 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}

@ -1,172 +1,6 @@
# 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.52.0] - 2024-05-12
### Added
- Separate threads for persisting RouterInfos and profiles to disk
- Give preference to address with direct connection
- Exclude addresses with incorrect static or intro key
- Avoid two firewalled routers in the row in tunnel
- Drop unsolicited database search replies
### Changed
- Increase number of hashes to 16 in exploratory lookup reply
- Reduce number of a RouterInfo lookup attempts to 5
- Reset stream RTO if outbound tunnel was changed
- Insert previously excluded floodfill back when successfully connected
- Increase maximum stream resend attempts to 9
- Reply to exploratory lookups with only confirmed routers if low tunnel build rate
- Don't accept too old RouterInfo
- Build client tunnels through confirmed routers only if low tunnel build rate
- Manage netDb requests more frequently
- Don't reply with closer than us only floodfills for lookup
### Fixed
- Crash on router lookup if exploratory pool is not ready
- Race condition in excluded peers for next lookup
- Excessive number of lookups for same destination
- Race condition with transport peers during shutdown
- Corrupted RouterInfo files
## [2.51.0] - 2024-04-06
### Added
- Non-blocking mode for UDP sockets
- Set SSU2 socket buffer size based on bandwidth limit
- Encrypted tunnel tests
- Support for multiple UDP server tunnels on one destination
- Publish medium congestion indication
- Local domain sockets for SOCKS proxy upstream
- Tunnel status "declined" in web console
- SAM error reply "Incompatible crypto" if remote destination has incompatible crypto
- Reduce amount of traffic by handling local message drops
- Keep SSU2 socket open even if it fails to bind
- Lower SSU2 resend traffic spikes
- Expiration for messages in SSU2 send queue
- Use EWMA for stream RTT estimation
- Request choking delay if too many NACKs in stream
- Allow 0ms latency for tunnel
- Randomize tunnels selection for tests
### Changed
- Upstream SOCKS proxy from SOCKS4 to SOCKS5
- Transit tunnels limit to 4 bytes. Default value to 10K
- Reply CANT_REACH_PEER if connect to ourselves in SAM
- Don't send already expired I2NP messages
- Use monotonic timer to measure tunnel test latency
- Standard NTCP2 frame doesn't exceed 16K
- Always send request through tunnels in case of restricted routes
- Don't delete connected routers from NetDb
- Send lookup reply directly to reply tunnel gateway if possible
- Reduce unreachable router ban interval to 8 minutes
- Don't request banned routers / don't try to connect to unreachable router
- Consider 'M' routers as low bandwidth
- Limit minimal received SSU2 packet size to 40 bytes
- Bob picks peer test session only if Charlie's address supports peer testing
- Reject peer test msg 2 if peer testing is not supported
- Don't request termination if SSU2 session was not established
- Set maximum SSU2 queue size depending on RTT value
- New streaming RTT calculation algorithm
- Don't double initial RTO for streams when changing tunnels
- Restore failed tunnel if test or data for inbound tunnel received
- Don't fail last remaining tunnel in pool
- Publish LeasetSet again if local destination was not ready or no tunnels
- Make more attempts to pick high bandwidth hop for client tunnel
- Reduced SSU2 session termination timeout to 165 seconds
- Reseeds list
### Fixed
- ECIESx25519 symmetric key tagset early expiration
- Encrypted LeaseSet lookup
- Outbound tunnel build fails if it's endpoint is the same as reply tunnel gateway
- I2PControl RouterManager returns invalid JSON when unknown params are passed
- Mix of data between different UDP sessions on the same server
- TARGET_OS_SIMULATOR check
- Handling of "reservedrange" param
- New NTCP2 session gets teminated upon termination of old one
- New SSU2 session gets teminated upon termination of old one
- Peer test to non-supporting router
- Streaming ackThrough off 1 if number of NACKs exceeds 255
- Race condition in ECIESx25519 tags table
- Good tunnel becomes failed
- Crash when packet comes to terminated stream
- Stream hangs during LeaseSet update
## [2.50.2] - 2024-01-06
###Fixed
- Crash with OpenSSL 3.2.0
- False positive clock skew detection
## [2.50.1] - 2023-12-23
###Fixed
- Support for new EdDSA usage behavior in OpenSSL 3.2.0
## [2.50.0] - 2023-12-18
### Added
- Support of concurrent ACCEPTs on SAM 3.1
- Haiku OS support
- Low bandwidth and far routers can expire before 1 hour
### Changed
- Don't pick too active peer for first hop
- Try peer test again if status is Unknown
- Send peer tests with random delay
- Reseeds list
### Fixed
- XSS vulnerability in addresshelper
- Publishing NAT64 ipv6 addresses
- Deadlock in AsyncSend callback
## [2.49.0] - 2023-09-18
### Added
- Handle SOCK5 authorization with empty user/password
- Drop incoming transport sessions from too old or from future routers
- Memory pool for router profiles
- Allow 0 hops in explicitPeers
### Changed
- Separate network and testing status
- Remove AVX code
- Improve NTCP2 transport session logging
- Select router with ipv4 for tunnel endpoint
- Consider all addresses non-published for U and H routers even if they have host/port
- Don't pick completely unreachable routers for tunnels
- Exclude SSU1 introducers from SSU2 addresses
- Don't create paired inbound tunnel if length is different
- Remove introducer from RouterInfo after 60 minutes
- Reduce SSU2 keep alive interval and add keep alive interval variance
- Don't pick too old sessions for introducer
### Fixed
- Version of the subnegotiation in user/password SOCKS5 response
- Send keepalive for existing session with introducer
- Buffer offset for EVP_EncryptFinal_ex() to include outlen
- Termination block size processing for transport sessions
- Crash if deleted BOB destination was shared between few BOB sessions
- Introducers with zero tag
- Padding for SSU2 path response
## [2.48.0] - 2023-06-12
### Added
- Allow user/password authentication method for SOCK5 proxy
- Publish reject all congestion cap 'G' if transit is not accepted
- 'critical' log level
- Print b32 on webconsole destination page
- Webconsole button to drop a remote LeaseSet
- limits.zombies param - minimum percentage of successfully created tunnels for routers cleanup
- Recognize real routers if successfully connected or responded to tunnel build request
### Changed
- Bypass slow transport sessions for first hop selection
- Limit AESNI inline asm to x86/x64
- Create smaller I2NP packets if possible
- Make router unreachable if AEAD tag verification fails in SessionCreated
- Don't include a router to floodfills list until it's confirmed as real
- Drop LeaseSet store request if not floodfill
- Bypass medium congestion('D') routers for client tunnels
- Publish encrypted RouterInfo through tunnels
- Check if s is valid x25519 public key
- Check if socket is open before sending data in SSU2
### Fixed
- Webconsole empty page if destination is not found
- i2p.streaming.answerPings param
- Reload tunnels
- Address caps for unspecified ipv6 address
- Incomplete HTTP headers in I2P tunnels
- SSU2 socket network exceptions on Windows
- Use of 'server' type tunnel port as inport (#1936)
## [2.47.0] - 2023-03-11 ## [2.47.0] - 2023-03-11
### Added ### Added
- Congestion caps - Congestion caps

@ -1,4 +1,4 @@
Copyright (c) 2013-2023, The PurpleI2P Project Copyright (c) 2013-2020, The PurpleI2P Project
All rights reserved. All rights reserved.

@ -67,9 +67,6 @@ else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS))) else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.bsd include Makefile.bsd
else ifneq (, $(findstring haiku, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.haiku
else # not supported else # not supported
$(error Not supported platform) $(error Not supported platform)
endif endif
@ -121,7 +118,7 @@ obj/%.o: %.cpp | mk_obj_dir
-include $(DEPS) -include $(DEPS)
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
$(CXX) $(DEFINES) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) -o $@ $(DEFINES) $(LDFLAGS) $^ $(LDLIBS)
$(SHLIB): $(LIB_OBJS) $(SHLIB): $(LIB_OBJS)
ifneq ($(USE_STATIC),yes) ifneq ($(USE_STATIC),yes)

@ -6,12 +6,7 @@ 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.
CXXVER := $(shell $(CXX) -dumpversion) NEEDED_CXXFLAGS = -std=c++11
ifeq (${CXXVER}, "4.2.1") # older clang always returned 4.2.1
NEEDED_CXXFLAGS = -std=c++11
else # newer versions support C++17
NEEDED_CXXFLAGS = -std=c++17
endif
DEFINES = -D_GLIBCXX_USE_NANOSLEEP=1 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

@ -1,10 +0,0 @@
CXX = g++
CXXFLAGS := -Wall -std=c++11
INCFLAGS = -I/system/develop/headers
DEFINES = -D_DEFAULT_SOURCE -D_GNU_SOURCE
LDLIBS = -lbe -lbsd -lnetwork -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
ifeq ($(USE_UPNP),yes)
DEFINES += -DUSE_UPNP
LDLIBS += -lminiupnpc
endif

@ -1,40 +1,41 @@
# root directory holding homebrew # root directory holding homebrew
BREWROOT = /opt/homebrew BREWROOT = /usr/local
BOOSTROOT = ${BREWROOT}/opt/boost BOOSTROOT = ${BREWROOT}/opt/boost
SSLROOT = ${BREWROOT}/opt/openssl@1.1 SSLROOT = ${BREWROOT}/opt/openssl@1.1
UPNPROOT = ${BREWROOT}/opt/miniupnpc UPNPROOT = ${BREWROOT}/opt/miniupnpc
CXXFLAGS = ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
LDFLAGS = ${LD_DEBUG}
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wno-overloaded-virtual ifndef TRAVIS
NEEDED_CXXFLAGS ?= -std=c++11 CXX = clang++
INCFLAGS ?= -I${SSLROOT}/include -I${BOOSTROOT}/include endif
LDFLAGS ?= ${LD_DEBUG}
DEFINES += -DMAC_OSX
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)
LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a LDLIBS = -lz ${SSLROOT}/lib/libcrypto.a ${SSLROOT}/lib/libssl.a ${BOOSTROOT}/lib/libboost_system.a ${BOOSTROOT}/lib/libboost_date_time.a ${BOOSTROOT}/lib/libboost_filesystem.a ${BOOSTROOT}/lib/libboost_program_options.a -lpthread
ifeq ($(USE_UPNP),yes)
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
endif
LDLIBS += -lpthread -ldl
else else
LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib LDFLAGS += -L${SSLROOT}/lib -L${BOOSTROOT}/lib
LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LDLIBS = -lz -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
ifeq ($(USE_UPNP),yes)
LDFLAGS += -L${UPNPROOT}/lib
LDLIBS += -lminiupnpc
endif
endif endif
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
DEFINES += -DUSE_UPNP LDFLAGS += -ldl
CXXFLAGS += -DUSE_UPNP
INCFLAGS += -I${UPNPROOT}/include INCFLAGS += -I${UPNPROOT}/include
ifeq ($(USE_STATIC),yes)
LDLIBS += ${UPNPROOT}/lib/libminiupnpc.a
else
LDFLAGS += -L${UPNPROOT}/lib
LDLIBS += -lminiupnpc
endif
endif endif
# OSX Notes
# http://www.hutsby.net/2011/08/macs-with-aes-ni.html
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
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 CXXFLAGS += -D__AES__ -maes
NEEDED_CXXFLAGS += -maes
DEFINES += -D__AES__
endif
endif endif
install: all install: all

@ -5,11 +5,14 @@ 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 -fPIC -msse LDFLAGS := ${LD_DEBUG} -static
NEEDED_CXXFLAGS += -std=c++17 NEEDED_CXXFLAGS += -std=c++17
DEFINES += -DWIN32_LEAN_AND_MEAN DEFINES += -DWIN32_LEAN_AND_MEAN
# Boost libraries suffix
BOOST_SUFFIX = -mt
# UPNP Support # UPNP Support
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
DEFINES += -DUSE_UPNP -DMINIUPNP_STATICLIB DEFINES += -DUSE_UPNP -DMINIUPNP_STATICLIB
@ -17,18 +20,17 @@ ifeq ($(USE_UPNP),yes)
endif endif
LDLIBS += \ LDLIBS += \
$(MINGW_PREFIX)/lib/libboost_system-mt.a \ -lboost_system$(BOOST_SUFFIX) \
$(MINGW_PREFIX)/lib/libboost_date_time-mt.a \ -lboost_date_time$(BOOST_SUFFIX) \
$(MINGW_PREFIX)/lib/libboost_filesystem-mt.a \ -lboost_filesystem$(BOOST_SUFFIX) \
$(MINGW_PREFIX)/lib/libboost_program_options-mt.a \ -lboost_program_options$(BOOST_SUFFIX) \
$(MINGW_PREFIX)/lib/libssl.a \ -lssl \
$(MINGW_PREFIX)/lib/libcrypto.a \ -lcrypto \
$(MINGW_PREFIX)/lib/libz.a \ -lz \
-lwsock32 \ -lwsock32 \
-lws2_32 \ -lws2_32 \
-liphlpapi \
-lcrypt32 \
-lgdi32 \ -lgdi32 \
-liphlpapi \
-lole32 \ -lole32 \
-luuid \ -luuid \
-lpthread -lpthread
@ -46,7 +48,6 @@ endif
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
NEEDED_CXXFLAGS += -maes NEEDED_CXXFLAGS += -maes
LDFLAGS += -maes
DEFINES += -D__AES__ DEFINES += -D__AES__
endif endif

@ -5,6 +5,7 @@ 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
LDFLAGS += -Wl,-bind_at_load
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread

@ -99,23 +99,13 @@ Current status: [![Crowdin](https://badges.crowdin.net/i2pd/localized.svg)](http
Donations Donations
--------- ---------
**E-Mail**: ```i2porignal at yandex.com``` BTC: 3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
**BTC**: ```3MDoGJW9TLMTCDGrR9bLgWXfm6sjmgy86f``` ETH: 0x9e5bac70d20d1079ceaa111127f4fb3bccce379d
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
**LTC**: ```LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59``` ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
**ETH**: ```0x9e5bac70d20d1079ceaa111127f4fb3bccce379d``` XMR: 497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH
**GST**: ```GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG```
**DASH**: ```Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF```
**ZEC**: ```t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ```
**ANC**: ```AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z```
**XMR**: ```497pJc7X4xqKvcLBLpSUtRgWqMMyo24u4btCos3cak6gbMkpobgSU6492ztUcUBghyeHpYeczB55s38NpuHoH5WGNSPDRMH```
License License
------- -------

@ -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(eLogCritical, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError()); LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
return false; return false;
} }
return false; return false;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -145,37 +145,30 @@ namespace win32
s << bytes << " Bytes\n"; s << bytes << " Bytes\n";
} }
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error) static void ShowNetworkStatus (std::stringstream& s, RouterStatus status)
{ {
switch (status) switch (status)
{ {
case eRouterStatusOK: s << "OK"; break; case eRouterStatusOK: s << "OK"; break;
case eRouterStatusTesting: s << "Test"; break;
case eRouterStatusFirewalled: s << "FW"; break; case eRouterStatusFirewalled: s << "FW"; break;
case eRouterStatusUnknown: s << "Unk"; break; case eRouterStatusUnknown: s << "Unk"; break;
case eRouterStatusProxy: s << "Proxy"; break; case eRouterStatusProxy: s << "Proxy"; break;
case eRouterStatusMesh: s << "Mesh"; break; case eRouterStatusMesh: s << "Mesh"; break;
default: s << "Unk"; default: s << "Unk";
}; };
if (testing) if (i2p::context.GetError () != eRouterErrorNone)
s << " (Test)";
if (error != eRouterErrorNone)
{ {
switch (error) switch (i2p::context.GetError ())
{ {
case eRouterErrorClockSkew: case eRouterErrorClockSkew:
s << " - " << tr("Clock skew"); s << " - Clock skew";
break; break;
case eRouterErrorOffline: case eRouterErrorOffline:
s << " - " << tr("Offline"); s << " - Offline";
break; break;
case eRouterErrorSymmetricNAT: case eRouterErrorSymmetricNAT:
s << " - " << tr("Symmetric NAT"); s << " - Symmetric NAT";
break;
case eRouterErrorFullConeNAT:
s << " - " << tr("Full cone NAT");
break;
case eRouterErrorNoDescriptors:
s << " - " << tr("No Descriptors");
break; break;
default: ; default: ;
} }
@ -186,11 +179,11 @@ namespace win32
{ {
s << "\n"; s << "\n";
s << "Status: "; s << "Status: ";
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ()); ShowNetworkStatus (s, i2p::context.GetStatus ());
if (i2p::context.SupportsV6 ()) if (i2p::context.SupportsV6 ())
{ {
s << " / "; s << " / ";
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ()); ShowNetworkStatus (s, i2p::context.GetStatusV6 ());
} }
s << "; "; s << "; ";
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n"; s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
@ -355,9 +348,6 @@ namespace win32
} }
} }
} }
#if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]];
#endif
} }
case WM_TRAYICON: case WM_TRAYICON:
{ {

@ -73,24 +73,16 @@ void UnSubscribeFromEvents()
} }
if (pNetEvent) if (pNetEvent)
{
pNetEvent->Release(); pNetEvent->Release();
}
if (pCPContainer) if (pCPContainer)
{
pCPContainer->Release(); pCPContainer->Release();
}
if (pNetworkListManager) if (pNetworkListManager)
{
pNetworkListManager->Release(); pNetworkListManager->Release();
}
if (pUnknown) if (pUnknown)
{
pUnknown->Release(); pUnknown->Release();
}
CoUninitialize(); CoUninitialize();
} }

@ -15,11 +15,10 @@
#include "Log.h" #include "Log.h"
#include "Transports.h" #include "Transports.h"
class CNetworkListManagerEvent final : public INetworkListManagerEvents 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)
{ {

@ -119,12 +119,12 @@ void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
} }
catch (DWORD dwError) catch (DWORD dwError)
{ {
LogPrint(eLogCritical, "Win32Service: Start error: ", dwError); LogPrint(eLogError, "Win32Service: Start error: ", dwError);
SetServiceStatus(SERVICE_STOPPED, dwError); SetServiceStatus(SERVICE_STOPPED, dwError);
} }
catch (...) catch (...)
{ {
LogPrint(eLogCritical, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_STOPPED); SetServiceStatus(SERVICE_STOPPED);
} }
} }
@ -162,7 +162,7 @@ void I2PService::Stop()
} }
catch (...) catch (...)
{ {
LogPrint(eLogCritical, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogError, "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(eLogCritical, "Win32Service: Pause error: ", dwError); LogPrint(eLogError, "Win32Service: Pause error: ", dwError);
SetServiceStatus(SERVICE_RUNNING); SetServiceStatus(SERVICE_RUNNING);
} }
catch (...) catch (...)
{ {
LogPrint(eLogCritical, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogError, "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(eLogCritical, "Win32Service: Continue error: ", dwError); LogPrint(eLogError, "Win32Service: Continue error: ", dwError);
SetServiceStatus(SERVICE_PAUSED); SetServiceStatus(SERVICE_PAUSED);
} }
catch (...) catch (...)
{ {
LogPrint(eLogCritical, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogError, "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(eLogCritical, "Win32Service: Shutdown error: ", dwError); LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError);
} }
catch (...) catch (...)
{ {
LogPrint(eLogCritical, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE); LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -25,7 +25,7 @@ project(
i2pd i2pd
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_VERSION}
HOMEPAGE_URL "https://i2pd.website/" HOMEPAGE_URL "https://i2pd.website/"
LANGUAGES C CXX LANGUAGES CXX
) )
# configurable options # configurable options
@ -121,7 +121,7 @@ if(WIN32)
) )
file(GLOB WIN32_RC ${WIN32_SRC_DIR}/*.rc) file(GLOB WIN32_RC ${WIN32_SRC_DIR}/*.rc)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN -DNOMINMAX") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWIN32_APP -DWIN32_LEAN_AND_MEAN")
endif() endif()
@ -139,10 +139,6 @@ if(APPLE)
add_definitions(-DMAC_OSX) add_definitions(-DMAC_OSX)
endif() endif()
if(HAIKU)
add_definitions(-D_DEFAULT_SOURCE -D_GNU_SOURCE)
endif()
if(MSVC) if(MSVC)
add_definitions(-DWINVER=0x0600) add_definitions(-DWINVER=0x0600)
add_definitions(-D_WIN32_WINNT=0x0600) add_definitions(-D_WIN32_WINNT=0x0600)
@ -201,11 +197,14 @@ 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 due to different ASM processing, so we hope OpenSSL has its own checks to run optimized code. # 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"))
if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
endif()
add_definitions(-D__AES__) add_definitions(-D__AES__)
endif() endif()
@ -278,19 +277,15 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif() 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) 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 REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic) find_package(Boost REQUIRED COMPONENTS system filesystem program_options date_time OPTIONAL_COMPONENTS atomic)
if(NOT DEFINED Boost_FOUND) if(NOT DEFINED Boost_INCLUDE_DIRS)
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_FOUND) if(NOT DEFINED OPENSSL_INCLUDE_DIR)
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()
@ -330,11 +325,7 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
message(STATUS " BINARY : ${WITH_BINARY}") message(STATUS " BINARY : ${WITH_BINARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}") message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS " UPnP : ${WITH_UPNP}") message(STATUS " UPnP : ${WITH_UPNP}")
if(WITH_GIT_VERSION)
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION} (${GIT_VERSION})")
else()
message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}") message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}")
endif()
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}") message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}") message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")

@ -1,42 +0,0 @@
# _________________________________________
# / Copy this file to the right location \
# | then load with: |
# | |
# | apparmor_parser -r -W |
# | /etc/apparmor.d/docker-i2pd |
# | |
# | docker run --security-opt |
# | "apparmor=docker-i2pd" ... |
# | purplei2p/i2pd |
# | |
# \ And "aa-status" to verify it's loaded. /
# -----------------------------------------
# \ ^__^
# \ (oo)\_______
# (__)\ )\/\
# ||----w |
# || ||
#include <tunables/global>
profile docker-i2pd flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
#include <abstractions/openssl>
#include <abstractions/nameservice>
/bin/busybox ix,
/usr/local/bin/i2pd ix,
/entrypoint.sh ixr,
/i2pd_certificates/** r,
/home/i2pd/data/** rw,
/home/i2pd/data/i2pd.pid k,
deny /home/i2pd/data/i2pd.conf w,
deny /home/i2pd/data/tunnels.conf w,
deny /home/i2pd/data/tunnels.d/** w,
deny /home/i2pd/data/certificates/** w,
deny /home/i2pd/data/i2pd.log r,
}

@ -1,34 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIF1zCCA7+gAwIBAgIRAMDqFR09Xuj8ZUu+oetSvAEwDQYJKoZIhvcNAQELBQAw
dTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxHjAcBgNVBAMM
FWFkbWluQHN0b3JteWNsb3VkLm9yZzAeFw0yNDAxMjUxNDE1MzBaFw0zNDAxMjUx
NDE1MzBaMHUxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgx
HjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMR4w
HAYDVQQDDBVhZG1pbkBzdG9ybXljbG91ZC5vcmcwggIiMA0GCSqGSIb3DQEBAQUA
A4ICDwAwggIKAoICAQDbGX+GikPzQXr9zvkrhfO9g0l49KHLNQhUKYqd6T+PfnGo
Fm0d3ZZVVQZ045vWgroOXDGGZZWxUIlb2inRaR2DF1TxN3pPYt59RgY9ZQ9+TL7o
isY91krCRygY8EcAmHIjlfZQ9dBVcL7CfyT0MYZA5Efee9+NDHSewTfQP9T2faIE
83Fcyd93a2mIHYjKUbJnojng/wgsy8srbsEuuTok4MIQmDj+B5nz+za2FgI0/ydh
srlMt4aGJF4/DIem9z9d0zBCOkwrmtFIzjNF1mOSA8ES4m5YnKA/y9rZlRidLPGu
prbXhPVnqHeOnHMz2QCw1wbVo504kl0bMqyEz2tVWsO9ep7iZoQs2xkFAEaegYNT
QLUpwVGlyuq3wXXwopFRffOSimGSazICwWI6j+K0pOtgefNJaWrqKYvtkj1SbK2L
LBNUIENz6VnB7KPRckuX6zxC8PpOiBK9BcftfO+xAz/wC6qq3riBPw30KKSym0nC
Zp5KciDn4Phtw9PGq8Bkl8SyWl0jtFnfTB1tzJkisf2qKcNHaFTEe2JW763YLbh/
AU+8X8evFu40qLgvOgKoyy5DLy6i8zetX+3t9K0Fxt9+Vzzq6lm5V/RS8iIPPn+M
q1/3Z5kD0KQBG9h/Gl8BH+lB71ZxPAOZ3SMu8DJZcxBLVmDWqQPCr5CKnoz0swID
AQABo2IwYDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
AQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wHgYDVR0OBBcEFWFkbWluQHN0b3JteWNs
b3VkLm9yZzANBgkqhkiG9w0BAQsFAAOCAgEARWOJ69vTHMneSXYscha+4Ytjg0RM
faewJNEGj8qy/Qvh9si2bWYNPRK6BlbHFS7pRYBLAnhaeLBGVv1CCR6GUMMe74zQ
UuMeAoWU6qMDmB3GfYoZJh8sIxpwHqyJeTdeccRbZ4sX4F6u3IHPXYiU/AgbYqH7
pYXQg2lCjXZYaDFAlEf5SlYUDOhhXe5kR8Edhlrsu32/JzA1DQK0JjxKCBp+DQmA
ltdOpQtAg03fHP4ssdj7VvjIDl28iIlATwBvHrdNm7T0tYWn6TWhvxbRqvfTxfaH
MvxnPdIJwNP4/9TyQkwjwHb1h+ucho3CnxI/AxspdOvT1ElMhP6Ce6rcS9pk11Rl
x0ChsqpWwDg7KYpg0qZFSKCTBp4zBq9xoMJ6BQcgMfyl736WbsCzFTEyfifp8beg
NxUa/Qk7w7cuSPGyMIKNOmOR7FLlFbtocy8sXVsUQdqnp/edelufdNe39U9uNtY6
yoXI9//Tc6NgOwy2Oyia0slZ5qHRkB7e4USXMRzJ3p4q9eCVKjAJs81Utp7O2U+9
vhbhwWP8CAnNTT1E5WS6EKtfrdqF7wjkV+noPGLDGmrXi01J1fSMAjMfVO+7/LOL
UN+G4ybKWnEhhOO27yidN8Xx6UrCS23DBlPPQAeA74dTsTExiOxf1o1EXzcQiMyO
LAj3/Ojbi1xkWhI=
-----END CERTIFICATE-----

@ -1,5 +1,2 @@
This forder contain files required for building debian packages. This forder contain systemd unit files.
To use systemd daemon control, place files from this directory to debian folder before building package.
The trunk repository is contains the packaging files for the latest stable version of Debian (if we not forgot to update them).
Files in subdirectories contains fixes to make possible to build package on specific versions of Debian/Ubuntu. They are used when building the release package.

@ -1,18 +0,0 @@
Source: i2pd
Section: net
Priority: optional
Maintainer: r4sas <r4sas@i2pmail.org>
Build-Depends: debhelper (>= 11~), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
Standards-Version: 4.2.0
Homepage: http://i2pd.website/
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd
Package: i2pd
Architecture: any
Pre-Depends: ${misc:Pre-Depends}, adduser
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
Description: Full-featured C++ implementation of I2P client.
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
communications over I2P are anonymous and end-to-end encrypted, participants
don't reveal their real IP addresses.

@ -1,18 +0,0 @@
Source: i2pd
Section: net
Priority: optional
Maintainer: r4sas <r4sas@i2pmail.org>
Build-Depends: debhelper (>= 9), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
Standards-Version: 3.9.8
Homepage: http://i2pd.website/
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd
Package: i2pd
Architecture: any
Pre-Depends: ${misc:Pre-Depends}, adduser
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
Description: Full-featured C++ implementation of I2P client.
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
communications over I2P are anonymous and end-to-end encrypted, participants
don't reveal their real IP addresses.

@ -1,17 +0,0 @@
Description: Enable UPnP usage in package
Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2022-03-23
--- i2pd.orig/Makefile
+++ i2pd/Makefile
@@ -31,7 +31,7 @@ include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no)
-USE_UPNP := $(or $(USE_UPNP),no)
+USE_UPNP := $(or $(USE_UPNP),yes)
DEBUG := $(or $(DEBUG),yes)
# for debugging purposes only, when commit hash needed in trunk builds in i2pd version string

@ -1,19 +0,0 @@
Description: Disable LogsDirectory and LogsDirectoryMode options in service
Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2023-05-17
--- a/contrib/i2pd.service
+++ b/contrib/i2pd.service
@@ -8,8 +8,8 @@ User=i2pd
Group=i2pd
RuntimeDirectory=i2pd
RuntimeDirectoryMode=0700
-LogsDirectory=i2pd
-LogsDirectoryMode=0700
+#LogsDirectory=i2pd
+#LogsDirectoryMode=0700
Type=forking
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/sh -c "kill -HUP $MAINPID"

@ -1,2 +0,0 @@
01-upnp.patch
02-service.patch

@ -1,18 +0,0 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
include /usr/share/dpkg/architecture.mk
ifeq ($(DEB_HOST_ARCH),i386)
export DEB_BUILD_OPTIONS=parallel=1
endif
export DEB_CXXFLAGS_MAINT_APPEND=-Wall -pedantic
export DEB_LDFLAGS_MAINT_APPEND=
%:
dh $@ --parallel
override_dh_auto_install:

@ -1,18 +0,0 @@
Source: i2pd
Section: net
Priority: optional
Maintainer: r4sas <r4sas@i2pmail.org>
Build-Depends: debhelper (>= 9), libboost-system-dev (>= 1.46), libboost-date-time-dev (>= 1.46), libboost-filesystem-dev (>= 1.46), libboost-program-options-dev (>= 1.46), libminiupnpc-dev, libssl-dev, zlib1g-dev
Standards-Version: 3.9.8
Homepage: http://i2pd.website/
Vcs-Git: git://github.com/PurpleI2P/i2pd.git
Vcs-Browser: https://github.com/PurpleI2P/i2pd
Package: i2pd
Architecture: any
Pre-Depends: ${misc:Pre-Depends}, adduser
Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base,
Description: Full-featured C++ implementation of I2P client.
I2P (Invisible Internet Protocol) is a universal anonymous network layer. All
communications over I2P are anonymous and end-to-end encrypted, participants
don't reveal their real IP addresses.

@ -1,17 +0,0 @@
Description: Enable UPnP usage in package
Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2022-03-23
--- i2pd.orig/Makefile
+++ i2pd/Makefile
@@ -31,7 +31,7 @@ include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no)
-USE_UPNP := $(or $(USE_UPNP),no)
+USE_UPNP := $(or $(USE_UPNP),yes)
DEBUG := $(or $(DEBUG),yes)
# for debugging purposes only, when commit hash needed in trunk builds in i2pd version string

@ -1,19 +0,0 @@
Description: Disable LogsDirectory and LogsDirectoryMode options in service
Author: r4sas <r4sas@i2pmail.org>
Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2023-05-17
--- a/contrib/i2pd.service
+++ b/contrib/i2pd.service
@@ -8,8 +8,8 @@ User=i2pd
Group=i2pd
RuntimeDirectory=i2pd
RuntimeDirectoryMode=0700
-LogsDirectory=i2pd
-LogsDirectoryMode=0700
+#LogsDirectory=i2pd
+#LogsDirectoryMode=0700
Type=forking
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/sh -c "kill -HUP $MAINPID"

@ -1,2 +0,0 @@
01-upnp.patch
02-service.patch

@ -1,13 +0,0 @@
#!/usr/bin/make -f
#export DH_VERBOSE=1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
include /usr/share/dpkg/architecture.mk
export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
export DEB_LDFLAGS_MAINT_APPEND =
%:
dh $@ --parallel
override_dh_auto_install:

@ -1,8 +0,0 @@
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

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: i2pd\n" "Project-Id-Version: i2pd\n"
"Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n" "Report-Msgid-Bugs-To: https://github.com/PurpleI2P/i2pd/issues\n"
"POT-Creation-Date: 2023-06-10 01:25\n" "POT-Creation-Date: 2023-01-19 04:18\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@ -18,28 +18,28 @@ msgstr ""
"X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n" "X-Poedit-SearchPath-0: daemon/HTTPServer.cpp\n"
"X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n" "X-Poedit-SearchPath-1: libi2pd_client/HTTPProxy.cpp\n"
#: daemon/HTTPServer.cpp:107 #: daemon/HTTPServer.cpp:106
#, c-format #, c-format
msgid "%d day" msgid "%d day"
msgid_plural "%d days" msgid_plural "%d days"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:111 #: daemon/HTTPServer.cpp:110
#, c-format #, c-format
msgid "%d hour" msgid "%d hour"
msgid_plural "%d hours" msgid_plural "%d hours"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:115 #: daemon/HTTPServer.cpp:114
#, c-format #, c-format
msgid "%d minute" msgid "%d minute"
msgid_plural "%d minutes" msgid_plural "%d minutes"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: daemon/HTTPServer.cpp:118 #: daemon/HTTPServer.cpp:117
#, c-format #, c-format
msgid "%d second" msgid "%d second"
msgid_plural "%d seconds" msgid_plural "%d seconds"
@ -47,578 +47,560 @@ msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#. tr: Kibibyte #. tr: Kibibyte
#: daemon/HTTPServer.cpp:126 #: daemon/HTTPServer.cpp:125 daemon/HTTPServer.cpp:153
#, c-format #, c-format
msgid "%.2f KiB" msgid "%.2f KiB"
msgstr "" msgstr ""
#. tr: Mebibyte #. tr: Mebibyte
#: daemon/HTTPServer.cpp:128 #: daemon/HTTPServer.cpp:127
#, c-format #, c-format
msgid "%.2f MiB" msgid "%.2f MiB"
msgstr "" msgstr ""
#. tr: Gibibyte #. tr: Gibibyte
#: daemon/HTTPServer.cpp:130 #: daemon/HTTPServer.cpp:129
#, c-format #, c-format
msgid "%.2f GiB" msgid "%.2f GiB"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:147 #: daemon/HTTPServer.cpp:146
msgid "building" msgid "building"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:148 #: daemon/HTTPServer.cpp:147
msgid "failed" msgid "failed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:149 #: daemon/HTTPServer.cpp:148
msgid "expiring" msgid "expiring"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:150 #: daemon/HTTPServer.cpp:149
msgid "established" msgid "established"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:151 #: daemon/HTTPServer.cpp:150
msgid "unknown" msgid "unknown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:153 #: daemon/HTTPServer.cpp:152
msgid "exploratory" msgid "exploratory"
msgstr "" msgstr ""
#. tr: Webconsole page title #. tr: Webconsole page title
#: daemon/HTTPServer.cpp:185 #: daemon/HTTPServer.cpp:183
msgid "Purple I2P Webconsole" msgid "Purple I2P Webconsole"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:190 #: daemon/HTTPServer.cpp:188
msgid "<b>i2pd</b> webconsole" msgid "<b>i2pd</b> webconsole"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:193 #: daemon/HTTPServer.cpp:191
msgid "Main page" msgid "Main page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:194 daemon/HTTPServer.cpp:742 #: daemon/HTTPServer.cpp:192 daemon/HTTPServer.cpp:712
msgid "Router commands" msgid "Router commands"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:395 #: daemon/HTTPServer.cpp:193 daemon/HTTPServer.cpp:387
#: daemon/HTTPServer.cpp:407 #: daemon/HTTPServer.cpp:399
msgid "Local Destinations" msgid "Local Destinations"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:365 #: daemon/HTTPServer.cpp:195 daemon/HTTPServer.cpp:357
#: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:474 #: daemon/HTTPServer.cpp:443 daemon/HTTPServer.cpp:449
#: daemon/HTTPServer.cpp:636 daemon/HTTPServer.cpp:682 #: daemon/HTTPServer.cpp:609 daemon/HTTPServer.cpp:652
#: daemon/HTTPServer.cpp:686 #: daemon/HTTPServer.cpp:656
msgid "LeaseSets" msgid "LeaseSets"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:692 #: daemon/HTTPServer.cpp:197 daemon/HTTPServer.cpp:662
msgid "Tunnels" msgid "Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:372 #: daemon/HTTPServer.cpp:199 daemon/HTTPServer.cpp:364
#: daemon/HTTPServer.cpp:813 daemon/HTTPServer.cpp:830 #: daemon/HTTPServer.cpp:781 daemon/HTTPServer.cpp:797
msgid "Transit Tunnels" msgid "Transit Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:203 daemon/HTTPServer.cpp:898 #: daemon/HTTPServer.cpp:201 daemon/HTTPServer.cpp:855
msgid "Transports" msgid "Transports"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:204 #: daemon/HTTPServer.cpp:202
msgid "I2P tunnels" msgid "I2P tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:206 daemon/HTTPServer.cpp:927 #: daemon/HTTPServer.cpp:204 daemon/HTTPServer.cpp:884
#: daemon/HTTPServer.cpp:937 #: daemon/HTTPServer.cpp:894
msgid "SAM sessions" msgid "SAM sessions"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:222 daemon/HTTPServer.cpp:1329 #: daemon/HTTPServer.cpp:220 daemon/HTTPServer.cpp:1278
#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1335 #: daemon/HTTPServer.cpp:1281 daemon/HTTPServer.cpp:1284
#: daemon/HTTPServer.cpp:1362 daemon/HTTPServer.cpp:1365 #: daemon/HTTPServer.cpp:1298 daemon/HTTPServer.cpp:1343
#: daemon/HTTPServer.cpp:1379 daemon/HTTPServer.cpp:1424 #: daemon/HTTPServer.cpp:1346 daemon/HTTPServer.cpp:1349
#: daemon/HTTPServer.cpp:1427 daemon/HTTPServer.cpp:1430
msgid "ERROR" msgid "ERROR"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:229 #: daemon/HTTPServer.cpp:227
msgid "OK" msgid "OK"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:230 #: daemon/HTTPServer.cpp:228
msgid "Testing" msgid "Testing"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:231 #: daemon/HTTPServer.cpp:229
msgid "Firewalled" msgid "Firewalled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:232 daemon/HTTPServer.cpp:235 #: daemon/HTTPServer.cpp:230 daemon/HTTPServer.cpp:233
#: daemon/HTTPServer.cpp:336 #: daemon/HTTPServer.cpp:329
msgid "Unknown" msgid "Unknown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:233 daemon/HTTPServer.cpp:382 #: daemon/HTTPServer.cpp:231 daemon/HTTPServer.cpp:374
#: daemon/HTTPServer.cpp:383 daemon/HTTPServer.cpp:1003 #: daemon/HTTPServer.cpp:375 daemon/HTTPServer.cpp:952
#: daemon/HTTPServer.cpp:1011 #: daemon/HTTPServer.cpp:961
msgid "Proxy" msgid "Proxy"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:234 #: daemon/HTTPServer.cpp:232
msgid "Mesh" msgid "Mesh"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:242 #: daemon/HTTPServer.cpp:240
msgid "Clock skew" msgid "Clock skew"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:245 #: daemon/HTTPServer.cpp:243
msgid "Offline" msgid "Offline"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:248 #: daemon/HTTPServer.cpp:246
msgid "Symmetric NAT" msgid "Symmetric NAT"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:251 #: daemon/HTTPServer.cpp:249
msgid "Full cone NAT" msgid "Full cone NAT"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:254 #: daemon/HTTPServer.cpp:252
msgid "No Descriptors" msgid "No Descriptors"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:263 #: daemon/HTTPServer.cpp:261
msgid "Uptime" msgid "Uptime"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:266 #: daemon/HTTPServer.cpp:264
msgid "Network status" msgid "Network status"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:271 #: daemon/HTTPServer.cpp:269
msgid "Network status v6" msgid "Network status v6"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:277 daemon/HTTPServer.cpp:284 #: daemon/HTTPServer.cpp:275 daemon/HTTPServer.cpp:282
msgid "Stopping in" msgid "Stopping in"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:291 #: daemon/HTTPServer.cpp:289
msgid "Family" msgid "Family"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:292 #: daemon/HTTPServer.cpp:290
msgid "Tunnel creation success rate" msgid "Tunnel creation success rate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:296 #: daemon/HTTPServer.cpp:291
msgid "Total tunnel creation success rate"
msgstr ""
#: daemon/HTTPServer.cpp:298
msgid "Received" msgid "Received"
msgstr "" msgstr ""
#. tr: Kibibyte/s #. tr: Kibibyte/s
#: daemon/HTTPServer.cpp:300 daemon/HTTPServer.cpp:303 #: daemon/HTTPServer.cpp:293 daemon/HTTPServer.cpp:296
#: daemon/HTTPServer.cpp:306 #: daemon/HTTPServer.cpp:299
#, c-format #, c-format
msgid "%.2f KiB/s" msgid "%.2f KiB/s"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:301 #: daemon/HTTPServer.cpp:294
msgid "Sent" msgid "Sent"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:304 #: daemon/HTTPServer.cpp:297
msgid "Transit" msgid "Transit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:307 #: daemon/HTTPServer.cpp:300
msgid "Data path" msgid "Data path"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:310 #: daemon/HTTPServer.cpp:303
msgid "Hidden content. Press on text to see." msgid "Hidden content. Press on text to see."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:314 #: daemon/HTTPServer.cpp:307
msgid "Router Ident" msgid "Router Ident"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:316 #: daemon/HTTPServer.cpp:309
msgid "Router Family" msgid "Router Family"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:317 #: daemon/HTTPServer.cpp:310
msgid "Router Caps" msgid "Router Caps"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:318 #: daemon/HTTPServer.cpp:311
msgid "Version" msgid "Version"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:319 #: daemon/HTTPServer.cpp:312
msgid "Our external address" msgid "Our external address"
msgstr "" msgstr ""
#. tr: Shown when router doesn't publish itself and have "Firewalled" state #. tr: Shown when router doesn't publish itself and have "Firewalled" state
#: daemon/HTTPServer.cpp:349 #: daemon/HTTPServer.cpp:341
msgid "supported" msgid "supported"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:363 #: daemon/HTTPServer.cpp:355
msgid "Routers" msgid "Routers"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:364 #: daemon/HTTPServer.cpp:356
msgid "Floodfills" msgid "Floodfills"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:371 daemon/HTTPServer.cpp:987 #: daemon/HTTPServer.cpp:363 daemon/HTTPServer.cpp:938
msgid "Client Tunnels" msgid "Client Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:381 #: daemon/HTTPServer.cpp:373
msgid "Services" msgid "Services"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383 #: daemon/HTTPServer.cpp:374 daemon/HTTPServer.cpp:375
#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385 #: daemon/HTTPServer.cpp:376 daemon/HTTPServer.cpp:377
#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387 #: daemon/HTTPServer.cpp:378 daemon/HTTPServer.cpp:379
msgid "Enabled" msgid "Enabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:382 daemon/HTTPServer.cpp:383 #: daemon/HTTPServer.cpp:374 daemon/HTTPServer.cpp:375
#: daemon/HTTPServer.cpp:384 daemon/HTTPServer.cpp:385 #: daemon/HTTPServer.cpp:376 daemon/HTTPServer.cpp:377
#: daemon/HTTPServer.cpp:386 daemon/HTTPServer.cpp:387 #: daemon/HTTPServer.cpp:378 daemon/HTTPServer.cpp:379
msgid "Disabled" msgid "Disabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:434 #: daemon/HTTPServer.cpp:422
msgid "Encrypted B33 address" msgid "Encrypted B33 address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:442 #: daemon/HTTPServer.cpp:431
msgid "Address registration line" msgid "Address registration line"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:447 #: daemon/HTTPServer.cpp:436
msgid "Domain" msgid "Domain"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:448 #: daemon/HTTPServer.cpp:437
msgid "Generate" msgid "Generate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:449 #: daemon/HTTPServer.cpp:438
msgid "" msgid ""
"<b>Note:</b> result string can be used only for registering 2LD domains " "<b>Note:</b> result string can be used only for registering 2LD domains "
"(example.i2p). For registering subdomains please use i2pd-tools." "(example.i2p). For registering subdomains please use i2pd-tools."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:457 #: daemon/HTTPServer.cpp:444
msgid "Address" msgid "Address"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:459 #: daemon/HTTPServer.cpp:444
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:460 #: daemon/HTTPServer.cpp:444
msgid "EncType" msgid "EncType"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:467 #: daemon/HTTPServer.cpp:454 daemon/HTTPServer.cpp:667
msgid "Expire LeaseSet"
msgstr ""
#: daemon/HTTPServer.cpp:479 daemon/HTTPServer.cpp:697
msgid "Inbound tunnels" msgid "Inbound tunnels"
msgstr "" msgstr ""
#. tr: Milliseconds #. tr: Milliseconds
#: daemon/HTTPServer.cpp:494 daemon/HTTPServer.cpp:514 #: daemon/HTTPServer.cpp:469 daemon/HTTPServer.cpp:489
#: daemon/HTTPServer.cpp:711 daemon/HTTPServer.cpp:731 #: daemon/HTTPServer.cpp:681 daemon/HTTPServer.cpp:701
#, c-format #, c-format
msgid "%dms" msgid "%dms"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:499 daemon/HTTPServer.cpp:716 #: daemon/HTTPServer.cpp:474 daemon/HTTPServer.cpp:686
msgid "Outbound tunnels" msgid "Outbound tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:521 #: daemon/HTTPServer.cpp:496
msgid "Tags" msgid "Tags"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:522 #: daemon/HTTPServer.cpp:497
msgid "Incoming" msgid "Incoming"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:529 daemon/HTTPServer.cpp:535 #: daemon/HTTPServer.cpp:504 daemon/HTTPServer.cpp:510
msgid "Outgoing" msgid "Outgoing"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:551 #: daemon/HTTPServer.cpp:507 daemon/HTTPServer.cpp:526
msgid "Destination" msgid "Destination"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:532 daemon/HTTPServer.cpp:814 #: daemon/HTTPServer.cpp:507
msgid "Amount" msgid "Amount"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:540 #: daemon/HTTPServer.cpp:515
msgid "Incoming Tags" msgid "Incoming Tags"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:548 daemon/HTTPServer.cpp:554 #: daemon/HTTPServer.cpp:523 daemon/HTTPServer.cpp:529
msgid "Tags sessions" msgid "Tags sessions"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:551 #: daemon/HTTPServer.cpp:526
msgid "Status" msgid "Status"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:561 daemon/HTTPServer.cpp:621 #: daemon/HTTPServer.cpp:536 daemon/HTTPServer.cpp:594
msgid "Local Destination" msgid "Local Destination"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:572 daemon/HTTPServer.cpp:960 #: daemon/HTTPServer.cpp:547 daemon/HTTPServer.cpp:917
msgid "Streams" msgid "Streams"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:595 #: daemon/HTTPServer.cpp:570
msgid "Close stream" msgid "Close stream"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:613 daemon/HTTPServer.cpp:1430 #: daemon/HTTPServer.cpp:599
msgid "Such destination is not found"
msgstr ""
#: daemon/HTTPServer.cpp:626
msgid "I2CP session not found" msgid "I2CP session not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:629 #: daemon/HTTPServer.cpp:602
msgid "I2CP is not enabled" msgid "I2CP is not enabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:658 #: daemon/HTTPServer.cpp:628
msgid "Invalid" msgid "Invalid"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:661 #: daemon/HTTPServer.cpp:631
msgid "Store type" msgid "Store type"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:662 #: daemon/HTTPServer.cpp:632
msgid "Expires" msgid "Expires"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:667 #: daemon/HTTPServer.cpp:637
msgid "Non Expired Leases" msgid "Non Expired Leases"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:670 #: daemon/HTTPServer.cpp:640
msgid "Gateway" msgid "Gateway"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:671 #: daemon/HTTPServer.cpp:641
msgid "TunnelID" msgid "TunnelID"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:672 #: daemon/HTTPServer.cpp:642
msgid "EndDate" msgid "EndDate"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:682 #: daemon/HTTPServer.cpp:652
msgid "floodfill mode is disabled" msgid "floodfill mode is disabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:693 #: daemon/HTTPServer.cpp:663
msgid "Queue size" msgid "Queue size"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:743 #: daemon/HTTPServer.cpp:713
msgid "Run peer test" msgid "Run peer test"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:744 #: daemon/HTTPServer.cpp:714
msgid "Reload tunnels configuration" msgid "Reload tunnels configuration"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:747 #: daemon/HTTPServer.cpp:717
msgid "Decline transit tunnels" msgid "Decline transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:749 #: daemon/HTTPServer.cpp:719
msgid "Accept transit tunnels" msgid "Accept transit tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:753 daemon/HTTPServer.cpp:758 #: daemon/HTTPServer.cpp:723 daemon/HTTPServer.cpp:728
msgid "Cancel graceful shutdown" msgid "Cancel graceful shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:755 daemon/HTTPServer.cpp:760 #: daemon/HTTPServer.cpp:725 daemon/HTTPServer.cpp:730
msgid "Start graceful shutdown" msgid "Start graceful shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:763 #: daemon/HTTPServer.cpp:733
msgid "Force shutdown" msgid "Force shutdown"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:764 #: daemon/HTTPServer.cpp:734
msgid "Reload external CSS styles" msgid "Reload external CSS styles"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:767 #: daemon/HTTPServer.cpp:737
msgid "" msgid ""
"<b>Note:</b> any action done here are not persistent and not changes your " "<b>Note:</b> any action done here are not persistent and not changes your "
"config files." "config files."
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:770 #: daemon/HTTPServer.cpp:739
msgid "Logging level" msgid "Logging level"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:779 #: daemon/HTTPServer.cpp:747
msgid "Transit tunnels limit" msgid "Transit tunnels limit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:784 daemon/HTTPServer.cpp:803 #: daemon/HTTPServer.cpp:752 daemon/HTTPServer.cpp:771
msgid "Change" msgid "Change"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:791 #: daemon/HTTPServer.cpp:759
msgid "Change language" msgid "Change language"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:830 #: daemon/HTTPServer.cpp:797
msgid "no transit tunnels currently built" msgid "no transit tunnels currently built"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:921 daemon/HTTPServer.cpp:944 #: daemon/HTTPServer.cpp:878 daemon/HTTPServer.cpp:901
msgid "SAM disabled" msgid "SAM disabled"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:937 #: daemon/HTTPServer.cpp:894
msgid "no sessions currently running" msgid "no sessions currently running"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:950 #: daemon/HTTPServer.cpp:907
msgid "SAM session not found" msgid "SAM session not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:955 #: daemon/HTTPServer.cpp:912
msgid "SAM Session" msgid "SAM Session"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1020 #: daemon/HTTPServer.cpp:969
msgid "Server Tunnels" msgid "Server Tunnels"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1036 #: daemon/HTTPServer.cpp:985
msgid "Client Forwards" msgid "Client Forwards"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1050 #: daemon/HTTPServer.cpp:999
msgid "Server Forwards" msgid "Server Forwards"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1250 #: daemon/HTTPServer.cpp:1199
msgid "Unknown page" msgid "Unknown page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1269 #: daemon/HTTPServer.cpp:1218
msgid "Invalid token" msgid "Invalid token"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1327 daemon/HTTPServer.cpp:1359 #: daemon/HTTPServer.cpp:1276 daemon/HTTPServer.cpp:1333
#: daemon/HTTPServer.cpp:1414 daemon/HTTPServer.cpp:1454 #: daemon/HTTPServer.cpp:1373
msgid "SUCCESS" msgid "SUCCESS"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1327 #: daemon/HTTPServer.cpp:1276
msgid "Stream closed" msgid "Stream closed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1329 #: daemon/HTTPServer.cpp:1278
msgid "Stream not found or already was closed" msgid "Stream not found or already was closed"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1332 daemon/HTTPServer.cpp:1365 #: daemon/HTTPServer.cpp:1281
msgid "Destination not found" msgid "Destination not found"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1335 #: daemon/HTTPServer.cpp:1284
msgid "StreamID can't be null" msgid "StreamID can't be null"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1337 daemon/HTTPServer.cpp:1367 #: daemon/HTTPServer.cpp:1286 daemon/HTTPServer.cpp:1351
#: daemon/HTTPServer.cpp:1432
msgid "Return to destination page" msgid "Return to destination page"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1338 daemon/HTTPServer.cpp:1368 #: daemon/HTTPServer.cpp:1287 daemon/HTTPServer.cpp:1300
#: daemon/HTTPServer.cpp:1381 daemon/HTTPServer.cpp:1456 #: daemon/HTTPServer.cpp:1375
#, c-format #, c-format
msgid "You will be redirected in %d seconds" msgid "You will be redirected in %d seconds"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1359 #: daemon/HTTPServer.cpp:1298
msgid "LeaseSet expiration time updated"
msgstr ""
#: daemon/HTTPServer.cpp:1362
msgid "LeaseSet is not found or already expired"
msgstr ""
#: daemon/HTTPServer.cpp:1379
#, c-format #, c-format
msgid "Transit tunnels count must not exceed %d" msgid "Transit tunnels count must not exceed %d"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1380 daemon/HTTPServer.cpp:1455 #: daemon/HTTPServer.cpp:1299 daemon/HTTPServer.cpp:1374
msgid "Back to commands list" msgid "Back to commands list"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1416 #: daemon/HTTPServer.cpp:1335
msgid "Register at reg.i2p" msgid "Register at reg.i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1417 #: daemon/HTTPServer.cpp:1336
msgid "Description" msgid "Description"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1417 #: daemon/HTTPServer.cpp:1336
msgid "A bit information about service on domain" msgid "A bit information about service on domain"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1418 #: daemon/HTTPServer.cpp:1337
msgid "Submit" msgid "Submit"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1424 #: daemon/HTTPServer.cpp:1343
msgid "Domain can't end with .b32.i2p" msgid "Domain can't end with .b32.i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1427 #: daemon/HTTPServer.cpp:1346
msgid "Domain must end with .i2p" msgid "Domain must end with .i2p"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1450 #: daemon/HTTPServer.cpp:1349
msgid "Such destination is not found"
msgstr ""
#: daemon/HTTPServer.cpp:1369
msgid "Unknown command" msgid "Unknown command"
msgstr "" msgstr ""
#: daemon/HTTPServer.cpp:1454 #: daemon/HTTPServer.cpp:1373
msgid "Command accepted" msgid "Command accepted"
msgstr "" msgstr ""
@ -642,20 +624,20 @@ msgstr ""
msgid "You may try to find this host on jump services below" msgid "You may try to find this host on jump services below"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:333 libi2pd_client/HTTPProxy.cpp:348 #: libi2pd_client/HTTPProxy.cpp:309 libi2pd_client/HTTPProxy.cpp:324
#: libi2pd_client/HTTPProxy.cpp:417 libi2pd_client/HTTPProxy.cpp:460 #: libi2pd_client/HTTPProxy.cpp:392 libi2pd_client/HTTPProxy.cpp:435
msgid "Invalid request" msgid "Invalid request"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:333 #: libi2pd_client/HTTPProxy.cpp:309
msgid "Proxy unable to parse your request" msgid "Proxy unable to parse your request"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:348 #: libi2pd_client/HTTPProxy.cpp:324
msgid "Addresshelper is not supported" msgid "Addresshelper is not supported"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:373 #: libi2pd_client/HTTPProxy.cpp:349
#, c-format #, c-format
msgid "" msgid ""
"Host %s is <font color=red>already in router's addressbook</font>. <b>Be " "Host %s is <font color=red>already in router's addressbook</font>. <b>Be "
@ -663,121 +645,121 @@ msgid ""
"<a href=\"%s%s%s&update=true\">Continue</a>." "<a href=\"%s%s%s&update=true\">Continue</a>."
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:375 #: libi2pd_client/HTTPProxy.cpp:351
msgid "Addresshelper forced update rejected" msgid "Addresshelper forced update rejected"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:382 #: libi2pd_client/HTTPProxy.cpp:358
#, c-format #, c-format
msgid "" msgid ""
"To add host <b>%s</b> in router's addressbook, click here: <a " "To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s"
"href=\"%s%s%s\">Continue</a>." "\">Continue</a>."
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:384 #: libi2pd_client/HTTPProxy.cpp:360
msgid "Addresshelper request" msgid "Addresshelper request"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:393 #: libi2pd_client/HTTPProxy.cpp:369
#, c-format #, c-format
msgid "" msgid ""
"Host %s added to router's addressbook from helper. Click here to proceed: <a " "Host %s added to router's addressbook from helper. Click here to proceed: <a "
"href=\"%s\">Continue</a>." "href=\"%s\">Continue</a>."
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:395 #: libi2pd_client/HTTPProxy.cpp:370
msgid "Addresshelper adding" msgid "Addresshelper adding"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:402 #: libi2pd_client/HTTPProxy.cpp:377
#, c-format #, c-format
msgid "" msgid ""
"Host %s is <font color=red>already in router's addressbook</font>. Click " "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>." "here to update record: <a href=\"%s%s%s&update=true\">Continue</a>."
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:404 #: libi2pd_client/HTTPProxy.cpp:379
msgid "Addresshelper update" msgid "Addresshelper update"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:417 #: libi2pd_client/HTTPProxy.cpp:392
msgid "Invalid request URI" msgid "Invalid request URI"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:460 #: libi2pd_client/HTTPProxy.cpp:435
msgid "Can't detect destination host from request" msgid "Can't detect destination host from request"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:477 libi2pd_client/HTTPProxy.cpp:481 #: libi2pd_client/HTTPProxy.cpp:452 libi2pd_client/HTTPProxy.cpp:456
msgid "Outproxy failure" msgid "Outproxy failure"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:477 #: libi2pd_client/HTTPProxy.cpp:452
msgid "Bad outproxy settings" msgid "Bad outproxy settings"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:480 #: libi2pd_client/HTTPProxy.cpp:455
#, c-format #, c-format
msgid "Host %s is not inside I2P network, but outproxy is not enabled" msgid "Host %s is not inside I2P network, but outproxy is not enabled"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:569 #: libi2pd_client/HTTPProxy.cpp:544
msgid "Unknown outproxy URL" msgid "Unknown outproxy URL"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:575 #: libi2pd_client/HTTPProxy.cpp:550
msgid "Cannot resolve upstream proxy" msgid "Cannot resolve upstream proxy"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:583 #: libi2pd_client/HTTPProxy.cpp:558
msgid "Hostname is too long" msgid "Hostname is too long"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:610 #: libi2pd_client/HTTPProxy.cpp:585
msgid "Cannot connect to upstream SOCKS proxy" msgid "Cannot connect to upstream SOCKS proxy"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:616 #: libi2pd_client/HTTPProxy.cpp:591
msgid "Cannot negotiate with SOCKS proxy" msgid "Cannot negotiate with SOCKS proxy"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:658 #: libi2pd_client/HTTPProxy.cpp:633
msgid "CONNECT error" msgid "CONNECT error"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:658 #: libi2pd_client/HTTPProxy.cpp:633
msgid "Failed to connect" msgid "Failed to connect"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:669 libi2pd_client/HTTPProxy.cpp:695 #: libi2pd_client/HTTPProxy.cpp:644 libi2pd_client/HTTPProxy.cpp:670
msgid "SOCKS proxy error" msgid "SOCKS proxy error"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:677 #: libi2pd_client/HTTPProxy.cpp:652
msgid "Failed to send request to upstream" msgid "Failed to send request to upstream"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:698 #: libi2pd_client/HTTPProxy.cpp:673
msgid "No reply from SOCKS proxy" msgid "No reply from SOCKS proxy"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:705 #: libi2pd_client/HTTPProxy.cpp:680
msgid "Cannot connect" msgid "Cannot connect"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:705 #: libi2pd_client/HTTPProxy.cpp:680
msgid "HTTP out proxy not implemented" msgid "HTTP out proxy not implemented"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:706 #: libi2pd_client/HTTPProxy.cpp:681
msgid "Cannot connect to upstream HTTP proxy" msgid "Cannot connect to upstream HTTP proxy"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:739 #: libi2pd_client/HTTPProxy.cpp:714
msgid "Host is down" msgid "Host is down"
msgstr "" msgstr ""
#: libi2pd_client/HTTPProxy.cpp:739 #: libi2pd_client/HTTPProxy.cpp:714
msgid "" msgid ""
"Can't create connection to requested host, it may be down. Please try again " "Can't create connection to requested host, it may be down. Please try again "
"later." "later."

@ -2,17 +2,12 @@
--- ---
``` ```
xgettext --omit-header -ctr: -ktr -kntr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp xgettext --omit-header -ctr: -ktr -ktr:1,2 daemon/HTTPServer.cpp libi2pd_client/HTTPProxy.cpp
``` ```
Regex for transforming gettext translations to our format: Regex for transforming gettext translations to our format:
--- ---
```
in: ^(\"|#[:.,]|msgctxt)(.*)$\n
out: <to empty line>
```
``` ```
in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)? in: msgid\ \"(.*)\"\nmsgid_plural\ \"(.*)\"\nmsgstr\[0\]\ \"(.*)\"\n(msgstr\[1\]\ \"(.*)\"\n)?(msgstr\[2\]\ \"(.*)\"\n)?(msgstr\[3\]\ \"(.*)\"\n)?(msgstr\[4\]\ \"(.*)\"\n)?(msgstr\[5\]\ \"(.*)\"\n)?
out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n out: #{"$2", {"$3", "$5", "$7", "$9", "$11"}},\n
@ -23,6 +18,10 @@ in: msgid\ \"(.*)\"\nmsgstr\ \"(.*)\"\n
out: {"$1", "$2"},\n out: {"$1", "$2"},\n
``` ```
```
in: ^#[:.,](.*)$\n
out: <to empty line>
```
``` ```
in: \n\n in: \n\n

@ -19,7 +19,7 @@
## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates ## Default: ~/.i2pd/certificates or /var/lib/i2pd/certificates
# certsdir = /var/lib/i2pd/certificates # certsdir = /var/lib/i2pd/certificates
## Where to write pidfile (default: /run/i2pd.pid, not used in Windows) ## Where to write pidfile (default: i2pd.pid, not used in Windows)
# pidfile = /run/i2pd.pid # pidfile = /run/i2pd.pid
## Logging configuration section ## Logging configuration section
@ -31,16 +31,15 @@
## * file - log entries to a file ## * file - log entries to a file
## * syslog - use syslog, see man 3 syslog ## * syslog - use syslog, see man 3 syslog
# 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, critical, none) ## Log messages above this level (debug, info, *warn, error, 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)
# logclftime = true # logclftime = true
## Daemon mode. Router will go to background after start. Ignored on Windows ## Daemon mode. Router will go to background after start. Ignored on Windows
## (default: true)
# daemon = true # daemon = true
## Specify a family, router belongs to (default - none) ## Specify a family, router belongs to (default - none)
@ -71,60 +70,58 @@
## don't just uncomment this ## don't just uncomment this
# port = 4567 # port = 4567
## Enable communication through ipv4 (default: true) ## Enable communication through ipv4
ipv4 = true ipv4 = true
## Enable communication through ipv6 (default: false) ## Enable communication through ipv6
ipv6 = false ipv6 = false
## Enable SSU transport
ssu = false
## Bandwidth configuration ## Bandwidth configuration
## L limit bandwidth to 32 KB/sec, O - to 256 KB/sec, P - to 2048 KB/sec, ## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
## X - unlimited ## X - unlimited
## Default is L (regular node) and X if floodfill mode enabled. ## Default is L (regular node) and X if floodfill mode enabled. If you want to
## If you want to share more bandwidth without floodfill mode, uncomment ## share more bandwidth without floodfill mode, uncomment that line and adjust
## that line and adjust value to your possibilities. Value can be set to ## value to your possibilities
## integer in kilobytes, it will apply that limit and flag will be used
## from next upper limit (example: if you set 4096 flag will be X, but real
## limit will be 4096 KB/s). Same can be done when floodfill mode is used,
## but keep in mind that low values may be negatively evaluated by Java
## router algorithms.
# bandwidth = L # bandwidth = L
## Max % of bandwidth limit for transit. 0-100 (default: 100) ## Max % of bandwidth limit for transit. 0-100. 100 by default
# share = 100 # share = 100
## Router will not accept transit tunnels, disabling transit traffic completely ## Router will not accept transit tunnels, disabling transit traffic completely
## (default: false) ## (default = false)
# notransit = true # notransit = true
## Router will be floodfill (default: false) ## Router will be floodfill
## Note: that mode uses much more network connections and CPU! ## Note: that mode uses much more network connections and CPU!
# floodfill = true # floodfill = true
[ntcp2] [ntcp2]
## Enable NTCP2 transport (default: true) ## Enable NTCP2 transport (default = true)
# enabled = true # enabled = true
## Publish address in RouterInfo (default: true) ## Publish address in RouterInfo (default = true)
# published = true # published = true
## Port for incoming connections (default is global port option value) ## Port for incoming connections (default is global port option value)
# port = 4567 # port = 4567
[ssu2] [ssu2]
## Enable SSU2 transport (default: true) ## Enable SSU2 transport
# enabled = true # enabled = true
## Publish address in RouterInfo (default: true) ## Publish address in RouterInfo
# published = true # published = true
## Port for incoming connections (default is global port option value) ## Port for incoming connections (default is global port option value or port + 1 if SSU is enabled)
# port = 4567 # port = 4567
[http] [http]
## Web Console settings ## Web Console settings
## Enable the Web Console (default: true) ## Uncomment and set to 'false' to disable Web Console
# enabled = true # enabled = true
## Address and port service will listen on (default: 127.0.0.1:7070) ## Address and port service will listen on
# address = 127.0.0.1 address = 127.0.0.1
# port = 7070 port = 7070
## Path to web console (default: /) ## Path to web console, default "/"
# webroot = / # webroot = /
## Enable Web Console authentication (default: false) ## Uncomment following lines to enable Web Console authentication
## You should not use Web Console via public networks without additional encryption. ## You should not use Web Console via public networks without additional encryption.
## HTTP authentication is not encryption layer! ## HTTP authentication is not encryption layer!
# auth = true # auth = true
@ -137,12 +134,12 @@ ipv6 = false
# lang = english # lang = english
[httpproxy] [httpproxy]
## Enable the HTTP proxy (default: true) ## Uncomment and set to 'false' to disable HTTP Proxy
# enabled = true # enabled = true
## Address and port service will listen on (default: 127.0.0.1:4444) ## Address and port service will listen on
# address = 127.0.0.1 address = 127.0.0.1
# port = 4444 port = 4444
## Optional keys file for proxy local destination (default: http-proxy-keys.dat) ## Optional keys file for proxy local destination
# keys = http-proxy-keys.dat # keys = http-proxy-keys.dat
## Enable address helper for adding .i2p domains with "jump URLs" (default: true) ## Enable address helper for adding .i2p domains with "jump URLs" (default: true)
## You should disable this feature if your i2pd HTTP Proxy is public, ## You should disable this feature if your i2pd HTTP Proxy is public,
@ -153,15 +150,15 @@ ipv6 = false
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. ## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
[socksproxy] [socksproxy]
## Enable the SOCKS proxy (default: true) ## Uncomment and set to 'false' to disable SOCKS Proxy
# enabled = true # enabled = true
## Address and port service will listen on (default: 127.0.0.1:4447) ## Address and port service will listen on
# address = 127.0.0.1 address = 127.0.0.1
# port = 4447 port = 4447
## Optional keys file for proxy local destination (default: socks-proxy-keys.dat) ## Optional keys file for proxy local destination
# keys = socks-proxy-keys.dat # keys = socks-proxy-keys.dat
## Socks outproxy. Example below is set to use Tor for all connections except i2p ## Socks outproxy. Example below is set to use Tor for all connections except i2p
## Enable using of SOCKS outproxy (works only with SOCKS4, default: false) ## Uncomment and set to 'true' to enable using of SOCKS outproxy
# outproxy.enabled = false # outproxy.enabled = false
## Address and port of outproxy ## Address and port of outproxy
# outproxy = 127.0.0.1 # outproxy = 127.0.0.1
@ -169,34 +166,34 @@ ipv6 = false
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc. ## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
[sam] [sam]
## Enable the SAM bridge (default: true) ## Comment or set to 'false' to disable SAM Bridge
# enabled = false enabled = true
## Address and ports service will listen on (default: 127.0.0.1:7656, udp: 7655) ## Address and ports service will listen on
# address = 127.0.0.1 # address = 127.0.0.1
# port = 7656 # port = 7656
# portudp = 7655 # portudp = 7655
[bob] [bob]
## Enable the BOB command channel (default: false) ## Uncomment and set to 'true' to enable BOB command channel
# enabled = false # enabled = false
## Address and port service will listen on (default: 127.0.0.1:2827) ## Address and port service will listen on
# address = 127.0.0.1 # address = 127.0.0.1
# port = 2827 # port = 2827
[i2cp] [i2cp]
## Enable the I2CP protocol (default: false) ## Uncomment and set to 'true' to enable I2CP protocol
# enabled = false # enabled = false
## Address and port service will listen on (default: 127.0.0.1:7654) ## Address and port service will listen on
# address = 127.0.0.1 # address = 127.0.0.1
# port = 7654 # port = 7654
[i2pcontrol] [i2pcontrol]
## Enable the I2PControl protocol (default: false) ## Uncomment and set to 'true' to enable I2PControl protocol
# enabled = false # enabled = false
## Address and port service will listen on (default: 127.0.0.1:7650) ## Address and port service will listen on
# address = 127.0.0.1 # address = 127.0.0.1
# port = 7650 # port = 7650
## Authentication password (default: itoopie) ## Authentication password. "itoopie" by default
# password = itoopie # password = itoopie
[precomputation] [precomputation]
@ -207,11 +204,11 @@ ipv6 = false
[upnp] [upnp]
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) ## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
# enabled = false # enabled = false
## Name i2pd appears in UPnP forwardings list (default: I2Pd) ## Name i2pd appears in UPnP forwardings list (default = I2Pd)
# name = I2Pd # name = I2Pd
[meshnets] [meshnets]
## Enable connectivity over the Yggdrasil network (default: false) ## Enable connectivity over the Yggdrasil network
# yggdrasil = false # yggdrasil = false
## You can bind address from your Yggdrasil subnet 300::/64 ## You can bind address from your Yggdrasil subnet 300::/64
## The address must first be added to the network interface ## The address must first be added to the network interface
@ -219,13 +216,13 @@ ipv6 = false
[reseed] [reseed]
## Options for bootstrapping into I2P network, aka reseeding ## Options for bootstrapping into I2P network, aka reseeding
## Enable reseed data verification (default: true) ## Enable or disable reseed data verification.
verify = true verify = true
## URLs to request reseed data from, separated by comma ## URLs to request reseed data from, separated by comma
## Default: "mainline" I2P Network reseeds ## Default: "mainline" I2P Network reseeds
# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ # urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/
## Reseed URLs through the Yggdrasil, separated by comma ## Reseed URLs through the Yggdrasil, separated by comma
# yggurls = http://[324:71e:281a:9ed3::ace]:7070/ # yggurls = http://[324:9de3:fea4:f6ac::ace]:7070/
## Path to local reseed data file (.su3) for manual reseeding ## Path to local reseed data file (.su3) for manual reseeding
# file = /path/to/i2pseeds.su3 # file = /path/to/i2pseeds.su3
## or HTTPS URL to reseed from ## or HTTPS URL to reseed from
@ -235,7 +232,7 @@ verify = true
## If you run i2pd behind a proxy server, set proxy server for reseeding here ## If you run i2pd behind a proxy server, set proxy server for reseeding here
## Should be http://address:port or socks://address:port ## Should be http://address:port or socks://address:port
# proxy = http://127.0.0.1:8118 # proxy = http://127.0.0.1:8118
## Minimum number of known routers, below which i2pd triggers reseeding (default: 25) ## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default
# threshold = 25 # threshold = 25
[addressbook] [addressbook]
@ -255,13 +252,13 @@ verify = true
# coresize = 0 # coresize = 0
[trust] [trust]
## Enable explicit trust options. (default: false) ## Enable explicit trust options. false by default
# enabled = true # enabled = true
## Make direct I2P connections only to routers in specified Family. ## Make direct I2P connections only to routers in specified Family.
# family = MyFamily # family = MyFamily
## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities. ## Make direct I2P connections only to routers specified here. Comma separated list of base64 identities.
# routers = # routers =
## Should we hide our router from other routers? (default: false) ## Should we hide our router from other routers? false by default
# hidden = true # hidden = true
[exploratory] [exploratory]
@ -280,6 +277,8 @@ verify = true
[cpuext] [cpuext]
## Use CPU AES-NI instructions set when work with cryptography when available (default: true) ## Use CPU AES-NI instructions set when work with cryptography when available (default: true)
# aesni = true # aesni = true
## Force usage of CPU instructions set, even if they not found (default: false) ## Use CPU AVX instructions set when work with cryptography when available (default: true)
# avx = true
## Force usage of CPU instructions set, even if they not found
## DO NOT TOUCH that option if you really don't know what are you doing! ## DO NOT TOUCH that option if you really don't know what are you doing!
# force = false # force = false

@ -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.52.0 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
@ -28,11 +28,9 @@ Requires: logrotate
Requires: systemd Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
%description %description
C++ implementation of I2P. C++ implementation of I2P.
%prep %prep
%setup -q -n i2pd-openssl %setup -q -n i2pd-openssl
@ -40,56 +38,72 @@ C++ implementation of I2P.
%build %build
cd build cd build
%if 0%{?rhel} == 7 %if 0%{?rhel} == 7
%cmake3 \ %cmake3 \
-DWITH_LIBRARY=OFF \ -DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \ -DWITH_UPNP=ON \
-DWITH_HARDENING=ON \ -DWITH_HARDENING=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
%else %else
%cmake \ %cmake \
-DWITH_LIBRARY=OFF \ -DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \ -DWITH_UPNP=ON \
-DWITH_HARDENING=ON \ -DWITH_HARDENING=ON \
%if 0%{?fedora} > 29 %if 0%{?fedora} > 29
-DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_SHARED_LIBS:BOOL=OFF \
. .
%else %else
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
%endif %endif
%endif
%if 0%{?rhel} == 9
pushd redhat-linux-build
%endif %endif
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} %if 0%{?fedora} >= 35
pushd redhat-linux-build pushd redhat-linux-build
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
%endif %endif
%endif
%if 0%{?mageia} > 7 %if 0%{?mageia} > 7
pushd build pushd build
%endif
%endif %endif
make %{?_smp_mflags} make %{?_smp_mflags}
%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 %if 0%{?rhel} == 9
popd popd
%endif %endif
%if 0%{?fedora} >= 33
popd
%endif
%if 0%{?mageia} > 7
popd
%endif
%install %install
pushd build pushd build
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} %if 0%{?rhel} == 9
pushd redhat-linux-build pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
pushd redhat-linux-build
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
%endif %endif
%endif
%if 0%{?mageia} %if 0%{?mageia}
pushd build pushd build
%endif
%endif %endif
chrpath -d i2pd chrpath -d i2pd
@ -144,27 +158,6 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Sun May 12 2024 orignal <orignal@i2pmail.org> - 2.52.0
- update to 2.52.0
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
- update to 2.51.0
* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
- update to 2.50.2
* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
- update to 2.50.1
* Mon Dec 18 2023 orignal <orignal@i2pmail.org> - 2.50.0
- update to 2.50.0
* Mon Sep 18 2023 orignal <orignal@i2pmail.org> - 2.49.0
- update to 2.49.0
* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
- update to 2.48.0
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0 * Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
- update to 2.47.0 - update to 2.47.0

@ -1,5 +1,5 @@
Name: i2pd Name: i2pd
Version: 2.52.0 Version: 2.47.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@ -26,11 +26,9 @@ Requires: logrotate
Requires: systemd Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
%description %description
C++ implementation of I2P. C++ implementation of I2P.
%prep %prep
%setup -q %setup -q
@ -38,56 +36,71 @@ C++ implementation of I2P.
%build %build
cd build cd build
%if 0%{?rhel} == 7 %if 0%{?rhel} == 7
%cmake3 \ %cmake3 \
-DWITH_LIBRARY=OFF \ -DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \ -DWITH_UPNP=ON \
-DWITH_HARDENING=ON \ -DWITH_HARDENING=ON \
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
%else %else
%cmake \ %cmake \
-DWITH_LIBRARY=OFF \ -DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \ -DWITH_UPNP=ON \
-DWITH_HARDENING=ON \ -DWITH_HARDENING=ON \
%if 0%{?fedora} > 29 %if 0%{?fedora} > 29
-DBUILD_SHARED_LIBS:BOOL=OFF \ -DBUILD_SHARED_LIBS:BOOL=OFF \
. .
%else %else
-DBUILD_SHARED_LIBS:BOOL=OFF -DBUILD_SHARED_LIBS:BOOL=OFF
%endif %endif
%endif
%if 0%{?rhel} == 9
pushd redhat-linux-build
%endif %endif
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} %if 0%{?fedora} >= 35
pushd redhat-linux-build pushd redhat-linux-build
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
%endif %endif
%endif
%if 0%{?mageia} > 7 %if 0%{?mageia} > 7
pushd build pushd build
%endif
%endif %endif
make %{?_smp_mflags} make %{?_smp_mflags}
%if 0%{?rhel} == 9 || 0%{?fedora} >= 33 || 0%{?mageia} > 7 %if 0%{?rhel} == 9
popd popd
%endif %endif
%if 0%{?fedora} >= 33
popd
%endif
%if 0%{?mageia} > 7
popd
%endif
%install %install
pushd build pushd build
%if 0%{?rhel} == 9 || 0%{?fedora} >= 35 || 0%{?eln} %if 0%{?rhel} == 9
pushd redhat-linux-build pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
pushd redhat-linux-build
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
%endif %endif
%endif
%if 0%{?mageia} %if 0%{?mageia}
pushd build pushd build
%endif
%endif %endif
chrpath -d i2pd chrpath -d i2pd
@ -142,27 +155,6 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Sun May 12 2024 orignal <orignal@i2pmail.org> - 2.52.0
- update to 2.52.0
* Sat Apr 06 2024 orignal <orignal@i2pmail.org> - 2.51.0
- update to 2.51.0
* Sat Jan 06 2024 orignal <orignal@i2pmail.org> - 2.50.2
- update to 2.50.2
* Sat Dec 23 2023 r4sas <r4sas@i2pmail.org> - 2.50.1
- update to 2.50.1
* Mon Dec 18 2023 orignal <orignal@i2pmail.org> - 2.50.0
- update to 2.50.0
* Mon Sep 18 2023 orignal <orignal@i2pmail.org> - 2.49.0
- update to 2.49.0
* Mon Jun 12 2023 orignal <orignal@i2pmail.org> - 2.48.0
- update to 2.48.0
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0 * Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
- update to 2.47.0 - update to 2.47.0

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -150,20 +150,17 @@ namespace util
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
bool avx; i2p::config::GetOption("cpuext.avx", avx);
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
bool ssu; i2p::config::GetOption("ssu", ssu); bool ssu; i2p::config::GetOption("ssu", ssu);
if (!ssu && i2p::config::IsDefault ("precomputation.elgamal")) if (!ssu && i2p::config::IsDefault ("precomputation.elgamal"))
precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly
i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt); i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces
int netID; i2p::config::GetOption("netid", netID); int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID); i2p::context.SetNetID (netID);
bool checkReserved; i2p::config::GetOption("reservedrange", checkReserved);
i2p::transport::transports.SetCheckReserved(checkReserved);
i2p::context.Init (); i2p::context.Init ();
i2p::transport::InitTransports (); i2p::transport::InitTransports ();
@ -179,7 +176,7 @@ namespace util
bool transit; i2p::config::GetOption("notransit", transit); bool transit; i2p::config::GetOption("notransit", transit);
i2p::context.SetAcceptsTunnels (!transit); i2p::context.SetAcceptsTunnels (!transit);
uint32_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
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels); i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels);
@ -188,7 +185,7 @@ namespace util
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth); std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
if (bandwidth.length () > 0) if (bandwidth.length () > 0)
{ {
if (bandwidth.length () == 1 && ((bandwidth[0] >= 'K' && bandwidth[0] <= 'P') || bandwidth[0] == 'X' )) if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
{ {
i2p::context.SetBandwidth (bandwidth[0]); i2p::context.SetBandwidth (bandwidth[0]);
LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps"); LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
@ -302,16 +299,18 @@ namespace util
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
LogPrint(eLogInfo, "Daemon: Starting Transports"); LogPrint(eLogInfo, "Daemon: Starting Transports");
if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled"); if(!ssu2) LogPrint(eLogInfo, "Daemon: SSU2 disabled");
if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled"); if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
i2p::transport::transports.SetCheckReserved(checkInReserved);
i2p::transport::transports.Start(ntcp2, ssu2); i2p::transport::transports.Start(ntcp2, ssu2);
if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2()) if (i2p::transport::transports.IsBoundSSU2() || i2p::transport::transports.IsBoundNTCP2())
LogPrint(eLogInfo, "Daemon: Transports started"); LogPrint(eLogInfo, "Daemon: Transports started");
else else
{ {
LogPrint(eLogCritical, "Daemon: Failed to start Transports"); LogPrint(eLogError, "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();
@ -330,7 +329,7 @@ namespace util
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogCritical, "Daemon: Failed to start Webconsole: ", ex.what ()); LogPrint (eLogError, "Daemon: Failed to start Webconsole: ", ex.what ());
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ()); ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
} }
} }
@ -357,7 +356,7 @@ namespace util
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogCritical, "Daemon: Failed to start I2PControl: ", ex.what ()); LogPrint (eLogError, "Daemon: Failed to start I2PControl: ", ex.what ());
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ()); ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -87,7 +87,6 @@ namespace http {
const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string"; const char HTTP_COMMAND_GET_REG_STRING[] = "get_reg_string";
const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage"; const char HTTP_COMMAND_SETLANGUAGE[] = "setlanguage";
const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css"; const char HTTP_COMMAND_RELOAD_CSS[] = "reload_css";
const char HTTP_COMMAND_EXPIRELEASE[] = "expirelease";
static std::string ConvertTime (uint64_t time) static std::string ConvertTime (uint64_t time)
{ {
@ -133,18 +132,22 @@ namespace http {
static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes) static void ShowTunnelDetails (std::stringstream& s, enum i2p::tunnel::TunnelState eState, bool explr, int bytes)
{ {
std::string state, stateText; std::string state, stateText;
switch (eState) switch (eState) {
{
case i2p::tunnel::eTunnelStateBuildReplyReceived : case i2p::tunnel::eTunnelStateBuildReplyReceived :
case i2p::tunnel::eTunnelStatePending : state = "building"; break; case i2p::tunnel::eTunnelStatePending : state = "building"; break;
case i2p::tunnel::eTunnelStateBuildFailed : state = "failed"; stateText = "declined"; break; case i2p::tunnel::eTunnelStateBuildFailed :
case i2p::tunnel::eTunnelStateTestFailed : state = "failed"; stateText = "test failed"; break; case i2p::tunnel::eTunnelStateTestFailed :
case i2p::tunnel::eTunnelStateFailed : state = "failed"; break; case i2p::tunnel::eTunnelStateFailed : state = "failed"; break;
case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break; case i2p::tunnel::eTunnelStateExpiring : state = "expiring"; break;
case i2p::tunnel::eTunnelStateEstablished : state = "established"; break; case i2p::tunnel::eTunnelStateEstablished : state = "established"; break;
default: state = "unknown"; break; default: state = "unknown"; break;
} }
if (stateText.empty ()) stateText = tr(state);
if (state == "building") stateText = tr("building");
else if (state == "failed") stateText = tr("failed");
else if (state == "expiring") stateText = tr("expiring");
else if (state == "established") stateText = tr("established");
else stateText = tr("unknown");
s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, "; s << "<span class=\"tunnel " << state << "\"> " << stateText << ((explr) ? " (" + tr("exploratory") + ")" : "") << "</span>, ";
ShowTraffic(s, bytes); ShowTraffic(s, bytes);
@ -153,7 +156,7 @@ namespace http {
static void SetLogLevel (const std::string& level) static void SetLogLevel (const std::string& level)
{ {
if (level == "none" || level == "critical" || level == "error" || level == "warn" || level == "info" || level == "debug") if (level == "none" || 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");
@ -218,19 +221,18 @@ namespace http {
s << "<b>" << tr("ERROR") << ":</b>&nbsp;" << string << "<br>\r\n"; s << "<b>" << tr("ERROR") << ":</b>&nbsp;" << string << "<br>\r\n";
} }
static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, bool testing, RouterError error) static void ShowNetworkStatus (std::stringstream& s, RouterStatus status, RouterError error)
{ {
switch (status) switch (status)
{ {
case eRouterStatusOK: s << tr("OK"); break; case eRouterStatusOK: s << tr("OK"); break;
case eRouterStatusTesting: s << tr("Testing"); break;
case eRouterStatusFirewalled: s << tr("Firewalled"); break; case eRouterStatusFirewalled: s << tr("Firewalled"); break;
case eRouterStatusUnknown: s << tr("Unknown"); break; case eRouterStatusUnknown: s << tr("Unknown"); break;
case eRouterStatusProxy: s << tr("Proxy"); break; case eRouterStatusProxy: s << tr("Proxy"); break;
case eRouterStatusMesh: s << tr("Mesh"); break; case eRouterStatusMesh: s << tr("Mesh"); break;
default: s << tr("Unknown"); default: s << tr("Unknown");
} }
if (testing)
s << " (" << tr("Testing") << ")";
if (error != eRouterErrorNone) if (error != eRouterErrorNone)
{ {
switch (error) switch (error)
@ -261,12 +263,12 @@ namespace http {
ShowUptime(s, i2p::context.GetUptime ()); ShowUptime(s, i2p::context.GetUptime ());
s << "<br>\r\n"; s << "<br>\r\n";
s << "<b>" << tr("Network status") << ":</b> "; s << "<b>" << tr("Network status") << ":</b> ";
ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetTesting(), i2p::context.GetError ()); ShowNetworkStatus (s, i2p::context.GetStatus (), i2p::context.GetError ());
s << "<br>\r\n"; s << "<br>\r\n";
if (i2p::context.SupportsV6 ()) if (i2p::context.SupportsV6 ())
{ {
s << "<b>" << tr("Network status v6") << ":</b> "; s << "<b>" << tr("Network status v6") << ":</b> ";
ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetTestingV6(), i2p::context.GetErrorV6 ()); ShowNetworkStatus (s, i2p::context.GetStatusV6 (), i2p::context.GetErrorV6 ());
s << "<br>\r\n"; s << "<br>\r\n";
} }
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
@ -419,12 +421,8 @@ namespace http {
static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token) static void ShowLeaseSetDestination (std::stringstream& s, std::shared_ptr<const i2p::client::LeaseSetDestination> dest, uint32_t token)
{ {
s << "<b>Base32:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"1\">";
s << dest->GetIdentHash ().ToBase32 () << "</textarea><br>\r\n<br>\r\n";
s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"8\">"; s << "<b>Base64:</b><br>\r\n<textarea readonly cols=\"80\" rows=\"8\">";
s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n"; s << dest->GetIdentity ()->ToBase64 () << "</textarea><br>\r\n<br>\r\n";
if (dest->IsEncryptedLeaseSet ()) if (dest->IsEncryptedLeaseSet ())
{ {
i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ()); i2p::data::BlindedPublicKey blinded (dest->GetIdentity (), dest->IsPerClientAuth ());
@ -436,11 +434,12 @@ namespace http {
if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ()) if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ())
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot); std::string webroot; i2p::config::GetOption("http.webroot", webroot);
auto base32 = dest->GetIdentHash ().ToBase32 ();
s << "<div class='slide'><label for='slide-regaddr'><b>" << tr("Address registration line") << "</b></label>\r\n<input type=\"checkbox\" id=\"slide-regaddr\" />\r\n<div class=\"slidecontent\">\r\n" s << "<div class='slide'><label for='slide-regaddr'><b>" << tr("Address registration line") << "</b></label>\r\n<input type=\"checkbox\" id=\"slide-regaddr\" />\r\n<div class=\"slidecontent\">\r\n"
"<form method=\"get\" action=\"" << webroot << "\">\r\n" "<form method=\"get\" action=\"" << webroot << "\">\r\n"
" <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_GET_REG_STRING << "\">\r\n" " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_GET_REG_STRING << "\">\r\n"
" <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n" " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n"
" <input type=\"hidden\" name=\"b32\" value=\"" << dest->GetIdentHash ().ToBase32 () << "\">\r\n" " <input type=\"hidden\" name=\"b32\" value=\"" << base32 << "\">\r\n"
" <b>" << tr("Domain") << ":</b>\r\n<input type=\"text\" maxlength=\"67\" name=\"name\" placeholder=\"domain.i2p\" required>\r\n" " <b>" << tr("Domain") << ":</b>\r\n<input type=\"text\" maxlength=\"67\" name=\"name\" placeholder=\"domain.i2p\" required>\r\n"
" <button type=\"submit\">" << tr("Generate") << "</button>\r\n" " <button type=\"submit\">" << tr("Generate") << "</button>\r\n"
"</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n"; "</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n";
@ -449,23 +448,9 @@ namespace http {
if (dest->GetNumRemoteLeaseSets()) if (dest->GetNumRemoteLeaseSets())
{ {
s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets () s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets ()
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n" << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>"<< tr("Address") << "</th><th>" << tr("Type") << "</th><th>" << tr("EncType") << "</th></thead><tbody class=\"tableitem\">";
<< "<table><thead>"
<< "<th>" << tr("Address") << "</th>"
<< "<th style=\"width:5px;\">&nbsp;</th>" // LeaseSet expiration button column
<< "<th>" << tr("Type") << "</th>"
<< "<th>" << tr("EncType") << "</th>"
<< "</thead><tbody class=\"tableitem\">";
for(auto& it: dest->GetLeaseSets ()) for(auto& it: dest->GetLeaseSets ())
{ s << "<tr><td>" << it.first.ToBase32 () << "</td><td>" << (int)it.second->GetStoreType () << "</td><td>" << (int)it.second->GetEncryptionType () <<"</td></tr>\r\n";
s << "<tr>"
<< "<td>" << it.first.ToBase32 () << "</td>"
<< "<td><a class=\"button\" href=\"/?cmd=" << HTTP_COMMAND_EXPIRELEASE<< "&b32=" << dest->GetIdentHash ().ToBase32 ()
<< "&lease=" << it.first.ToBase32 () << "&token=" << token << "\" title=\"" << tr("Expire LeaseSet") << "\"> &#10008; </a></td>"
<< "<td>" << (int)it.second->GetStoreType () << "</td>"
<< "<td>" << (int)it.second->GetEncryptionType () <<"</td>"
<< "</tr>\r\n";
}
s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n"; s << "</tbody></table>\r\n</div>\r\n</div>\r\n<br>\r\n";
} else } else
s << "<b>" << tr("LeaseSets") << ":</b> <i>0</i><br>\r\n<br>\r\n"; s << "<b>" << tr("LeaseSets") << ":</b> <i>0</i><br>\r\n<br>\r\n";
@ -606,8 +591,6 @@ namespace http {
} }
s << "</tbody>\r\n</table>"; s << "</tbody>\r\n</table>";
} }
else
ShowError(s, tr("Such destination is not found"));
} }
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id) void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id)
@ -765,14 +748,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 = i2p::tunnel::tunnels.GetMaxNumTransitTunnels ();
uint32_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";
@ -856,7 +838,6 @@ 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++;
} }
@ -975,42 +956,34 @@ namespace http {
void ShowI2PTunnels (std::stringstream& s) void ShowI2PTunnels (std::stringstream& s)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot); std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
auto& clientTunnels = i2p::client::context.GetClientTunnels (); for (auto& it: i2p::client::context.GetClientTunnels ())
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</div>\r\n"<< std::endl;
}
auto httpProxy = i2p::client::context.GetHttpProxy (); auto httpProxy = i2p::client::context.GetHttpProxy ();
if (httpProxy)
{
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "HTTP " << tr("Proxy") << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</div>\r\n"<< std::endl;
}
auto socksProxy = i2p::client::context.GetSocksProxy (); auto socksProxy = i2p::client::context.GetSocksProxy ();
if (!clientTunnels.empty () || httpProxy || socksProxy) if (socksProxy)
{ {
s << "<b>" << tr("Client Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
if (!clientTunnels.empty ()) s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
{ s << "SOCKS " << tr("Proxy") << "</a> &#8656; ";
for (auto& it: clientTunnels) s << i2p::client::context.GetAddressBook ().ToAddress(ident);
{ s << "</div>\r\n"<< std::endl;
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</div>\r\n"<< std::endl;
}
}
if (httpProxy)
{
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "HTTP " << tr("Proxy") << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</div>\r\n"<< std::endl;
}
if (socksProxy)
{
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
s << "<div class=\"listitem\"><a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "SOCKS " << tr("Proxy") << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "</div>\r\n"<< std::endl;
}
s << "</div>\r\n";
} }
s << "</div>\r\n";
auto& serverTunnels = i2p::client::context.GetServerTunnels (); auto& serverTunnels = i2p::client::context.GetServerTunnels ();
if (!serverTunnels.empty ()) { if (!serverTunnels.empty ()) {
@ -1337,36 +1310,6 @@ namespace http {
res.add_header("Refresh", redirect.c_str()); res.add_header("Refresh", redirect.c_str());
return; return;
} }
else if (cmd == HTTP_COMMAND_EXPIRELEASE)
{
std::string b32 = params["b32"];
std::string lease = params["lease"];
i2p::data::IdentHash ident, leaseident;
ident.FromBase32 (b32);
leaseident.FromBase32 (lease);
auto dest = i2p::client::context.FindLocalDestination (ident);
if (dest)
{
auto leaseset = dest->FindLeaseSet (leaseident);
if (leaseset)
{
leaseset->ExpireLease ();
s << "<b>" << tr("SUCCESS") << "</b>:&nbsp;" << tr("LeaseSet expiration time updated") << "<br>\r\n<br>\r\n";
}
else
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("LeaseSet is not found or already expired") << "<br>\r\n<br>\r\n";
}
else
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Destination not found") << "<br>\r\n<br>\r\n";
s << "<a href=\"" << webroot << "?page=local_destination&b32=" << b32 << "\">" << tr("Return to destination page") << "</a><br>\r\n";
s << "<p>" << tr("You will be redirected in %d seconds", COMMAND_REDIRECT_TIMEOUT) << "</b>";
redirect = std::to_string(COMMAND_REDIRECT_TIMEOUT) + "; url=" + webroot + "?page=local_destination&b32=" + b32;
res.add_header("Refresh", redirect.c_str());
return;
}
else if (cmd == HTTP_COMMAND_LIMITTRANSIT) else if (cmd == HTTP_COMMAND_LIMITTRANSIT)
{ {
uint32_t limit = std::stoul(params["limit"], nullptr); uint32_t limit = std::stoul(params["limit"], nullptr);

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -25,7 +25,7 @@ namespace http
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
const int COMMAND_REDIRECT_TIMEOUT = 5; // in seconds const int COMMAND_REDIRECT_TIMEOUT = 5; // in seconds
const int TRANSIT_TUNNELS_LIMIT = 1000000; const int TRANSIT_TUNNELS_LIMIT = 65535;
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection> class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{ {

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -338,11 +338,10 @@ namespace client
{ {
for (auto it = params.begin (); it != params.end (); it++) for (auto it = params.begin (); it != params.end (); it++)
{ {
if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
auto it1 = m_RouterManagerHandlers.find (it->first); auto it1 = m_RouterManagerHandlers.find (it->first);
if (it1 != m_RouterManagerHandlers.end ()) if (it1 != m_RouterManagerHandlers.end ()) {
{
if (it != params.begin ()) results << ",";
(this->*(it1->second))(results); (this->*(it1->second))(results);
} else } else
LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first); LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);

@ -1,15 +1,10 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifdef USE_UPNP #ifdef USE_UPNP
#include <string> #include <string>
#include <thread> #include <thread>
#include <boost/thread/thread.hpp>
#include <boost/asio.hpp>
#include "Log.h" #include "Log.h"
#include "RouterContext.h" #include "RouterContext.h"
@ -115,16 +110,10 @@ namespace transport
return; return;
} }
#if (MINIUPNPC_API_VERSION >= 18)
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr),
m_externalIPAddress, sizeof (m_externalIPAddress));
#else
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
#endif
m_upnpUrlsInitialized=err!=0; m_upnpUrlsInitialized=err!=0;
if (err == UPNP_IGD_VALID_CONNECTED) if (err == UPNP_IGD_VALID_CONNECTED)
{ {
#if (MINIUPNPC_API_VERSION < 18)
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(err != UPNPCOMMAND_SUCCESS) if(err != UPNPCOMMAND_SUCCESS)
{ {
@ -132,7 +121,6 @@ namespace transport
return; return;
} }
else else
#endif
{ {
LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL); LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL);
if (!m_externalIPAddress[0]) if (!m_externalIPAddress[0])
@ -178,11 +166,11 @@ namespace transport
if (address && !address->host.is_v6 () && address->port) if (address && !address->host.is_v6 () && address->port)
TryPortMapping (address); TryPortMapping (address);
} }
m_Timer.expires_from_now (boost::posix_time::minutes(UPNP_PORT_FORWARDING_INTERVAL)); // every 20 minutes m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
m_Timer.async_wait ([this](const boost::system::error_code& ecode) m_Timer.async_wait ([this](const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
PortMapping (); PortMapping ();
}); });
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -28,7 +28,6 @@ namespace i2p
namespace transport namespace transport
{ {
const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds const int UPNP_RESPONSE_TIMEOUT = 2000; // in milliseconds
const int UPNP_PORT_FORWARDING_INTERVAL = 20; // in minutes
enum enum
{ {

@ -162,27 +162,18 @@ namespace i2p
#ifndef ANDROID #ifndef ANDROID
if (lockf(pidFH, F_TLOCK, 0) != 0) if (lockf(pidFH, F_TLOCK, 0) != 0)
#else
struct flock fl;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
if (fcntl(pidFH, F_SETLK, &fl) != 0)
#endif
{ {
LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl; std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
return false; return false;
} }
#endif
char pid[10]; char pid[10];
sprintf(pid, "%d\n", getpid()); sprintf(pid, "%d\n", getpid());
ftruncate(pidFH, 0); ftruncate(pidFH, 0);
if (write(pidFH, pid, strlen(pid)) < 0) if (write(pidFH, pid, strlen(pid)) < 0)
{ {
LogPrint(eLogCritical, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl; std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
return false; return false;
} }

42
debian/changelog vendored

@ -1,45 +1,3 @@
i2pd (2.52.0-1) unstable; urgency=medium
* updated to version 2.52.0
-- orignal <orignal@i2pmail.org> Sun, 12 May 2024 16:00:00 +0000
i2pd (2.51.0-1) unstable; urgency=medium
* updated to version 2.51.0/0.9.62
-- orignal <orignal@i2pmail.org> Sat, 06 Apr 2024 16:00:00 +0000
i2pd (2.50.2-1) unstable; urgency=medium
* updated to version 2.50.2/0.9.61
-- orignal <orignal@i2pmail.org> Sat, 06 Jan 2024 16:00:00 +0000
i2pd (2.50.1-1) unstable; urgency=medium
* updated to version 2.50.1/0.9.61
-- r4sas <r4sas@i2pmail.org> Sat, 23 Dec 2023 18:30:00 +0000
i2pd (2.50.0-1) unstable; urgency=medium
* updated to version 2.50.0/0.9.61
-- orignal <orignal@i2pmail.org> Mon, 18 Dec 2023 16:00:00 +0000
i2pd (2.49.0-1) unstable; urgency=medium
* updated to version 2.49.0/0.9.60
-- orignal <orignal@i2pmail.org> Mon, 18 Sep 2023 16:00:00 +0000
i2pd (2.48.0-1) unstable; urgency=high
* updated to version 2.48.0/0.9.59
-- orignal <orignal@i2pmail.org> Mon, 12 Jun 2023 16:00:00 +0000
i2pd (2.47.0-1) unstable; urgency=high i2pd (2.47.0-1) unstable; urgency=high
* updated to version 2.47.0/0.9.58 * updated to version 2.47.0/0.9.58

2
debian/i2pd.1 vendored

@ -64,7 +64,7 @@ The network interface to bind to for IPv4 connections
The network interface to bind to for IPv6 connections The network interface to bind to for IPv6 connections
.TP .TP
\fB\-\-ipv4=\fR \fB\-\-ipv4=\fR
Enable communication through ipv4 (\fIenabled\fR by default) Enable communication through ipv6 (\fIenabled\fR by default)
.TP .TP
\fB\-\-ipv6\fR \fB\-\-ipv6\fR
Enable communication through ipv6 (\fIdisabled\fR by default) Enable communication through ipv6 (\fIdisabled\fR by default)

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2024, The PurpleI2P Project * Copyright (c) 2022-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
* *
@ -69,7 +69,6 @@ namespace chinese // language namespace
{"Stopping in", "距停止还有:"}, {"Stopping in", "距停止还有:"},
{"Family", "家族"}, {"Family", "家族"},
{"Tunnel creation success rate", "隧道创建成功率"}, {"Tunnel creation success rate", "隧道创建成功率"},
{"Total tunnel creation success rate", "当前隧道创建成功率"},
{"Received", "已接收"}, {"Received", "已接收"},
{"%.2f KiB/s", "%.2f KiB/s"}, {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "已发送"}, {"Sent", "已发送"},
@ -96,7 +95,6 @@ namespace chinese // language namespace
{"Address", "地址"}, {"Address", "地址"},
{"Type", "类型"}, {"Type", "类型"},
{"EncType", "加密类型"}, {"EncType", "加密类型"},
{"Expire LeaseSet", "到期租约集"},
{"Inbound tunnels", "入站隧道"}, {"Inbound tunnels", "入站隧道"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "出站隧道"}, {"Outbound tunnels", "出站隧道"},
@ -111,7 +109,6 @@ namespace chinese // language namespace
{"Local Destination", "本地目标"}, {"Local Destination", "本地目标"},
{"Streams", ""}, {"Streams", ""},
{"Close stream", "断开流"}, {"Close stream", "断开流"},
{"Such destination is not found", "找不到此目标"},
{"I2CP session not found", "未找到 I2CP 会话"}, {"I2CP session not found", "未找到 I2CP 会话"},
{"I2CP is not enabled", "I2CP 未启用"}, {"I2CP is not enabled", "I2CP 未启用"},
{"Invalid", "无效"}, {"Invalid", "无效"},
@ -153,8 +150,6 @@ namespace chinese // language namespace
{"StreamID can't be null", "StreamID 不能为空"}, {"StreamID can't be null", "StreamID 不能为空"},
{"Return to destination page", "返回目标页面"}, {"Return to destination page", "返回目标页面"},
{"You will be redirected in %d seconds", "您将在%d秒内被重定向"}, {"You will be redirected in %d seconds", "您将在%d秒内被重定向"},
{"LeaseSet expiration time updated", "租约集到期时间已更新"},
{"LeaseSet is not found or already expired", "租约集未找到或已过期"},
{"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"}, {"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"},
{"Back to commands list", "返回命令列表"}, {"Back to commands list", "返回命令列表"},
{"Register at reg.i2p", "在 reg.i2p 注册域名"}, {"Register at reg.i2p", "在 reg.i2p 注册域名"},
@ -163,6 +158,7 @@ namespace chinese // language namespace
{"Submit", "提交"}, {"Submit", "提交"},
{"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"}, {"Domain can't end with .b32.i2p", "域名不能以 .b32.i2p 结尾"},
{"Domain must end with .i2p", "域名必须以 .i2p 结尾"}, {"Domain must end with .i2p", "域名必须以 .i2p 结尾"},
{"Such destination is not found", "找不到此目标"},
{"Unknown command", "未知指令"}, {"Unknown command", "未知指令"},
{"Command accepted", "已接受指令"}, {"Command accepted", "已接受指令"},
{"Proxy error", "代理错误"}, {"Proxy error", "代理错误"},

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2024, The PurpleI2P Project * Copyright (c) 2022-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
* *
@ -36,18 +36,18 @@ namespace czech // language namespace
{"%.2f GiB", "%.2f GiB"}, {"%.2f GiB", "%.2f GiB"},
{"building", "vytváří se"}, {"building", "vytváří se"},
{"failed", "selhalo"}, {"failed", "selhalo"},
{"expiring", "vyprší platnost"}, {"expiring", "končící"},
{"established", "vytvořeno"}, {"established", "vytvořeno"},
{"unknown", "neznámý"}, {"unknown", "neznámý"},
{"exploratory", "průzkumné"}, {"exploratory", "průzkumné"},
{"Purple I2P Webconsole", "Purple I2P webová konzole"}, {"Purple I2P Webconsole", "Purple I2P Webkonsole"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webová konzole"}, {"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsole"},
{"Main page", "Hlavní stránka"}, {"Main page", "Hlavní stránka"},
{"Router commands", "Router příkazy"}, {"Router commands", "Router příkazy"},
{"Local Destinations", "Místní cíle"}, {"Local Destinations", "Lokální destinace"},
{"LeaseSets", "Sety pronájmu"}, {"LeaseSets", "LeaseSety"},
{"Tunnels", "Tunely"}, {"Tunnels", "Tunely"},
{"Transit Tunnels", "Tranzitní tunely"}, {"Transit Tunnels", "Transitní tunely"},
{"Transports", "Transporty"}, {"Transports", "Transporty"},
{"I2P tunnels", "I2P tunely"}, {"I2P tunnels", "I2P tunely"},
{"SAM sessions", "SAM relace"}, {"SAM sessions", "SAM relace"},
@ -61,21 +61,18 @@ namespace czech // language namespace
{"Clock skew", "Časová nesrovnalost"}, {"Clock skew", "Časová nesrovnalost"},
{"Offline", "Offline"}, {"Offline", "Offline"},
{"Symmetric NAT", "Symetrický NAT"}, {"Symmetric NAT", "Symetrický NAT"},
{"Full cone NAT", "Full cone NAT"},
{"No Descriptors", "Žádné popisovače"},
{"Uptime", "Doba provozu"}, {"Uptime", "Doba provozu"},
{"Network status", "Stav sítě"}, {"Network status", "Status sítě"},
{"Network status v6", "Stav sítě v6"}, {"Network status v6", "Status sítě v6"},
{"Stopping in", "Zastavuji za"}, {"Stopping in", "Zastavuji za"},
{"Family", "Rodina"}, {"Family", "Rodina"},
{"Tunnel creation success rate", "Úspěšnost vytváření tunelů"}, {"Tunnel creation success rate", "Úspěšnost vytváření tunelů"},
{"Total tunnel creation success rate", "Celková míra úspěšnosti vytváření tunelů"},
{"Received", "Přijato"}, {"Received", "Přijato"},
{"%.2f KiB/s", "%.2f KiB/s"}, {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Odesláno"}, {"Sent", "Odesláno"},
{"Transit", "Tranzit"}, {"Transit", "Tranzit"},
{"Data path", "Cesta k datovým souborům"}, {"Data path", "Cesta k data souborům"},
{"Hidden content. Press on text to see.", "Skrytý obsah. Pro zobrazení klikněte sem."}, {"Hidden content. Press on text to see.", "Skrytý kontent. Pro zobrazení, klikni na text."},
{"Router Ident", "Routerová Identita"}, {"Router Ident", "Routerová Identita"},
{"Router Family", "Rodina routerů"}, {"Router Family", "Rodina routerů"},
{"Router Caps", "Omezení Routerů"}, {"Router Caps", "Omezení Routerů"},
@ -96,7 +93,6 @@ namespace czech // language namespace
{"Address", "Adresa"}, {"Address", "Adresa"},
{"Type", "Typ"}, {"Type", "Typ"},
{"EncType", "EncType"}, {"EncType", "EncType"},
{"Expire LeaseSet", "Zrušit platnost setu pronájmu"},
{"Inbound tunnels", "Příchozí tunely"}, {"Inbound tunnels", "Příchozí tunely"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "Odchozí tunely"}, {"Outbound tunnels", "Odchozí tunely"},
@ -107,24 +103,21 @@ namespace czech // language namespace
{"Amount", "Množství"}, {"Amount", "Množství"},
{"Incoming Tags", "Příchozí štítky"}, {"Incoming Tags", "Příchozí štítky"},
{"Tags sessions", "Relace štítků"}, {"Tags sessions", "Relace štítků"},
{"Status", "Stav"}, {"Status", "Status"},
{"Local Destination", "Místní cíl"}, {"Local Destination", "Lokální Destinace"},
{"Streams", "Toky"}, {"Streams", "Toky"},
{"Close stream", "Uzavřít tok"}, {"Close stream", "Uzavřít tok"},
{"Such destination is not found", "Takováto destinace nebyla nalezena"},
{"I2CP session not found", "I2CP relace nenalezena"}, {"I2CP session not found", "I2CP relace nenalezena"},
{"I2CP is not enabled", "I2CP není zapnuto"}, {"I2CP is not enabled", "I2CP není zapnuto"},
{"Invalid", "Neplatný"}, {"Invalid", "Neplatný"},
{"Store type", "Druh uložení"}, {"Store type", "Druh uložení"},
{"Expires", "Vyprší"}, {"Expires", "Vyprší"},
{"Non Expired Leases", "Pronájmy, kterým nevypršela platnost"}, {"Non Expired Leases", "Nevypršené Leasy"},
{"Gateway", "Brána"}, {"Gateway", "Brána"},
{"TunnelID", "ID tunelu"}, {"TunnelID", "ID tunelu"},
{"EndDate", "Datum ukončení"}, {"EndDate", "Datum ukončení"},
{"floodfill mode is disabled", "režim floodfill je vypnut"},
{"Queue size", "Velikost fronty"}, {"Queue size", "Velikost fronty"},
{"Run peer test", "Spustit peer test"}, {"Run peer test", "Spustit peer test"},
{"Reload tunnels configuration", "Znovu načíst nastavení tunelů"},
{"Decline transit tunnels", "Odmítnout tranzitní tunely"}, {"Decline transit tunnels", "Odmítnout tranzitní tunely"},
{"Accept transit tunnels", "Přijmout tranzitní tunely"}, {"Accept transit tunnels", "Přijmout tranzitní tunely"},
{"Cancel graceful shutdown", "Zrušit hladké vypnutí"}, {"Cancel graceful shutdown", "Zrušit hladké vypnutí"},
@ -152,17 +145,14 @@ namespace czech // language namespace
{"Destination not found", "Destinace nenalezena"}, {"Destination not found", "Destinace nenalezena"},
{"StreamID can't be null", "StreamID nemůže být null"}, {"StreamID can't be null", "StreamID nemůže být null"},
{"Return to destination page", "Zpět na stránku destinací"}, {"Return to destination page", "Zpět na stránku destinací"},
{"You will be redirected in %d seconds", "Budete přesměrováni za %d sekund"}, {"Back to commands list", "Zpět na list příkazů"},
{"LeaseSet expiration time updated", "Aktualizován čas vypršení platnosti setu pronájmu"},
{"LeaseSet is not found or already expired", "Set pronájmu není k nalezení nebo již vypršela jeho platnost"},
{"Transit tunnels count must not exceed %d", "Počet tranzitních tunelů nesmí překročit %d"},
{"Back to commands list", "Zpět na seznam příkazů"},
{"Register at reg.i2p", "Zaregistrovat na reg.i2p"}, {"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
{"Description", "Popis"}, {"Description", "Popis"},
{"A bit information about service on domain", "Trochu informací o službě na doméně"}, {"A bit information about service on domain", "Trochu informací o službě na doméně"},
{"Submit", "Odeslat"}, {"Submit", "Odeslat"},
{"Domain can't end with .b32.i2p", "Doména nesmí končit na .b32.i2p"}, {"Domain can't end with .b32.i2p", "Doména nesmí končit na .b32.i2p"},
{"Domain must end with .i2p", "Doména musí končit s .i2p"}, {"Domain must end with .i2p", "Doména musí končit s .i2p"},
{"Such destination is not found", "Takováto destinace nebyla nalezena"},
{"Unknown command", "Neznámý příkaz"}, {"Unknown command", "Neznámý příkaz"},
{"Command accepted", "Příkaz přijat"}, {"Command accepted", "Příkaz přijat"},
{"Proxy error", "Chyba proxy serveru"}, {"Proxy error", "Chyba proxy serveru"},
@ -172,15 +162,6 @@ namespace czech // language namespace
{"You may try to find this host on jump services below", "Můžete se pokusit najít tohoto hostitele na startovacích službách níže"}, {"You may try to find this host on jump services below", "Můžete se pokusit najít tohoto hostitele na startovacích službách níže"},
{"Invalid request", "Neplatný požadavek"}, {"Invalid request", "Neplatný požadavek"},
{"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"}, {"Proxy unable to parse your request", "Proxy server nemohl zpracovat váš požadavek"},
{"Addresshelper is not supported", "Addresshelper není podporován"},
{"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>.", "Hostitel %s je <font color=red>již v adresáři routeru</font>. <b>Buďte opatrní: zdroj této URL může být škodlivý!</b> Klikněte zde pro aktualizaci záznamu: <a href=\"%s%s%s&update=true\">Pokračovat</a>."},
{"Addresshelper forced update rejected", "Addresshelperem vynucená aktualizace zamítnuta"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pro přidání hostitele <b>%s</b> do adresáře routeru, klikněte zde: <a href=\"%s%s%s\">Pokračovat</a>."},
{"Addresshelper request", "Požadavek Addresshelperu"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Hostitel %s přidán do adresáře routeru od pomocníka. Klikněte zde pro pokračování: <a href=\"%s\">Pokračovat</a>."},
{"Addresshelper adding", "Addresshelper přidávání"},
{"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>.", "Hostitel %s je <font color=red>již v adresáři routeru</font>. Klikněte zde pro aktualizaci záznamu: <a href=\"%s%s%s&update=true\">Pokračovat</a>."},
{"Addresshelper update", "Addresshelper aktualizace"},
{"Invalid request URI", "Neplatný URI požadavek"}, {"Invalid request URI", "Neplatný URI požadavek"},
{"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"}, {"Can't detect destination host from request", "Nelze zjistit cílového hostitele z požadavku"},
{"Outproxy failure", "Outproxy selhání"}, {"Outproxy failure", "Outproxy selhání"},

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2024, The PurpleI2P Project * Copyright (c) 2022-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
* *
@ -58,7 +58,7 @@ namespace french // language namespace
{"Unknown", "Inconnu"}, {"Unknown", "Inconnu"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Maillé"}, {"Mesh", "Maillé"},
{"Clock skew", "Décalage de l'horloge"}, {"Clock skew", "Horloge décalée"},
{"Offline", "Hors ligne"}, {"Offline", "Hors ligne"},
{"Symmetric NAT", "NAT symétrique"}, {"Symmetric NAT", "NAT symétrique"},
{"Full cone NAT", "NAT à cône complet"}, {"Full cone NAT", "NAT à cône complet"},
@ -68,8 +68,7 @@ namespace french // language namespace
{"Network status v6", "État du réseau v6"}, {"Network status v6", "État du réseau v6"},
{"Stopping in", "Arrêt dans"}, {"Stopping in", "Arrêt dans"},
{"Family", "Famille"}, {"Family", "Famille"},
{"Tunnel creation success rate", "Taux de création de tunnel réussie"}, {"Tunnel creation success rate", "Taux de succès de création de tunnels"},
{"Total tunnel creation success rate", "Taux total de création de tunnel réussie"},
{"Received", "Reçu"}, {"Received", "Reçu"},
{"%.2f KiB/s", "%.2f Kio/s"}, {"%.2f KiB/s", "%.2f Kio/s"},
{"Sent", "Envoyé"}, {"Sent", "Envoyé"},
@ -92,11 +91,10 @@ namespace french // language namespace
{"Address registration line", "Ligne d'inscription de l'adresse"}, {"Address registration line", "Ligne d'inscription de l'adresse"},
{"Domain", "Domaine"}, {"Domain", "Domaine"},
{"Generate", "Générer"}, {"Generate", "Générer"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note :</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."}, {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Note:</b> La chaîne résultante peut seulement être utilisée pour enregistrer les domaines 2LD (exemple.i2p). Pour enregistrer des sous-domaines, veuillez utiliser i2pd-tools."},
{"Address", "Adresse"}, {"Address", "Adresse"},
{"Type", "Type"}, {"Type", "Type"},
{"EncType", "EncType"}, {"EncType", "EncType"},
{"Expire LeaseSet", "Expirer le jeu de baux"},
{"Inbound tunnels", "Tunnels entrants"}, {"Inbound tunnels", "Tunnels entrants"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "Tunnels sortants"}, {"Outbound tunnels", "Tunnels sortants"},
@ -111,7 +109,6 @@ namespace french // language namespace
{"Local Destination", "Destination locale"}, {"Local Destination", "Destination locale"},
{"Streams", "Flux"}, {"Streams", "Flux"},
{"Close stream", "Fermer le flux"}, {"Close stream", "Fermer le flux"},
{"Such destination is not found", "Cette destination est introuvable"},
{"I2CP session not found", "Session I2CP introuvable"}, {"I2CP session not found", "Session I2CP introuvable"},
{"I2CP is not enabled", "I2CP est désactivé"}, {"I2CP is not enabled", "I2CP est désactivé"},
{"Invalid", "Invalide"}, {"Invalid", "Invalide"},
@ -131,7 +128,7 @@ namespace french // language namespace
{"Start graceful shutdown", "Démarrer l'arrêt gracieux"}, {"Start graceful shutdown", "Démarrer l'arrêt gracieux"},
{"Force shutdown", "Forcer l'arrêt"}, {"Force shutdown", "Forcer l'arrêt"},
{"Reload external CSS styles", "Rafraîchir les styles CSS externes"}, {"Reload external CSS styles", "Rafraîchir les styles CSS externes"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note :</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."}, {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Note:</b> Toute action effectuée ici n'est pas permanente et ne modifie pas vos fichiers de configuration."},
{"Logging level", "Niveau de journalisation"}, {"Logging level", "Niveau de journalisation"},
{"Transit tunnels limit", "Limite sur les tunnels transitoires"}, {"Transit tunnels limit", "Limite sur les tunnels transitoires"},
{"Change", "Changer"}, {"Change", "Changer"},
@ -153,8 +150,6 @@ namespace french // language namespace
{"StreamID can't be null", "StreamID ne peut pas être vide"}, {"StreamID can't be null", "StreamID ne peut pas être vide"},
{"Return to destination page", "Retourner à la page de destination"}, {"Return to destination page", "Retourner à la page de destination"},
{"You will be redirected in %d seconds", "Vous serez redirigé dans %d secondes"}, {"You will be redirected in %d seconds", "Vous serez redirigé dans %d secondes"},
{"LeaseSet expiration time updated", "Temps d'expiration du jeu de baux mis à jour"},
{"LeaseSet is not found or already expired", "Le jeu de baux est introuvable ou a déjà expiré"},
{"Transit tunnels count must not exceed %d", "Le nombre de tunnels de transit ne doit pas excéder %d"}, {"Transit tunnels count must not exceed %d", "Le nombre de tunnels de transit ne doit pas excéder %d"},
{"Back to commands list", "Retour à la liste des commandes"}, {"Back to commands list", "Retour à la liste des commandes"},
{"Register at reg.i2p", "Inscription à reg.i2p"}, {"Register at reg.i2p", "Inscription à reg.i2p"},
@ -163,23 +158,24 @@ namespace french // language namespace
{"Submit", "Soumettre"}, {"Submit", "Soumettre"},
{"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"}, {"Domain can't end with .b32.i2p", "Le domaine ne peut pas terminer par .b32.i2p"},
{"Domain must end with .i2p", "Le domaine doit terminer par .i2p"}, {"Domain must end with .i2p", "Le domaine doit terminer par .i2p"},
{"Such destination is not found", "Cette destination est introuvable"},
{"Unknown command", "Commande inconnue"}, {"Unknown command", "Commande inconnue"},
{"Command accepted", "Commande acceptée"}, {"Command accepted", "Commande acceptée"},
{"Proxy error", "Erreur de proxy"}, {"Proxy error", "Erreur de proxy"},
{"Proxy info", "Information sur le proxy"}, {"Proxy info", "Information sur le proxy"},
{"Proxy error: Host not found", "Erreur de proxy : Hôte introuvable"}, {"Proxy error: Host not found", "Erreur de proxy: Hôte introuvable"},
{"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"}, {"Remote host not found in router's addressbook", "Hôte distant introuvable dans le carnet d'adresse du routeur"},
{"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"}, {"You may try to find this host on jump services below", "Vous pouvez essayer de trouver cet hôte sur des services de redirection ci-dessous"},
{"Invalid request", "Requête invalide"}, {"Invalid request", "Requête invalide"},
{"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"}, {"Proxy unable to parse your request", "Proxy incapable de comprendre votre requête"},
{"Addresshelper is not supported", "Assistant d'adresse non supporté"}, {"Addresshelper is not supported", "Assistant d'adresse non supporté"},
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. <b>Attention : la source de cette URL peut être nuisible !</b> Cliquez ici pour mettre à jour l'enregistrement : <a href=\"%s%s%s&update=true\">Continuer</a>."}, {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. <b>Attention : la source de cette URL peut être nuisible !</b> Cliquez ici pour mettre à jour l'enregistrement : <a href=\"%s%s%s&update=true\">Continuer</a>."},
{"Addresshelper forced update rejected", "Mise à jour forcée des assistants d'adresses rejetée"}, {"Addresshelper forced update rejected", "Mise à jour forcée des assistants d'adresses rejetée"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pour ajouter l'hôte <b>%s</b> au carnet d'adresses du routeur, cliquez ici : <a href=\"%s%s%s\">Continuer</a>."}, {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Pour ajouter l'hôte <b>%s</b> au carnet d'adresses du routeur, cliquez ici : <a href=\"%s%s%s\">Continuer</a>."},
{"Addresshelper request", "Demande à l'assistant d'adresse"}, {"Addresshelper request", "Demande à l'assistant d'adresse"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'hôte %s a été ajouté au carnet d'adresses du routeur depuis l'assistant. Cliquez ici pour continuer : <a href=\"%s\">Continuer</a>."}, {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'hôte %s a été ajouté au carnet d'adresses du routeur depuis l'assistant. Cliquez ici pour continuer : <a href=\"%s\">Continuer</a>."},
{"Addresshelper adding", "Ajout de l'assistant d'adresse"}, {"Addresshelper adding", "Ajout de l'assistant d'adresse"},
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. Cliquez ici pour mettre à jour le dossier : <a href=\"%s%s%s&update=true\">Continuer</a>."}, {"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'hôte %s est <font color=red>déjà dans le carnet d'adresses du routeur</font>. Cliquez ici pour mettre à jour le dossier : <a href=\"%s%s%s&update=true\">Continuer</a>."},
{"Addresshelper update", "Mise à jour de l'assistant d'adresse"}, {"Addresshelper update", "Mise à jour de l'assistant d'adresse"},
{"Invalid request URI", "URI de la requête invalide"}, {"Invalid request URI", "URI de la requête invalide"},
{"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"}, {"Can't detect destination host from request", "Impossible de détecter l'hôte de destination à partir de la requête"},

@ -69,7 +69,6 @@ namespace italian // language namespace
{"Stopping in", "Arresto in"}, {"Stopping in", "Arresto in"},
{"Family", "Famiglia"}, {"Family", "Famiglia"},
{"Tunnel creation success rate", "Percentuale di tunnel creati con successo"}, {"Tunnel creation success rate", "Percentuale di tunnel creati con successo"},
{"Total tunnel creation success rate", "Percentuale di successo totale nella creazione del tunnel"},
{"Received", "Ricevuti"}, {"Received", "Ricevuti"},
{"%.2f KiB/s", "%.2f KiB/s"}, {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Inviati"}, {"Sent", "Inviati"},
@ -96,7 +95,6 @@ namespace italian // language namespace
{"Address", "Indirizzo"}, {"Address", "Indirizzo"},
{"Type", "Tipologia"}, {"Type", "Tipologia"},
{"EncType", "Tipo di crittografia"}, {"EncType", "Tipo di crittografia"},
{"Expire LeaseSet", "Scadenza LeaseSet"},
{"Inbound tunnels", "Tunnel in entrata"}, {"Inbound tunnels", "Tunnel in entrata"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "Tunnel in uscita"}, {"Outbound tunnels", "Tunnel in uscita"},
@ -111,7 +109,6 @@ namespace italian // language namespace
{"Local Destination", "Destinazione locale"}, {"Local Destination", "Destinazione locale"},
{"Streams", "Flussi"}, {"Streams", "Flussi"},
{"Close stream", "Interrompi il flusso"}, {"Close stream", "Interrompi il flusso"},
{"Such destination is not found", "Questa destinazione non è stata trovata"},
{"I2CP session not found", "Sessione I2CP non trovata"}, {"I2CP session not found", "Sessione I2CP non trovata"},
{"I2CP is not enabled", "I2CP non è abilitato"}, {"I2CP is not enabled", "I2CP non è abilitato"},
{"Invalid", "Invalido"}, {"Invalid", "Invalido"},
@ -153,8 +150,6 @@ namespace italian // language namespace
{"StreamID can't be null", "Lo StreamID non può essere null"}, {"StreamID can't be null", "Lo StreamID non può essere null"},
{"Return to destination page", "Ritorna alla pagina di destinazione"}, {"Return to destination page", "Ritorna alla pagina di destinazione"},
{"You will be redirected in %d seconds", "Sarai reindirizzato tra %d secondi"}, {"You will be redirected in %d seconds", "Sarai reindirizzato tra %d secondi"},
{"LeaseSet expiration time updated", "Tempo di scadenza LeaseSet aggiornato"},
{"LeaseSet is not found or already expired", "LeaseSet non trovato o già scaduto"},
{"Transit tunnels count must not exceed %d", "Il conteggio dei tunnel di transito non deve superare %d"}, {"Transit tunnels count must not exceed %d", "Il conteggio dei tunnel di transito non deve superare %d"},
{"Back to commands list", "Ritorna alla lista dei comandi"}, {"Back to commands list", "Ritorna alla lista dei comandi"},
{"Register at reg.i2p", "Registra a reg.i2p"}, {"Register at reg.i2p", "Registra a reg.i2p"},
@ -163,6 +158,7 @@ namespace italian // language namespace
{"Submit", "Invia"}, {"Submit", "Invia"},
{"Domain can't end with .b32.i2p", "I domini non possono terminare con .b32.i2p"}, {"Domain can't end with .b32.i2p", "I domini non possono terminare con .b32.i2p"},
{"Domain must end with .i2p", "I domini devono terminare con .i2p"}, {"Domain must end with .i2p", "I domini devono terminare con .i2p"},
{"Such destination is not found", "Questa destinazione non è stata trovata"},
{"Unknown command", "Comando sconosciuto"}, {"Unknown command", "Comando sconosciuto"},
{"Command accepted", "Comando accettato"}, {"Command accepted", "Comando accettato"},
{"Proxy error", "Errore del proxy"}, {"Proxy error", "Errore del proxy"},

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2023-2024, The PurpleI2P Project * Copyright (c) 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
* *
@ -31,186 +31,22 @@ namespace polish // language namespace
static std::map<std::string, std::string> strings static std::map<std::string, std::string> strings
{ {
{"%.2f KiB", "%.2f KiB"},
{"%.2f MiB", "%.2f MiB"},
{"%.2f GiB", "%.2f GiB"},
{"building", "Kompilowanie"}, {"building", "Kompilowanie"},
{"failed", "nieudane"}, {"failed", "nieudane"},
{"expiring", "wygasający"}, {"expiring", "wygasający"},
{"established", "ustanowiony"}, {"established", "ustanowiony"},
{"unknown", "nieznany"},
{"exploratory", "eksploracyjny"},
{"Purple I2P Webconsole", "Konsola webowa Purple I2P"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> konsola webowa"},
{"Main page", "Strona główna"}, {"Main page", "Strona główna"},
{"Router commands", "Komendy routera"}, {"Router commands", "Komendy routera"},
{"Local Destinations", "Lokalne miejsca docelowe"},
{"LeaseSets", "ZestawyNajmu"},
{"Tunnels", "Tunele"}, {"Tunnels", "Tunele"},
{"Transit Tunnels", "Tunele Tranzytu"},
{"Transports", "Transportery"},
{"I2P tunnels", "Tunele I2P"},
{"SAM sessions", "Sesje SAM"},
{"ERROR", "BŁĄD"},
{"OK", "Ok"}, {"OK", "Ok"},
{"Testing", "Testowanie"},
{"Firewalled", "Za zaporą sieciową"},
{"Unknown", "Nieznany"},
{"Proxy", "Proxy"},
{"Mesh", "Sieć"},
{"Clock skew", "Przesunięcie czasu"},
{"Offline", "Offline"},
{"Symmetric NAT", "Symetryczny NAT"},
{"Full cone NAT", "Pełny stożek NAT"},
{"No Descriptors", "Brak deskryptorów"},
{"Uptime", "Czas pracy"}, {"Uptime", "Czas pracy"},
{"Network status", "Stan sieci"},
{"Network status v6", "Stan sieci v6"},
{"Stopping in", "Zatrzymywanie za"},
{"Family", "Rodzina"},
{"Tunnel creation success rate", "Wskaźnik sukcesu tworzenia tunelu"},
{"Total tunnel creation success rate", "Całkowity wskaźnik sukcesu tworzenia tunelu"},
{"Received", "Odebrano"},
{"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Wysłane"}, {"Sent", "Wysłane"},
{"Transit", "Tranzyt"},
{"Data path", "Ścieżka do danych"},
{"Hidden content. Press on text to see.", "Ukryta zawartość. Naciśnij tekst, aby zobaczyć."},
{"Router Ident", "Identyfikator routera"},
{"Router Family", "Rodzina routera"},
{"Router Caps", "Możliwości routera"},
{"Version", "Wersja"},
{"Our external address", "Nasz zewnętrzny adres"},
{"supported", "wspierane"},
{"Routers", "Routery"},
{"Floodfills", "Floodfille"},
{"Client Tunnels", "Tunele Klienta"},
{"Services", "Usługi"},
{"Enabled", "Aktywny"},
{"Disabled", "Wyłączony"},
{"Encrypted B33 address", "Zaszyfrowany adres B33"},
{"Address registration line", "Linia rejestracji adresu"},
{"Domain", "Domena"},
{"Generate", "Generuj"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Uwaga:</b> wynik string może być używany tylko do rejestracji domen 2LD (przykład.i2p). Do rejestracji subdomen należy użyć narzędzi i2pd."},
{"Address", "Adres"},
{"Type", "Typ"},
{"EncType", "TypEnkrypcji"},
{"Expire LeaseSet", "Wygaśnij LeaseSet"},
{"Inbound tunnels", "Tunele przychodzące"},
{"%dms", "%dms"},
{"Outbound tunnels", "Tunele wychodzące"},
{"Tags", "Tagi"},
{"Incoming", "Przychodzące"},
{"Outgoing", "Wychodzące"},
{"Destination", "Miejsce docelowe"},
{"Amount", "Ilość"},
{"Incoming Tags", "Przychodzące tagi"},
{"Tags sessions", "Sesje tagów"},
{"Status", "Status"},
{"Local Destination", "Lokalne miejsce docelowe"},
{"Streams", "Strumienie"},
{"Close stream", "Zamknij strumień"},
{"Such destination is not found", "Nie znaleziono takiego miejsca docelowego"},
{"I2CP session not found", "Sesja I2CP nie została znaleziona"},
{"I2CP is not enabled", "I2CP nie jest włączone"},
{"Invalid", "Niepoprawny"},
{"Store type", "Rodzaj przechowywania"},
{"Expires", "Wygasa za"},
{"Non Expired Leases", "Leasingi niewygasłe"},
{"Gateway", "Brama"},
{"TunnelID", "IDTunelu"},
{"EndDate", "DataZakończenia"},
{"floodfill mode is disabled", "tryb floodfill jest wyłączony"},
{"Queue size", "Wielkość kolejki"},
{"Run peer test", "Wykonaj test peer"},
{"Reload tunnels configuration", "Załaduj ponownie konfigurację tuneli"},
{"Decline transit tunnels", "Odrzuć tunele tranzytowe"},
{"Accept transit tunnels", "Akceptuj tunele tranzytowe"},
{"Cancel graceful shutdown", "Anuluj łagodne wyłączenie"},
{"Start graceful shutdown", "Rozpocznij łagodne wyłączenie"},
{"Force shutdown", "Wymuś wyłączenie"},
{"Reload external CSS styles", "Odśwież zewnętrzne style CSS"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Uwaga:</b> każda akcja wykonana tutaj nie jest trwała i nie zmienia Twoich plików konfiguracyjnych."},
{"Logging level", "Poziom logowania"},
{"Transit tunnels limit", "Limit tuneli tranzytowych"},
{"Change", "Zmień"},
{"Change language", "Zmień język"},
{"no transit tunnels currently built", "brak obecnie zbudowanych tuneli tranzytowych"},
{"SAM disabled", "SAM wyłączony"},
{"no sessions currently running", "brak aktualnie uruchomionych sesji"},
{"SAM session not found", "Sesja SAM nie została znaleziona"},
{"SAM Session", "Sesja SAM"},
{"Server Tunnels", "Tunele Serwera"},
{"Client Forwards", "Przekierowania Klienta"},
{"Server Forwards", "Przekierowania Serwera"},
{"Unknown page", "Nieznana strona"},
{"Invalid token", "Nieprawidłowy token"},
{"SUCCESS", "SUKCES"},
{"Stream closed", "Strumień zamknięty"},
{"Stream not found or already was closed", "Strumień nie został znaleziony lub został już zamknięty"},
{"Destination not found", "Nie znaleziono punktu docelowego"},
{"StreamID can't be null", "StreamID nie może być null"},
{"Return to destination page", "Wróć do strony miejsca docelowego"},
{"You will be redirected in %d seconds", "Zostaniesz prekierowany za %d sekund"},
{"LeaseSet expiration time updated", "Zaktualizowano czas wygaśnięcia LeaseSet"},
{"LeaseSet is not found or already expired", "LeaseSet nie został znaleziony lub już wygasł"},
{"Transit tunnels count must not exceed %d", "Liczba tuneli tranzytowych nie może przekraczać %d"},
{"Back to commands list", "Powrót do listy poleceń"},
{"Register at reg.i2p", "Zarejestruj się na reg.i2p"},
{"Description", "Opis"},
{"A bit information about service on domain", "Trochę informacji o usłudze w domenie"},
{"Submit", "Zatwierdź"},
{"Domain can't end with .b32.i2p", "Domena nie może kończyć się na .b32.i2p"},
{"Domain must end with .i2p", "Domena musi kończyć się na .i2p"},
{"Unknown command", "Nieznana komenda"},
{"Command accepted", "Polecenie zaakceptowane"},
{"Proxy error", "Błąd serwera proxy"},
{"Proxy info", "Informacje o proxy"},
{"Proxy error: Host not found", "Błąd proxy: Nie znaleziono hosta"},
{"Remote host not found in router's addressbook", "Nie znaleziono zdalnego hosta w książce adresowej routera"},
{"You may try to find this host on jump services below", "Możesz znaleźć tego hosta na poniższych usługach skoku"},
{"Invalid request", "Nieprawidłowe żądanie"},
{"Proxy unable to parse your request", "Serwer proxy nie może przetworzyć Twojego żądania"},
{"Addresshelper is not supported", "Adresshelper nie jest obsługiwany"},
{"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 <font color=red>jest już w książce adresowej routera</font>. <b>Uważaj: źródło tego adresu URL może być szkodliwe!</b> Kliknij tutaj, aby zaktualizować rekord: <a href=\"%s%s%s&update=true\">Kontynuuj</a>."},
{"Addresshelper forced update rejected", "Wymuszona aktualizacja Addreshelper odrzucona"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Aby dodać host <b>%s</b> w książce adresowej routera, kliknij tutaj: <a href=\"%s%s%s\">Kontynuuj</a>."},
{"Addresshelper request", "Prośba Addresshelper"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s dodany do książki adresowej routera od pomocnika. Kliknij tutaj, aby kontynuować: <a href=\"%s\">Kontynuuj</a>."},
{"Addresshelper adding", "Dodawanie 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>.", "Host %s jest <font color=red>już w książce adresowej routera</font>. Kliknij tutaj, aby zaktualizować rekord: <a href=\"%s%s%s&update=true\">Kontynuuj</a>."},
{"Addresshelper update", "Aktualizacja Adresshelper"},
{"Invalid request URI", "Nieprawidłowe URI żądania"},
{"Can't detect destination host from request", "Nie można wykryć hosta docelowego z żądania"},
{"Outproxy failure", "Błąd proxy wyjściowego"},
{"Bad outproxy settings", "Błędne ustawienia proxy wyjściowych"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s nie jest wewnątrz sieci I2P, a proxy wyjściowe nie jest włączone"},
{"Unknown outproxy URL", "Nieznany adres URL proxy wyjściowego"},
{"Cannot resolve upstream proxy", "Nie można rozwiązać serwera proxy upstream"},
{"Hostname is too long", "Nazwa hosta jest zbyt długa"},
{"Cannot connect to upstream SOCKS proxy", "Nie można połączyć się z proxy SOCKS upstream"},
{"Cannot negotiate with SOCKS proxy", "Nie można negocjować z proxy SOCKS"},
{"CONNECT error", "Błąd POŁĄCZENIE"},
{"Failed to connect", "Nie udało się połączyć"},
{"SOCKS proxy error", "Błąd proxy SOCKS"},
{"Failed to send request to upstream", "Nie udało się wysłać żądania do upstream"},
{"No reply from SOCKS proxy", "Brak odpowiedzi od serwera proxy SOCKS"},
{"Cannot connect", "Nie można się połączyć"},
{"HTTP out proxy not implemented", "Serwer wyjściowy proxy HTTP nie został zaimplementowany"},
{"Cannot connect to upstream HTTP proxy", "Nie można połączyć się z proxy HTTP upstream"},
{"Host is down", "Host jest niedostępny"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Nie można utworzyć połączenia z żądanym hostem, może być wyłączony. Spróbuj ponownie później."},
{"", ""}, {"", ""},
}; };
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
{"%d days", {"%d dzień", "%d dni", "%d dni", "%d dni"}}, {"", {"", "", ""}},
{"%d hours", {"%d godzina", "%d godziny", "%d godzin", "%d godzin"}},
{"%d minutes", {"%d minuta", "%d minuty", "%d minut", "%d minut"}},
{"%d seconds", {"%d sekunda", "%d sekundy", "%d sekund", "%d sekund"}},
{"", {"", "", "", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale()

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2023-2024, The PurpleI2P Project * Copyright (c) 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
* *
@ -58,7 +58,7 @@ namespace portuguese // language namespace
{"Unknown", "Desconhecido"}, {"Unknown", "Desconhecido"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Malha"}, {"Mesh", "Malha"},
{"Clock skew", "Desvio de Relógio"}, {"Clock skew", "Defasagem do Relógio"},
{"Offline", "Desligado"}, {"Offline", "Desligado"},
{"Symmetric NAT", "NAT Simétrico"}, {"Symmetric NAT", "NAT Simétrico"},
{"Full cone NAT", "Full cone NAT"}, {"Full cone NAT", "Full cone NAT"},
@ -69,12 +69,11 @@ namespace portuguese // language namespace
{"Stopping in", "Parando em"}, {"Stopping in", "Parando em"},
{"Family", "Família"}, {"Family", "Família"},
{"Tunnel creation success rate", "Taxa de sucesso na criação de túneis"}, {"Tunnel creation success rate", "Taxa de sucesso na criação de túneis"},
{"Total tunnel creation success rate", "Taxa total de sucesso na criação de túneis"},
{"Received", "Recebido"}, {"Received", "Recebido"},
{"%.2f KiB/s", "%.2f KiB/s"}, {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Enviado"}, {"Sent", "Enviado"},
{"Transit", "Trânsito"}, {"Transit", "Trânsito"},
{"Data path", "Diretório de 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"},
@ -96,7 +95,6 @@ namespace portuguese // language namespace
{"Address", "Endereço"}, {"Address", "Endereço"},
{"Type", "Tipo"}, {"Type", "Tipo"},
{"EncType", "Tipo de Criptografia"}, {"EncType", "Tipo de Criptografia"},
{"Expire LeaseSet", "Expirar LeaseSet"},
{"Inbound tunnels", "Túneis de Entrada"}, {"Inbound tunnels", "Túneis de Entrada"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "Túneis de Saída"}, {"Outbound tunnels", "Túneis de Saída"},
@ -106,12 +104,11 @@ namespace portuguese // language namespace
{"Destination", "Destinos"}, {"Destination", "Destinos"},
{"Amount", "Quantidade"}, {"Amount", "Quantidade"},
{"Incoming Tags", "Etiquetas de Entrada"}, {"Incoming Tags", "Etiquetas de Entrada"},
{"Tags sessions", "Sessões de Etiquetas"}, {"Tags sessions", "Sessões de etiquetas"},
{"Status", "Estado"}, {"Status", "Estado"},
{"Local Destination", "Destino Local"}, {"Local Destination", "Destinos Locais"},
{"Streams", "Fluxos"}, {"Streams", "Fluxos"},
{"Close stream", "Fechar fluxo"}, {"Close stream", "Fechar fluxo"},
{"Such destination is not found", "Tal destino não foi encontrado"},
{"I2CP session not found", "Sessão do I2CP não encontrada"}, {"I2CP session not found", "Sessão do I2CP não encontrada"},
{"I2CP is not enabled", "I2CP não está ativado"}, {"I2CP is not enabled", "I2CP não está ativado"},
{"Invalid", "Inválido"}, {"Invalid", "Inválido"},
@ -148,43 +145,42 @@ namespace portuguese // language namespace
{"Invalid token", "Token Inválido"}, {"Invalid token", "Token Inválido"},
{"SUCCESS", "SUCESSO"}, {"SUCCESS", "SUCESSO"},
{"Stream closed", "Fluxo fechado"}, {"Stream closed", "Fluxo fechado"},
{"Stream not found or already was closed", "Fluxo não encontrado ou já fechado"}, {"Stream not found or already was closed", "Fluxo não encontrado ou já encerrado"},
{"Destination not found", "Destino não encontrado"}, {"Destination not found", "Destino não encontrado"},
{"StreamID can't be null", "StreamID não pode ser nulo"}, {"StreamID can't be null", "StreamID não pode ser nulo"},
{"Return to destination page", "Retornar para à página de destino"}, {"Return to destination page", "Retornar para à página de destino"},
{"You will be redirected in %d seconds", "Você será redirecionado em %d segundos"}, {"You will be redirected in %d seconds", "Você será redirecionado em %d segundos"},
{"LeaseSet expiration time updated", "Tempo de validade do LeaseSet atualizado"},
{"LeaseSet is not found or already expired", "LeaseSet não foi encontrado ou já expirou"},
{"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"}, {"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
{"Back to commands list", "Voltar para a lista de comandos"}, {"Back to commands list", "Voltar para a lista de comandos"},
{"Register at reg.i2p", "Registrar em reg.i2p"}, {"Register at reg.i2p", "Registrar na reg.i2p"},
{"Description", "Descrição"}, {"Description", "Descrição"},
{"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"}, {"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
{"Submit", "Enviar"}, {"Submit", "Enviar"},
{"Domain can't end with .b32.i2p", "O domínio não pode terminar com .b32.i2p"}, {"Domain can't end with .b32.i2p", "O domínio não pode terminar com .b32.i2p"},
{"Domain must end with .i2p", "O domínio não pode terminar com .i2p"}, {"Domain must end with .i2p", "O domínio não pode terminar com .i2p"},
{"Such destination is not found", "Tal destino não foi encontrado"},
{"Unknown command", "Comando desconhecido"}, {"Unknown command", "Comando desconhecido"},
{"Command accepted", "Comando aceito"}, {"Command accepted", "Comando aceito"},
{"Proxy error", "Erro no proxy"}, {"Proxy error", "Erro no proxy"},
{"Proxy info", "Informações do proxy"}, {"Proxy info", "Informações do proxy"},
{"Proxy error: Host not found", "Erro no proxy: Host não encontrado"}, {"Proxy error: Host not found", "Erro no proxy: Host não encontrado"},
{"Remote host not found in router's addressbook", "O host remoto não foi encontrado no livro de endereços do roteador"}, {"Remote host not found in router's addressbook", "O host remoto não foi encontrado no livro de endereços do roteador"},
{"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos serviços de jump abaixo"}, {"You may try to find this host on jump services below", "Você pode tentar encontrar este host nos jump services abaixo"},
{"Invalid request", "Requisição inválida"}, {"Invalid request", "Requisição inválida"},
{"Proxy unable to parse your request", "O proxy foi incapaz de processar a sua requisição"}, {"Proxy unable to parse your request", "O proxy foi incapaz de processar a sua requisição"},
{"Addresshelper is not supported", "O Auxiliar de Endereços não é suportado"}, {"Addresshelper is not supported", "O Auxiliar de Endereços não é suportado"},
{"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>.", "O host %s já <font color=red>está no catálogo de endereços do roteador</font>. <b>Cuidado: a fonte desta URL pode ser perigosa!</b> Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."}, {"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "O host %s já <font color=red>está no catálogo de endereços do roteador</font>. <b>Cuidado: a fonte desta URL pode ser perigosa!</b> Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
{"Addresshelper forced update rejected", "A atualização forçada do Auxiliar de Endereços foi rejeitada"}, {"Addresshelper forced update rejected", "A atualização forçada do Auxiliar de Endereços foi rejeitada"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Para adicionar o host <b> %s </b> ao catálogo de endereços do roteador, clique aqui: <a href='%s%s%s'>Continuar </a>."}, {"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Para adicionar o host <b> %s </b> ao catálogo de endereços do roteador, clique aqui: <a href='%s%s%s'>Continuar </a>."},
{"Addresshelper request", "Requisição ao Auxiliar de Endereços"}, {"Addresshelper request", "Requisição do Auxiliar de Endereços"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para prosseguir: <a href='%s'> Continuar </a>."}, {"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "O host %s foi adicionado ao catálogo de endereços do roteador por um auxiliar. Clique aqui para proceder: <a href='%s'> Continuar </a>."},
{"Addresshelper adding", "Auxiliar de Endereço adicionando"}, {"Addresshelper adding", "Auxiliar de Endereço adicionando"},
{"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>.", "O host %s já <font color=red>está no catálogo de endereços do roteador </font>. Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</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>.", "O host %s já <font color=red>está no catálogo de endereços do roteador </font>. Clique aqui para atualizar o registro: <a href=\"%s%s%s&update=true\">Continuar</a>."},
{"Addresshelper update", "Atualização do Auxiliar de Endereços"}, {"Addresshelper update", "Atualização do Auxiliar de Endereços"},
{"Invalid request URI", "A URI de requisição é inválida"}, {"Invalid request URI", "A URI de requisição é inválida"},
{"Can't detect destination host from request", "Incapaz de detectar o host de destino da requisição"}, {"Can't detect destination host from request", "Incapaz de detectar o host de destino da requisição"},
{"Outproxy failure", "Falha no outproxy"}, {"Outproxy failure", "Falha no outproxy"},
{"Bad outproxy settings", "Má configurações do outproxy"}, {"Bad outproxy settings", "Configurações ruins de outproxy"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "O host %s não está dentro da rede I2P, mas o outproxy não está ativado"}, {"Host %s is not inside I2P network, but outproxy is not enabled", "O host %s não está dentro da rede I2P, mas o outproxy não está ativado"},
{"Unknown outproxy URL", "URL de outproxy desconhecida"}, {"Unknown outproxy URL", "URL de outproxy desconhecida"},
{"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"}, {"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},

@ -69,7 +69,6 @@ namespace russian // language namespace
{"Stopping in", "Остановка через"}, {"Stopping in", "Остановка через"},
{"Family", "Семейство"}, {"Family", "Семейство"},
{"Tunnel creation success rate", "Успешно построенных туннелей"}, {"Tunnel creation success rate", "Успешно построенных туннелей"},
{"Total tunnel creation success rate", "Общий процент успешно построенных туннелей"},
{"Received", "Получено"}, {"Received", "Получено"},
{"%.2f KiB/s", "%.2f КиБ/с"}, {"%.2f KiB/s", "%.2f КиБ/с"},
{"Sent", "Отправлено"}, {"Sent", "Отправлено"},
@ -96,7 +95,6 @@ namespace russian // language namespace
{"Address", "Адрес"}, {"Address", "Адрес"},
{"Type", "Тип"}, {"Type", "Тип"},
{"EncType", "ТипШифр"}, {"EncType", "ТипШифр"},
{"Expire LeaseSet", "Просрочить Лизсет"},
{"Inbound tunnels", "Входящие туннели"}, {"Inbound tunnels", "Входящие туннели"},
{"%dms", "%dмс"}, {"%dms", "%dмс"},
{"Outbound tunnels", "Исходящие туннели"}, {"Outbound tunnels", "Исходящие туннели"},
@ -111,7 +109,6 @@ namespace russian // language namespace
{"Local Destination", "Локальное назначение"}, {"Local Destination", "Локальное назначение"},
{"Streams", "Стримы"}, {"Streams", "Стримы"},
{"Close stream", "Закрыть стрим"}, {"Close stream", "Закрыть стрим"},
{"Such destination is not found", "Такая точка назначения не найдена"},
{"I2CP session not found", "I2CP сессия не найдена"}, {"I2CP session not found", "I2CP сессия не найдена"},
{"I2CP is not enabled", "I2CP не включен"}, {"I2CP is not enabled", "I2CP не включен"},
{"Invalid", "Некорректный"}, {"Invalid", "Некорректный"},
@ -153,8 +150,6 @@ namespace russian // language namespace
{"StreamID can't be null", "StreamID не может быть пустым"}, {"StreamID can't be null", "StreamID не может быть пустым"},
{"Return to destination page", "Вернуться на страницу точки назначения"}, {"Return to destination page", "Вернуться на страницу точки назначения"},
{"You will be redirected in %d seconds", "Вы будете переадресованы через %d секунд"}, {"You will be redirected in %d seconds", "Вы будете переадресованы через %d секунд"},
{"LeaseSet expiration time updated", "Время действия LeaseSet обновлено"},
{"LeaseSet is not found or already expired", "Лизсет не найден или время действия уже истекло"},
{"Transit tunnels count must not exceed %d", "Число транзитных туннелей не должно превышать %d"}, {"Transit tunnels count must not exceed %d", "Число транзитных туннелей не должно превышать %d"},
{"Back to commands list", "Вернуться к списку команд"}, {"Back to commands list", "Вернуться к списку команд"},
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"}, {"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
@ -163,6 +158,7 @@ namespace russian // language namespace
{"Submit", "Отправить"}, {"Submit", "Отправить"},
{"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"}, {"Domain can't end with .b32.i2p", "Домен не может заканчиваться на .b32.i2p"},
{"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"}, {"Domain must end with .i2p", "Домен должен заканчиваться на .i2p"},
{"Such destination is not found", "Такая точка назначения не найдена"},
{"Unknown command", "Неизвестная команда"}, {"Unknown command", "Неизвестная команда"},
{"Command accepted", "Команда принята"}, {"Command accepted", "Команда принята"},
{"Proxy error", "Ошибка прокси"}, {"Proxy error", "Ошибка прокси"},

@ -61,8 +61,6 @@ namespace swedish // language namespace
{"Clock skew", "Tidsförskjutning"}, {"Clock skew", "Tidsförskjutning"},
{"Offline", "Nedkopplad"}, {"Offline", "Nedkopplad"},
{"Symmetric NAT", "Symmetrisk NAT"}, {"Symmetric NAT", "Symmetrisk NAT"},
{"Full cone NAT", "Full kon NAT"},
{"No Descriptors", "Inga Beskrivningar"},
{"Uptime", "Upptid"}, {"Uptime", "Upptid"},
{"Network status", "Nätverkstillstånd"}, {"Network status", "Nätverkstillstånd"},
{"Network status v6", "Nätverkstillstånd v6"}, {"Network status v6", "Nätverkstillstånd v6"},
@ -109,7 +107,6 @@ namespace swedish // language namespace
{"Local Destination", "Lokal Plats"}, {"Local Destination", "Lokal Plats"},
{"Streams", "Strömmar"}, {"Streams", "Strömmar"},
{"Close stream", "Stäng strömmen"}, {"Close stream", "Stäng strömmen"},
{"Such destination is not found", "En sådan plats hittas ej"},
{"I2CP session not found", "I2CP-period hittades inte"}, {"I2CP session not found", "I2CP-period hittades inte"},
{"I2CP is not enabled", "I2CP är inte påslaget"}, {"I2CP is not enabled", "I2CP är inte påslaget"},
{"Invalid", "Ogiltig"}, {"Invalid", "Ogiltig"},
@ -119,10 +116,8 @@ namespace swedish // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "EndDate"}, {"EndDate", "EndDate"},
{"floodfill mode is disabled", "Floodfill läget är inaktiverat"},
{"Queue size", "Köstorlek"}, {"Queue size", "Köstorlek"},
{"Run peer test", "Utför utsiktstest"}, {"Run peer test", "Utför utsiktstest"},
{"Reload tunnels configuration", "Ladda om tunnelkonfiguration"},
{"Decline transit tunnels", "Avvisa förmedlande tunnlar"}, {"Decline transit tunnels", "Avvisa förmedlande tunnlar"},
{"Accept transit tunnels", "Tillåt förmedlande tunnlar"}, {"Accept transit tunnels", "Tillåt förmedlande tunnlar"},
{"Cancel graceful shutdown", "Avbryt välvillig avstängning"}, {"Cancel graceful shutdown", "Avbryt välvillig avstängning"},
@ -159,6 +154,7 @@ namespace swedish // language namespace
{"Submit", "Skicka"}, {"Submit", "Skicka"},
{"Domain can't end with .b32.i2p", "Domänen får inte sluta med .b32.i2p"}, {"Domain can't end with .b32.i2p", "Domänen får inte sluta med .b32.i2p"},
{"Domain must end with .i2p", "Domänen måste sluta med .i2p"}, {"Domain must end with .i2p", "Domänen måste sluta med .i2p"},
{"Such destination is not found", "En sådan plats hittas ej"},
{"Unknown command", "Okänt kommando"}, {"Unknown command", "Okänt kommando"},
{"Command accepted", "Kommando accepterades"}, {"Command accepted", "Kommando accepterades"},
{"Proxy error", "Proxyfel"}, {"Proxy error", "Proxyfel"},
@ -169,14 +165,6 @@ namespace swedish // language namespace
{"Invalid request", "Ogiltig förfrågan"}, {"Invalid request", "Ogiltig förfrågan"},
{"Proxy unable to parse your request", "Proxyt kan inte behandla din förfrågan"}, {"Proxy unable to parse your request", "Proxyt kan inte behandla din förfrågan"},
{"Addresshelper is not supported", "Adresshjälparen stöds ej"}, {"Addresshelper is not supported", "Adresshjälparen stöds ej"},
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. <b>Var försiktig: källan till denna URL kan vara skadlig!</b> Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
{"Addresshelper forced update rejected", "Tvingad uppdatering av adresshjälparen nekad"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "För att lägga till värd <b>%s</b> i routerns adressbok, klicka här: <a href=\"%s%s%s\">Fortsätt</a>."},
{"Addresshelper request", "Adresshjälpare förfrågan"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Värd %s tillagd i routerns adressbok från hjälparen. Klicka här för att fortsätta: <a href=\"%s\">Fortsätt</a>."},
{"Addresshelper adding", "Adresshjälpare tilläggning"},
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Värd %s är <font color=red>redan i routerns adressbok</font>. Klicka här för att uppdatera registreringen: <a href=\"%s%s%s&update=true\">Fortsätt</a>."},
{"Addresshelper update", "Adresshjälpare uppdatering"},
{"Invalid request URI", "Ogiltig förfrågnings-URI"}, {"Invalid request URI", "Ogiltig förfrågnings-URI"},
{"Can't detect destination host from request", "Kan inte upptäcka platsvärden från förfrågan"}, {"Can't detect destination host from request", "Kan inte upptäcka platsvärden från förfrågan"},
{"Outproxy failure", "Utproxyfel"}, {"Outproxy failure", "Utproxyfel"},

@ -69,7 +69,6 @@ namespace ukrainian // language namespace
{"Stopping in", "Зупинка через"}, {"Stopping in", "Зупинка через"},
{"Family", "Сімейство"}, {"Family", "Сімейство"},
{"Tunnel creation success rate", "Успішно побудованих тунелів"}, {"Tunnel creation success rate", "Успішно побудованих тунелів"},
{"Total tunnel creation success rate", "Загальна кількість створених тунелів"},
{"Received", "Отримано"}, {"Received", "Отримано"},
{"%.2f KiB/s", "%.2f КіБ/с"}, {"%.2f KiB/s", "%.2f КіБ/с"},
{"Sent", "Відправлено"}, {"Sent", "Відправлено"},
@ -96,7 +95,6 @@ namespace ukrainian // language namespace
{"Address", "Адреса"}, {"Address", "Адреса"},
{"Type", "Тип"}, {"Type", "Тип"},
{"EncType", "ТипШифр"}, {"EncType", "ТипШифр"},
{"Expire LeaseSet", "Завершити LeaseSet"},
{"Inbound tunnels", "Вхідні тунелі"}, {"Inbound tunnels", "Вхідні тунелі"},
{"%dms", "%dмс"}, {"%dms", "%dмс"},
{"Outbound tunnels", "Вихідні тунелі"}, {"Outbound tunnels", "Вихідні тунелі"},
@ -111,7 +109,6 @@ namespace ukrainian // language namespace
{"Local Destination", "Локальні Призначення"}, {"Local Destination", "Локальні Призначення"},
{"Streams", "Потоки"}, {"Streams", "Потоки"},
{"Close stream", "Закрити потік"}, {"Close stream", "Закрити потік"},
{"Such destination is not found", "Така точка призначення не знайдена"},
{"I2CP session not found", "I2CP сесія не знайдена"}, {"I2CP session not found", "I2CP сесія не знайдена"},
{"I2CP is not enabled", "I2CP не увікнуто"}, {"I2CP is not enabled", "I2CP не увікнуто"},
{"Invalid", "Некоректний"}, {"Invalid", "Некоректний"},
@ -153,8 +150,6 @@ namespace ukrainian // language namespace
{"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"}, {"StreamID can't be null", "Ідентифікатор потоку не може бути порожнім"},
{"Return to destination page", "Повернутися на сторінку точки призначення"}, {"Return to destination page", "Повернутися на сторінку точки призначення"},
{"You will be redirected in %d seconds", "Ви будете переадресовані через %d секунд"}, {"You will be redirected in %d seconds", "Ви будете переадресовані через %d секунд"},
{"LeaseSet expiration time updated", "Час закінчення LeaseSet оновлено"},
{"LeaseSet is not found or already expired", "LeaseSet не знайдено або вже закінчився"},
{"Transit tunnels count must not exceed %d", "Кількість транзитних тунелів не повинна перевищувати %d"}, {"Transit tunnels count must not exceed %d", "Кількість транзитних тунелів не повинна перевищувати %d"},
{"Back to commands list", "Повернутися до списку команд"}, {"Back to commands list", "Повернутися до списку команд"},
{"Register at reg.i2p", "Зареєструвати на reg.i2p"}, {"Register at reg.i2p", "Зареєструвати на reg.i2p"},
@ -163,6 +158,7 @@ namespace ukrainian // language namespace
{"Submit", "Надіслати"}, {"Submit", "Надіслати"},
{"Domain can't end with .b32.i2p", "Домен не може закінчуватися на .b32.i2p"}, {"Domain can't end with .b32.i2p", "Домен не може закінчуватися на .b32.i2p"},
{"Domain must end with .i2p", "Домен повинен закінчуватися на .i2p"}, {"Domain must end with .i2p", "Домен повинен закінчуватися на .i2p"},
{"Such destination is not found", "Така точка призначення не знайдена"},
{"Unknown command", "Невідома команда"}, {"Unknown command", "Невідома команда"},
{"Command accepted", "Команда прийнята"}, {"Command accepted", "Команда прийнята"},
{"Proxy error", "Помилка проксі"}, {"Proxy error", "Помилка проксі"},

@ -69,7 +69,6 @@ namespace uzbek // language namespace
{"Stopping in", "Ichida to'xtatish"}, {"Stopping in", "Ichida to'xtatish"},
{"Family", "Oila"}, {"Family", "Oila"},
{"Tunnel creation success rate", "Tunnel yaratish muvaffaqiyat darajasi"}, {"Tunnel creation success rate", "Tunnel yaratish muvaffaqiyat darajasi"},
{"Total tunnel creation success rate", "Tunnel yaratishning umumiy muvaffaqiyat darajasi"},
{"Received", "Qabul qilindi"}, {"Received", "Qabul qilindi"},
{"%.2f KiB/s", "%.2f KiB/s"}, {"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Yuborilgan"}, {"Sent", "Yuborilgan"},
@ -96,7 +95,6 @@ namespace uzbek // language namespace
{"Address", "Manzil"}, {"Address", "Manzil"},
{"Type", "Turi"}, {"Type", "Turi"},
{"EncType", "ShifrlashTuri"}, {"EncType", "ShifrlashTuri"},
{"Expire LeaseSet", "LeaseSet muddati tugaydi"},
{"Inbound tunnels", "Kirish tunnellari"}, {"Inbound tunnels", "Kirish tunnellari"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "Chiquvchi tunnellar"}, {"Outbound tunnels", "Chiquvchi tunnellar"},
@ -111,7 +109,6 @@ namespace uzbek // language namespace
{"Local Destination", "Mahalliy joylanish"}, {"Local Destination", "Mahalliy joylanish"},
{"Streams", "Strim"}, {"Streams", "Strim"},
{"Close stream", "Strimni o'chirish"}, {"Close stream", "Strimni o'chirish"},
{"Such destination is not found", "Bunday yo'nalish topilmadi"},
{"I2CP session not found", "I2CP sessiyasi topilmadi"}, {"I2CP session not found", "I2CP sessiyasi topilmadi"},
{"I2CP is not enabled", "I2CP yoqilmagan"}, {"I2CP is not enabled", "I2CP yoqilmagan"},
{"Invalid", "Noto'g'ri"}, {"Invalid", "Noto'g'ri"},
@ -153,8 +150,6 @@ namespace uzbek // language namespace
{"StreamID can't be null", "StreamID bo'sh bo'lishi mumkin emas"}, {"StreamID can't be null", "StreamID bo'sh bo'lishi mumkin emas"},
{"Return to destination page", "Manzilgoh sahifasiga qaytish"}, {"Return to destination page", "Manzilgoh sahifasiga qaytish"},
{"You will be redirected in %d seconds", "Siz %d soniyadan song boshqa yonalishga yonaltirilasiz"}, {"You will be redirected in %d seconds", "Siz %d soniyadan song boshqa yonalishga yonaltirilasiz"},
{"LeaseSet expiration time updated", "LeaseSet amal qilish muddati yangilandi"},
{"LeaseSet is not found or already expired", "LeaseSet topilmadi yoki muddati tugagan"},
{"Transit tunnels count must not exceed %d", "Tranzit tunnellar soni %d dan oshmasligi kerak"}, {"Transit tunnels count must not exceed %d", "Tranzit tunnellar soni %d dan oshmasligi kerak"},
{"Back to commands list", "Buyruqlar ro'yxatiga qaytish"}, {"Back to commands list", "Buyruqlar ro'yxatiga qaytish"},
{"Register at reg.i2p", "Reg.i2p-da ro'yxatdan o'ting"}, {"Register at reg.i2p", "Reg.i2p-da ro'yxatdan o'ting"},
@ -163,6 +158,7 @@ namespace uzbek // language namespace
{"Submit", "Yuborish"}, {"Submit", "Yuborish"},
{"Domain can't end with .b32.i2p", "Domen .b32.i2p bilan tugashi mumkin emas"}, {"Domain can't end with .b32.i2p", "Domen .b32.i2p bilan tugashi mumkin emas"},
{"Domain must end with .i2p", "Domen .i2p bilan tugashi kerak"}, {"Domain must end with .i2p", "Domen .i2p bilan tugashi kerak"},
{"Such destination is not found", "Bunday yo'nalish topilmadi"},
{"Unknown command", "Noma'lum buyruq"}, {"Unknown command", "Noma'lum buyruq"},
{"Command accepted", "Buyruq qabul qilindi"}, {"Command accepted", "Buyruq qabul qilindi"},
{"Proxy error", "Proksi xatosi"}, {"Proxy error", "Proksi xatosi"},

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -28,11 +28,6 @@ namespace data
return T32; return T32;
} }
bool IsBase32 (char ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7');
}
static void iT64Build(void); static void iT64Build(void);
/* /*
@ -60,11 +55,6 @@ namespace data
return T64; return T64;
} }
bool IsBase64 (char ch)
{
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '-' || ch == '~';
}
/* /*
* Reverse Substitution Table (built in run time) * Reverse Substitution Table (built in run time)
*/ */
@ -197,9 +187,6 @@ namespace data
else else
return 0; return 0;
if(*InBuffer == P64)
return 0;
ps = (unsigned char *)(InBuffer + InCount - 1); ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 ) while ( *ps-- == P64 )
outCount--; outCount--;
@ -282,7 +269,7 @@ namespace data
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen) size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
{ {
unsigned int tmp = 0, bits = 0; int tmp = 0, bits = 0;
size_t ret = 0; size_t ret = 0;
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
{ {
@ -311,7 +298,7 @@ namespace data
size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen) size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen)
{ {
size_t ret = 0, pos = 1; size_t ret = 0, pos = 1;
unsigned int bits = 8, tmp = inBuf[0]; int bits = 8, tmp = inBuf[0];
while (ret < outLen && (bits > 0 || pos < len)) while (ret < outLen && (bits > 0 || pos < len))
{ {
if (bits < 5) if (bits < 5)

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -19,11 +19,9 @@ namespace data {
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable (); const char * GetBase32SubstitutionTable ();
const char * GetBase64SubstitutionTable (); const char * GetBase64SubstitutionTable ();
bool IsBase64 (char ch);
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
bool IsBase32 (char ch);
/** /**
* Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes * Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -7,62 +7,52 @@
*/ */
#include "CPU.h" #include "CPU.h"
#if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h>
#endif
#include "Log.h" #include "Log.h"
#ifndef bit_AES #ifndef bit_AES
#define bit_AES (1 << 25) #define bit_AES (1 << 25)
#endif #endif
#ifndef bit_AVX
#if defined(__GNUC__) && __GNUC__ < 6 && IS_X86 #define bit_AVX (1 << 28)
#include <cpuid.h>
#endif #endif
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace i2p namespace i2p
{ {
namespace cpu namespace cpu
{ {
bool aesni = false; bool aesni = false;
bool avx = false;
inline bool cpu_support_aes() void Detect(bool AesSwitch, bool AvxSwitch, bool force)
{ {
#if IS_X86 #if defined(__x86_64__) || defined(__i386__)
#if defined(__clang__) int info[4];
# if (__clang_major__ >= 6) __cpuid(0, info[0], info[1], info[2], info[3]);
__builtin_cpu_init(); if (info[0] >= 0x00000001) {
# endif __cpuid(0x00000001, info[0], info[1], info[2], info[3]);
return __builtin_cpu_supports("aes"); #if defined (_WIN32) && (WINVER == 0x0501) // WinXP
#elif (defined(__GNUC__) && __GNUC__ >= 6) if (AesSwitch && force) { // only if forced
__builtin_cpu_init(); #else
return __builtin_cpu_supports("aes"); if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) {
#elif (defined(__GNUC__) && __GNUC__ < 6)
int cpu_info[4];
bool flag = false;
__cpuid(0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
if (cpu_info[0] >= 0x00000001) {
__cpuid(0x00000001, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
flag = ((cpu_info[2] & bit_AES) != 0);
}
return flag;
#elif defined(_MSC_VER)
int cpu_info[4];
__cpuid(cpu_info, 1);
return ((cpu_info[2] & bit_AES) != 0);
#endif #endif
aesni = true;
}
#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
if (AvxSwitch && force) { // only if forced
#else
if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) {
#endif #endif
return false; avx = true;
} }
void Detect(bool AesSwitch, bool force)
{
if ((cpu_support_aes() && AesSwitch) || (AesSwitch && force)) {
aesni = true;
} }
#endif // defined(__x86_64__) || defined(__i386__)
LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled")); LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled"));
LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled"));
} }
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -9,31 +9,14 @@
#ifndef LIBI2PD_CPU_H #ifndef LIBI2PD_CPU_H
#define LIBI2PD_CPU_H #define LIBI2PD_CPU_H
#if defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IX86) || defined(__i386__)
# define IS_X86 1
# if defined(_M_AMD64) || defined(__x86_64__)
# define IS_X86_64 1
# else
# define IS_X86_64 0
# endif
#else
# define IS_X86 0
# define IS_X86_64 0
#endif
#if defined(__AES__) && !defined(_MSC_VER) && IS_X86
# define SUPPORTS_AES 1
#else
# define SUPPORTS_AES 0
#endif
namespace i2p namespace i2p
{ {
namespace cpu namespace cpu
{ {
extern bool aesni; extern bool aesni;
extern bool avx;
void Detect(bool AesSwitch, bool force); void Detect(bool AesSwitch, bool AvxSwitch, bool force);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -77,8 +77,7 @@ namespace config {
limits.add_options() limits.add_options()
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint32_t>()->default_value(10000), "Maximum active transit tunnels (default:10000)") ("limits.transittunnels", value<uint16_t>()->default_value(5000), "Maximum active transit tunnels (default:5000)")
("limits.zombies", value<double>()->default_value(0), "Minimum percentage of successfully created tunnels under which tunnel cleanup is paused (default [%]: 0.00)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored") ("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored") ("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored") ("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
@ -193,7 +192,7 @@ namespace config {
options_description precomputation("Precomputation options"); options_description precomputation("Precomputation options");
precomputation.add_options() precomputation.add_options()
("precomputation.elgamal", ("precomputation.elgamal",
#if (defined(_M_AMD64) || defined(__x86_64__)) #if defined(__x86_64__)
value<bool>()->default_value(false), value<bool>()->default_value(false),
#else #else
value<bool>()->default_value(true), value<bool>()->default_value(true),
@ -205,7 +204,7 @@ namespace config {
reseed.add_options() reseed.add_options()
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature") ("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed") ("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed")
("reseed.floodfill", value<std::string>()->default_value(""), "Ignored. Always empty") ("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from")
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from") ("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from")
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from") ("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks") ("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
@ -221,8 +220,7 @@ namespace config {
"https://reseed-pl.i2pd.xyz/," "https://reseed-pl.i2pd.xyz/,"
"https://www2.mk16.de/," "https://www2.mk16.de/,"
"https://i2p.ghativega.in/," "https://i2p.ghativega.in/,"
"https://i2p.novg.net/," "https://i2p.novg.net/"
"https://reseed.stormycloud.org/"
), "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/,"
@ -309,7 +307,7 @@ namespace config {
options_description cpuext("CPU encryption extensions options"); options_description cpuext("CPU encryption extensions options");
cpuext.add_options() cpuext.add_options()
("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used") ("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used")
("cpuext.avx", bool_switch()->default_value(false), "Deprecated option") ("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used")
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") ("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines")
; ;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -28,7 +28,6 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Log.h" #include "Log.h"
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -160,7 +159,7 @@ namespace crypto
// DH/ElGamal // DH/ElGamal
#if !IS_X86_64 #if !defined(__x86_64__)
const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226; const int ELGAMAL_SHORT_EXPONENT_NUM_BITS = 226;
const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1; const int ELGAMAL_SHORT_EXPONENT_NUM_BYTES = ELGAMAL_SHORT_EXPONENT_NUM_BITS/8+1;
#endif #endif
@ -362,7 +361,7 @@ namespace crypto
BIGNUM * b1 = BN_CTX_get (ctx); BIGNUM * b1 = BN_CTX_get (ctx);
BIGNUM * b = BN_CTX_get (ctx); BIGNUM * b = BN_CTX_get (ctx);
// select random k // select random k
#if IS_X86_64 #if defined(__x86_64__)
BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64 BN_rand (k, ELGAMAL_FULL_EXPONENT_NUM_BITS, -1, 1); // full exponent for x64
#else #else
BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits BN_rand (k, ELGAMAL_SHORT_EXPONENT_NUM_BITS, -1, 1); // short exponent of 226 bits
@ -429,7 +428,7 @@ namespace crypto
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub) void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub)
{ {
#if IS_X86 || defined(_MSC_VER) #if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
RAND_bytes (priv, 256); RAND_bytes (priv, 256);
#else #else
// lower 226 bits (28 bytes and 2 bits) only. short exponent // lower 226 bits (28 bytes and 2 bits) only. short exponent
@ -556,7 +555,7 @@ namespace crypto
} }
// AES // AES
#if SUPPORTS_AES #ifdef __AES__
#define KeyExpansion256(round0,round1) \ #define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \ "pshufd $0xff, %%xmm2, %%xmm2 \n" \
"movaps %%xmm1, %%xmm4 \n" \ "movaps %%xmm1, %%xmm4 \n" \
@ -581,7 +580,7 @@ namespace crypto
"movaps %%xmm3, "#round1"(%[sched]) \n" "movaps %%xmm3, "#round1"(%[sched]) \n"
#endif #endif
#if SUPPORTS_AES #ifdef __AES__
void ECBCryptoAESNI::ExpandKey (const AESKey& key) void ECBCryptoAESNI::ExpandKey (const AESKey& key)
{ {
__asm__ __asm__
@ -622,7 +621,7 @@ namespace crypto
#endif #endif
#if SUPPORTS_AES #ifdef __AES__
#define EncryptAES256(sched) \ #define EncryptAES256(sched) \
"pxor (%["#sched"]), %%xmm0 \n" \ "pxor (%["#sched"]), %%xmm0 \n" \
"aesenc 16(%["#sched"]), %%xmm0 \n" \ "aesenc 16(%["#sched"]), %%xmm0 \n" \
@ -643,18 +642,16 @@ namespace crypto
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out) void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
: : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
: [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) );
: "%xmm0", "memory"
);
} }
else else
#endif #endif
@ -663,7 +660,7 @@ namespace crypto
} }
} }
#if SUPPORTS_AES #ifdef __AES__
#define DecryptAES256(sched) \ #define DecryptAES256(sched) \
"pxor 224(%["#sched"]), %%xmm0 \n" \ "pxor 224(%["#sched"]), %%xmm0 \n" \
"aesdec 208(%["#sched"]), %%xmm0 \n" \ "aesdec 208(%["#sched"]), %%xmm0 \n" \
@ -684,18 +681,16 @@ namespace crypto
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out) void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
DecryptAES256(sched) DecryptAES256(sched)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
: : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
: [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) );
: "%xmm0", "memory"
);
} }
else else
#endif #endif
@ -704,7 +699,7 @@ namespace crypto
} }
} }
#if SUPPORTS_AES #ifdef __AES__
#define CallAESIMC(offset) \ #define CallAESIMC(offset) \
"movaps "#offset"(%[shed]), %%xmm0 \n" \ "movaps "#offset"(%[shed]), %%xmm0 \n" \
"aesimc %%xmm0, %%xmm0 \n" \ "aesimc %%xmm0, %%xmm0 \n" \
@ -713,7 +708,7 @@ namespace crypto
void ECBEncryption::SetKey (const AESKey& key) void ECBEncryption::SetKey (const AESKey& key)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
ExpandKey (key); ExpandKey (key);
@ -727,30 +722,28 @@ namespace crypto
void ECBDecryption::SetKey (const AESKey& key) void ECBDecryption::SetKey (const AESKey& key)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
ExpandKey (key); // expand encryption key first ExpandKey (key); // expand encryption key first
// then invert it using aesimc // then invert it using aesimc
__asm__ __asm__
( (
CallAESIMC(16) CallAESIMC(16)
CallAESIMC(32) CallAESIMC(32)
CallAESIMC(48) CallAESIMC(48)
CallAESIMC(64) CallAESIMC(64)
CallAESIMC(80) CallAESIMC(80)
CallAESIMC(96) CallAESIMC(96)
CallAESIMC(112) CallAESIMC(112)
CallAESIMC(128) CallAESIMC(128)
CallAESIMC(144) CallAESIMC(144)
CallAESIMC(160) CallAESIMC(160)
CallAESIMC(176) CallAESIMC(176)
CallAESIMC(192) CallAESIMC(192)
CallAESIMC(208) CallAESIMC(208)
: : : [shed]"r"(GetKeySchedule ()) : "%xmm0", "memory"
: [shed]"r"(GetKeySchedule ()) );
: "%xmm0", "memory"
);
} }
else else
#endif #endif
@ -761,28 +754,28 @@ namespace crypto
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"1: \n" "1: \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
"movups %%xmm1, (%[iv]) \n" "movups %%xmm1, (%[iv]) \n"
: :
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "cc", "memory" : "%xmm0", "%xmm1", "cc", "memory"
); );
} }
else else
#endif #endif
@ -806,22 +799,22 @@ namespace crypto
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched) EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"movups %%xmm0, (%[iv]) \n" "movups %%xmm0, (%[iv]) \n"
: :
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out) [in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
} }
else else
#endif #endif
@ -830,29 +823,29 @@ namespace crypto
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"1: \n" "1: \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched) DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n" "movaps %%xmm2, %%xmm1 \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
"movups %%xmm1, (%[iv]) \n" "movups %%xmm1, (%[iv]) \n"
: :
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory" : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
); );
} }
else else
#endif #endif
@ -876,22 +869,22 @@ namespace crypto
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
"movups (%[iv]), %%xmm1 \n" "movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movups %%xmm0, (%[iv]) \n" "movups %%xmm0, (%[iv]) \n"
DecryptAES256(sched) DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
: :
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out) [in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
} }
else else
#endif #endif
@ -900,34 +893,34 @@ namespace crypto
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
// encrypt IV // encrypt IV
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
// double IV encryption // double IV encryption
EncryptAES256(sched_iv) EncryptAES256(sched_iv)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
// encrypt data, IV is xmm1 // encrypt data, IV is xmm1
"1: \n" "1: \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched_l) EncryptAES256(sched_l)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
: :
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()), : [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "cc", "memory" : "%xmm0", "%xmm1", "cc", "memory"
); );
} }
else else
#endif #endif
@ -941,35 +934,35 @@ namespace crypto
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{ {
#if SUPPORTS_AES #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
__asm__ __asm__
( (
// decrypt IV // decrypt IV
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n" "movaps %%xmm0, %%xmm1 \n"
// double IV encryption // double IV encryption
DecryptAES256(sched_iv) DecryptAES256(sched_iv)
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
// decrypt data, IV is xmm1 // decrypt data, IV is xmm1
"1: \n" "1: \n"
"add $16, %[in] \n" "add $16, %[in] \n"
"add $16, %[out] \n" "add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n" "movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n" "movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched_l) DecryptAES256(sched_l)
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n" "movaps %%xmm2, %%xmm1 \n"
"dec %[num] \n" "dec %[num] \n"
"jnz 1b \n" "jnz 1b \n"
: :
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()), : [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes [in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory" : "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
); );
} }
else else
#endif #endif
@ -998,7 +991,7 @@ namespace crypto
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen); EVP_EncryptUpdate(ctx, NULL, &outlen, ad, adLen);
EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen); EVP_EncryptUpdate(ctx, buf, &outlen, msg, msgLen);
EVP_EncryptFinal_ex(ctx, buf + outlen, &outlen); EVP_EncryptFinal_ex(ctx, buf, &outlen);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, buf + msgLen);
} }
else else
@ -1292,9 +1285,9 @@ namespace crypto
} }
}*/ }*/
void InitCrypto (bool precomputation, bool aesni, bool force) void InitCrypto (bool precomputation, bool aesni, bool avx, bool force)
{ {
i2p::cpu::Detect (aesni, force); i2p::cpu::Detect (aesni, avx, force);
#if LEGACY_OPENSSL #if LEGACY_OPENSSL
SSL_library_init (); SSL_library_init ();
#endif #endif
@ -1304,7 +1297,7 @@ namespace crypto
CRYPTO_set_locking_callback (OpensslLockingCallback);*/ CRYPTO_set_locking_callback (OpensslLockingCallback);*/
if (precomputation) if (precomputation)
{ {
#if IS_X86_64 #if defined(__x86_64__)
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255]; g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES); PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
#else #else
@ -1319,7 +1312,7 @@ namespace crypto
if (g_ElggTable) if (g_ElggTable)
{ {
DestroyElggTable (g_ElggTable, DestroyElggTable (g_ElggTable,
#if IS_X86_64 #if defined(__x86_64__)
ELGAMAL_FULL_EXPONENT_NUM_BYTES ELGAMAL_FULL_EXPONENT_NUM_BYTES
#else #else
ELGAMAL_SHORT_EXPONENT_NUM_BYTES ELGAMAL_SHORT_EXPONENT_NUM_BYTES

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -150,7 +150,7 @@ namespace crypto
}; };
#if SUPPORTS_AES #ifdef __AES__
class ECBCryptoAESNI class ECBCryptoAESNI
{ {
public: public:
@ -167,7 +167,7 @@ namespace crypto
}; };
#endif #endif
#if SUPPORTS_AES #ifdef __AES__
class ECBEncryption: public ECBCryptoAESNI class ECBEncryption: public ECBCryptoAESNI
#else #else
class ECBEncryption class ECBEncryption
@ -183,7 +183,7 @@ namespace crypto
AES_KEY m_Key; AES_KEY m_Key;
}; };
#if SUPPORTS_AES #ifdef __AES__
class ECBDecryption: public ECBCryptoAESNI class ECBDecryption: public ECBCryptoAESNI
#else #else
class ECBDecryption class ECBDecryption
@ -307,7 +307,7 @@ namespace crypto
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
// init and terminate // init and terminate
void InitCrypto (bool precomputation, bool aesni, bool force); void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
void TerminateCrypto (); void TerminateCrypto ();
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2021, 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
* *
@ -19,7 +19,7 @@ namespace i2p
namespace datagram namespace datagram
{ {
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip): DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip):
m_Owner (owner), m_DefaultReceiver (nullptr), m_DefaultRawReceiver (nullptr), m_Gzip (gzip) m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip)
{ {
if (m_Gzip) if (m_Gzip)
m_Deflator.reset (new i2p::data::GzipDeflator); m_Deflator.reset (new i2p::data::GzipDeflator);
@ -119,79 +119,19 @@ namespace datagram
void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
{ {
auto r = FindRawReceiver(toPort); if (m_RawReceiver)
m_RawReceiver (fromPort, toPort, buf, len);
if (r)
r (fromPort, toPort, buf, len);
else else
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram"); LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
} }
void DatagramDestination::SetReceiver (const Receiver& receiver, uint16_t port)
{
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
m_ReceiversByPorts[port] = receiver;
if (!m_DefaultReceiver) {
m_DefaultReceiver = receiver;
m_DefaultReceiverPort = port;
}
}
void DatagramDestination::ResetReceiver (uint16_t port)
{
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
m_ReceiversByPorts.erase (port);
if (m_DefaultReceiverPort == port) {
m_DefaultReceiver = nullptr;
m_DefaultReceiverPort = 0;
}
}
void DatagramDestination::SetRawReceiver (const RawReceiver& receiver, uint16_t port)
{
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
m_RawReceiversByPorts[port] = receiver;
if (!m_DefaultRawReceiver) {
m_DefaultRawReceiver = receiver;
m_DefaultRawReceiverPort = port;
}
}
void DatagramDestination::ResetRawReceiver (uint16_t port)
{
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
m_RawReceiversByPorts.erase (port);
if (m_DefaultRawReceiverPort == port) {
m_DefaultRawReceiver = nullptr;
m_DefaultRawReceiverPort = 0;
}
}
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port) DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
{ {
std::lock_guard<std::mutex> lock(m_ReceiversMutex); std::lock_guard<std::mutex> lock(m_ReceiversMutex);
Receiver r = nullptr; Receiver r = m_Receiver;
auto itr = m_ReceiversByPorts.find(port); auto itr = m_ReceiversByPorts.find(port);
if (itr != m_ReceiversByPorts.end()) if (itr != m_ReceiversByPorts.end())
r = itr->second; r = itr->second;
else {
r = m_DefaultReceiver;
}
return r;
}
DatagramDestination::RawReceiver DatagramDestination::FindRawReceiver(uint16_t port)
{
std::lock_guard<std::mutex> lock(m_RawReceiversMutex);
RawReceiver r = nullptr;
auto itr = m_RawReceiversByPorts.find(port);
if (itr != m_RawReceiversByPorts.end())
r = itr->second;
else {
r = m_DefaultRawReceiver;
}
return r; return r;
} }
@ -485,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->SendTunnelDataMsgs(send); routingPath->outboundTunnel->SendTunnelDataMsg(send);
} }
m_SendQueue.clear(); m_SendQueue.clear();
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -126,12 +126,14 @@ namespace datagram
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
void ResetReceiver () { m_Receiver = nullptr; };
void SetReceiver (const Receiver& receiver, uint16_t port); void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; };
void ResetReceiver (uint16_t port); void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
void SetRawReceiver (const RawReceiver& receiver, uint16_t port); void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; };
void ResetRawReceiver (uint16_t port); void ResetRawReceiver () { m_RawReceiver = nullptr; };
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote); std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
@ -148,26 +150,20 @@ namespace datagram
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
Receiver FindReceiver(uint16_t port); Receiver FindReceiver(uint16_t port);
RawReceiver FindRawReceiver(uint16_t port);
private: private:
std::shared_ptr<i2p::client::ClientDestination> m_Owner; std::shared_ptr<i2p::client::ClientDestination> m_Owner;
Receiver m_Receiver; // default
RawReceiver m_RawReceiver; // default
bool m_Gzip; // gzip compression of data messages
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions; std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
Receiver m_DefaultReceiver;
RawReceiver m_DefaultRawReceiver;
uint16_t m_DefaultReceiverPort;
uint16_t m_DefaultRawReceiverPort;
std::mutex m_ReceiversMutex; std::mutex m_ReceiversMutex;
std::mutex m_RawReceiversMutex; std::map<uint16_t, Receiver> m_ReceiversByPorts;
std::unordered_map<uint16_t, Receiver> m_ReceiversByPorts;
std::unordered_map<uint16_t, RawReceiver> m_RawReceiversByPorts;
bool m_Gzip; // gzip compression of data messages
i2p::data::GzipInflator m_Inflator; i2p::data::GzipInflator m_Inflator;
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator; std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
std::vector<uint8_t> m_From, m_Signature; std::vector<uint8_t> m_From, m_Signature;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -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(eLogCritical, "Destination: Invalid value i2cp.leaseSetPrivKey: ", it->second); LogPrint(eLogError, "Destination: Invalid value i2cp.leaseSetPrivKey ", it->second);
m_LeaseSetPrivKey.reset (nullptr); m_LeaseSetPrivKey.reset (nullptr);
} }
} }
@ -262,6 +262,17 @@ namespace client
return nullptr; return nullptr;
} }
} }
else
{
auto ls = i2p::data::netdb.FindLeaseSet (ident);
if (ls && !ls->IsExpired ())
{
ls->PopulateLeases (); // since we don't store them in netdb
std::lock_guard<std::mutex> _lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets[ident] = ls;
return ls;
}
}
return nullptr; return nullptr;
} }
@ -367,12 +378,9 @@ namespace client
HandleDataMessage (payload, len); HandleDataMessage (payload, len);
break; break;
case eI2NPDeliveryStatus: case eI2NPDeliveryStatus:
// we assume tunnel tests non-encrypted
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET)); HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
break; break;
case eI2NPTunnelTest:
if (m_Pool)
m_Pool->ProcessTunnelTest (bufbe32toh (payload + TUNNEL_TEST_MSGID_OFFSET), bufbe64toh (payload + TUNNEL_TEST_TIMESTAMP_OFFSET));
break;
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
HandleDatabaseStoreMessage (payload, len); HandleDatabaseStoreMessage (payload, len);
break; break;
@ -410,7 +418,6 @@ namespace client
} }
i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET); i2p::data::IdentHash key (buf + DATABASE_STORE_KEY_OFFSET);
std::shared_ptr<i2p::data::LeaseSet> leaseSet; std::shared_ptr<i2p::data::LeaseSet> leaseSet;
std::shared_ptr<LeaseSetRequest> request;
switch (buf[DATABASE_STORE_TYPE_OFFSET]) switch (buf[DATABASE_STORE_TYPE_OFFSET])
{ {
case i2p::data::NETDB_STORE_TYPE_LEASESET: // 1 case i2p::data::NETDB_STORE_TYPE_LEASESET: // 1
@ -466,59 +473,34 @@ namespace client
case i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2: // 5 case i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2: // 5
{ {
auto it2 = m_LeaseSetRequests.find (key); auto it2 = m_LeaseSetRequests.find (key);
if (it2 != m_LeaseSetRequests.end ()) if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
{ {
request = it2->second; auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
m_LeaseSetRequests.erase (it2); it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
if (request->requestedBlindedKey) if (ls2->IsValid () && !ls2->IsExpired ())
{ {
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, leaseSet = ls2;
request->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ()); std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
if (ls2->IsValid () && !ls2->IsExpired ()) m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
{ m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
leaseSet = ls2;
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
}
else
LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
} }
else else
{ LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
// publishing verification doesn't have requestedBlindedKey
auto localLeaseSet = GetLeaseSetMt ();
if (localLeaseSet->GetStoreHash () == key)
{
auto ls = std::make_shared<i2p::data::LeaseSet2> (i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2,
localLeaseSet->GetBuffer (), localLeaseSet->GetBufferLen (), false);
leaseSet = ls;
}
else
LogPrint (eLogWarning, "Destination: Encrypted LeaseSet2 received for request without blinded key");
}
} }
else else
LogPrint (eLogWarning, "Destination: Couldn't find request for encrypted LeaseSet2"); LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2");
break; break;
} }
default: default:
LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped"); LogPrint (eLogError, "Destination: Unexpected client's DatabaseStore type ", buf[DATABASE_STORE_TYPE_OFFSET], ", dropped");
} }
if (!request) auto it1 = m_LeaseSetRequests.find (key);
{ if (it1 != m_LeaseSetRequests.end ())
auto it1 = m_LeaseSetRequests.find (key);
if (it1 != m_LeaseSetRequests.end ())
{
request = it1->second;
m_LeaseSetRequests.erase (it1);
}
}
if (request)
{ {
request->requestTimeoutTimer.cancel (); it1->second->requestTimeoutTimer.cancel ();
request->Complete (leaseSet); if (it1->second) it1->second->Complete (leaseSet);
m_LeaseSetRequests.erase (it1);
} }
} }
@ -531,41 +513,36 @@ namespace client
if (it != m_LeaseSetRequests.end ()) if (it != m_LeaseSetRequests.end ())
{ {
auto request = it->second; auto request = it->second;
for (int i = 0; i < num; i++) bool found = false;
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST)
{ {
i2p::data::IdentHash peerHash (buf + 33 + i*32); for (int i = 0; i < num; i++)
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
{ {
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); i2p::data::IdentHash peerHash (buf + 33 + i*32);
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
{
LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
}
} }
}
SendNextLeaseSetRequest (key, request);
}
else
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
}
void LeaseSetDestination::SendNextLeaseSetRequest (const i2p::data::IdentHash& key, auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded);
std::shared_ptr<LeaseSetRequest> request) if (floodfill)
{ {
bool found = false; LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ());
if (request->excluded.size () < MAX_NUM_FLOODFILLS_PER_REQUEST) if (SendLeaseSetRequest (key, floodfill, request))
{ found = true;
auto floodfill = i2p::data::netdb.GetClosestFloodfill (key, request->excluded); }
if (floodfill) }
if (!found)
{ {
LogPrint (eLogInfo, "Destination: Requesting ", key.ToBase64 (), " at ", floodfill->GetIdentHash ().ToBase64 ()); LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
if (SendLeaseSetRequest (key, floodfill, request)) request->Complete (nullptr);
found = true; m_LeaseSetRequests.erase (key);
} }
} }
if (!found) else
{ LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills");
request->Complete (nullptr);
m_LeaseSetRequests.erase (key);
}
} }
void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID) void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID)
@ -612,7 +589,12 @@ namespace client
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
return; return;
} }
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetStoreHash (), m_ExcludedFloodfills); if (!m_Pool->GetInboundTunnels ().size () || !m_Pool->GetOutboundTunnels ().size ())
{
LogPrint (eLogError, "Destination: Can't publish LeaseSet. Destination is not ready");
return;
}
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
if (!floodfill) if (!floodfill)
{ {
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found"); LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
@ -623,39 +605,26 @@ namespace client
auto inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)); auto inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (!outbound || !inbound) if (!outbound || !inbound)
{ {
if (!m_Pool->GetInboundTunnels ().empty () && !m_Pool->GetOutboundTunnels ().empty ()) LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill");
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
if (floodfill)
{ {
LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill"); outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); if (outbound)
floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetStoreHash (), m_ExcludedFloodfills);
if (floodfill)
{ {
outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)); inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (outbound) if (!inbound)
{ LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (!inbound)
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
}
else
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
} }
else else
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found"); LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
} }
else else
LogPrint (eLogDebug, "Destination: No tunnels in pool"); LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
if (!floodfill || !outbound || !inbound) if (!floodfill || !outbound || !inbound)
{ {
// we can't publish now
m_ExcludedFloodfills.clear (); m_ExcludedFloodfills.clear ();
m_PublishReplyToken = 1; // dummy non-zero value
// try again after a while
LogPrint (eLogInfo, "Destination: Can't publish LeasetSet because destination is not ready. Try publishing again after ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds");
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
shared_from_this (), std::placeholders::_1));
return; return;
} }
} }
@ -663,19 +632,10 @@ namespace client
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound)); auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound));
auto s = shared_from_this ();
msg->onDrop = [s]()
{
s->GetService ().post([s]()
{
s->m_PublishConfirmationTimer.cancel ();
s->HandlePublishConfirmationTimer (boost::system::error_code());
});
};
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.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->SendTunnelDataMsgTo (floodfill->GetIdentHash (), 0, msg); outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg);
m_LastSubmissionTime = ts; m_LastSubmissionTime = ts;
} }
@ -688,7 +648,7 @@ namespace client
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
{ {
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds or failed. will try again"); LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
Publish (); Publish ();
} }
else else
@ -801,7 +761,7 @@ namespace client
void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey) void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey)
{ {
std::unordered_set<i2p::data::IdentHash> excluded; std::set<i2p::data::IdentHash> excluded;
auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded); auto floodfill = i2p::data::netdb.GetClosestFloodfill (dest, excluded);
if (floodfill) if (floodfill)
{ {
@ -873,18 +833,9 @@ namespace client
AddECIESx25519Key (replyKey, replyTag); AddECIESx25519Key (replyKey, replyTag);
else else
AddSessionKey (replyKey, replyTag); AddSessionKey (replyKey, replyTag);
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
auto msg = WrapMessageForRouter (nextFloodfill, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); request->outboundTunnel->SendTunnelDataMsg (
auto s = shared_from_this ();
msg->onDrop = [s, dest, request]()
{
s->GetService ().post([s, dest, request]()
{
s->SendNextLeaseSetRequest (dest, request);
});
};
request->outboundTunnel->SendTunnelDataMsgs (
{ {
i2p::tunnel::TunnelMessageBlock i2p::tunnel::TunnelMessageBlock
{ {
@ -979,7 +930,7 @@ namespace client
bool isPublic, const std::map<std::string, std::string> * params): bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (service, isPublic, params), LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_LastPort (0), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
m_DatagramDestination (nullptr), m_RefCounter (0), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(service) m_ReadyChecker(service)
{ {
@ -1049,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 = std::stoi (it->second); // 1 for true m_IsStreamingAnswerPings = (it->second == "true");
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{ {
@ -1063,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 (eLogCritical, "Destination: No auth keys read for auth type: ", authType); LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType);
m_AuthKeys = nullptr; m_AuthKeys = nullptr;
} }
} }
@ -1077,7 +1028,7 @@ namespace client
} }
catch (std::exception & ex) catch (std::exception & ex)
{ {
LogPrint(eLogCritical, "Destination: Unable to parse parameters for destination: ", ex.what()); LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
} }
} }
@ -1096,30 +1047,22 @@ namespace client
void ClientDestination::Stop () void ClientDestination::Stop ()
{ {
LogPrint(eLogDebug, "Destination: Stopping destination ", GetIdentHash().ToBase32(), ".b32.i2p");
LeaseSetDestination::Stop (); LeaseSetDestination::Stop ();
m_ReadyChecker.cancel(); m_ReadyChecker.cancel();
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination");
m_StreamingDestination->Stop (); m_StreamingDestination->Stop ();
//m_StreamingDestination->SetOwner (nullptr); //m_StreamingDestination->SetOwner (nullptr);
m_StreamingDestination = nullptr; m_StreamingDestination = nullptr;
LogPrint(eLogDebug, "Destination: -> Stopping Streaming Destination by ports");
for (auto& it: m_StreamingDestinationsByPorts) for (auto& it: m_StreamingDestinationsByPorts)
{ {
it.second->Stop (); it.second->Stop ();
//it.second->SetOwner (nullptr); //it.second->SetOwner (nullptr);
} }
m_StreamingDestinationsByPorts.clear (); m_StreamingDestinationsByPorts.clear ();
m_LastStreamingDestination = nullptr;
if (m_DatagramDestination) if (m_DatagramDestination)
{ {
LogPrint(eLogDebug, "Destination: -> Stopping Datagram Destination");
delete m_DatagramDestination; delete m_DatagramDestination;
m_DatagramDestination = nullptr; m_DatagramDestination = nullptr;
} }
LogPrint(eLogDebug, "Destination: -> Stopping done");
} }
void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len) void ClientDestination::HandleDataMessage (const uint8_t * buf, size_t len)
@ -1139,15 +1082,9 @@ namespace client
case PROTOCOL_TYPE_STREAMING: case PROTOCOL_TYPE_STREAMING:
{ {
// streaming protocol // streaming protocol
if (toPort != m_LastPort || !m_LastStreamingDestination) auto dest = GetStreamingDestination (toPort);
{ if (dest)
m_LastStreamingDestination = GetStreamingDestination (toPort); dest->HandleDataMessagePayload (buf, length);
if (!m_LastStreamingDestination)
m_LastStreamingDestination = m_StreamingDestination; // if no destination on port use default
m_LastPort = toPort;
}
if (m_LastStreamingDestination)
m_LastStreamingDestination->HandleDataMessagePayload (buf, length);
else else
LogPrint (eLogError, "Destination: Missing streaming destination"); LogPrint (eLogError, "Destination: Missing streaming destination");
} }
@ -1171,7 +1108,7 @@ namespace client
} }
} }
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port) void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port)
{ {
if (!streamRequestComplete) if (!streamRequestComplete)
{ {
@ -1201,7 +1138,7 @@ namespace client
} }
} }
void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port) void ClientDestination::CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
{ {
if (!streamRequestComplete) if (!streamRequestComplete)
{ {
@ -1220,7 +1157,7 @@ namespace client
} }
template<typename Dest> template<typename Dest>
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, uint16_t port) std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStreamSync (const Dest& dest, int port)
{ {
volatile bool done = false; volatile bool done = false;
std::shared_ptr<i2p::stream::Stream> stream; std::shared_ptr<i2p::stream::Stream> stream;
@ -1244,17 +1181,17 @@ namespace client
return stream; return stream;
} }
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, uint16_t port) std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (const i2p::data::IdentHash& dest, int port)
{ {
return CreateStreamSync (dest, port); return CreateStreamSync (dest, port);
} }
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port) std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port)
{ {
return CreateStreamSync (dest, port); return CreateStreamSync (dest, port);
} }
std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port) std::shared_ptr<i2p::stream::Stream> ClientDestination::CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
return m_StreamingDestination->CreateNewOutgoingStream (remote, port); return m_StreamingDestination->CreateNewOutgoingStream (remote, port);
@ -1291,7 +1228,7 @@ namespace client
}); });
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (uint16_t port) const std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
{ {
if (port) if (port)
{ {
@ -1299,9 +1236,8 @@ namespace client
if (it != m_StreamingDestinationsByPorts.end ()) if (it != m_StreamingDestinationsByPorts.end ())
return it->second; return it->second;
} }
else // if port is zero, use default destination // if port is zero or not found, use default destination
return m_StreamingDestination; return m_StreamingDestination;
return nullptr;
} }
void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor) void ClientDestination::AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor)
@ -1329,7 +1265,7 @@ namespace client
m_StreamingDestination->AcceptOnce (acceptor); m_StreamingDestination->AcceptOnce (acceptor);
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (uint16_t port, bool gzip) std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::CreateStreamingDestination (int port, bool gzip)
{ {
auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip); auto dest = std::make_shared<i2p::stream::StreamingDestination> (GetSharedFromThis (), port, gzip);
if (port) if (port)
@ -1339,7 +1275,7 @@ namespace client
return dest; return dest;
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (uint16_t port) std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::RemoveStreamingDestination (int port)
{ {
if (port) if (port)
{ {
@ -1400,7 +1336,7 @@ namespace client
f1.write ((char *)keys->priv, 256); f1.write ((char *)keys->priv, 256);
return; return;
} }
LogPrint(eLogCritical, "Destinations: Can't save keys to ", path); LogPrint(eLogError, "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)
@ -1477,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 (eLogCritical, "Destination: Unexpected auth key: ", it.second.substr (pos+1)); LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1));
} }
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -14,8 +14,7 @@
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <map> #include <map>
#include <unordered_map> #include <set>
#include <unordered_set>
#include <string> #include <string>
#include <functional> #include <functional>
#include <boost/asio.hpp> #include <boost/asio.hpp>
@ -97,7 +96,7 @@ namespace client
struct LeaseSetRequest struct LeaseSetRequest
{ {
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {}; LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
std::unordered_set<i2p::data::IdentHash> excluded; std::set<i2p::data::IdentHash> excluded;
uint64_t requestTime; uint64_t requestTime;
boost::asio::deadline_timer requestTimeoutTimer; boost::asio::deadline_timer requestTimeoutTimer;
std::list<RequestComplete> requestComplete; std::list<RequestComplete> requestComplete;
@ -176,7 +175,6 @@ namespace client
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr); void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request); bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
void SendNextLeaseSetRequest (const i2p::data::IdentHash& key, std::shared_ptr<LeaseSetRequest> request);
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
void HandleCleanupTimer (const boost::system::error_code& ecode); void HandleCleanupTimer (const boost::system::error_code& ecode);
void CleanupRemoteLeaseSets (); void CleanupRemoteLeaseSets ();
@ -186,8 +184,8 @@ namespace client
boost::asio::io_service& m_Service; boost::asio::io_service& m_Service;
mutable std::mutex m_RemoteLeaseSetsMutex; mutable std::mutex m_RemoteLeaseSetsMutex;
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets; std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests; std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool; std::shared_ptr<i2p::tunnel::TunnelPool> m_Pool;
std::mutex m_LeaseSetMutex; std::mutex m_LeaseSetMutex;
@ -195,7 +193,7 @@ namespace client
bool m_IsPublic; bool m_IsPublic;
uint32_t m_PublishReplyToken; uint32_t m_PublishReplyToken;
uint64_t m_LastSubmissionTime; // in seconds uint64_t m_LastSubmissionTime; // in seconds
std::unordered_set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing std::set<i2p::data::IdentHash> m_ExcludedFloodfills; // for publishing
boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer, boost::asio::deadline_timer m_PublishConfirmationTimer, m_PublishVerificationTimer,
m_PublishDelayTimer, m_CleanupTimer; m_PublishDelayTimer, m_CleanupTimer;
@ -243,15 +241,15 @@ namespace client
int GetRefCounter () const { return m_RefCounter; }; int GetRefCounter () const { return m_RefCounter; };
// streaming // streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (uint16_t port, bool gzip = true); // additional std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (uint16_t port = 0) const; std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination (int port = 0) const;
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (uint16_t port); std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (int port);
// following methods operate with default streaming destination // following methods operate with default streaming destination
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, uint16_t port = 0); void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0);
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0); void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, uint16_t port = 0); // sync std::shared_ptr<i2p::stream::Stream> CreateStream (const i2p::data::IdentHash& dest, int port = 0); // sync
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, uint16_t port = 0); // sync std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0); // sync
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, uint16_t port = 0); std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void SendPing (const i2p::data::IdentHash& to); void SendPing (const i2p::data::IdentHash& to);
void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to); void SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to);
void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptStreams (const i2p::stream::StreamingDestination::Acceptor& acceptor);
@ -287,7 +285,7 @@ namespace client
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params); void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
template<typename Dest> template<typename Dest>
std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, uint16_t port); std::shared_ptr<i2p::stream::Stream> CreateStreamSync (const Dest& dest, int port);
private: private:
@ -299,7 +297,6 @@ namespace client
bool m_IsStreamingAnswerPings; bool m_IsStreamingAnswerPings;
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts; std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
std::shared_ptr<i2p::stream::StreamingDestination> m_LastStreamingDestination; uint16_t m_LastPort; // for server tunnels
i2p::datagram::DatagramDestination * m_DatagramDestination; i2p::datagram::DatagramDestination * m_DatagramDestination;
int m_RefCounter; // how many clients(tunnels) use this destination int m_RefCounter; // how many clients(tunnels) use this destination

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -117,12 +117,6 @@ namespace garlic
return session->HandleNextMessage (buf, len, shared_from_this (), index); return session->HandleNextMessage (buf, len, shared_from_this (), index);
} }
bool ReceiveRatchetTagSet::IsSessionTerminated () const
{
return !m_Session || m_Session->IsTerminated ();
}
SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key): SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
ReceiveRatchetTagSet (nullptr), m_Destination (destination) ReceiveRatchetTagSet (nullptr), m_Destination (destination)
{ {
@ -863,7 +857,7 @@ namespace garlic
payloadLen += msg->GetPayloadLength () + 13; payloadLen += msg->GetPayloadLength () + 13;
if (m_Destination) payloadLen += 32; if (m_Destination) payloadLen += 32;
} }
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASESET_CONFIRMATION_TIMEOUT) if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
{ {
// resubmit non-confirmed LeaseSet // resubmit non-confirmed LeaseSet
SetLeaseSetUpdateStatus (eLeaseSetUpdated); SetLeaseSetUpdateStatus (eLeaseSetUpdated);
@ -1154,9 +1148,9 @@ namespace garlic
return len; return len;
} }
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<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 ((msg ? msg->GetPayloadLength () : 0) + 128); auto m = NewI2NPMessage ();
m->Align (12); // in order to get buf aligned to 16 (12 + 4) m->Align (12); // in order to get buf aligned to 16 (12 + 4)
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;
@ -1174,21 +1168,15 @@ namespace garlic
htobe32buf (m->GetPayload (), offset); htobe32buf (m->GetPayload (), offset);
m->len += offset + 4; m->len += offset + 4;
m->FillI2NPMessageHeader (eI2NPGarlic); m->FillI2NPMessageHeader (eI2NPGarlic);
if (msg->onDrop)
{
// move onDrop to the wrapping I2NP messages
m->onDrop = msg->onDrop;
msg->onDrop = nullptr;
}
return m; return m;
} }
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<I2NPMessage> msg, const uint8_t * routerPublicKey) std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey)
{ {
// 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 ((msg ? msg->GetPayloadLength () : 0) + 128); auto m = NewI2NPMessage ();
m->Align (12); // in order to get buf aligned to 16 (12 + 4) m->Align (12); // in order to get buf aligned to 16 (12 + 4)
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;
@ -1217,12 +1205,6 @@ namespace garlic
htobe32buf (m->GetPayload (), offset); htobe32buf (m->GetPayload (), offset);
m->len += offset + 4; m->len += offset + 4;
m->FillI2NPMessageHeader (eI2NPGarlic); m->FillI2NPMessageHeader (eI2NPGarlic);
if (msg->onDrop)
{
// move onDrop to the wrapping I2NP messages
m->onDrop = msg->onDrop;
msg->onDrop = nullptr;
}
return m; return m;
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2021, 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
* *
@ -86,7 +86,6 @@ namespace garlic
virtual bool IsIndexExpired (int index) const; virtual bool IsIndexExpired (int index) const;
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index); virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
virtual bool IsSessionTerminated () const;
private: private:
@ -102,9 +101,8 @@ namespace garlic
SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key); SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key);
bool IsIndexExpired (int index) const override { return false; }; bool IsIndexExpired (int index) const { return false; };
bool HandleNextMessage (uint8_t * buf, size_t len, int index) override; bool HandleNextMessage (uint8_t * buf, size_t len, int index);
bool IsSessionTerminated () const override { return false; }
private: private:
@ -247,8 +245,8 @@ namespace garlic
i2p::crypto::NoiseSymmetricState m_CurrentNoiseState; i2p::crypto::NoiseSymmetricState m_CurrentNoiseState;
}; };
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<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);
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<I2NPMessage> msg, const uint8_t * routerPublicKey); std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -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 ((bool)BN_is_bit_set (x, 0) != isHighestBitSet) if (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

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -9,11 +9,6 @@
#include <algorithm> #include <algorithm>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#if defined(MAC_OSX)
#include <boost/system/system_error.hpp>
#include <TargetConditionals.h>
#endif
#ifdef _WIN32 #ifdef _WIN32
#include <shlobj.h> #include <shlobj.h>
#include <windows.h> #include <windows.h>
@ -54,11 +49,7 @@ namespace fs {
const std::string GetUTF8DataDir () { const std::string GetUTF8DataDir () {
#ifdef _WIN32 #ifdef _WIN32
#if (BOOST_VERSION >= 108500)
boost::filesystem::path path (dataDir);
#else
boost::filesystem::wpath path (dataDir); boost::filesystem::wpath path (dataDir);
#endif
auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) ); // convert path to UTF-8 auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) ); // convert path to UTF-8
auto dataDirUTF8 = path.string(); auto dataDirUTF8 = path.string();
boost::filesystem::path::imbue(loc); // Return locale settings back boost::filesystem::path::imbue(loc); // Return locale settings back
@ -91,11 +82,7 @@ namespace fs {
} }
else else
{ {
#if (BOOST_VERSION >= 108500)
dataDir = boost::filesystem::path(commonAppData).string() + "\\" + appName;
#else
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName; dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
#endif
} }
#else #else
dataDir = "/var/lib/" + appName; dataDir = "/var/lib/" + appName;
@ -120,11 +107,7 @@ namespace fs {
} }
else else
{ {
#if (BOOST_VERSION >= 108500)
auto execPath = boost::filesystem::path(localAppData).parent_path();
#else
auto execPath = boost::filesystem::wpath(localAppData).parent_path(); auto execPath = boost::filesystem::wpath(localAppData).parent_path();
#endif
// if config file exists in .exe's folder use it // if config file exists in .exe's folder use it
if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string if(boost::filesystem::exists(execPath/"i2pd.conf")) // TODO: magic string
@ -143,11 +126,7 @@ namespace fs {
} }
else else
{ {
#if (BOOST_VERSION >= 108500)
dataDir = boost::filesystem::path(localAppData).string() + "\\" + appName;
#else
dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName; dataDir = boost::filesystem::wpath(localAppData).string() + "\\" + appName;
#endif
} }
} }
} }
@ -157,14 +136,6 @@ namespace fs {
dataDir = (home != NULL && strlen(home) > 0) ? home : ""; dataDir = (home != NULL && strlen(home) > 0) ? home : "";
dataDir += "/Library/Application Support/" + appName; dataDir += "/Library/Application Support/" + appName;
return; return;
#elif defined(__HAIKU__)
char *home = getenv("HOME");
if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/config/settings/" + appName;
} else {
dataDir = "/tmp/" + appName;
}
return;
#else /* other unix */ #else /* other unix */
#if defined(ANDROID) #if defined(ANDROID)
const char * ext = getenv("EXTERNAL_STORAGE"); const char * ext = getenv("EXTERNAL_STORAGE");
@ -272,22 +243,8 @@ namespace fs {
auto p = root + i2p::fs::dirSep + prefix1 + chars[i]; auto p = root + i2p::fs::dirSep + prefix1 + chars[i];
if (boost::filesystem::exists(p)) if (boost::filesystem::exists(p))
continue; continue;
#if TARGET_OS_SIMULATOR
// ios simulator fs says it is case sensitive, but it is not
boost::system::error_code ec;
if (boost::filesystem::create_directory(p, ec))
continue;
switch (ec.value()) {
case boost::system::errc::file_exists:
case boost::system::errc::success:
continue;
default:
throw boost::system::system_error( ec, __func__ );
}
#else
if (boost::filesystem::create_directory(p)) if (boost::filesystem::create_directory(p))
continue; /* ^ throws exception on failure */ continue; /* ^ throws exception on failure */
#endif
return false; return false;
} }
return true; return true;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2022, 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, (int)m_SigningKeys.size () + 1)); m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
} }
SSL_free (ssl); SSL_free (ssl);
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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,7 +80,7 @@ namespace garlic
void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts) void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts)
{ {
if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASESET_CONFIRMATION_TIMEOUT) if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
{ {
if (GetOwner ()) if (GetOwner ())
GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
@ -232,7 +232,7 @@ namespace garlic
if (GetOwner ()) if (GetOwner ())
{ {
// resubmit non-confirmed LeaseSet // resubmit non-confirmed LeaseSet
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASESET_CONFIRMATION_TIMEOUT) if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
{ {
SetLeaseSetUpdateStatus (eLeaseSetUpdated); SetLeaseSetUpdateStatus (eLeaseSetUpdated);
SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed SetSharedRoutingPath (nullptr); // invalidate path since leaseset was not confirmed
@ -588,7 +588,7 @@ namespace garlic
auto it = m_ECIESx25519Tags.find (tag); auto it = m_ECIESx25519Tags.find (tag);
if (it != m_ECIESx25519Tags.end ()) if (it != m_ECIESx25519Tags.end ())
{ {
if (it->second.tagset && it->second.tagset->HandleNextMessage (buf, len, it->second.index)) if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
m_LastTagset = it->second.tagset; m_LastTagset = it->second.tagset;
else else
LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
@ -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->SendTunnelDataMsgTo (gwHash, gwTunnel, msg); tunnel->SendTunnelDataMsg (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");
} }
@ -887,7 +887,8 @@ namespace garlic
} }
else else
{ {
if (it->second.tagset->IsSessionTerminated ()) auto session = it->second.tagset->GetSession ();
if (!session || session->IsTerminated())
{ {
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
numExpiredTags++; numExpiredTags++;
@ -1074,7 +1075,7 @@ namespace garlic
{ {
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel (); auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
if (tunnel) if (tunnel)
tunnel->SendTunnelDataMsgTo (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset, msgID)); tunnel->SendTunnelDataMsg (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");
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -50,7 +50,7 @@ namespace garlic
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
const int LEASESET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
@ -221,7 +221,7 @@ namespace garlic
struct ECIESX25519AEADRatchetIndexTagset struct ECIESX25519AEADRatchetIndexTagset
{ {
int index; int index;
ReceiveRatchetTagSetPtr tagset; // null if used ReceiveRatchetTagSetPtr tagset;
}; };
class GarlicDestination: public i2p::data::LocalDestination class GarlicDestination: public i2p::data::LocalDestination

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -36,11 +36,6 @@ 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);
@ -48,10 +43,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len) std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
{ {
len += I2NP_HEADER_SIZE + 2; return (len < I2NP_MAX_SHORT_MESSAGE_SIZE - I2NP_HEADER_SIZE - 2) ? NewI2NPShortMessage () : NewI2NPMessage ();
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)
@ -72,17 +64,13 @@ namespace i2p
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT); SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
} }
bool I2NPMessage::IsExpired (uint64_t ts) const bool I2NPMessage::IsExpired () const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
auto exp = GetExpiration (); auto exp = GetExpiration ();
return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future
} }
bool I2NPMessage::IsExpired () const
{
return IsExpired (i2p::util::GetMillisecondsSinceEpoch ());
}
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID) std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
{ {
auto msg = NewI2NPMessage (len); auto msg = NewI2NPMessage (len);
@ -115,17 +103,6 @@ namespace i2p
return newMsg; return newMsg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelTestMsg (uint32_t msgID)
{
auto m = NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload ();
htobe32buf (buf + TUNNEL_TEST_MSGID_OFFSET, msgID);
htobe64buf (buf + TUNNEL_TEST_TIMESTAMP_OFFSET, i2p::util::GetMonotonicMicroseconds ());
m->len += TUNNEL_TEST_SIZE;
m->FillI2NPMessageHeader (eI2NPTunnelTest);
return m;
}
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID) std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
{ {
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
@ -147,10 +124,9 @@ 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::unordered_set<i2p::data::IdentHash> * excludedPeers) uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{ {
int cnt = excludedPeers ? excludedPeers->size () : 0; auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
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;
@ -171,6 +147,7 @@ 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)
@ -192,7 +169,7 @@ namespace i2p
} }
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::unordered_set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
const uint8_t * replyTag, bool replyECIES) const uint8_t * replyTag, bool replyECIES)
{ {
@ -384,20 +361,10 @@ namespace i2p
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
{ {
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
{
LogPrint (eLogWarning, "I2NP: Failed to decrypt tunnel build record");
return false;
}
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32) && // if next ident is now ours
!(clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG)) // and not endpoint
{
LogPrint (eLogWarning, "I2NP: Next ident is ours in tunnel build record");
return false;
}
uint8_t retCode = 0; uint8_t retCode = 0;
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && i2p::context.GetCongestionLevel (false) < CONGESTION_LEVEL_FULL) if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ())
{ {
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),
@ -449,11 +416,6 @@ namespace i2p
{ {
int num = buf[0]; int num = buf[0];
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
if (num > i2p::tunnel::MAX_NUM_RECORDS)
{
LogPrint (eLogError, "I2NP: Too many records in VaribleTunnelBuild message ", num);
return;
}
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1) if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
{ {
LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len); LogPrint (eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
@ -507,11 +469,6 @@ namespace i2p
{ {
int num = buf[0]; int num = buf[0];
LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID); LogPrint (eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
if (num > i2p::tunnel::MAX_NUM_RECORDS)
{
LogPrint (eLogError, "I2NP: Too many records in TunnelBuildReply message ", num);
return;
}
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
if (len < num*recordSize + 1) if (len < num*recordSize + 1)
{ {
@ -543,11 +500,6 @@ namespace i2p
{ {
int num = buf[0]; int num = buf[0];
LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records"); LogPrint (eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
if (num > i2p::tunnel::MAX_NUM_RECORDS)
{
LogPrint (eLogError, "I2NP: Too many records in ShortTunnelBuild message ", num);
return;
}
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1) if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1)
{ {
LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len); LogPrint (eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
@ -602,24 +554,16 @@ namespace i2p
memcpy (ivKey, noiseState.m_CK + 32, 32); memcpy (ivKey, noiseState.m_CK + 32, 32);
} }
else else
{
if (!memcmp ((const uint8_t *)i2p::context.GetIdentHash (), clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // if next ident is now ours
{
LogPrint (eLogWarning, "I2NP: Next ident is ours in short request record");
return;
}
memcpy (ivKey, noiseState.m_CK , 32); memcpy (ivKey, noiseState.m_CK , 32);
}
// check if we accept this tunnel // check if we accept this tunnel
std::shared_ptr<i2p::tunnel::TransitTunnel> transitTunnel;
uint8_t retCode = 0; uint8_t retCode = 0;
if (!i2p::context.AcceptsTunnels () || i2p::context.GetCongestionLevel (false) >= CONGESTION_LEVEL_FULL) if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ())
retCode = 30; retCode = 30;
if (!retCode) if (!retCode)
{ {
// create new transit tunnel // create new transit tunnel
transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
@ -653,22 +597,11 @@ namespace i2p
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
} }
// send reply // send reply
auto onDrop = [transitTunnel]()
{
if (transitTunnel)
{
auto t = transitTunnel->GetCreationTime ();
if (t > i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT)
// make transit tunnel expired
transitTunnel->SetCreationTime (t - i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT);
}
};
if (isEndpoint) if (isEndpoint)
{ {
auto replyMsg = NewI2NPShortMessage (); auto replyMsg = NewI2NPShortMessage ();
replyMsg->Concat (buf, len); replyMsg->Concat (buf, len);
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
if (transitTunnel) replyMsg->onDrop = onDrop;
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (), if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local? clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
{ {
@ -686,21 +619,15 @@ namespace i2p
uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET); uint32_t tunnelID = bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID); auto tunnel = i2p::tunnel::tunnels.GetTunnel (tunnelID);
if (tunnel) if (tunnel)
{
tunnel->SendTunnelDataMsg (replyMsg); tunnel->SendTunnelDataMsg (replyMsg);
tunnel->FlushTunnelDataMsgs ();
}
else else
LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply"); LogPrint (eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
} }
} }
else else
{ transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
auto msg = CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len, CreateI2NPMessage (eI2NPShortTunnelBuild, buf, len,
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
if (transitTunnel) msg->onDrop = onDrop;
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, msg);
}
return; return;
} }
record += SHORT_TUNNEL_BUILD_RECORD_SIZE; record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
@ -760,11 +687,7 @@ namespace i2p
return msg; return msg;
} }
else else
{ return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
auto newMsg = CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
if (msg->onDrop) newMsg->onDrop = msg->onDrop;
return newMsg;
}
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
@ -802,38 +725,46 @@ namespace i2p
return l; return l;
} }
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg) void HandleI2NPMessage (uint8_t * msg, size_t len)
{ {
if (msg) if (len < I2NP_HEADER_SIZE)
{ {
uint8_t typeID = msg->GetTypeID(); LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
uint32_t msgID = msg->GetMsgID(); return;
LogPrint (eLogDebug, "I2NP: Handling tunnel build message with len=", msg->GetLength(),", type=", (int)typeID, ", msgID=", (unsigned int)msgID); }
uint8_t * payload = msg->GetPayload(); uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
auto size = msg->GetPayloadLength(); uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
switch (typeID) LogPrint (eLogDebug, "I2NP: Msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
{ uint8_t * buf = msg + I2NP_HEADER_SIZE;
case eI2NPVariableTunnelBuild: auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
HandleVariableTunnelBuildMsg (msgID, payload, size); len -= I2NP_HEADER_SIZE;
break; if (size > len)
case eI2NPShortTunnelBuild: {
HandleShortTunnelBuildMsg (msgID, payload, size); LogPrint (eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
break; size = len;
case eI2NPVariableTunnelBuildReply: }
HandleTunnelBuildReplyMsg (msgID, payload, size, false); switch (typeID)
break; {
case eI2NPShortTunnelBuildReply: case eI2NPVariableTunnelBuild:
HandleTunnelBuildReplyMsg (msgID, payload, size, true); HandleVariableTunnelBuildMsg (msgID, buf, size);
break; break;
case eI2NPTunnelBuild: case eI2NPShortTunnelBuild:
HandleTunnelBuildMsg (payload, size); HandleShortTunnelBuildMsg (msgID, buf, size);
break; break;
case eI2NPTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
// TODO: HandleTunnelBuildReplyMsg (msgID, buf, size, false);
break; break;
default: case eI2NPShortTunnelBuildReply:
LogPrint (eLogError, "I2NP: Unexpected message with type", (int)typeID, " during handling TBM; skipping"); HandleTunnelBuildReplyMsg (msgID, buf, size, true);
} break;
case eI2NPTunnelBuild:
HandleTunnelBuildMsg (buf, size);
break;
case eI2NPTunnelBuildReply:
// TODO:
break;
default:
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
} }
} }
@ -846,12 +777,10 @@ namespace i2p
switch (typeID) switch (typeID)
{ {
case eI2NPTunnelData: case eI2NPTunnelData:
if (!msg->from) i2p::tunnel::tunnels.PostTunnelData (msg);
i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
case eI2NPTunnelGateway: case eI2NPTunnelGateway:
if (!msg->from) i2p::tunnel::tunnels.PostTunnelData (msg);
i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
case eI2NPGarlic: case eI2NPGarlic:
{ {
@ -862,18 +791,10 @@ namespace i2p
break; break;
} }
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
// forward to netDb if came directly or through exploratory tunnel as response to our request
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
i2p::data::netdb.PostI2NPMsg (msg);
break;
case eI2NPDatabaseSearchReply: case eI2NPDatabaseSearchReply:
if (!msg->from || !msg->from->GetTunnelPool () || msg->from->GetTunnelPool ()->IsExploratory ())
i2p::data::netdb.PostDatabaseSearchReplyMsg (msg);
break;
case eI2NPDatabaseLookup: case eI2NPDatabaseLookup:
// forward to netDb if floodfill and came directly // forward to netDb
if (!msg->from && i2p::context.IsFloodfill ()) i2p::data::netdb.PostI2NPMsg (msg);
i2p::data::netdb.PostI2NPMsg (msg);
break; break;
case eI2NPDeliveryStatus: case eI2NPDeliveryStatus:
{ {
@ -883,25 +804,17 @@ namespace i2p
i2p::context.ProcessDeliveryStatusMessage (msg); i2p::context.ProcessDeliveryStatusMessage (msg);
break; break;
} }
case eI2NPTunnelTest:
if (msg->from && msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessTunnelTest (msg);
break;
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
case eI2NPTunnelBuild:
case eI2NPShortTunnelBuild:
// forward to tunnel thread
if (!msg->from)
i2p::tunnel::tunnels.PostTunnelData (msg);
break;
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
case eI2NPShortTunnelBuild:
case eI2NPShortTunnelBuildReply: case eI2NPShortTunnelBuildReply:
// forward to tunnel thread // forward to tunnel thread
i2p::tunnel::tunnels.PostTunnelData (msg); i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
default: default:
LogPrint(eLogError, "I2NP: Unexpected I2NP message with type ", int(typeID), " during handling; skipping"); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
} }
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -11,9 +11,8 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include <unordered_set> #include <set>
#include <memory> #include <memory>
#include <functional>
#include "Crypto.h" #include "Crypto.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Identity.h" #include "Identity.h"
@ -48,11 +47,6 @@ namespace i2p
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4; const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8; const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8;
// TunnelTest
const size_t TUNNEL_TEST_MSGID_OFFSET = 0;
const size_t TUNNEL_TEST_TIMESTAMP_OFFSET = TUNNEL_TEST_MSGID_OFFSET + 4;
const size_t TUNNEL_TEST_SIZE = TUNNEL_TEST_TIMESTAMP_OFFSET + 8;
// DatabaseStore // DatabaseStore
const size_t DATABASE_STORE_KEY_OFFSET = 0; const size_t DATABASE_STORE_KEY_OFFSET = 0;
const size_t DATABASE_STORE_TYPE_OFFSET = DATABASE_STORE_KEY_OFFSET + 32; const size_t DATABASE_STORE_TYPE_OFFSET = DATABASE_STORE_KEY_OFFSET + 32;
@ -121,8 +115,7 @@ namespace i2p
eI2NPVariableTunnelBuild = 23, eI2NPVariableTunnelBuild = 23,
eI2NPVariableTunnelBuildReply = 24, eI2NPVariableTunnelBuildReply = 24,
eI2NPShortTunnelBuild = 25, eI2NPShortTunnelBuild = 25,
eI2NPShortTunnelBuildReply = 26, eI2NPShortTunnelBuildReply = 26
eI2NPTunnelTest = 231
}; };
const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80; const uint8_t TUNNEL_BUILD_RECORD_GATEWAY_FLAG = 0x80;
@ -145,16 +138,8 @@ namespace tunnel
class TunnelPool; class TunnelPool;
} }
const int CONGESTION_LEVEL_MEDIUM = 70;
const int CONGESTION_LEVEL_HIGH = 90;
const int CONGESTION_LEVEL_FULL = 100;
const size_t I2NP_MAX_MESSAGE_SIZE = 62708; const size_t I2NP_MAX_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_LOCAL_EXPIRATION_TIMEOUT_FACTOR = 3; // multiples of RTT
const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN = 200000; // in microseconds
const unsigned int I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX = 2000000; // in microseconds
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
@ -163,11 +148,9 @@ namespace tunnel
uint8_t * buf; uint8_t * buf;
size_t len, offset, maxLen; size_t len, offset, maxLen;
std::shared_ptr<i2p::tunnel::InboundTunnel> from; std::shared_ptr<i2p::tunnel::InboundTunnel> from;
std::function<void ()> onDrop;
uint64_t enqueueTime; // monotonic microseconds
I2NPMessage (): buf (nullptr), len (I2NP_HEADER_SIZE + 2), I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
offset(2), maxLen (0), from (nullptr), enqueueTime (0) {}; // reserve 2 bytes for NTCP header offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
// header accessors // header accessors
uint8_t * GetHeader () { return GetBuffer (); }; uint8_t * GetHeader () { return GetBuffer (); };
@ -177,9 +160,7 @@ namespace tunnel
void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); }; void SetMsgID (uint32_t msgID) { htobe32buf (GetHeader () + I2NP_HEADER_MSGID_OFFSET, msgID); };
uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); }; uint32_t GetMsgID () const { return bufbe32toh (GetHeader () + I2NP_HEADER_MSGID_OFFSET); };
void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); }; void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); };
void SetEnqueueTime (uint64_t mts) { enqueueTime = mts; };
uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); }; uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
uint64_t GetEnqueueTime () const { return enqueueTime; };
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); }; void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); }; uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); };
void UpdateSize () { SetSize (GetPayloadLength ()); }; void UpdateSize () { SetSize (GetPayloadLength ()); };
@ -259,6 +240,7 @@ namespace tunnel
SetSize (len - offset - I2NP_HEADER_SIZE); SetSize (len - offset - I2NP_HEADER_SIZE);
SetChks (0); SetChks (0);
} }
void ToNTCP2 () void ToNTCP2 ()
{ {
uint8_t * ntcp2 = GetNTCP2Header (); uint8_t * ntcp2 = GetNTCP2Header ();
@ -269,9 +251,6 @@ namespace tunnel
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true); void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true);
void RenewI2NPMessageHeader (); void RenewI2NPMessageHeader ();
bool IsExpired () const; bool IsExpired () const;
bool IsExpired (uint64_t ts) const; // in milliseconds
void Drop () { if (onDrop) { onDrop (); onDrop = nullptr; }; }
}; };
template<int sz> template<int sz>
@ -283,7 +262,6 @@ 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);
@ -291,12 +269,11 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr); std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateTunnelTestMsg (uint32_t msgID);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID); std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
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 = false, std::unordered_set<i2p::data::IdentHash> * excludedPeers = nullptr); uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::unordered_set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false); const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
@ -316,7 +293,7 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len); size_t GetI2NPMessageLength (const uint8_t * msg, size_t len);
void HandleTunnelBuildI2NPMessage (std::shared_ptr<I2NPMessage> msg); void HandleI2NPMessage (uint8_t * msg, size_t len);
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg); void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg);
class I2NPMessagesHandler class I2NPMessagesHandler

@ -14,7 +14,7 @@
#if defined(__FreeBSD__) || defined(__NetBSD__) #if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h> #include <sys/endian.h>
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__) || defined(__HAIKU__) #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__)
#include <endian.h> #include <endian.h>
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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,6 +187,7 @@ namespace data
IdentityEx::~IdentityEx () IdentityEx::~IdentityEx ()
{ {
delete m_Verifier;
} }
IdentityEx& IdentityEx::operator=(const IdentityEx& other) IdentityEx& IdentityEx::operator=(const IdentityEx& other)
@ -200,8 +201,9 @@ 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;
} }
@ -210,10 +212,11 @@ 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;
} }
@ -246,8 +249,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 ();
} }
@ -283,6 +286,7 @@ 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;
@ -297,6 +301,7 @@ 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;
@ -304,12 +309,14 @@ 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;
@ -366,29 +373,52 @@ namespace data
return nullptr; return nullptr;
} }
void IdentityEx::CreateVerifier () void IdentityEx::CreateVerifier () const
{ {
if (!m_Verifier) if (m_Verifier) return; // don't create again
auto verifier = CreateVerifier (GetSigningKeyType ());
if (verifier)
{ {
auto verifier = CreateVerifier (GetSigningKeyType ()); auto keyLen = verifier->GetPublicKeyLen ();
if (verifier) if (keyLen <= 128)
verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen);
else
{ {
auto keyLen = verifier->GetPublicKeyLen (); // for P521
if (keyLen <= 128) uint8_t * signingKey = new uint8_t[keyLen];
verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen); memcpy (signingKey, m_StandardIdentity.signingKey, 128);
else size_t excessLen = keyLen - 128;
{ memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
// for P521 verifier->SetPublicKey (signingKey);
uint8_t * signingKey = new uint8_t[keyLen]; delete[] signingKey;
memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = keyLen - 128;
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
verifier->SetPublicKey (signingKey);
delete[] signingKey;
}
} }
m_Verifier.reset (verifier);
} }
UpdateVerifier (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)
@ -581,7 +611,7 @@ namespace data
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1) if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey)); m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ()) else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey + (sizeof(Identity::signingKey) - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH))); // TODO: remove public key check m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
else else
{ {
// public key is not required // public key is not required
@ -790,14 +820,11 @@ namespace data
return keys; return keys;
} }
IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay) IdentHash CreateRoutingKey (const IdentHash& ident)
{ {
uint8_t buf[41]; // ident + yyyymmdd uint8_t buf[41]; // ident + yyyymmdd
memcpy (buf, (const uint8_t *)ident, 32); memcpy (buf, (const uint8_t *)ident, 32);
if (nextDay) i2p::util::GetCurrentDate ((char *)(buf + 32));
i2p::util::GetNextDayDate ((char *)(buf + 32));
else
i2p::util::GetCurrentDate ((char *)(buf + 32));
IdentHash key; IdentHash key;
SHA256(buf, 40, key); SHA256(buf, 40, key);
return key; return key;
@ -806,12 +833,29 @@ namespace data
XORMetric operator^(const IdentHash& key1, const IdentHash& key2) XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
{ {
XORMetric m; XORMetric m;
#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL (); if(i2p::cpu::avx)
m.metric_ll[0] = hash1[0] ^ hash2[0]; {
m.metric_ll[1] = hash1[1] ^ hash2[1]; __asm__
m.metric_ll[2] = hash1[2] ^ hash2[2]; (
m.metric_ll[3] = hash1[3] ^ hash2[3]; "vmovups %1, %%ymm0 \n"
"vmovups %2, %%ymm1 \n"
"vxorps %%ymm0, %%ymm1, %%ymm1 \n"
"vmovups %%ymm1, %0 \n"
: "=m"(*m.metric)
: "m"(*key1), "m"(*key2)
: "memory", "%xmm0", "%xmm1" // should be replaced by %ymm0/1 once supported by compiler
);
}
else
#endif
{
const uint64_t * hash1 = key1.GetLL (), * hash2 = key2.GetLL ();
m.metric_ll[0] = hash1[0] ^ hash2[0];
m.metric_ll[1] = hash1[1] ^ hash2[1];
m.metric_ll[2] = hash1[2] ^ hash2[2];
m.metric_ll[3] = hash1[3] ^ hash2[3];
}
return m; return m;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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,7 +13,9 @@
#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"
@ -116,6 +118,7 @@ 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);
@ -125,13 +128,15 @@ namespace data
private: private:
void CreateVerifier (); void CreateVerifier () const;
void UpdateVerifier (i2p::crypto::Verifier * verifier) const;
private: private:
Identity m_StandardIdentity; Identity m_StandardIdentity;
IdentHash m_IdentHash; IdentHash m_IdentHash;
std::unique_ptr<i2p::crypto::Verifier> m_Verifier; mutable i2p::crypto::Verifier * m_Verifier = nullptr;
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];
}; };
@ -206,7 +211,7 @@ namespace data
bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; }; bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; };
}; };
IdentHash CreateRoutingKey (const IdentHash& ident, bool nextDay = false); IdentHash CreateRoutingKey (const IdentHash& ident);
XORMetric operator^(const IdentHash& key1, const IdentHash& key2); XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
// destination for delivery instructions // destination for delivery instructions

@ -81,13 +81,13 @@ namespace data
{ {
if (bit1) if (bit1)
{ {
if (root->one) return; // something wrong if (root->one) return; // someting wrong
root->one = new DHTNode; root->one = new DHTNode;
root = root->one; root = root->one;
} }
else else
{ {
if (root->zero) return; // something wrong if (root->zero) return; // someting wrong
root->zero = new DHTNode; root->zero = new DHTNode;
root = root->zero; root = root->zero;
} }

@ -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 = netdb.NewIdentity (m_Buffer, m_BufferLen); m_Identity = std::make_shared<IdentityEx>(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: Incorrect number of leases", (int)num); LogPrint (eLogError, "LeaseSet: Rncorrect 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 = netdb.NewIdentity (buf, len); identity = std::make_shared<IdentityEx>(buf, len);
SetIdentity (identity); SetIdentity (identity);
} }
else else

@ -96,9 +96,6 @@ namespace data
void Encrypt (const uint8_t * data, uint8_t * encrypted) const; void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
bool IsDestination () const { return true; }; bool IsDestination () const { return true; };
// used in webconsole
void ExpireLease () { m_ExpirationTime = i2p::util::GetSecondsSinceEpoch (); };
protected: protected:
void UpdateLeasesBegin (); void UpdateLeasesBegin ();

@ -20,12 +20,11 @@ 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 "debug" // eLogDebug
"debug" // eLogDebug
}; };
/** /**
@ -33,11 +32,10 @@ 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 */
@ -55,7 +53,6 @@ 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;
@ -126,14 +123,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(eLogCritical, "Log: Unknown loglevel: ", level); LogPrint(eLogError, "Log: Unknown loglevel: ", level);
return; return;
} }
LogPrint(eLogInfo, "Log: Logging level set to ", level); LogPrint(eLogInfo, "Log: Logging level set to ", level);
@ -216,7 +212,7 @@ namespace log {
m_LogStream = os; m_LogStream = os;
return; return;
} }
LogPrint(eLogCritical, "Log: Can't open file ", path); LogPrint(eLogError, "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,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -27,7 +27,6 @@
enum LogLevel enum LogLevel
{ {
eLogNone = 0, eLogNone = 0,
eLogCritical,
eLogError, eLogError,
eLogWarning, eLogWarning,
eLogInfo, eLogInfo,
@ -87,8 +86,8 @@ namespace log {
Log (); Log ();
~Log (); ~Log ();
LogType GetLogType () const { return m_Destination; }; LogType GetLogType () { return m_Destination; };
LogLevel GetLogLevel () const { return m_MinLevel; }; LogLevel GetLogLevel () { return m_MinLevel; };
void Start (); void Start ();
void Stop (); void Stop ();
@ -160,11 +159,6 @@ namespace log {
} // log } // log
} // i2p } // i2p
inline bool CheckLogLevel (LogLevel level) noexcept
{
return level <= i2p::log::Logger().GetLogLevel ();
}
/** internal usage only -- folding args array to single string */ /** internal usage only -- folding args array to single string */
template<typename TValue> template<typename TValue>
void LogPrint (std::stringstream& s, TValue&& arg) noexcept void LogPrint (std::stringstream& s, TValue&& arg) noexcept
@ -190,7 +184,9 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
template<typename... TArgs> template<typename... TArgs>
void LogPrint (LogLevel level, TArgs&&... args) noexcept void LogPrint (LogLevel level, TArgs&&... args) noexcept
{ {
if (!CheckLogLevel (level)) return; i2p::log::Log &log = i2p::log::Logger();
if (level > log.GetLogLevel ())
return;
// fold message to single string // fold message to single string
std::stringstream ss; std::stringstream ss;
@ -203,7 +199,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str()); auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str());
msg->tid = std::this_thread::get_id(); msg->tid = std::this_thread::get_id();
i2p::log::Logger().Append(msg); log.Append(msg);
} }
/** /**

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -19,10 +19,9 @@
#include "RouterContext.h" #include "RouterContext.h"
#include "Transports.h" #include "Transports.h"
#include "NetDb.hpp" #include "NetDb.hpp"
#include "NTCP2.h"
#include "HTTP.h" #include "HTTP.h"
#include "util.h" #include "util.h"
#include "Socks5.h"
#include "NTCP2.h"
#if defined(__linux__) && !defined(_NETINET_IN_H) #if defined(__linux__) && !defined(_NETINET_IN_H)
#include <linux/in6.h> #include <linux/in6.h>
@ -129,8 +128,7 @@ namespace transport
options[1] = 2; // ver options[1] = 2; // ver
htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 2, paddingLength); // padLen
// m3p2Len // m3p2Len
auto riBuffer = i2p::context.CopyRouterInfoBuffer (); auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen ();
auto bufLen = riBuffer->GetBufferLen ();
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
htobe16buf (options + 4, m3p2Len); htobe16buf (options + 4, m3p2Len);
// fill m3p2 payload (RouterInfo block) // fill m3p2 payload (RouterInfo block)
@ -139,7 +137,7 @@ namespace transport
m3p2[0] = eNTCP2BlkRouterInfo; // block m3p2[0] = eNTCP2BlkRouterInfo; // block
htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
m3p2[3] = 0; // flag m3p2[3] = 0; // flag
memcpy (m3p2 + 4, riBuffer->data (), bufLen); // TODO: eliminate extra copy memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex
// 2 bytes reserved // 2 bytes reserved
htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds
// 4 bytes reserved // 4 bytes reserved
@ -375,20 +373,9 @@ namespace transport
m_Socket.close (); m_Socket.close ();
transports.PeerDisconnected (shared_from_this ()); transports.PeerDisconnected (shared_from_this ());
m_Server.RemoveNTCP2Session (shared_from_this ()); m_Server.RemoveNTCP2Session (shared_from_this ());
for (auto& it: m_SendQueue)
it->Drop ();
m_SendQueue.clear (); m_SendQueue.clear ();
SetSendQueueSize (0); m_SendQueueSize = 0;
auto remoteIdentity = GetRemoteIdentity (); LogPrint (eLogDebug, "NTCP2: Session terminated");
if (remoteIdentity)
{
LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (),
" (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated");
}
else
{
LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (), " terminated");
}
} }
} }
@ -412,7 +399,6 @@ namespace transport
m_IsEstablished = true; m_IsEstablished = true;
m_Establisher.reset (nullptr); m_Establisher.reset (nullptr);
SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT); SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT);
SendQueue ();
transports.PeerConnected (shared_from_this ()); transports.PeerConnected (shared_from_this ());
} }
@ -438,7 +424,7 @@ namespace transport
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts) void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
{ {
if (m_NextReceivedBuffer && !m_IsReceiving && if (m_NextReceivedBuffer && !m_IsReceiving &&
ts > GetLastActivityTimestamp () + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT) ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
{ {
delete[] m_NextReceivedBuffer; delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = nullptr; m_NextReceivedBuffer = nullptr;
@ -466,7 +452,6 @@ 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));
} }
@ -544,7 +529,6 @@ 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));
} }
@ -558,7 +542,6 @@ 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))
@ -580,11 +563,7 @@ namespace transport
SendSessionConfirmed (); SendSessionConfirmed ();
} }
else else
{
if (GetRemoteIdentity ())
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); // assume wrong s key
Terminate (); Terminate ();
}
} }
} }
@ -667,7 +646,6 @@ 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];
@ -705,22 +683,13 @@ namespace transport
i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag i2p::data::RouterInfo ri (buf.data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
if (ri.IsUnreachable ()) if (ri.IsUnreachable ())
{ {
LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ()); LogPrint (eLogError, "NTCP2: Signature verification failed in SessionConfirmed");
SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail); SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
return; return;
} }
LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (), if (i2p::util::GetMillisecondsSinceEpoch () > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
" (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
{
LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
SendTerminationAndTerminate (eNTCP2Message3Error);
return;
}
if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
{ {
LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds"); LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed");
SendTerminationAndTerminate (eNTCP2Message3Error); SendTerminationAndTerminate (eNTCP2Message3Error);
return; return;
} }
@ -794,7 +763,7 @@ namespace transport
void NTCP2Session::ServerLogin () void NTCP2Session::ServerLogin ()
{ {
SetTerminationTimeout (NTCP2_ESTABLISH_TIMEOUT); SetTerminationTimeout (NTCP2_ESTABLISH_TIMEOUT);
SetLastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
m_Establisher->CreateEphemeralKey (); m_Establisher->CreateEphemeralKey ();
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer, 64), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (), std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (),
@ -838,19 +807,14 @@ namespace transport
CreateNextReceivedBuffer (m_NextReceivedLen); CreateNextReceivedBuffer (m_NextReceivedLen);
boost::system::error_code ec; boost::system::error_code ec;
size_t moreBytes = m_Socket.available(ec); size_t moreBytes = m_Socket.available(ec);
if (!ec) if (!ec && moreBytes >= m_NextReceivedLen)
{ {
if (moreBytes >= m_NextReceivedLen) // read and process message immediately if available
{ moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
// read and process message immediately if available HandleReceived (ec, moreBytes);
moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
HandleReceived (ec, moreBytes);
}
else
Receive ();
} }
else else
LogPrint (eLogWarning, "NTCP2: Socket error: ", ec.message ()); Receive ();
} }
else else
{ {
@ -882,8 +846,9 @@ namespace transport
} }
else else
{ {
UpdateNumReceivedBytes (bytes_transferred + 2); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2); m_NumReceivedBytes += bytes_transferred + 2; // + length
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred);
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false))
@ -911,7 +876,7 @@ namespace transport
auto size = bufbe16toh (frame + offset); auto size = bufbe16toh (frame + offset);
offset += 2; offset += 2;
LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size); LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
if (offset + size > len) if (size > len)
{ {
LogPrint (eLogError, "NTCP2: Unexpected block length ", size); LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
break; break;
@ -1056,11 +1021,6 @@ namespace transport
macBuf = m_NextSendBuffer + paddingLen; macBuf = m_NextSendBuffer + paddingLen;
totalLen += paddingLen; totalLen += paddingLen;
} }
if (totalLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
{
LogPrint (eLogError, "NTCP2: Frame to send is too long ", totalLen);
return;
}
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers
@ -1085,12 +1045,6 @@ namespace transport
delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr; delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
return; return;
} }
if (payloadLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
{
LogPrint (eLogError, "NTCP2: Buffer to send is too long ", payloadLen);
delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
return;
}
// encrypt // encrypt
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
@ -1115,10 +1069,11 @@ namespace transport
} }
else else
{ {
UpdateNumSentBytes (bytes_transferred); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
m_NumSentBytes += bytes_transferred;
i2p::transport::transports.UpdateSentBytes (bytes_transferred); i2p::transport::transports.UpdateSentBytes (bytes_transferred);
LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred); LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred);
if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime) if (m_LastActivityTimestamp > m_NextRouterInfoResendTime)
{ {
m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL + m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD; rand ()%NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
@ -1127,41 +1082,30 @@ namespace transport
else else
{ {
SendQueue (); SendQueue ();
SetSendQueueSize (m_SendQueue.size ()); m_SendQueueSize = m_SendQueue.size ();
} }
} }
} }
void NTCP2Session::SendQueue () void NTCP2Session::SendQueue ()
{ {
if (!m_SendQueue.empty () && m_IsEstablished) if (!m_SendQueue.empty ())
{ {
std::vector<std::shared_ptr<I2NPMessage> > msgs; std::vector<std::shared_ptr<I2NPMessage> > msgs;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
size_t s = 0; size_t s = 0;
while (!m_SendQueue.empty ()) while (!m_SendQueue.empty ())
{ {
auto msg = m_SendQueue.front (); auto msg = m_SendQueue.front ();
if (!msg || msg->IsExpired (ts))
{
// drop null or expired message
if (msg) msg->Drop ();
m_SendQueue.pop_front ();
continue;
}
size_t len = msg->GetNTCP2Length (); size_t len = msg->GetNTCP2Length ();
if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header
{ {
msgs.push_back (msg); msgs.push_back (msg);
s += (len + 3); s += (len + 3);
m_SendQueue.pop_front (); m_SendQueue.pop_front ();
if (s >= NTCP2_SEND_AFTER_FRAME_SIZE)
break; // send frame right a way
} }
else if (len + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) else if (len + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
{ {
LogPrint (eLogError, "NTCP2: I2NP message of size ", len, " can't be sent. Dropped"); LogPrint (eLogError, "NTCP2: I2NP message of size ", len, " can't be sent. Dropped");
msg->Drop ();
m_SendQueue.pop_front (); m_SendQueue.pop_front ();
} }
else else
@ -1171,33 +1115,13 @@ namespace transport
} }
} }
void NTCP2Session::MoveSendQueue (std::shared_ptr<NTCP2Session> other)
{
if (!other || m_SendQueue.empty ()) return;
std::vector<std::shared_ptr<I2NPMessage> > msgs;
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: m_SendQueue)
if (!it->IsExpired (ts))
msgs.push_back (it);
else
it->Drop ();
m_SendQueue.clear ();
if (!msgs.empty ())
other->PostI2NPMessages (msgs);
}
size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len) size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
{ {
if (len < 3) return 0; if (len < 3) return 0;
len -= 3; len -= 3;
if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero
size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100; size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
{
int l = (int)NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
if (l <= 0) return 0;
paddingSize = l;
}
if (paddingSize > len) paddingSize = len; if (paddingSize > len) paddingSize = len;
if (paddingSize) if (paddingSize)
{ {
@ -1206,7 +1130,7 @@ namespace transport
RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes)); RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
m_NextPaddingSize = 0; m_NextPaddingSize = 0;
} }
paddingSize = m_PaddingSizes[m_NextPaddingSize++] % (paddingSize + 1); paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize;
} }
buf[0] = eNTCP2BlkPadding; // blk buf[0] = eNTCP2BlkPadding; // blk
htobe16buf (buf + 1, paddingSize); // size htobe16buf (buf + 1, paddingSize); // size
@ -1217,8 +1141,7 @@ namespace transport
void NTCP2Session::SendRouterInfo () void NTCP2Session::SendRouterInfo ()
{ {
if (!IsEstablished ()) return; if (!IsEstablished ()) return;
auto riBuffer = i2p::context.CopyRouterInfoBuffer (); auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
auto riLen = riBuffer->GetBufferLen ();
size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
// DateTime block // DateTime block
@ -1229,7 +1152,7 @@ namespace transport
m_NextSendBuffer[9] = eNTCP2BlkRouterInfo; m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
m_NextSendBuffer[12] = 0; // flag m_NextSendBuffer[12] = 0; // flag
memcpy (m_NextSendBuffer + 13, riBuffer->data (), riLen); // TODO: eliminate extra copy memcpy (m_NextSendBuffer + 13, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
// padding block // padding block
auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64); auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
payloadLen += paddingSize; payloadLen += paddingSize;
@ -1272,14 +1195,9 @@ namespace transport
void NTCP2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs) void NTCP2Session::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
{ {
if (m_IsTerminated) return; if (m_IsTerminated) return;
bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2;
for (auto it: msgs) for (auto it: msgs)
if (isSemiFull && it->onDrop) m_SendQueue.push_back (std::move (it));
it->Drop (); // drop earlier because we can handle it if (!m_IsSending)
else
m_SendQueue.push_back (std::move (it));
if (!m_IsSending && m_IsEstablished)
SendQueue (); SendQueue ();
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE) else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
{ {
@ -1287,12 +1205,12 @@ namespace transport
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE); GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
Terminate (); Terminate ();
} }
SetSendQueueSize (m_SendQueue.size ()); m_SendQueueSize = m_SendQueue.size ();
} }
void NTCP2Session::SendLocalRouterInfo (bool update) void NTCP2Session::SendLocalRouterInfo (bool update)
{ {
if (update || !IsOutgoing ()) // we send it in SessionConfirmed for outgoing session if (update || !IsOutgoing ()) // we send it in SessionConfirmed for ougoing session
m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
} }
@ -1320,7 +1238,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(eLogCritical, "NTCP2: Failed to resolve proxy ", e.message()); LogPrint(eLogError, "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));
@ -1348,7 +1266,7 @@ namespace transport
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogCritical, "NTCP2: Failed to bind to v4 port ", address->port, ex.what()); LogPrint(eLogError, "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;
} }
@ -1391,7 +1309,7 @@ namespace transport
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogCritical, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what()); LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ()); ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
continue; continue;
} }
@ -1442,7 +1360,6 @@ namespace transport
{ {
// replace by new session // replace by new session
auto s = it->second; auto s = it->second;
s->MoveSendQueue (session);
m_NTCP2Sessions.erase (it); m_NTCP2Sessions.erase (it);
s->Terminate (); s->Terminate ();
} }
@ -1459,11 +1376,7 @@ namespace transport
void NTCP2Server::RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session) void NTCP2Server::RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session)
{ {
if (session && session->GetRemoteIdentity ()) if (session && session->GetRemoteIdentity ())
{ m_NTCP2Sessions.erase (session->GetRemoteIdentity ()->GetIdentHash ());
auto it = m_NTCP2Sessions.find (session->GetRemoteIdentity ()->GetIdentHash ());
if (it != m_NTCP2Sessions.end () && it->second == session)
m_NTCP2Sessions.erase (it);
}
} }
std::shared_ptr<NTCP2Session> NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident) std::shared_ptr<NTCP2Session> NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident)
@ -1481,8 +1394,7 @@ namespace transport
LogPrint (eLogError, "NTCP2: Can't connect to unspecified address"); LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
return; return;
} }
LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint (), LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint ());
" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
GetService ().post([this, conn]() GetService ().post([this, conn]()
{ {
if (this->AddNTCP2Session (conn)) if (this->AddNTCP2Session (conn))
@ -1538,8 +1450,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint (), LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint ());
" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
conn->ClientLogin (); conn->ClientLogin ();
} }
} }
@ -1553,7 +1464,7 @@ namespace transport
if (!ec) if (!ec)
{ {
LogPrint (eLogDebug, "NTCP2: Connected from ", ep); LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
if (!i2p::transport::transports.IsInReservedRange(ep.address ())) if (!i2p::util::net::IsInReservedRange(ep.address ()))
{ {
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second) if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
{ {
@ -1600,7 +1511,7 @@ namespace transport
if (!ec) if (!ec)
{ {
LogPrint (eLogDebug, "NTCP2: Connected from ", ep); LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
if (!i2p::transport::transports.IsInReservedRange(ep.address ()) || if (!i2p::util::net::IsInReservedRange(ep.address ()) ||
i2p::util::net::IsYggdrasilAddress (ep.address ())) i2p::util::net::IsYggdrasilAddress (ep.address ()))
{ {
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second) if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
@ -1748,17 +1659,46 @@ namespace transport
case eSocksProxy: case eSocksProxy:
{ {
// TODO: support username/password auth etc // TODO: support username/password auth etc
Socks5Handshake (conn->GetSocket(), conn->GetRemoteEndpoint (), static const uint8_t buff[3] = {SOCKS5_VER, 0x01, 0x00};
[conn, timer](const boost::system::error_code& ec) boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff, 3), boost::asio::transfer_all(),
{ [] (const boost::system::error_code & ec, std::size_t transferred)
timer->cancel(); {
if (!ec) (void) transferred;
conn->ClientLogin(); if(ec)
else {
LogPrint(eLogWarning, "NTCP2: SOCKS5 write error ", ec.message());
}
});
auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
[this, readbuff, timer, conn](const boost::system::error_code & ec, std::size_t transferred)
{
if(ec)
{ {
LogPrint(eLogError, "NTCP2: SOCKS proxy handshake error ", ec.message()); LogPrint(eLogError, "NTCP2: SOCKS5 read error ", ec.message());
timer->cancel();
conn->Terminate(); conn->Terminate();
return;
} }
else if(transferred == 2)
{
if((*readbuff)[1] == 0x00)
{
AfterSocksHandshake(conn, timer);
return;
}
else if ((*readbuff)[1] == 0xff)
{
LogPrint(eLogError, "NTCP2: SOCKS5 proxy rejected authentication");
timer->cancel();
conn->Terminate();
return;
}
LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]);
}
LogPrint(eLogError, "NTCP2: SOCKS5 server gave invalid response");
timer->cancel();
conn->Terminate();
}); });
break; break;
} }
@ -1827,6 +1767,71 @@ namespace transport
} }
} }
void NTCP2Server::AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer)
{
// build request
size_t sz = 6; // header + port
auto buff = std::make_shared<std::vector<int8_t> >(256);
auto readbuff = std::make_shared<std::vector<int8_t> >(256);
(*buff)[0] = SOCKS5_VER;
(*buff)[1] = SOCKS5_CMD_CONNECT;
(*buff)[2] = 0x00;
auto& ep = conn->GetRemoteEndpoint ();
if(ep.address ().is_v4 ())
{
(*buff)[3] = SOCKS5_ATYP_IPV4;
auto addrbytes = ep.address ().to_v4().to_bytes();
sz += 4;
memcpy(buff->data () + 4, addrbytes.data(), 4);
}
else if (ep.address ().is_v6 ())
{
(*buff)[3] = SOCKS5_ATYP_IPV6;
auto addrbytes = ep.address ().to_v6().to_bytes();
sz += 16;
memcpy(buff->data () + 4, addrbytes.data(), 16);
}
else
{
// We mustn't really fall here because all connections are made to IP addresses
LogPrint(eLogError, "NTCP2: Tried to connect to unexpected address via proxy");
return;
}
htobe16buf(buff->data () + sz - 2, ep.port ());
boost::asio::async_write(conn->GetSocket(), boost::asio::buffer(buff->data (), sz), boost::asio::transfer_all(),
[buff](const boost::system::error_code & ec, std::size_t written)
{
if(ec)
{
LogPrint(eLogError, "NTCP2: Failed to write handshake to socks proxy ", ec.message());
return;
}
});
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), SOCKS5_UDP_IPV4_REQUEST_HEADER_SIZE), // read min reply size
boost::asio::transfer_all(),
[timer, conn, readbuff](const boost::system::error_code & e, std::size_t transferred)
{
if (e)
LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
else if (!(*readbuff)[1]) // succeeded
{
boost::system::error_code ec;
size_t moreBytes = conn->GetSocket ().available(ec);
if (moreBytes) // read remaining portion of reply if ipv6 received
boost::asio::read (conn->GetSocket (), boost::asio::buffer(readbuff->data (), moreBytes), boost::asio::transfer_all (), ec);
timer->cancel();
conn->ClientLogin();
return;
}
else
LogPrint(eLogError, "NTCP2: Proxy reply error ", (int)(*readbuff)[1]);
timer->cancel();
conn->Terminate();
});
}
void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress) void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
{ {
auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0)); auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0));

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2022, 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
* *
@ -28,7 +28,6 @@ namespace transport
{ {
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
const size_t NTCP2_SEND_AFTER_FRAME_SIZE = 16386; // send frame when exceeds this size
const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287; const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287;
const size_t NTCP2_SESSION_CREATED_MAX_SIZE = 287; const size_t NTCP2_SESSION_CREATED_MAX_SIZE = 287;
const int NTCP2_MAX_PADDING_RATIO = 6; // in % const int NTCP2_MAX_PADDING_RATIO = 6; // in %
@ -151,7 +150,6 @@ namespace transport
void SendLocalRouterInfo (bool update) override; // after handshake or by update void SendLocalRouterInfo (bool update) override; // after handshake or by update
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override; void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) override;
void MoveSendQueue (std::shared_ptr<NTCP2Session> other);
private: private:
@ -268,6 +266,7 @@ namespace transport
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
// timer // timer
void ScheduleTermination (); void ScheduleTermination ();

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, 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
* *
@ -10,12 +10,11 @@
#define NETDB_H__ #define NETDB_H__
// this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs // this file is called NetDb.hpp to resolve conflict with libc's netdb.h on case insensitive fs
#include <inttypes.h> #include <inttypes.h>
#include <unordered_set> #include <set>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <future>
#include "Base.h" #include "Base.h"
#include "Gzip.h" #include "Gzip.h"
@ -39,23 +38,16 @@ namespace data
{ {
const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_ROUTERS = 90;
const int NETDB_MIN_FLOODFILLS = 5; const int NETDB_MIN_FLOODFILLS = 5;
const int NETDB_NUM_FLOODFILLS_THRESHOLD = 1000; const int NETDB_MIN_TUNNEL_CREATION_SUCCESS_RATE = 8; // in percents
const int NETDB_NUM_ROUTERS_THRESHOLD = 4*NETDB_NUM_FLOODFILLS_THRESHOLD;
const int NETDB_TUNNEL_CREATION_RATE_THRESHOLD = 10; // in %
const int NETDB_CHECK_FOR_EXPIRATION_UPTIME = 600; // 10 minutes, in seconds
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
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_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 58); // 0.9.58 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
const size_t NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES = 16;
const size_t NETDB_MAX_EXPLORATORY_SELECTION_SIZE = 500;
const int NETDB_EXPLORATORY_SELECTION_UPDATE_INTERVAL = 82; // in seconds. for floodfill
const int NETDB_NEXT_DAY_ROUTER_INFO_THRESHOLD = 45; // in minutes
const int NETDB_NEXT_DAY_LEASESET_THRESHOLD = 10; // in minutes
/** function for visiting a leaseset stored in a floodfill */ /** function for visiting a leaseset stored in a floodfill */
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor; typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
@ -85,22 +77,26 @@ namespace data
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const; std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true); void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true);
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
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, bool endpoint) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse, bool endpoint) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::unordered_set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::unordered_set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::unordered_set<IdentHash>& excluded, bool nextDay = false) const; std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::unordered_set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::vector<IdentHash> GetExploratoryNonFloodfill (const IdentHash& destination, size_t num, const std::unordered_set<IdentHash>& excluded); std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const; std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void ExcludeReachableTransports (const IdentHash& ident, RouterInfo::CompatibleTransports transports);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
void PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); // to NetdbReq thread
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; };
@ -120,11 +116,7 @@ namespace data
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
void ClearRouterInfos () { m_RouterInfos.clear (); }; void ClearRouterInfos () { m_RouterInfos.clear (); };
template<typename... TArgs> std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer (TArgs&&... args)
{
return m_RouterInfoBuffersPool.AcquireSharedMt (std::forward<TArgs>(args)...);
}
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r); bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); }; std::shared_ptr<RouterInfo::Address> NewRouterInfoAddress () { return m_RouterInfoAddressesPool.AcquireSharedMt (); };
boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses () boost::shared_ptr<RouterInfo::Addresses> NewRouterInfoAddresses ()
@ -135,19 +127,17 @@ 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); };
std::shared_ptr<RouterProfile> NewRouterProfile () { return m_RouterProfilesPool.AcquireSharedMt (); }; uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
private: private:
void Load (); void Load ();
bool LoadRouterInfo (const std::string& path, uint64_t ts); bool LoadRouterInfo (const std::string& path, uint64_t ts);
void SaveUpdated (); void SaveUpdated ();
void PersistRouters (std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > >&& update, void Run (); // exploratory thread
std::list<std::string>&& remove); void Explore (int numDestinations);
void Run (); void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg, bool andNextDay = false);
void ManageRouterInfos ();
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
@ -159,10 +149,6 @@ namespace data
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const; std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
private: private:
mutable std::mutex m_LeaseSetsMutex; mutable std::mutex m_LeaseSetsMutex;
@ -181,20 +167,21 @@ namespace data
Families m_Families; Families m_Families;
i2p::fs::HashedStorage m_Storage; i2p::fs::HashedStorage m_Storage;
std::shared_ptr<NetDbRequests> m_Requests; friend class NetDbRequests;
NetDbRequests m_Requests;
bool m_PersistProfiles; bool m_PersistProfiles;
std::future<void> m_SavingProfiles, m_DeletingProfiles, m_PersistingRouters;
std::vector<std::shared_ptr<const RouterInfo> > m_ExploratorySelection; /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
std::set<IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken = 0;
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool; i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
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;
i2p::util::MemoryPoolMt<RouterProfile> m_RouterProfilesPool;
}; };
extern NetDb netdb; extern NetDb netdb;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2024, The PurpleI2P Project * Copyright (c) 2013-2020, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -10,28 +10,12 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Transports.h" #include "Transports.h"
#include "NetDb.hpp" #include "NetDb.hpp"
#include "ECIESX25519AEADRatchetSession.h"
#include "RouterContext.h"
#include "Timestamp.h"
#include "NetDbRequests.h" #include "NetDbRequests.h"
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
RequestedDestination::RequestedDestination (const IdentHash& destination, bool isExploratory, bool direct):
m_Destination (destination), m_IsExploratory (isExploratory), m_IsDirect (direct), m_IsActive (true),
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_LastRequestTime (0), m_NumAttempts (0)
{
if (i2p::context.IsFloodfill ())
m_ExcludedPeers.insert (i2p::context.GetIdentHash ()); // exclude self if floodfill
}
RequestedDestination::~RequestedDestination ()
{
InvokeRequestComplete (nullptr);
}
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router, std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{ {
@ -44,8 +28,7 @@ namespace data
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
if(router) if(router)
m_ExcludedPeers.insert (router->GetIdentHash ()); m_ExcludedPeers.insert (router->GetIdentHash ());
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch (); m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
m_NumAttempts++;
return msg; return msg;
} }
@ -54,154 +37,80 @@ namespace data
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
m_ExcludedPeers.insert (floodfill); m_ExcludedPeers.insert (floodfill);
m_NumAttempts++; m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
m_LastRequestTime = i2p::util::GetSecondsSinceEpoch ();
return msg; return msg;
} }
bool RequestedDestination::IsExcluded (const IdentHash& ident) const
{
return m_ExcludedPeers.count (ident);
}
void RequestedDestination::ClearExcludedPeers () void RequestedDestination::ClearExcludedPeers ()
{ {
m_ExcludedPeers.clear (); m_ExcludedPeers.clear ();
} }
void RequestedDestination::InvokeRequestComplete (std::shared_ptr<RouterInfo> r)
{
if (!m_RequestComplete.empty ())
{
for (auto it: m_RequestComplete)
if (it != nullptr) it (r);
m_RequestComplete.clear ();
}
}
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r) void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
{ {
if (m_IsActive) if (m_RequestComplete)
{ {
m_IsActive = false; m_RequestComplete (r);
InvokeRequestComplete (r); m_RequestComplete = nullptr;
} }
} }
void RequestedDestination::Fail () void RequestedDestination::Fail ()
{ {
if (m_IsActive) if (m_RequestComplete)
{ {
m_IsActive = false; m_RequestComplete (nullptr);
InvokeRequestComplete (nullptr); m_RequestComplete = nullptr;
} }
} }
NetDbRequests::NetDbRequests ():
RunnableServiceWithWork ("NetDbReq"),
m_ManageRequestsTimer (GetIOService ()), m_ExploratoryTimer (GetIOService ()),
m_CleanupTimer (GetIOService ()), m_DiscoveredRoutersTimer (GetIOService ()),
m_Rng(i2p::util::GetMonotonicMicroseconds () % 1000000LL)
{
}
NetDbRequests::~NetDbRequests ()
{
Stop ();
}
void NetDbRequests::Start () void NetDbRequests::Start ()
{ {
if (!IsRunning ())
{
StartIOService ();
ScheduleManageRequests ();
ScheduleCleanup ();
if (!i2p::context.IsHidden ())
ScheduleExploratory (EXPLORATORY_REQUEST_INTERVAL);
}
} }
void NetDbRequests::Stop () void NetDbRequests::Stop ()
{ {
if (IsRunning ()) m_RequestedDestinations.clear ();
{
m_ManageRequestsTimer.cancel ();
m_ExploratoryTimer.cancel ();
m_CleanupTimer.cancel ();
StopIOService ();
m_RequestedDestinations.clear ();
m_RequestedDestinationsPool.CleanUpMt ();
}
}
void NetDbRequests::ScheduleCleanup ()
{
m_CleanupTimer.expires_from_now (boost::posix_time::seconds(REQUESTED_DESTINATIONS_POOL_CLEANUP_INTERVAL));
m_CleanupTimer.async_wait (std::bind (&NetDbRequests::HandleCleanupTimer,
this, std::placeholders::_1));
} }
void NetDbRequests::HandleCleanupTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
m_RequestedDestinationsPool.CleanUpMt ();
ScheduleCleanup ();
}
}
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
bool isExploratory, bool direct, RequestedDestination::RequestComplete requestComplete)
{ {
// request RouterInfo directly // request RouterInfo directly
auto dest = m_RequestedDestinationsPool.AcquireSharedMt (destination, isExploratory, direct); auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
if (requestComplete) dest->SetRequestComplete (requestComplete);
dest->AddRequestComplete (requestComplete);
auto ret = m_RequestedDestinations.emplace (destination, dest);
if (!ret.second) // not inserted
{ {
dest->ResetRequestComplete (); // don't call requestComplete in destructor std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
dest = ret.first->second; // existing one if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
if (requestComplete) return nullptr;
{
if (dest->IsActive ())
dest->AddRequestComplete (requestComplete);
else
requestComplete (nullptr);
}
return nullptr;
} }
return dest; return dest;
} }
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r) void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
{ {
GetIOService ().post ([this, ident, r]() std::shared_ptr<RequestedDestination> request;
{
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
auto it = m_RequestedDestinations.find (ident);
if (it != m_RequestedDestinations.end ())
{ {
std::shared_ptr<RequestedDestination> request; request = it->second;
auto it = m_RequestedDestinations.find (ident); m_RequestedDestinations.erase (it);
if (it != m_RequestedDestinations.end ()) }
{ }
request = it->second; if (request)
if (request->IsExploratory ()) {
m_RequestedDestinations.erase (it); if (r)
// otherwise cache for a while request->Success (r);
} else
if (request) request->Fail ();
{ }
if (r)
request->Success (r);
else
request->Fail ();
}
});
} }
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
{ {
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
auto it = m_RequestedDestinations.find (ident); auto it = m_RequestedDestinations.find (ident);
if (it != m_RequestedDestinations.end ()) if (it != m_RequestedDestinations.end ())
return it->second; return it->second;
@ -211,344 +120,48 @@ namespace data
void NetDbRequests::ManageRequests () void NetDbRequests::ManageRequests ()
{ {
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
{ {
auto& dest = it->second; auto& dest = it->second;
if (dest->IsActive () || ts < dest->GetCreationTime () + REQUEST_CACHE_TIME) bool done = false;
if (ts < dest->GetCreationTime () + 60) // request is worthless after 1 minute
{ {
if (!dest->IsExploratory ()) if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
{ {
// regular request auto count = dest->GetExcludedPeers ().size ();
bool done = false; if (!dest->IsExploratory () && count < 7)
if (ts < dest->GetCreationTime () + MAX_REQUEST_TIME)
{
if (ts > dest->GetLastRequestTime () + MIN_REQUEST_TIME) // try next floodfill if no response after min interval
done = !SendNextRequest (dest);
}
else // request is expired
done = true;
if (done)
dest->Fail ();
it++;
}
else
{
// exploratory
if (ts >= dest->GetCreationTime () + MAX_EXPLORATORY_REQUEST_TIME)
{
dest->Fail ();
it = m_RequestedDestinations.erase (it); // delete expired exploratory request right a way
}
else
it++;
}
}
else
it = m_RequestedDestinations.erase (it);
}
}
bool NetDbRequests::SendNextRequest (std::shared_ptr<RequestedDestination> dest)
{
if (!dest || !dest->IsActive ()) return false;
bool ret = true;
auto count = dest->GetNumAttempts ();
if (!dest->IsExploratory () && count < MAX_NUM_REQUEST_ATTEMPTS)
{
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill)
{
bool direct = dest->IsDirect ();
if (direct && !nextFloodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
!i2p::transport::transports.IsConnected (nextFloodfill->GetIdentHash ()))
direct = false; // floodfill can't be reached directly
auto s = shared_from_this ();
auto onDrop = [s, dest]()
{
if (dest->IsActive ())
{
s->GetIOService ().post ([s, dest]()
{
if (dest->IsActive ()) s->SendNextRequest (dest);
});
}
};
if (direct)
{
if (CheckLogLevel (eLogDebug))
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " directly");
auto msg = dest->CreateRequestMessage (nextFloodfill->GetIdentHash ());
msg->onDrop = onDrop;
i2p::transport::transports.SendMessage (nextFloodfill->GetIdentHash (), msg);
}
else
{
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
if (pool)
{ {
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool->GetNextOutboundTunnel (); auto outbound = pool->GetNextOutboundTunnel ();
auto inbound = pool->GetNextInboundTunnel (); auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound) if (nextFloodfill && outbound && inbound)
{ outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
if (CheckLogLevel (eLogDebug)) dest->CreateRequestMessage (nextFloodfill, inbound));
LogPrint (eLogDebug, "NetDbReq: Try ", dest->GetDestination ().ToBase64 (), " at ", count, " floodfill ", nextFloodfill->GetIdentHash ().ToBase64 (), " through tunnels");
auto msg = dest->CreateRequestMessage (nextFloodfill, inbound);
msg->onDrop = onDrop;
outbound->SendTunnelDataMsgTo (nextFloodfill->GetIdentHash (), 0,
i2p::garlic::WrapECIESX25519MessageForRouter (msg, nextFloodfill->GetIdentity ()->GetEncryptionPublicKey ()));
}
else else
{ {
ret = false; done = true;
if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels"); if (!inbound) LogPrint (eLogWarning, "NetDbReq: No inbound tunnels");
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels"); if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
} }
} }
else else
{ {
ret = false; if (!dest->IsExploratory ())
LogPrint (eLogWarning, "NetDbReq: Exploratory pool is not ready"); LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
done = true;
} }
} }
} }
else else // delete obsolete request
{ done = true;
ret = false;
LogPrint (eLogWarning, "NetDbReq: No more floodfills for ", dest->GetDestination ().ToBase64 (), " after ", count, "attempts");
}
}
else
{
if (!dest->IsExploratory ())
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after ", MAX_NUM_REQUEST_ATTEMPTS," attempts");
ret = false;
}
return ret;
}
void NetDbRequests::ScheduleManageRequests ()
{
m_ManageRequestsTimer.expires_from_now (boost::posix_time::seconds(MANAGE_REQUESTS_INTERVAL));
m_ManageRequestsTimer.async_wait (std::bind (&NetDbRequests::HandleManageRequestsTimer,
this, std::placeholders::_1));
}
void NetDbRequests::HandleManageRequestsTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
if (i2p::tunnel::tunnels.GetExploratoryPool ()) // expolratory pool is ready?
ManageRequests ();
ScheduleManageRequests ();
}
}
void NetDbRequests::PostDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
{
GetIOService ().post ([this, msg]()
{
HandleDatabaseSearchReplyMsg (msg);
});
}
void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg)
{
const uint8_t * buf = msg->GetPayload ();
char key[48];
int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48);
key[l] = 0;
size_t num = buf[32]; // num
LogPrint (eLogDebug, "NetDbReq: DatabaseSearchReply for ", key, " num=", num);
IdentHash ident (buf);
bool isExploratory = false;
auto dest = FindRequest (ident);
if (dest && dest->IsActive ())
{
isExploratory = dest->IsExploratory ();
if (!isExploratory && (num > 0 || dest->GetNumAttempts () < 3)) // before 3-rd attempt might be just bad luck
{
// try to send next requests
if (!SendNextRequest (dest))
RequestComplete (ident, nullptr);
}
else
// no more requests for destination possible. delete it
RequestComplete (ident, nullptr);
}
else /*if (!m_FloodfillBootstrap)*/
{
LogPrint (eLogInfo, "NetDbReq: Unsolicited or late database search reply for ", key);
return;
}
// try responses
if (num > NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES)
{
LogPrint (eLogWarning, "NetDbReq: Too many peer hashes ", num, " in database search reply, Reduced to ", NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES);
num = NETDB_MAX_NUM_SEARCH_REPLY_PEER_HASHES;
}
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
{
// request outstanding routers
for (auto it: m_DiscoveredRouterHashes)
RequestRouter (it);
m_DiscoveredRouterHashes.clear ();
m_DiscoveredRoutersTimer.cancel ();
}
for (size_t i = 0; i < num; i++)
{
IdentHash router (buf + 33 + i*32);
if (CheckLogLevel (eLogDebug))
LogPrint (eLogDebug, "NetDbReq: ", i, ": ", router.ToBase64 ());
if (isExploratory)
// postpone request
m_DiscoveredRouterHashes.push_back (router);
else
// send request right a way
RequestRouter (router);
}
if (isExploratory && !m_DiscoveredRouterHashes.empty ())
ScheduleDiscoveredRoutersRequest ();
}
void NetDbRequests::RequestRouter (const IdentHash& router)
{
auto r = netdb.FindRouter (router);
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
{
// router with ident not found or too old (1 hour)
LogPrint (eLogDebug, "NetDbReq: Found new/outdated router. Requesting RouterInfo...");
if (!IsRouterBanned (router))
RequestDestination (router, nullptr, true);
else
LogPrint (eLogDebug, "NetDbReq: Router ", router.ToBase64 (), " is banned. Skipped");
}
else
LogPrint (eLogDebug, "NetDbReq: [:|||:]");
}
void NetDbRequests::PostRequestDestination (const IdentHash& destination,
const RequestedDestination::RequestComplete& requestComplete, bool direct)
{
GetIOService ().post ([this, destination, requestComplete, direct]()
{
RequestDestination (destination, requestComplete, direct);
});
}
void NetDbRequests::RequestDestination (const IdentHash& destination, const RequestedDestination::RequestComplete& requestComplete, bool direct)
{
auto dest = CreateRequest (destination, false, direct, requestComplete); // non-exploratory
if (dest)
{
if (!SendNextRequest (dest))
RequestComplete (destination, nullptr);
}
else
LogPrint (eLogWarning, "NetDbReq: Destination ", destination.ToBase64(), " is requested already or cached");
}
void NetDbRequests::Explore (int numDestinations)
{
// new requests
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
bool throughTunnels = outbound && inbound;
uint8_t randomHash[32];
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
LogPrint (eLogInfo, "NetDbReq: Exploring new ", numDestinations, " routers ...");
for (int i = 0; i < numDestinations; i++)
{
RAND_bytes (randomHash, 32);
auto dest = CreateRequest (randomHash, true, !throughTunnels); // exploratory
if (!dest)
{
LogPrint (eLogWarning, "NetDbReq: Exploratory destination is requested already");
return;
}
auto floodfill = netdb.GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill)
{
if (i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
throughTunnels = false;
if (throughTunnels)
{
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeRouter,
floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg () // tell floodfill about us
});
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeRouter,
floodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (floodfill, inbound) // explore
});
}
else
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
}
else
RequestComplete (randomHash, nullptr);
}
if (throughTunnels && msgs.size () > 0)
outbound->SendTunnelDataMsgs (msgs);
}
void NetDbRequests::ScheduleExploratory (uint64_t interval) if (done)
{ it = m_RequestedDestinations.erase (it);
m_ExploratoryTimer.expires_from_now (boost::posix_time::seconds(interval));
m_ExploratoryTimer.async_wait (std::bind (&NetDbRequests::HandleExploratoryTimer,
this, std::placeholders::_1));
}
void NetDbRequests::HandleExploratoryTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
auto numRouters = netdb.GetNumRouters ();
auto nextExploratoryInterval = numRouters < 2500 ? (EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL)/2 :
EXPLORATORY_REQUEST_INTERVAL + m_Rng () % EXPLORATORY_REQUEST_INTERVAL_VARIANCE;
if (numRouters)
{
if (i2p::transport::transports.IsOnline () && i2p::transport::transports.IsRunning ())
{
// explore only if online
numRouters = 800/numRouters;
if (numRouters < 1) numRouters = 1;
if (numRouters > 9) numRouters = 9;
Explore (numRouters);
}
}
else else
LogPrint (eLogError, "NetDbReq: No known routers, reseed seems to be totally failed"); ++it;
ScheduleExploratory (nextExploratoryInterval);
}
}
void NetDbRequests::ScheduleDiscoveredRoutersRequest ()
{
m_DiscoveredRoutersTimer.expires_from_now (boost::posix_time::milliseconds(
DISCOVERED_REQUEST_INTERVAL + m_Rng () % DISCOVERED_REQUEST_INTERVAL_VARIANCE));
m_DiscoveredRoutersTimer.async_wait (std::bind (&NetDbRequests::HandleDiscoveredRoutersTimer,
this, std::placeholders::_1));
}
void NetDbRequests::HandleDiscoveredRoutersTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
if (!m_DiscoveredRouterHashes.empty ())
{
RequestRouter (m_DiscoveredRouterHashes.front ());
m_DiscoveredRouterHashes.pop_front ();
if (!m_DiscoveredRouterHashes.empty ()) // more hashes to request
ScheduleDiscoveredRoutersRequest ();
}
} }
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save