Compare commits

..

4 Commits

Author SHA1 Message Date
R4SAS
a7a882582f [gha] test again with 20.04
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2023-01-22 20:42:32 +03:00
R4SAS
250696a7b5 [gha] revert to 18.04, change static build options
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2023-01-22 20:34:44 +03:00
R4SAS
af7905744e [gha] update ubuntu build base to 20.04
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2023-01-22 19:12:01 +03:00
R4SAS
db2364e9aa [gha] add ubuntu static build
Signed-off-by: R4SAS <r4sas@i2pmail.org>
2023-01-22 19:03:49 +03:00
109 changed files with 1768 additions and 3819 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,52 +0,0 @@
name: Build on Windows with MSVC
on: [push, pull_request]
jobs:
build:
name: Build
runs-on: windows-latest
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Build and install zlib
run: |
powershell -Command "(Invoke-WebRequest -Uri https://raw.githubusercontent.com/r4sas/zlib.install/master/install.bat -OutFile install_zlib.bat)"
powershell -Command "(Get-Content install_zlib.bat) | Set-Content install_zlib.bat" # fixing line endings
set BUILD_TYPE=Debug
./install_zlib.bat
set BUILD_TYPE=Release
./install_zlib.bat
del install_zlib.bat
- name: Install Boost
uses: crazy-max/ghaction-chocolatey@v2
with:
args: install boost-msvc-14.3
- name: Install OpenSSL
uses: crazy-max/ghaction-chocolatey@v2
with:
args: install openssl
- name: Configure
working-directory: build
run: cmake -DWITH_STATIC=ON .
- name: Build
working-directory: build
run: cmake --build . --config Debug -- -m
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: i2pd-msvc
path: build/Debug/i2pd.*

View File

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

View File

@@ -5,45 +5,50 @@ on: [push, pull_request]
jobs: jobs:
build-make: build-make:
name: Make with USE_UPNP=${{ matrix.with_upnp }} name: Make with USE_UPNP=${{ matrix.with_upnp }}
runs-on: ubuntu-latest runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
with_upnp: ['yes', 'no'] with_upnp: ['yes', 'no']
steps: steps:
- name: Checkout - uses: actions/checkout@v2
uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application - name: build application
run: make USE_UPNP=${{ matrix.with_upnp }} -j3 run: make USE_UPNP=${{ matrix.with_upnp }} -j3
build-cmake: build-cmake:
name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }} name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }}
runs-on: ubuntu-latest runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
with_upnp: ['ON', 'OFF'] with_upnp: ['ON', 'OFF']
steps: steps:
- name: Checkout - uses: actions/checkout@v2
uses: actions/checkout@v3
- name: install packages - name: install packages
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential cmake libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev sudo apt-get install build-essential cmake libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application - name: build application
run: | run: |
cd build cd build
cmake -DWITH_UPNP=${{ matrix.with_upnp }} . cmake -DWITH_UPNP=${{ matrix.with_upnp }} .
make -j3 make -j3
build-static:
name: Static build with UPnP
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: install packages
run: |
sudo apt-get update
sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application
run: make DEBUG=no USE_STATIC=yes USE_UPNP=yes -j`nproc`
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: i2pd-amd64-static
path: i2pd

View File

@@ -10,7 +10,6 @@ on:
jobs: jobs:
build: build:
name: Building container for ${{ matrix.platform }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
packages: write packages: write
@@ -27,7 +26,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v2
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
@@ -58,12 +57,9 @@ jobs:
tags: | tags: |
purplei2p/i2pd:latest-${{ matrix.archname }} purplei2p/i2pd:latest-${{ matrix.archname }}
ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }} ghcr.io/purplei2p/i2pd:latest-${{ matrix.archname }}
provenance: false
push: push:
name: Pushing merged manifest
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
packages: write packages: write
contents: read contents: read
@@ -72,7 +68,7 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v2
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v2
@@ -94,37 +90,51 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push latest manifest image to Docker Hub - name: Create and push latest manifest image to Docker Hub
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: Noelware/docker-manifest-action@master uses: Noelware/docker-manifest-action@master
with: with:
inputs: purplei2p/i2pd:latest base-image: purplei2p/i2pd:latest
images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
push: true push: true
- name: Create and push latest manifest image to GHCR - name: Create and push latest manifest image to GHCR
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
uses: Noelware/docker-manifest-action@master uses: Noelware/docker-manifest-action@master
with: with:
inputs: ghcr.io/purplei2p/i2pd:latest base-image: ghcr.io/purplei2p/i2pd:latest
images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
push: true push: true
- name: Store release version to env - name: Store release version to env
if: ${{ startsWith(github.ref, 'refs/tags/') }} if: ${{ startsWith(github.ref, 'refs/tags/') }}
run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
- name: Create and push release manifest to Docker Hub - name: Create and push release manifest image to Docker Hub
if: ${{ startsWith(github.ref, 'refs/tags/') }} if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: Noelware/docker-manifest-action@master uses: Noelware/docker-manifest-action@master
with: with:
inputs: purplei2p/i2pd:latest,purplei2p/i2pd:latest-release,purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} base-image: purplei2p/i2pd:latest-release
images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7 extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
push: true push: true
- name: Create and push release manifest to GHCR - name: Create and push release manifest image to GHCR
if: ${{ startsWith(github.ref, 'refs/tags/') }} if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: Noelware/docker-manifest-action@master uses: Noelware/docker-manifest-action@master
with: with:
inputs: ghcr.io/purplei2p/i2pd:latest,ghcr.io/purplei2p/i2pd:latest-release,ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} base-image: ghcr.io/purplei2p/i2pd:latest-release
images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7 extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
push: true
- name: Create and push versioned manifest image to Docker Hub
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: Noelware/docker-manifest-action@master
with:
base-image: purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
extra-images: purplei2p/i2pd:latest-amd64,purplei2p/i2pd:latest-i386,purplei2p/i2pd:latest-arm64,purplei2p/i2pd:latest-armv7
push: true
- name: Create and push versioned manifest image to GHCR
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: Noelware/docker-manifest-action@master
with:
base-image: ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
extra-images: ghcr.io/purplei2p/i2pd:latest-amd64,ghcr.io/purplei2p/i2pd:latest-i386,ghcr.io/purplei2p/i2pd:latest-arm64,ghcr.io/purplei2p/i2pd:latest-armv7
push: true push: true

View File

@@ -1,59 +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.47.0] - 2023-03-11
### Added
- Congestion caps
- SAM UDP port parameter
- Support domain addresses for yggdrasil reseeds
### Changed
- DHT for floodfills instead plain list
- Process router's messages in separate thread
- Don't publish non-reachable router
- Send and check target destination in first streaming SYN packet
- Reseeds list
### Fixed
- Memory leak in windows network state detection
- Reseed attempts from invalid address
## [2.46.1] - 2023-02-20
### Fixed
- Race condition while getting router's peer profile
- Creation of new router.info
- Displaying LeaseSets in the webconsole
- Crash when processing ACK request
## [2.46.0] - 2023-02-15
### Added
- Limit number of acked SSU2 packets to 511
- Localization to Swedish, Portuguese, Turkish, Polish
- Periodically send Datetime block in NTCP2 and SSU2
- Don't select random port from reserved
- In memory table for peer profiles
- Store if router was unreachable in it's peer profile
- Show IPv6 addresses in square brackets in webconsole
- Check referer when processing Addresshelper
### Changed
- Algorithm for tunnel creation success rate calculation
- Drop incoming NTCP2 and SSU2 connection if published IP doesn't match actual endpoint
- Exclude actually unreachable router from netdb for 2 hours
- Select first hop from high bandwidth peers for client tunnels
- Drop too long or too short LeaseSet
- Delete router from netdb if became invalid after update
- Terminate existing session if clock skew detected
- Close previous UDP socket if open before reopening
- Minimal version for floodfill is 0.9.51
- Sort transports by endpoints in webconsole
### Fixed
- Deadlock during processing I2NP block with Garlic in ECIES encrypted message to router
- Race condition with encrypted LeaseSets
- HTTP query detection
- Connection attempts to IPs from invalid ranges
- Publish "0.0.0.0" in RouterInfo
- Crash upon receiving PeerTest 7
- Tunnels for closed SAM session socket
- Missing NTCP2 address in RouterInfo if enabled back
## [2.45.1] - 2023-01-11 ## [2.45.1] - 2023-01-11
### Added ### Added
- Full Cone NAT status error - Full Cone NAT status error

View File

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

View File

@@ -6,8 +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.
NEEDED_CXXFLAGS = -std=c++11 NEEDED_CXXFLAGS = -std=c++11 -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
LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread

View File

@@ -33,38 +33,26 @@ endif
NEEDED_CXXFLAGS += -fPIC NEEDED_CXXFLAGS += -fPIC
ifeq ($(USE_STATIC),yes) LDLIBS += -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lssl -lcrypto -lz
# NOTE: on glibc you will get this warning:
# Using 'getaddrinfo' in statically linked applications requires at runtime
# the shared libraries from the glibc version used for linking
LIBDIR := /usr/lib/$(SYS)
LDLIBS += $(LIBDIR)/libboost_system.a
LDLIBS += $(LIBDIR)/libboost_date_time.a
LDLIBS += $(LIBDIR)/libboost_filesystem.a
LDLIBS += $(LIBDIR)/libboost_program_options.a
LDLIBS += $(LIBDIR)/libssl.a
LDLIBS += $(LIBDIR)/libcrypto.a
LDLIBS += $(LIBDIR)/libz.a
ifeq ($(USE_UPNP),yes)
LDLIBS += $(LIBDIR)/libminiupnpc.a
endif
LDLIBS += -lpthread -ldl
else
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
ifeq ($(USE_UPNP),yes)
LDLIBS += -lminiupnpc
endif
endif
# UPNP Support (miniupnpc 1.5 and higher) # UPNP Support (miniupnpc 1.5 and higher)
ifeq ($(USE_UPNP),yes) ifeq ($(USE_UPNP),yes)
DEFINES += -DUSE_UPNP LDLIBS += -lminiupnpc
NEEDED_CXXFLAGS += -DUSE_UPNP
endif
# NOTE: on glibc you will get this warning:
# Using 'getaddrinfo' in statically linked applications requires at runtime
# the shared libraries from the glibc version used for linking
ifeq ($(USE_STATIC),yes)
LDLIBS += -static -ldl -lpthread -static-libgcc -static-libstdc++
else
LDLIBS += -lpthread
endif endif
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
NEEDED_CXXFLAGS += -maes NEEDED_CXXFLAGS += -D__AES__ -maes
DEFINES += -D__AES__
endif endif
endif endif

View File

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

View File

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

View File

@@ -64,7 +64,7 @@ namespace util
//setlocale(LC_ALL, "Russian"); //setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C"); setlocale(LC_TIME, "C");
#ifdef WIN32_APP #ifdef WIN32_APP
if (!i2p::win32::StartWin32App (isDaemon)) return false; if (!i2p::win32::StartWin32App ()) return false;
#endif #endif
bool ret = Daemon_Singleton::start(); bool ret = Daemon_Singleton::start();
if (ret && i2p::log::Logger().GetLogType() == eLogFile) if (ret && i2p::log::Logger().GetLogType() == eLogFile)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -21,7 +21,7 @@ BOOL I2PService::isService()
HWINSTA hWinStation = GetProcessWindowStation(); HWINSTA hWinStation = GetProcessWindowStation();
if (hWinStation != NULL) if (hWinStation != NULL)
{ {
USEROBJECTFLAGS uof = { FALSE, FALSE, 0 }; USEROBJECTFLAGS uof = { 0 };
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0)) if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
{ {
bIsService = TRUE; bIsService = TRUE;

14
build/.gitignore vendored
View File

@@ -1,13 +1,6 @@
# Various generated files # Various generated files
/CMakeFiles/ /CMakeFiles/
/Testing/
/tests/
/.ninja_*
/arch.c
/build.ninja
/i2pd /i2pd
/i2pd.exe
/i2pd.exe.debug
/libi2pd.a /libi2pd.a
/libi2pdclient.a /libi2pdclient.a
/libi2pdlang.a /libi2pdlang.a
@@ -15,13 +8,8 @@
/CMakeCache.txt /CMakeCache.txt
/CPackConfig.cmake /CPackConfig.cmake
/CPackSourceConfig.cmake /CPackSourceConfig.cmake
/CTestTestfile.cmake
/install_manifest.txt /install_manifest.txt
/Makefile /arch.c
# windows build script # windows build script
i2pd*.zip i2pd*.zip
build*.log build*.log
# MVS project files
*.vcxproj
*.vcxproj.filters
*.sln

View File

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

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2017-2023, The PurpleI2P Project # Copyright (c) 2017-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
# See full license text in LICENSE file at top of project tree # See full license text in LICENSE file at top of project tree
@@ -18,7 +18,7 @@ set(archdetect_c_code "
|| defined(_M_ARM64) \\ || defined(_M_ARM64) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8) || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8)
#error cmake_ARCH arm64 #error cmake_ARCH arm64
#elif defined(__ARM_ARCH_7__) \\ #if defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\ || defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\ || defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\ || defined(__ARM_ARCH_7M__) \\
@@ -83,13 +83,13 @@ function(target_architecture output_var)
# First let's normalize the order of the values # First let's normalize the order of the values
# Note that it's not possible to compile PowerPC applications if you are using # Note that it's not possible to compile PowerPC applications if you are using
# the OS X SDK version 10.7 or later - you'll need 10.4/10.5/10.6 for that, so we # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
# disable it by default. Also, ppc64 is not supported in 10.6. # disable it by default
# See this page for more information: # See this page for more information:
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4 # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime. # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise; 10.6 also supports ppc. # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES}) foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
if("${osx_arch}" STREQUAL "ppc" AND ppc_support) if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
@@ -133,11 +133,11 @@ function(target_architecture output_var)
enable_language(C) enable_language(C)
# Detect the architecture in a rather creative way... # Detect the architecture in a rather creative way...
# This compiles a small C program which is a series of ifdefs that selects # This compiles a small C program which is a series of ifdefs that selects a
# a particular #error preprocessor directive whose message string contains # particular #error preprocessor directive whose message string contains the
# the target architecture. The program will always fail to compile (both because # target architecture. The program will always fail to compile (both because
# file is not a valid C program, and obviously because of the presence of # file is not a valid C program, and obviously because of the presence of the
# the #error preprocessor directives... but by exploiting the preprocessor in this # #error preprocessor directives... but by exploiting the preprocessor in this
# way, we can detect the correct target architecture even when cross-compiling, # way, we can detect the correct target architecture even when cross-compiling,
# since the program itself never needs to be run (only the compiler/preprocessor) # since the program itself never needs to be run (only the compiler/preprocessor)
try_run( try_run(

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ out: {"$1", "$2"},\n
``` ```
``` ```
in: ^#[:.,](.*)$\n in: ^#[:.](.*)$\n
out: <to empty line> out: <to empty line>
``` ```

View File

@@ -129,8 +129,7 @@ port = 7070
# pass = changeme # pass = changeme
## Select webconsole language ## Select webconsole language
## Currently supported english (default), afrikaans, armenian, chinese, czech, french, ## Currently supported english (default), afrikaans, armenian, chinese, czech, french,
## german, italian, polish, portuguese, russian, spanish, turkish, turkmen, ukrainian ## german, italian, russian, spanish, turkmen, ukrainian and uzbek languages
## and uzbek languages
# lang = english # lang = english
[httpproxy] [httpproxy]
@@ -168,10 +167,9 @@ port = 4447
[sam] [sam]
## Comment or set to 'false' to disable SAM Bridge ## Comment or set to 'false' to disable SAM Bridge
enabled = true enabled = true
## Address and ports service will listen on ## Address and port service will listen on
# address = 127.0.0.1 # address = 127.0.0.1
# port = 7656 # port = 7656
# portudp = 7655
[bob] [bob]
## Uncomment and set to 'true' to enable BOB command channel ## Uncomment and set to 'true' to enable BOB command channel

View File

@@ -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.47.0 Version: 2.45.1
Release: git%{git_hash}%{?dist} Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd Conflicts: i2pd
@@ -158,15 +158,6 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Sat Mar 11 2023 orignal <orignal@i2pmail.org> - 2.47.0
- update to 2.47.0
* Mon Feb 20 2023 r4sas <r4sas@i2pmail.org> - 2.46.1
- update to 2.46.1
* Wed Feb 15 2023 orignal <orignal@i2pmail.org> - 2.46.0
- update to 2.46.0
* Wed Jan 11 2023 orignal <orignal@i2pmail.org> - 2.45.1 * Wed Jan 11 2023 orignal <orignal@i2pmail.org> - 2.45.1
- update to 2.45.1 - update to 2.45.1

View File

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

View File

@@ -179,7 +179,7 @@ namespace util
uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels); uint16_t transitTunnels; i2p::config::GetOption("limits.transittunnels", transitTunnels);
if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels")) if (isFloodfill && i2p::config::IsDefault ("limits.transittunnels"))
transitTunnels *= 2; // double default number of transit tunnels for floodfill transitTunnels *= 2; // double default number of transit tunnels for floodfill
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (transitTunnels); SetMaxNumTransitTunnels (transitTunnels);
/* this section also honors 'floodfill' flag, if set above */ /* this section also honors 'floodfill' flag, if set above */
std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth); std::string bandwidth; i2p::config::GetOption("bandwidth", bandwidth);
@@ -269,7 +269,7 @@ namespace util
if (hidden) if (hidden)
{ {
LogPrint(eLogInfo, "Daemon: Hidden mode enabled"); LogPrint(eLogInfo, "Daemon: Hidden mode enabled");
i2p::context.SetHidden(true); i2p::data::netdb.SetHidden(true);
} }
std::string httpLang; i2p::config::GetOption("http.lang", httpLang); std::string httpLang; i2p::config::GetOption("http.lang", httpLang);
@@ -334,12 +334,10 @@ namespace util
} }
} }
LogPrint(eLogInfo, "Daemon: Starting Tunnels"); LogPrint(eLogInfo, "Daemon: Starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
LogPrint(eLogInfo, "Daemon: Starting Router context");
i2p::context.Start();
LogPrint(eLogInfo, "Daemon: Starting Client"); LogPrint(eLogInfo, "Daemon: Starting Client");
i2p::client::context.Start (); i2p::client::context.Start ();
@@ -368,8 +366,6 @@ namespace util
LogPrint(eLogInfo, "Daemon: Shutting down"); LogPrint(eLogInfo, "Daemon: Shutting down");
LogPrint(eLogInfo, "Daemon: Stopping Client"); LogPrint(eLogInfo, "Daemon: Stopping Client");
i2p::client::context.Stop(); i2p::client::context.Stop();
LogPrint(eLogInfo, "Daemon: Stopping Router context");
i2p::context.Stop();
LogPrint(eLogInfo, "Daemon: Stopping Tunnels"); LogPrint(eLogInfo, "Daemon: Stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();

View File

@@ -289,11 +289,6 @@ namespace http {
if (family.length () > 0) if (family.length () > 0)
s << "<b>"<< tr("Family") << ":</b> " << family << "<br>\r\n"; s << "<b>"<< tr("Family") << ":</b> " << family << "<br>\r\n";
s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n"; s << "<b>" << tr("Tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate () << "%<br>\r\n";
bool isTotalTCSR;
i2p::config::GetOption("http.showTotalTCSR", isTotalTCSR);
if (isTotalTCSR) {
s << "<b>" << tr("Total tunnel creation success rate") << ":</b> " << i2p::tunnel::tunnels.GetTotalTunnelCreationSuccessRate() << "%<br/>\r\n";
}
s << "<b>" << tr("Received") << ":</b> "; s << "<b>" << tr("Received") << ":</b> ";
ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ()); ShowTraffic (s, i2p::transport::transports.GetTotalReceivedBytes ());
s << " (" << tr(/* tr: Kibibyte/s */ "%.2f KiB/s", (double) i2p::transport::transports.GetInBandwidth15s () / 1024) << ")<br>\r\n"; s << " (" << tr(/* tr: Kibibyte/s */ "%.2f KiB/s", (double) i2p::transport::transports.GetInBandwidth15s () / 1024) << ")<br>\r\n";
@@ -334,15 +329,14 @@ namespace http {
default: default:
s << tr("Unknown"); s << tr("Unknown");
} }
bool v6 = address->IsV6 (); if (address->IsV6 ())
if (v6)
{ {
if (address->IsV4 ()) s << "v4"; if (address->IsV4 ()) s << "v4";
s << "v6"; s << "v6";
} }
s << "</td>\r\n"; s << "</td>\r\n";
if (address->published) if (address->published)
s << "<td>" << (v6 ? "[" : "") << address->host.to_string() << (v6 ? "]:" : ":") << address->port << "</td>\r\n"; s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n";
else else
{ {
s << "<td>" << tr(/* tr: Shown when router doesn't publish itself and have "Firewalled" state */ "supported"); s << "<td>" << tr(/* tr: Shown when router doesn't publish itself and have "Firewalled" state */ "supported");
@@ -554,7 +548,7 @@ namespace http {
<< tr("Streams") << tr("Streams")
<< "</caption>\r\n<thead>\r\n<tr>" << "</caption>\r\n<thead>\r\n<tr>"
<< "<th style=\"width:25px;\">StreamID</th>" << "<th style=\"width:25px;\">StreamID</th>"
<< "<th style=\"width:5px;\">&nbsp;</th>" // Stream closing button column << "<th style=\"width:5px;\" \\>" // Stream closing button column
<< "<th class=\"streamdest\">Destination</th>" << "<th class=\"streamdest\">Destination</th>"
<< "<th>Sent</th>" << "<th>Sent</th>"
<< "<th>Received</th>" << "<th>Received</th>"
@@ -625,10 +619,7 @@ namespace http {
if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET) if (storeType == i2p::data::NETDB_STORE_TYPE_LEASESET)
ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen())); ls.reset (new i2p::data::LeaseSet (leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
else else
{ ls.reset (new i2p::data::LeaseSet2 (storeType, leaseSet->GetBuffer(), leaseSet->GetBufferLen()));
ls.reset (new i2p::data::LeaseSet2 (storeType));
ls->Update (leaseSet->GetBuffer(), leaseSet->GetBufferLen(), false);
}
if (!ls) return; if (!ls) return;
s << "<div class=\"leaseset listitem"; s << "<div class=\"leaseset listitem";
if (ls->IsExpired()) if (ls->IsExpired())
@@ -754,7 +745,7 @@ namespace http {
s << " <a class=\"button" << (loglevel == eLogInfo ? " selected" : "") << "\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n"; s << " <a class=\"button" << (loglevel == 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 (); uint16_t maxTunnels = 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";
@@ -813,46 +804,37 @@ namespace http {
template<typename Sessions> template<typename Sessions>
static void ShowTransportSessions (std::stringstream& s, const Sessions& sessions, const std::string name) static void ShowTransportSessions (std::stringstream& s, const Sessions& sessions, const std::string name)
{ {
auto comp = [](typename Sessions::mapped_type a, typename Sessions::mapped_type b)
{ return a->GetRemoteEndpoint() < b->GetRemoteEndpoint(); };
std::set<typename Sessions::mapped_type, decltype(comp)> sortedSessions(comp);
for (const auto& it : sessions)
{
auto ret = sortedSessions.insert(it.second);
if (!ret.second)
LogPrint(eLogError, "HTTPServer: Duplicate remote endpoint detected: ", (*ret.first)->GetRemoteEndpoint());
}
std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0; std::stringstream tmp_s, tmp_s6; uint16_t cnt = 0, cnt6 = 0;
for (const auto& it: sortedSessions) for (const auto& it: sessions )
{ {
auto endpoint = it->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
if (it && it->IsEstablished () && endpoint.address ().is_v4 ()) if (it.second && it.second->IsEstablished () && endpoint.address ().is_v4 ())
{ {
tmp_s << "<div class=\"listitem\">\r\n"; tmp_s << "<div class=\"listitem\">\r\n";
if (it->IsOutgoing ()) tmp_s << " &#8658; "; if (it.second->IsOutgoing ()) tmp_s << " &#8658; ";
tmp_s << i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()) << ": " tmp_s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< endpoint.address ().to_string () << ":" << endpoint.port (); << endpoint.address ().to_string () << ":" << endpoint.port ();
if (!it->IsOutgoing ()) tmp_s << " &#8658; "; if (!it.second->IsOutgoing ()) tmp_s << " &#8658; ";
tmp_s << " [" << it->GetNumSentBytes () << ":" << it->GetNumReceivedBytes () << "]"; tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it->GetRelayTag ()) if (it.second->GetRelayTag ())
tmp_s << " [itag:" << it->GetRelayTag () << "]"; tmp_s << " [itag:" << it.second->GetRelayTag () << "]";
if (it->GetSendQueueSize () > 0) if (it.second->GetSendQueueSize () > 0)
tmp_s << " [queue:" << it->GetSendQueueSize () << "]"; tmp_s << " [queue:" << it.second->GetSendQueueSize () << "]";
tmp_s << "</div>\r\n" << std::endl; tmp_s << "</div>\r\n" << std::endl;
cnt++; cnt++;
} }
if (it && it->IsEstablished () && endpoint.address ().is_v6 ()) if (it.second && it.second->IsEstablished () && endpoint.address ().is_v6 ())
{ {
tmp_s6 << "<div class=\"listitem\">\r\n"; tmp_s6 << "<div class=\"listitem\">\r\n";
if (it->IsOutgoing ()) tmp_s6 << " &#8658; "; if (it.second->IsOutgoing ()) tmp_s6 << " &#8658; ";
tmp_s6 << i2p::data::GetIdentHashAbbreviation (it->GetRemoteIdentity ()->GetIdentHash ()) << ": " tmp_s6 << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": "
<< "[" << endpoint.address ().to_string () << "]:" << endpoint.port (); << "[" << endpoint.address ().to_string () << "]:" << endpoint.port ();
if (!it->IsOutgoing ()) tmp_s6 << " &#8658; "; if (!it.second->IsOutgoing ()) tmp_s6 << " &#8658; ";
tmp_s6 << " [" << it->GetNumSentBytes () << ":" << it->GetNumReceivedBytes () << "]"; tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it->GetRelayTag ()) if (it.second->GetRelayTag ())
tmp_s6 << " [itag:" << it->GetRelayTag () << "]"; tmp_s6 << " [itag:" << it.second->GetRelayTag () << "]";
if (it->GetSendQueueSize () > 0) if (it.second->GetSendQueueSize () > 0)
tmp_s6 << " [queue:" << it->GetSendQueueSize () << "]"; tmp_s6 << " [queue:" << it.second->GetSendQueueSize () << "]";
tmp_s6 << "</div>\r\n" << std::endl; tmp_s6 << "</div>\r\n" << std::endl;
cnt6++; cnt6++;
} }
@@ -1314,7 +1296,7 @@ namespace http {
{ {
uint32_t limit = std::stoul(params["limit"], nullptr); uint32_t limit = std::stoul(params["limit"], nullptr);
if (limit > 0 && limit <= TRANSIT_TUNNELS_LIMIT) if (limit > 0 && limit <= TRANSIT_TUNNELS_LIMIT)
i2p::tunnel::tunnels.SetMaxNumTransitTunnels (limit); SetMaxNumTransitTunnels (limit);
else { else {
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Transit tunnels count must not exceed %d", TRANSIT_TUNNELS_LIMIT) << "\r\n<br>\r\n<br>\r\n"; s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Transit tunnels count must not exceed %d", TRANSIT_TUNNELS_LIMIT) << "\r\n<br>\r\n<br>\r\n";
s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n"; s << "<a href=\"" << webroot << "?page=commands\">" << tr("Back to commands list") << "</a>\r\n<br>\r\n";

26
debian/changelog vendored
View File

@@ -1,32 +1,8 @@
i2pd (2.47.0-1) unstable; urgency=high
* updated to version 2.47.0/0.9.58
-- orignal <orignal@i2pmail.org> Sat, 11 Mar 2023 16:00:00 +0000
i2pd (2.46.1-2) unstable; urgency=critical
* re-pushed release due to new critical bug
-- r4sas <r4sas@i2pmail.org> Mon, 20 Feb 2023 23:40:00 +0000
i2pd (2.46.1-1) unstable; urgency=high
* updated to version 2.46.1/0.9.57
-- r4sas <r4sas@i2pmail.org> Mon, 20 Feb 2023 02:45:00 +0000
i2pd (2.46.0-1) unstable; urgency=high
* updated to version 2.46.0/0.9.57
-- orignal <orignal@i2pmail.org> Wed, 15 Feb 2023 19:00:00 +0000
i2pd (2.45.1-1) unstable; urgency=medium i2pd (2.45.1-1) unstable; urgency=medium
* updated to version 2.45.1/0.9.57 * updated to version 2.45.1/0.9.57
-- orignal <orignal@i2pmail.org> Wed, 11 Jan 2023 19:00:00 +0000 -- orignal <orignal@i2pmail.org> Wed, 11 Jan 2023 19:00:00 +0000
i2pd (2.45.0-1) unstable; urgency=high i2pd (2.45.0-1) unstable; urgency=high

2
debian/conffiles vendored Normal file
View File

@@ -0,0 +1,2 @@
/etc/i2pd/i2pd.conf
/etc/i2pd/tunnels.conf

2
debian/rules vendored
View File

@@ -8,6 +8,6 @@ export DEB_CXXFLAGS_MAINT_APPEND = -Wall -pedantic
export DEB_LDFLAGS_MAINT_APPEND = export DEB_LDFLAGS_MAINT_APPEND =
%: %:
dh $@ dh $@ --parallel
override_dh_auto_install: override_dh_auto_install:

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -40,7 +40,6 @@ namespace armenian // language namespace
{"established", "կարգավոյված է"}, {"established", "կարգավոյված է"},
{"unknown", "անհայտ"}, {"unknown", "անհայտ"},
{"exploratory", "հետազոտոկան"}, {"exploratory", "հետազոտոկան"},
{"Purple I2P Webconsole", "Վեբ-կոնսոլ Purple I2P"},
{"<b>i2pd</b> webconsole", "Վեբ-կոնսոլ <b>i2pd</b>"}, {"<b>i2pd</b> webconsole", "Վեբ-կոնսոլ <b>i2pd</b>"},
{"Main page", "Գլխավոր էջ"}, {"Main page", "Գլխավոր էջ"},
{"Router commands", "Երթուղիչի հրահանգներ"}, {"Router commands", "Երթուղիչի հրահանգներ"},
@@ -58,10 +57,10 @@ namespace armenian // language namespace
{"Unknown", "Անհայտ"}, {"Unknown", "Անհայտ"},
{"Proxy", "Պրոկսի"}, {"Proxy", "Պրոկսի"},
{"Mesh", "MESH-ցանց"}, {"Mesh", "MESH-ցանց"},
{"Error", "Սխալ"},
{"Clock skew", "Ոչ ճշգրիտ ժամանակ"}, {"Clock skew", "Ոչ ճշգրիտ ժամանակ"},
{"Offline", "Օֆլայն"}, {"Offline", "Օֆլայն"},
{"Symmetric NAT", "Սիմետրիկ NAT"}, {"Symmetric NAT", "Սիմետրիկ NAT"},
{"Full cone NAT", "Full cone NAT"},
{"Uptime", "Առկայություն"}, {"Uptime", "Առկայություն"},
{"Network status", "Ցանցի կարգավիճակ"}, {"Network status", "Ցանցի կարգավիճակ"},
{"Network status v6", "Ցանցի կարգավիճակ v6"}, {"Network status v6", "Ցանցի կարգավիճակ v6"},
@@ -90,7 +89,7 @@ namespace armenian // language namespace
{"Address registration line", "Հասցեի գրանցման տող"}, {"Address registration line", "Հասցեի գրանցման տող"},
{"Domain", "Տիրույթ"}, {"Domain", "Տիրույթ"},
{"Generate", "Գեներացնել"}, {"Generate", "Գեներացնել"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը:"}, {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Նշում. </b> արդյունքի տողը կարող է օգտագործվել միայն 2LD տիրույթներ գրանցելու համար (example.i2p): Ենթատիրույթներ գրանցելու համար խնդրում ենք օգտագործել i2pd-tools գործիքակազմը"},
{"Address", "Հասցե"}, {"Address", "Հասցե"},
{"Type", "Տեսակը"}, {"Type", "Տեսակը"},
{"EncType", "Գաղտնագրի տեսակը"}, {"EncType", "Գաղտնագրի տեսակը"},
@@ -117,6 +116,7 @@ namespace armenian // language namespace
{"Gateway", "Դարպաս"}, {"Gateway", "Դարպաս"},
{"TunnelID", "Թունելի ID"}, {"TunnelID", "Թունելի ID"},
{"EndDate", "Ավարտ"}, {"EndDate", "Ավարտ"},
{"not floodfill", "ոչ floodfill-ներ"},
{"Queue size", "Հերթի չափսը"}, {"Queue size", "Հերթի չափսը"},
{"Run peer test", "Գործարկել փորձարկումը"}, {"Run peer test", "Գործարկել փորձարկումը"},
{"Decline transit tunnels", "Մերժել տարանցիկ թունելներ"}, {"Decline transit tunnels", "Մերժել տարանցիկ թունելներ"},
@@ -146,7 +146,10 @@ namespace armenian // language namespace
{"Destination not found", "Հասցեի վայրը չի գտնվել"}, {"Destination not found", "Հասցեի վայրը չի գտնվել"},
{"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 5 seconds", "Դուք կտեղափոխվեք 5 վայրկյանից"},
{"Transit tunnels count must not exceed 65535", "Տարանցիկ թունելների քանակը չպետք է գերազանցի 65535-ը"},
{"Back to commands list", "Վերադառնալ հրահանգների ցուցակ"}, {"Back to commands list", "Վերադառնալ հրահանգների ցուցակ"},
{"Register at reg.i2p", "Գրանցել reg.i2p-ում"},
{"Description", "Նկարագրություն"}, {"Description", "Նկարագրություն"},
{"A bit information about service on domain", "Մի փոքր տեղեկատվություն տիրոիյթում գտնվող ծառայության մասին"}, {"A bit information about service on domain", "Մի փոքր տեղեկատվություն տիրոիյթում գտնվող ծառայության մասին"},
{"Submit", "Ուղարկվել"}, {"Submit", "Ուղարկվել"},
@@ -162,26 +165,34 @@ namespace armenian // language namespace
{"You may try to find this host on jump services below", "Ստորև Դուք կարող եք գտնել այս հոսթը jump ծառայությունների միջոցով"}, {"You may try to find this host on jump services below", "Ստորև Դուք կարող եք գտնել այս հոսթը jump ծառայությունների միջոցով"},
{"Invalid request", "Սխալ հարցում"}, {"Invalid request", "Սխալ հարցում"},
{"Proxy unable to parse your request", "Պրոկսին չի կարող հասկանալ Ձեր հարցումը"}, {"Proxy unable to parse your request", "Պրոկսին չի կարող հասկանալ Ձեր հարցումը"},
{"Invalid request URI", "Սխալ ձևավորված URI հարցում"}, {"addresshelper is not supported", "addresshelper-ը համատեղելի չէ"},
{"Host", "Հոսթ"},
{"added to router's addressbook from helper", "Ավելացված է երթուղիչի հասցեագրքում helper-ի միջոցով"},
{"Click here to proceed:", "Շարունակելու համար սեղմեք այստեղ"},
{"Continue", "Շարունակել"},
{"Addresshelper found", "addresshelper-ը գնտված է"},
{"already in router's addressbook", "արդեն առկա է երթուղիչի հասցեագրքում"},
{"Click here to update record:", "Սեղմեկ այստեղ որպեսզի թարվացնեք գրառումը"},
{"invalid request uri", "Սխալ ձևավորված URI հարցում"},
{"Can't detect destination host from request", "Չհաջողվեց հայնտաբերեկ վայրի հասցեն նշված հարցմամբ"}, {"Can't detect destination host from request", "Չհաջողվեց հայնտաբերեկ վայրի հասցեն նշված հարցմամբ"},
{"Outproxy failure", "Սխալ արտաքին պրոքսի"}, {"Outproxy failure", "Սխալ արտաքին պրոքսի"},
{"Bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"}, {"bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Հոսթ %s Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"}, {"not inside I2P network, but outproxy is not enabled", "Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
{"Unknown outproxy URL", "Արտաքին պրոքսիի անհայտ URL"}, {"unknown outproxy url", "արտաքին պրոքսիի անհայտ URL"},
{"Cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"}, {"cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
{"Hostname is too long", "Հոսթի անունը չափազանց երկար է"}, {"hostname too long", "Հոսթի անունը չափազանց երկար է"},
{"Cannot connect to upstream SOCKS proxy", "Չհաջողվեց միանալ վերադաս SOCKS պրոկսի սերվերին"}, {"cannot connect to upstream socks proxy", "չհաջողվեց միանալ վերադաս socks պրոկսիին"},
{"Cannot negotiate with SOCKS proxy", "Չհաջողվեց պայմանավորվել վերադաս SOCKS պրոկսիի հետ"}, {"Cannot negotiate with socks proxy", "Չհաջողվեց պայմանավորվել վերադաս socks պրոկսիի հետ"},
{"CONNECT error", "Սխալ CONNECT հարցում"}, {"CONNECT error", "Սխալ CONNECT հարցում"},
{"Failed to connect", "Միանալ չhաջողվեց"}, {"Failed to Connect", "Միանալ չhաջողվեց"},
{"SOCKS proxy error", "Սխալ SOCKS պրոկսի"}, {"socks proxy error", "Սխալ SOCKS պրոկսի"},
{"Failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"}, {"failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
{"No reply from SOCKS proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"}, {"No Reply From socks proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
{"Cannot connect", "Հնարավոր չե միանալ"}, {"cannot connect", "Հնարավոր չե միանալ"},
{"HTTP out proxy not implemented", "Արտաքին HTTP պրոկսին դեռ իրականացված չէ"}, {"http out proxy not implemented", "Արտաքին http պրոկսին դեռ իրականացված չէ"},
{"Cannot connect to upstream HTTP proxy", "Չհաջողվեց միանալ վերադաս HTTP պրոկսի սերվերին"}, {"cannot connect to upstream http proxy", "Չհաջողվեց միանալ վերադաս http պրոկսի սերվերին"},
{"Host is down", "Հոսթն անհասանելի է"}, {"Host is down", "Հոսթն անհասանելի է"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ:"}, {"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ"},
{"", ""}, {"", ""},
}; };

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2023, The PurpleI2P Project * Copyright (c) 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,6 +13,7 @@
#include "I18N.h" #include "I18N.h"
// Simplified Chinese localization file // Simplified Chinese localization file
// This is an example translation file without strings in it.
namespace i2p namespace i2p
{ {
@@ -45,7 +46,7 @@ namespace chinese // language namespace
{"Main page", "主页"}, {"Main page", "主页"},
{"Router commands", "路由命令"}, {"Router commands", "路由命令"},
{"Local Destinations", "本地目标"}, {"Local Destinations", "本地目标"},
{"LeaseSets", ""}, {"LeaseSets", ""},
{"Tunnels", "隧道"}, {"Tunnels", "隧道"},
{"Transit Tunnels", "中转隧道"}, {"Transit Tunnels", "中转隧道"},
{"Transports", "传输"}, {"Transports", "传输"},
@@ -57,12 +58,11 @@ namespace chinese // language namespace
{"Firewalled", "受到防火墙限制"}, {"Firewalled", "受到防火墙限制"},
{"Unknown", "未知"}, {"Unknown", "未知"},
{"Proxy", "代理"}, {"Proxy", "代理"},
{"Mesh", "组网"}, {"Mesh", "Mesh组网"},
{"Error", "错误"},
{"Clock skew", "时钟偏移"}, {"Clock skew", "时钟偏移"},
{"Offline", "离线"}, {"Offline", "离线"},
{"Symmetric NAT", "对称 NAT"}, {"Symmetric NAT", "对称 NAT"},
{"Full cone NAT", "全锥型NAT"},
{"No Descriptors", "无描述符"},
{"Uptime", "运行时间"}, {"Uptime", "运行时间"},
{"Network status", "IPv4 网络状态"}, {"Network status", "IPv4 网络状态"},
{"Network status v6", "IPv6 网络状态"}, {"Network status v6", "IPv6 网络状态"},
@@ -91,12 +91,12 @@ namespace chinese // language namespace
{"Address registration line", "地址域名注册"}, {"Address registration line", "地址域名注册"},
{"Domain", "域名"}, {"Domain", "域名"},
{"Generate", "生成"}, {"Generate", "生成"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>注意:</b> 结果字符串只能用于注册级域名(例如example.i2p)。若需注册三级域名,请使用 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>注意:</b> 结果字符串只能用于注册级域名(例如example.i2p)。若需注册域名,请使用 i2pd-tools。"},
{"Address", "地址"}, {"Address", "地址"},
{"Type", "类型"}, {"Type", "类型"},
{"EncType", "加密类型"}, {"EncType", "加密类型"},
{"Inbound tunnels", "入站隧道"}, {"Inbound tunnels", "入站隧道"},
{"%dms", "%dms"}, {"%dms", "%d毫秒"},
{"Outbound tunnels", "出站隧道"}, {"Outbound tunnels", "出站隧道"},
{"Tags", "标签"}, {"Tags", "标签"},
{"Incoming", "传入"}, {"Incoming", "传入"},
@@ -118,10 +118,9 @@ namespace chinese // language namespace
{"Gateway", "网关"}, {"Gateway", "网关"},
{"TunnelID", "隧道 ID"}, {"TunnelID", "隧道 ID"},
{"EndDate", "结束日期"}, {"EndDate", "结束日期"},
{"floodfill mode is disabled", "洪泛已禁用"}, {"not floodfill", "洪泛"},
{"Queue size", "队列大小"}, {"Queue size", "队列大小"},
{"Run peer test", "运行节点测试"}, {"Run peer test", "运行节点测试"},
{"Reload tunnels configuration", "重新载入隧道配置"},
{"Decline transit tunnels", "拒绝中转隧道"}, {"Decline transit tunnels", "拒绝中转隧道"},
{"Accept transit tunnels", "允许中转隧道"}, {"Accept transit tunnels", "允许中转隧道"},
{"Cancel graceful shutdown", "取消平滑关闭"}, {"Cancel graceful shutdown", "取消平滑关闭"},
@@ -129,7 +128,7 @@ namespace chinese // language namespace
{"Force shutdown", "强制停止"}, {"Force shutdown", "强制停止"},
{"Reload external CSS styles", "重载外部 CSS 样式"}, {"Reload external CSS styles", "重载外部 CSS 样式"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>注意:</b> 此处完成的任何操作都不是永久的,不会更改您的配置文件。"}, {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>注意:</b> 此处完成的任何操作都不是永久的,不会更改您的配置文件。"},
{"Logging level", "日志级别"}, {"Logging level", "日志记录级别"},
{"Transit tunnels limit", "中转隧道限制"}, {"Transit tunnels limit", "中转隧道限制"},
{"Change", "修改"}, {"Change", "修改"},
{"Change language", "更改语言"}, {"Change language", "更改语言"},
@@ -149,8 +148,8 @@ namespace chinese // language namespace
{"Destination not found", "找不到目标"}, {"Destination not found", "找不到目标"},
{"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 5 seconds", "您将在5秒内被重定向"},
{"Transit tunnels count must not exceed %d", "中转隧道数量限制为 %d"}, {"Transit tunnels count must not exceed 65535", "中转隧道数量不能超过 65535"},
{"Back to commands list", "返回命令列表"}, {"Back to commands list", "返回命令列表"},
{"Register at reg.i2p", "在 reg.i2p 注册域名"}, {"Register at reg.i2p", "在 reg.i2p 注册域名"},
{"Description", "描述"}, {"Description", "描述"},
@@ -165,36 +164,35 @@ namespace chinese // language namespace
{"Proxy info", "代理信息"}, {"Proxy info", "代理信息"},
{"Proxy error: Host not found", "代理错误:未找到主机"}, {"Proxy error: Host not found", "代理错误:未找到主机"},
{"Remote host not found in router's addressbook", "在路由地址簿中未找到远程主机"}, {"Remote host not found in router's addressbook", "在路由地址簿中未找到远程主机"},
{"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务中找到主机"}, {"You may try to find this host on jump services below", "您可以尝试在下方的跳转服务中找到主机"},
{"Invalid request", "无效请求"}, {"Invalid request", "无效请求"},
{"Proxy unable to parse your request", "代理无法解析您的请求"}, {"Proxy unable to parse your request", "代理无法解析您的请求"},
{"Addresshelper is not supported", "不支持地址助手"}, {"addresshelper is not supported", "不支持地址助手"},
{"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>.", "主机 %s <font color=red>已在路由地址簿中</font>。<b>请注意:此地址的来源可能是有害的!</b>点击此处更新记录:<a href=\"%s%s%s&update=true\">继续</a>"}, {"Host", "主机"},
{"Addresshelper forced update rejected", "地址助手强制更新被拒绝"}, {"added to router's addressbook from helper", "将此地址从地址助手添加到路由地址簿"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "若要在路由器地址簿中添加主机 <b>%s</b> 请点击这里: <a href=\"%s%s%s\">继续</a>"}, {"Click here to proceed:", "点击此处继续:"},
{"Addresshelper request", "请求地址助手"}, {"Continue", "继续"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "主机 %s 已通过地址助手添加到路由地址簿中。点击此处继续:<a href=\"%s\">继续</a>"}, {"Addresshelper found", "已找到地址助手"},
{"Addresshelper adding", "正在添加地址助手"}, {"already in router's addressbook", "已在路由地址簿中"},
{"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>.", "主机 %s <font color=red>已在路由地址簿中</font>。点击此处更新记录:<a href=\"%s%s%s&update=true\">继续</a>"}, {"Click here to update record:", "点击此处更新地址簿记录"},
{"Addresshelper update", "更新地址助手"}, {"invalid request uri", "无效的 URL 请求"},
{"Invalid request URI", "无效的 URI 请求"},
{"Can't detect destination host from request", "无法从请求中检测到目标主机"}, {"Can't detect destination host from request", "无法从请求中检测到目标主机"},
{"Outproxy failure", "出口代理故障"}, {"Outproxy failure", "出口代理故障"},
{"Bad outproxy settings", "错误的出口代理设置"}, {"bad outproxy settings", "错误的出口代理设置"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "主机 %s 不在 I2P 网络内,但出口代理未启用"}, {"not inside I2P network, but outproxy is not enabled", "该地址不在 I2P 网络内,但未启用出口代理"},
{"Unknown outproxy URL", "未知的出口代理地址"}, {"unknown outproxy url", "未知的出口代理地址"},
{"Cannot resolve upstream proxy", "无法解析上游代理"}, {"cannot resolve upstream proxy", "无法解析上游代理"},
{"Hostname is too long", "主机名过长"}, {"hostname too long", "主机名过长"},
{"Cannot connect to upstream SOCKS proxy", "无法连接到上游 SOCKS 代理"}, {"cannot connect to upstream socks proxy", "无法连接到上游 socks 代理"},
{"Cannot negotiate with SOCKS proxy", "无法与 SOCKS 代理协商"}, {"Cannot negotiate with socks proxy", "无法与 socks 代理协商"},
{"CONNECT error", "连接错误"}, {"CONNECT error", "连接错误"},
{"Failed to connect", "连接失败"}, {"Failed to Connect", "连接失败"},
{"SOCKS proxy error", "SOCKS 代理错误"}, {"socks proxy error", "socks 代理错误"},
{"Failed to send request to upstream", "向上游发送请求失败"}, {"failed to send request to upstream", "向上游发送请求失败"},
{"No reply from SOCKS proxy", "没有来自 SOCKS 代理的回复"}, {"No Reply From socks proxy", "没有来自 socks 代理的回复"},
{"Cannot connect", "无法连接"}, {"cannot connect", "无法连接"},
{"HTTP out proxy not implemented", "HTTP 出口代理未实现"}, {"http out proxy not implemented", "http 出口代理未实现"},
{"Cannot connect to upstream HTTP proxy", "无法连接到上游 HTTP 代理"}, {"cannot connect to upstream http proxy", "无法连接到上游 http 代理"},
{"Host is down", "主机已关闭"}, {"Host is down", "主机已关闭"},
{"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线,请稍后再试。"}, {"Can't create connection to requested host, it may be down. Please try again later.", "无法创建到目标主机的连接。主机可能已下线,请稍后再试。"},
{"", ""}, {"", ""},
@@ -202,9 +200,9 @@ namespace chinese // language namespace
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
{"%d days", {"%d "}}, {"%d days", {"%d "}},
{"%d hours", {"%d "}}, {"%d hours", {"%d 时"}},
{"%d minutes", {"%d 分"}}, {"%d minutes", {"%d 分"}},
{"%d seconds", {"%d 秒"}}, {"%d seconds", {"%d 秒"}},
{"", {""}}, {"", {""}},
}; };

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -58,6 +58,7 @@ namespace czech // language namespace
{"Unknown", "Neznámý"}, {"Unknown", "Neznámý"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Síť"}, {"Mesh", "Síť"},
{"Error", "Chyba"},
{"Clock skew", "Časová nesrovnalost"}, {"Clock skew", "Časová nesrovnalost"},
{"Offline", "Offline"}, {"Offline", "Offline"},
{"Symmetric NAT", "Symetrický NAT"}, {"Symmetric NAT", "Symetrický NAT"},
@@ -116,6 +117,7 @@ namespace czech // language namespace
{"Gateway", "Brána"}, {"Gateway", "Brána"},
{"TunnelID", "ID tunelu"}, {"TunnelID", "ID tunelu"},
{"EndDate", "Datum ukončení"}, {"EndDate", "Datum ukončení"},
{"not floodfill", "není floodfill"},
{"Queue size", "Velikost fronty"}, {"Queue size", "Velikost fronty"},
{"Run peer test", "Spustit peer test"}, {"Run peer test", "Spustit peer test"},
{"Decline transit tunnels", "Odmítnout tranzitní tunely"}, {"Decline transit tunnels", "Odmítnout tranzitní tunely"},
@@ -145,6 +147,8 @@ 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 5 seconds", "Budete přesměrováni za 5 vteřin"},
{"Transit tunnels count must not exceed 65535", "Počet tranzitních tunelů nesmí přesáhnout 65535"},
{"Back to commands list", "Zpět na list příkazů"}, {"Back to commands list", "Zpět na list příkazů"},
{"Register at reg.i2p", "Zaregistrovat na reg.i2p"}, {"Register at reg.i2p", "Zaregistrovat na reg.i2p"},
{"Description", "Popis"}, {"Description", "Popis"},
@@ -162,24 +166,32 @@ 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"},
{"Invalid request URI", "Neplatný URI požadavek"}, {"addresshelper is not supported", "Adresshelper není podporován"},
{"Host", "Hostitel"},
{"added to router's addressbook from helper", "přidáno do adresáře routeru od pomocníka"},
{"Click here to proceed:", "Pro pokračování, klikněte zde:"},
{"Continue", "Pokračovat"},
{"Addresshelper found", "Adresář nalezen"},
{"already in router's addressbook", "je již v adresáři routeru"},
{"Click here to update record:", "Pro aktualizaci záznamu, klikněte zde:"},
{"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í"},
{"Bad outproxy settings", "Špatné outproxy nastavení"}, {"bad outproxy settings", "špatné outproxy nastavení"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Hostitel %s není uvnitř I2P sítě a outproxy není nastavena"}, {"not inside I2P network, but outproxy is not enabled", "není uvnitř I2P sítě a outproxy není nastavena"},
{"Unknown outproxy URL", "Neznámá outproxy URL"}, {"unknown outproxy url", "neznámá outproxy URL"},
{"Cannot resolve upstream proxy", "Nelze rozluštit upstream proxy server"}, {"cannot resolve upstream proxy", "nelze rozluštit upstream proxy server"},
{"Hostname is too long", "Název hostitele je příliš dlouhý"}, {"hostname too long", "Název hostitele je příliš dlouhý"},
{"Cannot connect to upstream SOCKS proxy", "Nelze se připojit k upstream SOCKS proxy serveru"}, {"cannot connect to upstream socks proxy", "nelze se připojit k upstream socks proxy serveru"},
{"Cannot negotiate with SOCKS proxy", "Nelze vyjednávat se SOCKS proxy serverem"}, {"Cannot negotiate with socks proxy", "Nelze vyjednávat se socks proxy serverem"},
{"CONNECT error", "Chyba PŘIPOJENÍ"}, {"CONNECT error", "Chyba PŘIPOJENÍ"},
{"Failed to connect", "Připojení se nezdařilo"}, {"Failed to Connect", "Připojení se nezdařilo"},
{"SOCKS proxy error", "Chyba SOCKS proxy serveru"}, {"socks proxy error", "chyba socks proxy serveru"},
{"Failed to send request to upstream", "Odeslání žádosti upstream serveru se nezdařilo"}, {"failed to send request to upstream", "odeslání žádosti upstream serveru se nezdařilo"},
{"No reply from SOCKS proxy", "Žádná odpověď od SOCKS proxy serveru"}, {"No Reply From socks proxy", "Žádná odpověď od socks proxy serveru"},
{"Cannot connect", "Nelze se připojit"}, {"cannot connect", "nelze se připojit"},
{"HTTP out proxy not implemented", "HTTP out proxy není implementován"}, {"http out proxy not implemented", "http out proxy není implementován"},
{"Cannot connect to upstream HTTP proxy", "Nelze se připojit k upstream HTTP proxy serveru"}, {"cannot connect to upstream http proxy", "nelze se připojit k upstream socks proxy serveru"},
{"Host is down", "Hostitel je nedostupný"}, {"Host is down", "Hostitel je nedostupný"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Připojení k požadovanému hostiteli nelze vytvořit, může být nedostupný. Zkuste to, prosím, znovu později."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Připojení k požadovanému hostiteli nelze vytvořit, může být nedostupný. Zkuste to, prosím, znovu později."},
{"", ""}, {"", ""},

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -58,11 +58,10 @@ namespace french // language namespace
{"Unknown", "Inconnu"}, {"Unknown", "Inconnu"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Maillé"}, {"Mesh", "Maillé"},
{"Error", "Erreur"},
{"Clock skew", "Horloge décalée"}, {"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"},
{"No Descriptors", "Aucuns Descripteurs"},
{"Uptime", "Temps de fonctionnement"}, {"Uptime", "Temps de fonctionnement"},
{"Network status", "État du réseau"}, {"Network status", "État du réseau"},
{"Network status v6", "État du réseau v6"}, {"Network status v6", "État du réseau v6"},
@@ -70,7 +69,7 @@ namespace french // language namespace
{"Family", "Famille"}, {"Family", "Famille"},
{"Tunnel creation success rate", "Taux de succès de création de tunnels"}, {"Tunnel creation success rate", "Taux de succès de création de tunnels"},
{"Received", "Reçu"}, {"Received", "Reçu"},
{"%.2f KiB/s", "%.2f Kio/s"}, {"%.2f KiB/s", "%.2f kio/s"},
{"Sent", "Envoyé"}, {"Sent", "Envoyé"},
{"Transit", "Transité"}, {"Transit", "Transité"},
{"Data path", "Emplacement des données"}, {"Data path", "Emplacement des données"},
@@ -82,7 +81,6 @@ namespace french // language namespace
{"Our external address", "Notre adresse externe"}, {"Our external address", "Notre adresse externe"},
{"supported", "supporté"}, {"supported", "supporté"},
{"Routers", "Routeurs"}, {"Routers", "Routeurs"},
{"Floodfills", "Remplisseurs"},
{"Client Tunnels", "Tunnels clients"}, {"Client Tunnels", "Tunnels clients"},
{"Services", "Services"}, {"Services", "Services"},
{"Enabled", "Activé"}, {"Enabled", "Activé"},
@@ -94,7 +92,6 @@ namespace french // language namespace
{"<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"},
{"Inbound tunnels", "Tunnels entrants"}, {"Inbound tunnels", "Tunnels entrants"},
{"%dms", "%dms"}, {"%dms", "%dms"},
{"Outbound tunnels", "Tunnels sortants"}, {"Outbound tunnels", "Tunnels sortants"},
@@ -118,10 +115,8 @@ namespace french // language namespace
{"Gateway", "Passerelle"}, {"Gateway", "Passerelle"},
{"TunnelID", "ID du tunnel"}, {"TunnelID", "ID du tunnel"},
{"EndDate", "Date de fin"}, {"EndDate", "Date de fin"},
{"floodfill mode is disabled", "le mode de remplissage est désactivé"},
{"Queue size", "Longueur de la file"}, {"Queue size", "Longueur de la file"},
{"Run peer test", "Lancer test des pairs"}, {"Run peer test", "Lancer test des pairs"},
{"Reload tunnels configuration", "Recharger la configuration des tunnels"},
{"Decline transit tunnels", "Refuser les tunnels transitoires"}, {"Decline transit tunnels", "Refuser les tunnels transitoires"},
{"Accept transit tunnels", "Accepter les tunnels transitoires"}, {"Accept transit tunnels", "Accepter les tunnels transitoires"},
{"Cancel graceful shutdown", "Annuler l'arrêt gracieux"}, {"Cancel graceful shutdown", "Annuler l'arrêt gracieux"},
@@ -139,8 +134,6 @@ namespace french // language namespace
{"SAM session not found", "session SAM introuvable"}, {"SAM session not found", "session SAM introuvable"},
{"SAM Session", "Session SAM"}, {"SAM Session", "Session SAM"},
{"Server Tunnels", "Tunnels serveurs"}, {"Server Tunnels", "Tunnels serveurs"},
{"Client Forwards", "Transmission du client"},
{"Server Forwards", "Transmission du serveur"},
{"Unknown page", "Page inconnue"}, {"Unknown page", "Page inconnue"},
{"Invalid token", "Jeton invalide"}, {"Invalid token", "Jeton invalide"},
{"SUCCESS", "SUCCÈS"}, {"SUCCESS", "SUCCÈS"},
@@ -149,8 +142,8 @@ namespace french // language namespace
{"Destination not found", "Destination introuvable"}, {"Destination not found", "Destination introuvable"},
{"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 5 seconds", "Vous allez être redirigé dans cinq secondes"},
{"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 65535", "Le nombre de tunnels transitoires ne doit pas dépasser 65535"},
{"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"},
{"Description", "Description"}, {"Description", "Description"},
@@ -168,33 +161,32 @@ namespace french // language namespace
{"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", "Hôte"},
{"Addresshelper forced update rejected", "Mise à jour forcée des assistants d'adresses rejetée"}, {"added to router's addressbook from helper", "Ajouté au carnet d'adresse du routeur par l'assistant"},
{"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>."}, {"Click here to proceed:", "Cliquez ici pour continuer:"},
{"Addresshelper request", "Demande à l'assistant d'adresse"}, {"Continue", "Continuer"},
{"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 found", "Assistant d'adresse trouvé"},
{"Addresshelper adding", "Ajout de l'assistant d'adresse"}, {"already in router's addressbook", "déjà dans le carnet d'adresses du routeur"},
{"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>."}, {"Click here to update record:", "Cliquez ici pour mettre à jour le carnet 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"},
{"Outproxy failure", "Échec de proxy de sortie"}, {"Outproxy failure", "Échec de proxy de sortie"},
{"Bad outproxy settings", "Mauvaise configuration du proxy de sortie"}, {"bad outproxy settings", "Mauvaise configuration du proxy de sortie"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Hôte %s pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"}, {"not inside I2P network, but outproxy is not enabled", "pas dans le réseau I2P, mais le proxy de sortie n'est pas activé"},
{"Unknown outproxy URL", "URL du proxy de sortie inconnu"}, {"unknown outproxy url", "URL du proxy de sortie inconnu"},
{"Cannot resolve upstream proxy", "Impossible de résoudre l'adresse du proxy en amont"}, {"cannot resolve upstream proxy", "impossible de résoudre l'adresse du proxy en amont"},
{"Hostname is too long", "Nom d'hôte trop long"}, {"hostname too long", "nom d'hôte trop long"},
{"Cannot connect to upstream SOCKS proxy", "Impossible de se connecter au proxy SOCKS en amont"}, {"cannot connect to upstream socks proxy", "impossible de se connecter au proxy socks en amont"},
{"Cannot negotiate with SOCKS proxy", "Impossible de négocier avec le proxy SOCKS"}, {"Cannot negotiate with socks proxy", "Impossible de négocier avec le proxy socks"},
{"CONNECT error", "Erreur de connexion"}, {"CONNECT error", "Erreur de connexion"},
{"Failed to connect", "Échec de connexion"}, {"Failed to Connect", "Échec de connexion"},
{"SOCKS proxy error", "Erreur de proxy SOCKS"}, {"socks proxy error", "Erreur de proxy socks"},
{"Failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"}, {"failed to send request to upstream", "Erreur lors de l'envoie de la requête en amont"},
{"No reply from SOCKS proxy", "Pas de réponse du proxy SOCKS"}, {"No Reply From socks proxy", "Pas de réponse du proxy socks"},
{"Cannot connect", "Impossible de connecter"}, {"cannot connect", "impossible de connecter"},
{"HTTP out proxy not implemented", "Proxy de sortie HTTP non implémenté"}, {"http out proxy not implemented", "Proxy de sortie HTTP non implémenté"},
{"Cannot connect to upstream HTTP proxy", "Impossible de se connecter au proxy HTTP en amont"}, {"cannot connect to upstream http proxy", "impossible de se connecter au proxy HTTP en amont"},
{"Host is down", "Hôte hors service"}, {"Host is down", "Hôte hors service"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossible d'établir une connexion avec l'hôte, il est peut-être hors service. Veuillez réessayer plus tard."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Impossible d'établir une connexion avec l'hôte, il est peut-être hors service. Veuillez réessayer plus tard."},
{"", ""}, {"", ""},

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -58,10 +58,10 @@ namespace german // language namespace
{"Unknown", "Unbekannt"}, {"Unknown", "Unbekannt"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Mesh"}, {"Mesh", "Mesh"},
{"Error", "Fehler"},
{"Clock skew", "Zeitabweichung"}, {"Clock skew", "Zeitabweichung"},
{"Offline", "Offline"}, {"Offline", "Offline"},
{"Symmetric NAT", "Symmetrisches NAT"}, {"Symmetric NAT", "Symmetrisches NAT"},
{"No Descriptors", "Keine Beschreibungen"},
{"Uptime", "Laufzeit"}, {"Uptime", "Laufzeit"},
{"Network status", "Netzwerkstatus"}, {"Network status", "Netzwerkstatus"},
{"Network status v6", "Netzwerkstatus v6"}, {"Network status v6", "Netzwerkstatus v6"},
@@ -117,10 +117,9 @@ namespace german // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Enddatum"}, {"EndDate", "Enddatum"},
{"floodfill mode is disabled", "Floodfill Modus ist deaktiviert"}, {"not floodfill", "kein Floodfill"},
{"Queue size", "Größe der Warteschlange"}, {"Queue size", "Größe der Warteschlange"},
{"Run peer test", "Peer-Test durchführen"}, {"Run peer test", "Peer-Test durchführen"},
{"Reload tunnels configuration", "Tunnel Konfiguration neu laden"},
{"Decline transit tunnels", "Transittunnel ablehnen"}, {"Decline transit tunnels", "Transittunnel ablehnen"},
{"Accept transit tunnels", "Transittunnel akzeptieren"}, {"Accept transit tunnels", "Transittunnel akzeptieren"},
{"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"}, {"Cancel graceful shutdown", "Beende das kontrollierte Herunterfahren"},
@@ -148,8 +147,8 @@ namespace german // language namespace
{"Destination not found", "Ziel nicht gefunden"}, {"Destination not found", "Ziel nicht gefunden"},
{"StreamID can't be null", "StreamID kann nicht null sein"}, {"StreamID can't be null", "StreamID kann nicht null sein"},
{"Return to destination page", "Zurück zur Ziel-Seite"}, {"Return to destination page", "Zurück zur Ziel-Seite"},
{"You will be redirected in %d seconds", "Du wirst umgeleitet in %d Sekunden"}, {"You will be redirected in 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
{"Transit tunnels count must not exceed %d", "Die Anzahl der Transittunnel darf nicht über %d gehen"}, {"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
{"Back to commands list", "Zurück zur Befehlsliste"}, {"Back to commands list", "Zurück zur Befehlsliste"},
{"Register at reg.i2p", "Auf reg.i2p registrieren"}, {"Register at reg.i2p", "Auf reg.i2p registrieren"},
{"Description", "Beschreibung"}, {"Description", "Beschreibung"},
@@ -167,33 +166,32 @@ namespace german // language namespace
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"}, {"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einem der nachfolgenden Jump-Services finden"},
{"Invalid request", "Ungültige Anfrage"}, {"Invalid request", "Ungültige Anfrage"},
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"}, {"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht verarbeiten"},
{"Addresshelper is not supported", "Adresshelfer wird nicht unterstützt"}, {"addresshelper is not supported", "Addresshelfer wird nicht unterstützt"},
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s ist <font color=red>bereits im Adressbuch des Routers</font>. <b>Vorsicht: Die Quelle dieser URL kann schädlich sein!</b> Klicken Sie hier, um den Datensatz zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."}, {"Host", "Host"},
{"Addresshelper forced update rejected", "Adresshelfer gezwungene Aktualisierung abgelehnt"}, {"added to router's addressbook from helper", "vom Helfer zum Router-Adressbuch hinzugefügt"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Um den Host <b>%s</b> im Adressbuch des Routers hinzuzufügen, klicken Sie hier: <a href=\"%s%s%s\">Weiter</a>."}, {"Click here to proceed:", "Klicke hier um fortzufahren:"},
{"Addresshelper request", "Adresshelfer gefunden"}, {"Continue", "Fortsetzen"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Host %s wurde vom Helfer zum Adressbuch des Routers hinzugefügt. Klicken Sie hier, um fortzufahren: <a href=\"%s\">Weiter</a>."}, {"Addresshelper found", "Adresshelfer gefunden"},
{"Addresshelper adding", "Adresshelfer hinzufügen"}, {"already in router's addressbook", "bereits im Adressbuch des Routers"},
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "Host %s ist <font color=red>bereits im Adressbuch des Routers</font>. Klicken Sie hier, um den Eintrag zu aktualisieren: <a href=\"%s%s%s&update=true\">Weiter</a>."}, {"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
{"Addresshelper update", "Adresshelfer aktualisieren"}, {"invalid request uri", "ungültige Anfrage-URI"},
{"Invalid request URI", "Ungültige Anfrage-URI"},
{"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"}, {"Can't detect destination host from request", "Kann den Ziel-Host von der Anfrage nicht erkennen"},
{"Outproxy failure", "Outproxy-Fehler"}, {"Outproxy failure", "Outproxy-Fehler"},
{"Bad outproxy settings", "Ungültige Outproxy-Einstellungen"}, {"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"}, {"not inside I2P network, but outproxy is not enabled", "außerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
{"Unknown outproxy URL", "Unbekannte Outproxy-URL"}, {"unknown outproxy url", "unbekannte Outproxy-URL"},
{"Cannot resolve upstream proxy", "Kann den Upstream-Proxy nicht auflösen"}, {"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
{"Hostname is too long", "Hostname zu lang"}, {"hostname too long", "Hostname zu lang"},
{"Cannot connect to upstream SOCKS proxy", "Kann keine Verbindung zum Upstream-SOCKS-Proxy herstellen"}, {"cannot connect to upstream socks proxy", "Kann keine Verbindung zum Upstream-Socks-Proxy herstellen"},
{"Cannot negotiate with SOCKS proxy", "Kann nicht mit SOCKS-Proxy verhandeln"}, {"Cannot negotiate with socks proxy", "Kann nicht mit Socks-Proxy verhandeln"},
{"CONNECT error", "CONNECT-Fehler"}, {"CONNECT error", "CONNECT-Fehler"},
{"Failed to connect", "Verbindung konnte nicht hergestellt werden"}, {"Failed to Connect", "Verbindung konnte nicht hergestellt werden"},
{"SOCKS proxy error", "SOCKS-Proxy-Fehler"}, {"socks proxy error", "Socks-Proxy-Fehler"},
{"Failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"}, {"failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
{"No reply from SOCKS proxy", "Keine Antwort vom SOCKS-Proxy"}, {"No Reply From socks proxy", "Keine Antwort vom Socks-Proxy"},
{"Cannot connect", "Kann nicht verbinden"}, {"cannot connect", "kann nicht verbinden"},
{"HTTP out proxy not implemented", "HTTP-Outproxy nicht implementiert"}, {"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
{"Cannot connect to upstream HTTP proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"}, {"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
{"Host is down", "Host ist offline"}, {"Host is down", "Host ist offline"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbauen, vielleicht ist er offline. Versuche es später noch mal."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Konnte keine Verbindung zum angefragten Host aufbauen, vielleicht ist er offline. Versuche es später noch mal."},
{"", ""}, {"", ""},

View File

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

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021-2023, The PurpleI2P Project * Copyright (c) 2021-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
* *
@@ -31,12 +31,9 @@ namespace i18n
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace italian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace italian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace polish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace portuguese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace turkish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
@@ -54,12 +51,9 @@ namespace i18n
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} }, { "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} }, { "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
{ "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} }, { "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} },
{ "polish", {"Polski", "pl", i2p::i18n::polish::GetLocale} },
{ "portuguese", {"Português", "pt", i2p::i18n::portuguese::GetLocale} },
{ "russian", {"Русский язык", "ru", i2p::i18n::russian::GetLocale} }, { "russian", {"Русский язык", "ru", i2p::i18n::russian::GetLocale} },
{ "spanish", {"Español", "es", i2p::i18n::spanish::GetLocale} }, { "spanish", {"Español", "es", i2p::i18n::spanish::GetLocale} },
{ "swedish", {"Svenska", "sv", i2p::i18n::swedish::GetLocale} }, { "swedish", {"Svenska", "sv", i2p::i18n::swedish::GetLocale} },
{ "turkish", {"Türk dili", "tr", i2p::i18n::turkish::GetLocale} },
{ "turkmen", {"Türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} }, { "turkmen", {"Türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
{ "ukrainian", {"Украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} }, { "ukrainian", {"Украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
{ "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} }, { "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} },

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -58,11 +58,10 @@ namespace italian // language namespace
{"Unknown", "Sconosciuto"}, {"Unknown", "Sconosciuto"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Mesh"}, {"Mesh", "Mesh"},
{"Error", "Errore"},
{"Clock skew", "Orologio disallineato"}, {"Clock skew", "Orologio disallineato"},
{"Offline", "Disconnesso"}, {"Offline", "Disconnesso"},
{"Symmetric NAT", "NAT simmetrico"}, {"Symmetric NAT", "NAT simmetrico"},
{"Full cone NAT", "Cono completo NAT"},
{"No Descriptors", "Nessun descrittore"},
{"Uptime", "In funzione da"}, {"Uptime", "In funzione da"},
{"Network status", "Stato della rete"}, {"Network status", "Stato della rete"},
{"Network status v6", "Stato della rete v6"}, {"Network status v6", "Stato della rete v6"},
@@ -118,10 +117,9 @@ namespace italian // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Data di fine"}, {"EndDate", "Data di fine"},
{"floodfill mode is disabled", "la modalità floodfill è disabilitata"}, {"not floodfill", "no floodfill"},
{"Queue size", "Dimensione della coda"}, {"Queue size", "Dimensione della coda"},
{"Run peer test", "Esegui il test dei peer"}, {"Run peer test", "Esegui il test dei peer"},
{"Reload tunnels configuration", "Ricarica la configurazione dei tunnel"},
{"Decline transit tunnels", "Rifiuta tunnel di transito"}, {"Decline transit tunnels", "Rifiuta tunnel di transito"},
{"Accept transit tunnels", "Accetta tunnel di transito"}, {"Accept transit tunnels", "Accetta tunnel di transito"},
{"Cancel graceful shutdown", "Annulla l'interruzione controllata"}, {"Cancel graceful shutdown", "Annulla l'interruzione controllata"},
@@ -149,8 +147,8 @@ namespace italian // language namespace
{"Destination not found", "Destinazione non trovata"}, {"Destination not found", "Destinazione non trovata"},
{"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 5 seconds", "Verrai reindirizzato in 5 secondi"},
{"Transit tunnels count must not exceed %d", "Il conteggio dei tunnel di transito non deve superare %d"}, {"Transit tunnels count must not exceed 65535", "Il numero di tunnel di transito non può superare i 65535"},
{"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"},
{"Description", "Descrizione"}, {"Description", "Descrizione"},
@@ -168,33 +166,32 @@ namespace italian // language namespace
{"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"}, {"You may try to find this host on jump services below", "Si può provare a trovare questo host sui servizi di salto qui sotto"},
{"Invalid request", "Richiesta non valida"}, {"Invalid request", "Richiesta non valida"},
{"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"}, {"Proxy unable to parse your request", "Il proxy non è in grado di elaborare la tua richiesta"},
{"Addresshelper is not supported", "Addresshelper non è supportato"}, {"addresshelper is not supported", "addresshelper non è supportato"},
{"Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'host %s è <font color=red>già nella rubrica del router</font>. <b>Attenzione: la fonte di questo URL potrebbe essere dannosa!</b> Fai clic qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."}, {"Host", "Host"},
{"Addresshelper forced update rejected", "Aggiornamento forzato dell'helper degli indirizzi rifiutato"}, {"added to router's addressbook from helper", "aggiunto alla rubrica tramite l'helper"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Per aggiungere host <b>%s</b> nella rubrica del router, clicca qui: <a href=\"%s%s%s\">Continua</a>."}, {"Click here to proceed:", "Clicca qui per procedere:"},
{"Addresshelper request", "Richiesta di indirizzo helper"}, {"Continue", "Continua"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "L'host %s viene aggiunto alla rubrica del router dall'helper. Fai clic qui per procedere: <a href=\"%s\">Continua</a>."}, {"Addresshelper found", "Addresshelper trovato"},
{"Addresshelper adding", "Aggiunta di Addresshelper"}, {"already in router's addressbook", "già presente nella rubrica del router"},
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'host %s è <font color=red>già nella rubrica del router</font>. Clicca qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."}, {"Click here to update record:", "Clicca qui per aggiornare l'elemento:"},
{"Addresshelper update", "Aggiornamento dell'helper degli indirizzi"}, {"invalid request uri", "uri della richiesta non valido"},
{"Invalid request URI", "URI della richiesta non valido"},
{"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"}, {"Can't detect destination host from request", "Impossibile determinare l'host di destinazione dalla richiesta"},
{"Outproxy failure", "Fallimento del proxy di uscita"}, {"Outproxy failure", "Fallimento del proxy di uscita"},
{"Bad outproxy settings", "Impostazioni errate del proxy di uscita"}, {"bad outproxy settings", "impostazioni errate del proxy di uscita"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Host %s non all'interno della rete I2P, ma il proxy di uscita non è abilitato"}, {"not inside I2P network, but outproxy is not enabled", "non all'interno della rete I2P, ma il proxy di uscita non è abilitato"},
{"Unknown outproxy URL", "URL del proxy di uscita sconosciuto"}, {"unknown outproxy url", "url del proxy di uscita sconosciuto"},
{"Cannot resolve upstream proxy", "Impossibile identificare il flusso a monte del proxy"}, {"cannot resolve upstream proxy", "impossibile identificare il flusso a monte del proxy"},
{"Hostname is too long", "Il nome dell'host è troppo lungo"}, {"hostname too long", "il nome dell'host è troppo lungo"},
{"Cannot connect to upstream SOCKS proxy", "Impossibile connettersi al flusso a monte del proxy SOCKS"}, {"cannot connect to upstream socks proxy", "impossibile connettersi al flusso a monte del proxy socks"},
{"Cannot negotiate with SOCKS proxy", "Impossibile negoziare con il proxy SOCKS"}, {"Cannot negotiate with socks proxy", "Impossibile negoziare con il proxy socks"},
{"CONNECT error", "Errore di connessione"}, {"CONNECT error", "Errore di connessione"},
{"Failed to connect", "Connessione fallita"}, {"Failed to Connect", "Connessione fallita"},
{"SOCKS proxy error", "Errore del proxy SOCKS"}, {"socks proxy error", "errore del proxy socks"},
{"Failed to send request to upstream", "Invio della richiesta a monte non riuscito"}, {"failed to send request to upstream", "invio della richiesta a monte non riuscito"},
{"No reply from SOCKS proxy", "Nessuna risposta dal proxy SOCKS"}, {"No Reply From socks proxy", "Nessuna risposta dal proxy socks"},
{"Cannot connect", "Impossibile connettersi"}, {"cannot connect", "impossibile connettersi"},
{"HTTP out proxy not implemented", "Proxy HTTP di uscita non implementato"}, {"http out proxy not implemented", "proxy http di uscita non implementato"},
{"Cannot connect to upstream HTTP proxy", "Impossibile connettersi al flusso a monte del proxy HTTP"}, {"cannot connect to upstream http proxy", "impossibile connettersi al proxy http a monte"},
{"Host is down", "L'host è offline"}, {"Host is down", "L'host è offline"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Impossibile creare la connessione all'host richiesto, probabilmente è offline. Riprova più tardi."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Impossibile creare la connessione all'host richiesto, probabilmente è offline. Riprova più tardi."},
{"", ""}, {"", ""},

View File

@@ -1,59 +0,0 @@
/*
* Copyright (c) 2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <map>
#include <vector>
#include <string>
#include <memory>
#include "I18N.h"
// Polish localization file
namespace i2p
{
namespace i18n
{
namespace polish // language namespace
{
// language name in lowercase
static std::string language = "polish";
// See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) {
return (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
}
static std::map<std::string, std::string> strings
{
{"building", "Kompilowanie"},
{"failed", "nieudane"},
{"expiring", "wygasający"},
{"established", "ustanowiony"},
{"Main page", "Strona główna"},
{"Router commands", "Komendy routera"},
{"Tunnels", "Tunele"},
{"OK", "Ok"},
{"Uptime", "Czas pracy"},
{"Sent", "Wysłane"},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"", {"", "", ""}},
};
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
}
} // language
} // i18n
} // i2p

View File

@@ -1,219 +0,0 @@
/*
* Copyright (c) 2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <map>
#include <vector>
#include <string>
#include <memory>
#include "I18N.h"
// Portuguese localization file
namespace i2p
{
namespace i18n
{
namespace portuguese // language namespace
{
// language name in lowercase
static std::string language = "portuguese";
// See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) {
return n != 1 ? 1 : 0;
}
static std::map<std::string, std::string> strings
{
{"%.2f KiB", "%.2f KiB"},
{"%.2f MiB", "%.2f MiB"},
{"%.2f GiB", "%.2f GiB"},
{"building", "construindo"},
{"failed", "falhou"},
{"expiring", "expirando"},
{"established", "estabelecido"},
{"unknown", "desconhecido"},
{"exploratory", "exploratório"},
{"Purple I2P Webconsole", "Webconsole Purple I2P"},
{"<b>i2pd</b> webconsole", "webconsole <b>i2pd</b>"},
{"Main page", "Página Principal"},
{"Router commands", "Comandos do Roteador"},
{"Local Destinations", "Destinos Locais"},
{"LeaseSets", "LeaseSets"},
{"Tunnels", "Túneis"},
{"Transit Tunnels", "Túneis de Trânsito"},
{"Transports", "Transportes"},
{"I2P tunnels", "Túneis I2P"},
{"SAM sessions", "Sessões do SAM"},
{"ERROR", "ERRO"},
{"OK", "OK"},
{"Testing", "Testando"},
{"Firewalled", "Sob Firewall"},
{"Unknown", "Desconhecido"},
{"Proxy", "Proxy"},
{"Mesh", "Malha"},
{"Clock skew", "Defasagem do Relógio"},
{"Offline", "Desligado"},
{"Symmetric NAT", "NAT Simétrico"},
{"Full cone NAT", "Full cone NAT"},
{"No Descriptors", "Sem Descritores"},
{"Uptime", "Tempo Ativo"},
{"Network status", "Estado da rede"},
{"Network status v6", "Estado da rede v6"},
{"Stopping in", "Parando em"},
{"Family", "Família"},
{"Tunnel creation success rate", "Taxa de sucesso na criação de túneis"},
{"Received", "Recebido"},
{"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Enviado"},
{"Transit", "Trânsito"},
{"Data path", "Diretório dos dados"},
{"Hidden content. Press on text to see.", "Conteúdo oculto. Clique no texto para revelar."},
{"Router Ident", "Identidade do Roteador"},
{"Router Family", "Família do Roteador"},
{"Router Caps", "Limites do Roteador"},
{"Version", "Versão"},
{"Our external address", "Nosso endereço externo"},
{"supported", "suportado"},
{"Routers", "Roteadores"},
{"Floodfills", "Modo Inundação"},
{"Client Tunnels", "Túneis de Clientes"},
{"Services", "Serviços"},
{"Enabled", "Ativado"},
{"Disabled", "Desativado"},
{"Encrypted B33 address", "Endereço B33 criptografado"},
{"Address registration line", "Linha de cadastro de endereço"},
{"Domain", "Domínio"},
{"Generate", "Gerar"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b> Nota: </b>A string resultante só pode ser usada para registrar domínios 2LD (exemplo.i2p). Para registrar subdomínios por favor utilize o i2pd-tools."},
{"Address", "Endereço"},
{"Type", "Tipo"},
{"EncType", "Tipo de Criptografia"},
{"Inbound tunnels", "Túneis de Entrada"},
{"%dms", "%dms"},
{"Outbound tunnels", "Túneis de Saída"},
{"Tags", "Etiquetas"},
{"Incoming", "Entradas"},
{"Outgoing", "Saídas"},
{"Destination", "Destinos"},
{"Amount", "Quantidade"},
{"Incoming Tags", "Etiquetas de Entrada"},
{"Tags sessions", "Sessões de etiquetas"},
{"Status", "Estado"},
{"Local Destination", "Destinos Locais"},
{"Streams", "Fluxos"},
{"Close stream", "Fechar fluxo"},
{"I2CP session not found", "Sessão do I2CP não encontrada"},
{"I2CP is not enabled", "I2CP não está ativado"},
{"Invalid", "Inválido"},
{"Store type", "Tipo de armazenamento"},
{"Expires", "Expira em"},
{"Non Expired Leases", "Sessões não expiradas"},
{"Gateway", "Gateway"},
{"TunnelID", "TunnelID"},
{"EndDate", "Data final"},
{"floodfill mode is disabled", "Mode de inundação está desativado"},
{"Queue size", "Tamanho da fila"},
{"Run peer test", "Executar teste de peers"},
{"Reload tunnels configuration", "Recarregar a configuração dos túneis"},
{"Decline transit tunnels", "Negar túneis de trânsito"},
{"Accept transit tunnels", "Aceitar túneis de trânsito"},
{"Cancel graceful shutdown", "Cancelar desligamento gracioso"},
{"Start graceful shutdown", "Iniciar desligamento gracioso"},
{"Force shutdown", "Forçar desligamento"},
{"Reload external CSS styles", "Recarregar estilos CSS externos"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Nota: </b> Qualquer ação feita aqui não será permanente e não altera os seus arquivos de configuração."},
{"Logging level", "Nível de registro"},
{"Transit tunnels limit", "Limite de túneis de trânsito"},
{"Change", "Mudar"},
{"Change language", "Trocar idioma"},
{"no transit tunnels currently built", "Nenhum túnel de trânsito construido no momento"},
{"SAM disabled", "SAM desativado"},
{"no sessions currently running", "Nenhuma sessão funcionando no momento"},
{"SAM session not found", "Nenhuma sessão do SAM encontrada"},
{"SAM Session", "Sessão do SAM"},
{"Server Tunnels", "Túneis de Servidor"},
{"Client Forwards", "Túneis de Cliente"},
{"Server Forwards", "Encaminhamentos de Servidor"},
{"Unknown page", "Página desconhecida"},
{"Invalid token", "Token Inválido"},
{"SUCCESS", "SUCESSO"},
{"Stream closed", "Fluxo fechado"},
{"Stream not found or already was closed", "Fluxo não encontrado ou já encerrado"},
{"Destination not found", "Destino não encontrado"},
{"StreamID can't be null", "StreamID não pode ser nulo"},
{"Return to destination page", "Retornar para à página de destino"},
{"You will be redirected in %d seconds", "Você será redirecionado em %d segundos"},
{"Transit tunnels count must not exceed %d", "A contagem de túneis de trânsito não deve exceder %d"},
{"Back to commands list", "Voltar para a lista de comandos"},
{"Register at reg.i2p", "Registrar na reg.i2p"},
{"Description", "Descrição"},
{"A bit information about service on domain", "Algumas informações sobre o serviço no domínio"},
{"Submit", "Enviar"},
{"Domain can't end with .b32.i2p", "O domínio não pode terminar com .b32.i2p"},
{"Domain must end with .i2p", "O domínio não pode terminar com .i2p"},
{"Such destination is not found", "Tal destino não foi encontrado"},
{"Unknown command", "Comando desconhecido"},
{"Command accepted", "Comando aceito"},
{"Proxy error", "Erro no proxy"},
{"Proxy info", "Informações do proxy"},
{"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"},
{"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"},
{"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"},
{"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"},
{"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 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 proceder: <a href='%s'> Continuar </a>."},
{"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>."},
{"Addresshelper update", "Atualização do Auxiliar de Endereços"},
{"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"},
{"Outproxy failure", "Falha no 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"},
{"Unknown outproxy URL", "URL de outproxy desconhecida"},
{"Cannot resolve upstream proxy", "Não é possível resolver o proxy de entrada"},
{"Hostname is too long", "O hostname é muito longo"},
{"Cannot connect to upstream SOCKS proxy", "Não é possível se conectar ao proxy SOCKS de entrada"},
{"Cannot negotiate with SOCKS proxy", "Não é possível negociar com o proxy SOCKS"},
{"CONNECT error", "Erro de CONEXÃO"},
{"Failed to connect", "Falha ao conectar"},
{"SOCKS proxy error", "Erro no proxy SOCKS"},
{"Failed to send request to upstream", "Falha ao enviar requisição para o fluxo de entrada"},
{"No reply from SOCKS proxy", "Sem resposta do proxy SOCKS"},
{"Cannot connect", "Impossível conectar"},
{"HTTP out proxy not implemented", "proxy de saída HTTP não implementado"},
{"Cannot connect to upstream HTTP proxy", "Não é possível conectar ao proxy HTTP de entrada"},
{"Host is down", "Host está desligado"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Não é possível se conectar ao host requisitado, talvez ele esteja for do ar. Por favor, tente novamente mais tarde."},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"%d days", {"%d Dia", "%d Dias"}},
{"%d hours", {"%d hora", "%d horas"}},
{"%d minutes", {"%d minuto", "%d minutos"}},
{"%d seconds", {"%d Segundo", "%d segundos"}},
{"", {"", ""}},
};
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
}
} // language
} // i18n
} // i2p

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -40,7 +40,6 @@ namespace russian // language namespace
{"established", "работает"}, {"established", "работает"},
{"unknown", "неизвестно"}, {"unknown", "неизвестно"},
{"exploratory", "исследовательский"}, {"exploratory", "исследовательский"},
{"Purple I2P Webconsole", "Веб-консоль Purple I2P"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"}, {"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
{"Main page", "Главная"}, {"Main page", "Главная"},
{"Router commands", "Команды роутера"}, {"Router commands", "Команды роутера"},
@@ -58,11 +57,10 @@ namespace russian // language namespace
{"Unknown", "Неизвестно"}, {"Unknown", "Неизвестно"},
{"Proxy", "Прокси"}, {"Proxy", "Прокси"},
{"Mesh", "MESH-сеть"}, {"Mesh", "MESH-сеть"},
{"Error", "Ошибка"},
{"Clock skew", "Не точное время"}, {"Clock skew", "Не точное время"},
{"Offline", "Оффлайн"}, {"Offline", "Оффлайн"},
{"Symmetric NAT", "Симметричный NAT"}, {"Symmetric NAT", "Симметричный NAT"},
{"Full cone NAT", "Full cone NAT"},
{"No Descriptors", "Нет дескрипторов"},
{"Uptime", "В сети"}, {"Uptime", "В сети"},
{"Network status", "Сетевой статус"}, {"Network status", "Сетевой статус"},
{"Network status v6", "Сетевой статус v6"}, {"Network status v6", "Сетевой статус v6"},
@@ -118,10 +116,9 @@ namespace russian // language namespace
{"Gateway", "Шлюз"}, {"Gateway", "Шлюз"},
{"TunnelID", "ID туннеля"}, {"TunnelID", "ID туннеля"},
{"EndDate", "Заканчивается"}, {"EndDate", "Заканчивается"},
{"floodfill mode is disabled", "режим флудфила отключен"}, {"not floodfill", "не флудфил"},
{"Queue size", "Размер очереди"}, {"Queue size", "Размер очереди"},
{"Run peer test", "Запустить тестирование"}, {"Run peer test", "Запустить тестирование"},
{"Reload tunnels configuration", "Перезагрузить конфигурацию туннелей"},
{"Decline transit tunnels", "Отклонять транзитные туннели"}, {"Decline transit tunnels", "Отклонять транзитные туннели"},
{"Accept transit tunnels", "Принимать транзитные туннели"}, {"Accept transit tunnels", "Принимать транзитные туннели"},
{"Cancel graceful shutdown", "Отменить плавную остановку"}, {"Cancel graceful shutdown", "Отменить плавную остановку"},
@@ -149,8 +146,8 @@ namespace russian // language namespace
{"Destination not found", "Точка назначения не найдена"}, {"Destination not found", "Точка назначения не найдена"},
{"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 5 seconds", "Вы будете переадресованы через 5 секунд"},
{"Transit tunnels count must not exceed %d", "Число транзитных туннелей не должно превышать %d"}, {"Transit tunnels count must not exceed 65535", "Число транзитных туннелей не должно превышать 65535"},
{"Back to commands list", "Вернуться к списку команд"}, {"Back to commands list", "Вернуться к списку команд"},
{"Register at reg.i2p", "Зарегистрировать на reg.i2p"}, {"Register at reg.i2p", "Зарегистрировать на reg.i2p"},
{"Description", "Описание"}, {"Description", "Описание"},
@@ -168,33 +165,32 @@ namespace russian // language namespace
{"You may try to find this host on jump services below", "Вы можете попробовать найти узел через джамп сервисы ниже"}, {"You may try to find this host on jump services below", "Вы можете попробовать найти узел через джамп сервисы ниже"},
{"Invalid request", "Некорректный запрос"}, {"Invalid request", "Некорректный запрос"},
{"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"}, {"Proxy unable to parse your request", "Прокси не может разобрать ваш запрос"},
{"Addresshelper is not supported", "Addresshelper не поддерживается"}, {"addresshelper is not supported", "addresshelper не поддерживается"},
{"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>.", "Узел %s <font color=red>уже в адресной книге роутера</font>. <b>Будьте осторожны: источник данной ссылки может быть вредоносным!</b> Нажмите здесь, чтобы обновить запись: <a href=\"%s%s%s&update=true\">Продолжить</a>."}, {"Host", "Узел"},
{"Addresshelper forced update rejected", "Принудительное обновление через Addresshelper отклонено"}, {"added to router's addressbook from helper", "добавлен в адресную книгу роутера через хелпер"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Чтобы добавить узел <b>%s</b> в адресную книгу роутера, нажмите здесь: <a href=\"%s%s%s\"родолжить</a>."}, {"Click here to proceed:", "Нажмите здесь, чтобы продолжить:"},
{"Addresshelper request", "Запрос добавления Addresshelper"}, {"Continue", "Продолжить"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Узел %s добавлен в адресную книгу роутера через хелпер. Нажмите здесь, чтобы продолжить: <a href=\"%s\">Продолжить</a>."}, {"Addresshelper found", "Найден addresshelper"},
{"Addresshelper adding", "Добавление Addresshelper"}, {"already in router's addressbook", "уже в адресной книге роутера"},
{"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>.", "Узел %s <font color=red>уже в адресной книге роутера</font>. Нажмите здесь, чтобы обновить запись: <a href=\"%s%s%s&update=true\">Продолжить</a>."}, {"Click here to update record:", "Нажмите здесь, чтобы обновить запись:"},
{"Addresshelper update", "Обновление записи через Addresshelper"}, {"invalid request uri", "некорректный URI запроса"},
{"Invalid request URI", "Некорректный URI запроса"},
{"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"}, {"Can't detect destination host from request", "Не удалось определить адрес назначения из запроса"},
{"Outproxy failure", "Ошибка внешнего прокси"}, {"Outproxy failure", "Ошибка внешнего прокси"},
{"Bad outproxy settings", "Некорректные настройки внешнего прокси"}, {"bad outproxy settings", "некорректные настройки внешнего прокси"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Узел %s не в I2P сети, но внешний прокси не включен"}, {"not inside I2P network, but outproxy is not enabled", "не в I2P сети, но внешний прокси не включен"},
{"Unknown outproxy URL", "Неизвестный URL внешнего прокси"}, {"unknown outproxy url", "неизвестный URL внешнего прокси"},
{"Cannot resolve upstream proxy", "Не удается определить вышестоящий прокси"}, {"cannot resolve upstream proxy", "не удается определить вышестоящий прокси"},
{"Hostname is too long", "Имя хоста слишком длинное"}, {"hostname too long", "имя хоста слишком длинное"},
{"Cannot connect to upstream SOCKS proxy", "Не удалось подключиться к вышестоящему SOCKS прокси серверу"}, {"cannot connect to upstream socks proxy", "не удается подключиться к вышестоящему SOCKS прокси"},
{"Cannot negotiate with SOCKS proxy", "Не удается договориться с вышестоящим SOCKS прокси"}, {"Cannot negotiate with socks proxy", "Не удается договориться с вышестоящим SOCKS прокси"},
{"CONNECT error", "Ошибка CONNECT запроса"}, {"CONNECT error", "Ошибка CONNECT запроса"},
{"Failed to connect", "Не удалось соединиться"}, {"Failed to Connect", "Не удалось подключиться"},
{"SOCKS proxy error", "Ошибка SOCKS прокси"}, {"socks proxy error", "ошибка SOCKS прокси"},
{"Failed to send request to upstream", "Не удалось отправить запрос вышестоящему прокси серверу"}, {"failed to send request to upstream", "не удалось отправить запрос вышестоящему прокси"},
{"No reply from SOCKS proxy", "Нет ответа от SOCKS прокси сервера"}, {"No Reply From socks proxy", "Нет ответа от SOCKS прокси сервера"},
{"Cannot connect", "Не удалось подключиться"}, {"cannot connect", "не удалось подключиться"},
{"HTTP out proxy not implemented", "Поддержка внешнего HTTP прокси сервера не реализована"}, {"http out proxy not implemented", "поддержка внешнего HTTP прокси сервера не реализована"},
{"Cannot connect to upstream HTTP proxy", "Не удалось подключиться к вышестоящему HTTP прокси серверу"}, {"cannot connect to upstream http proxy", "не удалось подключиться к вышестоящему HTTP прокси серверу"},
{"Host is down", "Узел недоступен"}, {"Host is down", "Узел недоступен"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному узлу, возможно он не в сети. Попробуйте повторить запрос позже."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Не удалось установить соединение к запрошенному узлу, возможно он не в сети. Попробуйте повторить запрос позже."},
{"", ""}, {"", ""},

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2022-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -58,6 +58,7 @@ namespace spanish // language namespace
{"Unknown", "Desconocido"}, {"Unknown", "Desconocido"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Malla"}, {"Mesh", "Malla"},
{"Error", "Error"},
{"Clock skew", "Reloj desfasado"}, {"Clock skew", "Reloj desfasado"},
{"Offline", "Desconectado"}, {"Offline", "Desconectado"},
{"Symmetric NAT", "NAT simétrico"}, {"Symmetric NAT", "NAT simétrico"},
@@ -116,6 +117,7 @@ namespace spanish // language namespace
{"Gateway", "Puerta de enlace"}, {"Gateway", "Puerta de enlace"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "FechaVenc"}, {"EndDate", "FechaVenc"},
{"not floodfill", "no inundado"},
{"Queue size", "Tamaño de cola"}, {"Queue size", "Tamaño de cola"},
{"Run peer test", "Ejecutar prueba de par"}, {"Run peer test", "Ejecutar prueba de par"},
{"Decline transit tunnels", "Rechazar túneles de tránsito"}, {"Decline transit tunnels", "Rechazar túneles de tránsito"},
@@ -145,6 +147,8 @@ namespace spanish // language namespace
{"Destination not found", "Destino no encontrado"}, {"Destination not found", "Destino no encontrado"},
{"StreamID can't be null", "StreamID no puede ser nulo"}, {"StreamID can't be null", "StreamID no puede ser nulo"},
{"Return to destination page", "Volver a la página de destino"}, {"Return to destination page", "Volver a la página de destino"},
{"You will be redirected in 5 seconds", "Serás redirigido en 5 segundos"},
{"Transit tunnels count must not exceed 65535", "La cantidad de túneles de tránsito no puede exceder 65535"},
{"Back to commands list", "Volver a lista de comandos"}, {"Back to commands list", "Volver a lista de comandos"},
{"Register at reg.i2p", "Registrar en reg.i2p"}, {"Register at reg.i2p", "Registrar en reg.i2p"},
{"Description", "Descripción"}, {"Description", "Descripción"},
@@ -162,24 +166,32 @@ namespace spanish // language namespace
{"You may try to find this host on jump services below", "Puede intentar encontrar este dominio en los siguientes servicios de salto"}, {"You may try to find this host on jump services below", "Puede intentar encontrar este dominio en los siguientes servicios de salto"},
{"Invalid request", "Solicitud inválida"}, {"Invalid request", "Solicitud inválida"},
{"Proxy unable to parse your request", "Proxy no puede procesar su solicitud"}, {"Proxy unable to parse your request", "Proxy no puede procesar su solicitud"},
{"Invalid request URI", "URI de solicitud inválida"}, {"addresshelper is not supported", "ayudante de dirección no soportado"},
{"Host", "Dominio"},
{"added to router's addressbook from helper", "añadido a la libreta de direcciones desde el ayudante"},
{"Click here to proceed:", "Haga clic aquí para continuar:"},
{"Continue", "Continuar"},
{"Addresshelper found", "Se encontró ayudante de dirección"},
{"already in router's addressbook", "ya se encontró en libreta de direcciones"},
{"Click here to update record:", "Haga clic aquí para actualizar el registro:"},
{"invalid request uri", "uri de solicitud inválida"},
{"Can't detect destination host from request", "No se puede detectar el host de destino de la solicitud"}, {"Can't detect destination host from request", "No se puede detectar el host de destino de la solicitud"},
{"Outproxy failure", "Fallo en el proxy saliente"}, {"Outproxy failure", "Fallo en el proxy saliente"},
{"Bad outproxy settings", "Configuración de outproxy incorrecta"}, {"bad outproxy settings", "configuración de outproxy incorrecta"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Dominio %s no está dentro de la red I2P, pero el proxy de salida no está activado"}, {"not inside I2P network, but outproxy is not enabled", "no está dentro de la red I2P, pero el proxy de salida no está activado"},
{"Unknown outproxy URL", "URL de proxy outproxy desconocido"}, {"unknown outproxy url", "url de proxy outproxy desconocido"},
{"Cannot resolve upstream proxy", "No se puede resolver el proxy de upstream"}, {"cannot resolve upstream proxy", "no se puede resolver el proxy de upstream"},
{"Hostname is too long", "Nombre de dominio muy largo"}, {"hostname too long", "nombre de dominio muy largo"},
{"Cannot connect to upstream SOCKS proxy", "No se puede conectar al proxy SOCKS principal"}, {"cannot connect to upstream socks proxy", "no se puede conectar al proxy socks principal"},
{"Cannot negotiate with SOCKS proxy", "No se puede negociar con el proxy SOCKS"}, {"Cannot negotiate with socks proxy", "No se puede negociar con el proxy socks"},
{"CONNECT error", "Error de CONNECT"}, {"CONNECT error", "Error de CONNECT"},
{"Failed to connect", "Error al conectar"}, {"Failed to Connect", "Error al Conectar"},
{"SOCKS proxy error", "Error de proxy SOCKS"}, {"socks proxy error", "error de proxy socks"},
{"Failed to send request to upstream", "No se pudo enviar petición al principal"}, {"failed to send request to upstream", "no se pudo enviar petición al principal"},
{"No reply from SOCKS proxy", "Sin respuesta del proxy SOCKS"}, {"No Reply From socks proxy", "Sin respuesta del proxy socks"},
{"Cannot connect", "No se puede conectar"}, {"cannot connect", "no se puede conectar"},
{"HTTP out proxy not implemented", "Proxy externo HTTP no implementado"}, {"http out proxy not implemented", "proxy externo http no implementado"},
{"Cannot connect to upstream HTTP proxy", "No se puede conectar al proxy HTTP principal"}, {"cannot connect to upstream http proxy", "no se puede conectar al proxy http principal"},
{"Host is down", "Servidor caído"}, {"Host is down", "Servidor caído"},
{"Can't create connection to requested host, it may be down. Please try again later.", "No se puede crear la conexión al servidor solicitado, puede estar caído. Intente de nuevo más tarde."}, {"Can't create connection to requested host, it may be down. Please try again later.", "No se puede crear la conexión al servidor solicitado, puede estar caído. Intente de nuevo más tarde."},
{"", ""}, {"", ""},

View File

@@ -41,7 +41,7 @@ namespace swedish // language namespace
{"unknown", "okänt"}, {"unknown", "okänt"},
{"exploratory", "utforskande"}, {"exploratory", "utforskande"},
{"Purple I2P Webconsole", "Purple I2P Webbkonsoll"}, {"Purple I2P Webconsole", "Purple I2P Webbkonsoll"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b>-Webbkonsoll"}, {"<b>i2pd</b> webbkonsoll", "<b>i2pd</b>-Webbkonsoll"},
{"Main page", "Huvudsida"}, {"Main page", "Huvudsida"},
{"Router commands", "Routerkommandon"}, {"Router commands", "Routerkommandon"},
{"Local Destinations", "Lokala Platser"}, {"Local Destinations", "Lokala Platser"},
@@ -58,6 +58,7 @@ namespace swedish // language namespace
{"Unknown", "Okänt"}, {"Unknown", "Okänt"},
{"Proxy", "Proxy"}, {"Proxy", "Proxy"},
{"Mesh", "Mesh"}, {"Mesh", "Mesh"},
{"Error", "Fel"},
{"Clock skew", "Tidsförskjutning"}, {"Clock skew", "Tidsförskjutning"},
{"Offline", "Nedkopplad"}, {"Offline", "Nedkopplad"},
{"Symmetric NAT", "Symmetrisk NAT"}, {"Symmetric NAT", "Symmetrisk NAT"},
@@ -116,6 +117,7 @@ namespace swedish // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "EndDate"}, {"EndDate", "EndDate"},
{"not floodfill", "inte Översvämningsfyllare"},
{"Queue size", "Köstorlek"}, {"Queue size", "Köstorlek"},
{"Run peer test", "Utför utsiktstest"}, {"Run peer test", "Utför utsiktstest"},
{"Decline transit tunnels", "Avvisa förmedlande tunnlar"}, {"Decline transit tunnels", "Avvisa förmedlande tunnlar"},
@@ -145,8 +147,8 @@ namespace swedish // language namespace
{"Destination not found", "Plats hittades ej"}, {"Destination not found", "Plats hittades ej"},
{"StreamID can't be null", "Ström-ID kan inte vara null"}, {"StreamID can't be null", "Ström-ID kan inte vara null"},
{"Return to destination page", "Återvänd till platssidan"}, {"Return to destination page", "Återvänd till platssidan"},
{"You will be redirected in %d seconds", "Du omdirigeras inom %d sekunder"}, {"You will be redirected in 5 seconds", "Du omdirigeras inom fem sekunder"},
{"Transit tunnels count must not exceed %d", "Förmedlande tunnlar får inte överstiga %d"}, {"Transit tunnels count must not exceed 65535", "Förmedlande tunnlar får inte överstiga 65535"},
{"Back to commands list", "Tillbaka till kommandolistan"}, {"Back to commands list", "Tillbaka till kommandolistan"},
{"Register at reg.i2p", "Registrera vid reg.i2p"}, {"Register at reg.i2p", "Registrera vid reg.i2p"},
{"Description", "Beskrivning"}, {"Description", "Beskrivning"},
@@ -164,25 +166,32 @@ namespace swedish // language namespace
{"You may try to find this host on jump services below", "Du kan försöka att hitta värden genom hopptjänsterna nedan"}, {"You may try to find this host on jump services below", "Du kan försöka att hitta värden genom hopptjänsterna nedan"},
{"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"},
{"Invalid request URI", "Ogiltig förfrågnings-URI"}, {"Host", "Värd"},
{"added to router's addressbook from helper", "tillagd i routerns adressbok från adresshjälparen"},
{"Click here to proceed:", "Tryck här för att fortsätta:"},
{"Continue", "Fortsätt"},
{"Addresshelper found", "Adresshjälpare hittad"},
{"already in router's addressbook", "finns redan i routerns adressbok"},
{"Click here to update record:", "Tryck här för att uppdatera:"},
{"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"},
{"Bad outproxy settings", "Ogiltig utproxyinställning"}, {"bad outproxy settings", "ogiltig utproxyinställning"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Värd %s är inte inom I2P-näverket, men utproxy är inte påslaget"}, {"not inside I2P network, but outproxy is not enabled", "adressen är inte inom I2P-näverket, men utproxy är inte påslaget"},
{"Unknown outproxy URL", "okänt Utproxy-URL"}, {"unknown outproxy url", "okänt Utproxy-URL"},
{"Cannot resolve upstream proxy", "Hittar inte uppströmsproxyt"}, {"cannot resolve upstream proxy", "hittar inte uppströmsproxyt"},
{"Hostname is too long", "Värdnamnet är för långt"}, {"hostname too long", "värdnamnet är för långt"},
{"Cannot connect to upstream SOCKS proxy", "Kan inte ansluta till uppström SOCKS-proxy"}, {"cannot connect to upstream socks proxy", "kan inte ansluta till uppströmsproxyt"},
{"Cannot negotiate with SOCKS proxy", "Kan inte förhandla med SOCKSproxyt"}, {"Cannot negotiate with socks proxy", "Kan inte förhandla med socksproxyt"},
{"CONNECT error", "CONNECT-fel"}, {"CONNECT error", "CONNECT-fel"},
{"Failed to connect", "Anslutningen misslyckades"}, {"Failed to Connect", "Anslutningen misslyckades"},
{"SOCKS proxy error", "SOCKSproxyfel"}, {"socks proxy error", "Socksproxyfel"},
{"Failed to send request to upstream", "Förfrågan uppströms kunde ej skickas"}, {"failed to send request to upstream", "förfrågan uppströms kunde ej skickas"},
{"No reply from SOCKS proxy", "Fick inget svar från SOCKSproxyt"}, {"No Reply From socks proxy", "Fick inget svar från socksproxyt"},
{"Cannot connect", "Kan inte ansluta"}, {"cannot connect", "kan inte ansluta"},
{"HTTP out proxy not implemented", "HTTP-Utproxy ej implementerat"}, {"http out proxy not implemented", "HTTP-Utproxy ej implementerat"},
{"Cannot connect to upstream HTTP proxy", "Kan inte ansluta till uppströms HTTP-proxy"}, {"cannot connect to upstream http proxy", "Kan inte ansluta till uppströms HTTP-proxy"},
{"Host is down", "Värden är nere"}, {"Host is down", "Värden är nere"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Kan inte ansluta till värden, den kan vara nere. Vänligen försök senare."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Kan inte ansluta till värden, den kan vara nere. Vänligen försök senare."},
{"", ""}, {"", ""},
@@ -190,10 +199,10 @@ namespace swedish // language namespace
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
{"%d days", {"%d dag", "%d dagar"}}, {"%d days", {"%d Dag", "%d Dagar"}},
{"%d hours", {"%d timme", "%d timmar"}}, {"%d hours", {"%d Timme", "%d Timmar"}},
{"%d minutes", {"%d minut", "%d minuter"}}, {"%d minutes", {"%d Minut", "%d Minuter"}},
{"%d seconds", {"%d sekund", "%d sekunder"}}, {"%d seconds", {"%d Sekund", "%d Sekunder"}},
{"", {"", ""}}, {"", {"", ""}},
}; };

View File

@@ -1,114 +0,0 @@
/*
* Copyright (c) 2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <map>
#include <vector>
#include <string>
#include <memory>
#include "I18N.h"
// Turkish localization file
namespace i2p
{
namespace i18n
{
namespace turkish // language namespace
{
// language name in lowercase
static std::string language = "turkish";
// See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) {
return n != 1 ? 1 : 0;
}
static std::map<std::string, std::string> strings
{
{"%.2f KiB", "%.2f KiB"},
{"%.2f MiB", "%.2f MiB"},
{"%.2f GiB", "%.2f GiB"},
{"building", "kuruluyor"},
{"failed", "başarısız"},
{"expiring", "süresi geçiyor"},
{"established", "kurulmuş"},
{"unknown", "bilinmeyen"},
{"Purple I2P Webconsole", "Mor I2P Webkonsolu"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> webkonsolu"},
{"Main page", "Ana sayfa"},
{"Router commands", "Router komutları"},
{"Local Destinations", "Yerel Hedefler"},
{"Tunnels", "Tüneller"},
{"Transit Tunnels", "Transit Tünelleri"},
{"Transports", "Taşıma"},
{"I2P tunnels", "I2P tünelleri"},
{"SAM sessions", "SAM oturumları"},
{"ERROR", "HATA"},
{"OK", "TAMAM"},
{"Testing", "Test ediliyor"},
{"Firewalled", "Güvenlik Duvarı Kısıtlaması"},
{"Unknown", "Bilinmeyen"},
{"Proxy", "Proxy"},
{"Clock skew", "Saat sorunu"},
{"Offline", "Çevrimdışı"},
{"Symmetric NAT", "Simetrik NAT"},
{"Full cone NAT", "Full cone NAT"},
{"No Descriptors", "Tanımlayıcı Yok"},
{"Uptime", "Bağlantı süresi"},
{"Network status", "Ağ durumu"},
{"Network status v6", "Ağ durumu v6"},
{"Family", "Aile"},
{"Tunnel creation success rate", "Tünel oluşturma başarı oranı"},
{"Received", "Alındı"},
{"%.2f KiB/s", "%.2f KiB/s"},
{"Sent", "Gönderildi"},
{"Transit", "Transit"},
{"Data path", "Veri yolu"},
{"Hidden content. Press on text to see.", "Gizlenmiş içerik. Görmek için yazıya tıklayınız."},
{"Router Family", "Router Familyası"},
{"Decline transit tunnels", "Transit tünellerini reddet"},
{"Accept transit tunnels", "Transit tünellerini kabul et"},
{"Cancel graceful shutdown", "Düzgün durdurmayı iptal Et"},
{"Start graceful shutdown", "Düzgün durdurmayı başlat"},
{"Force shutdown", "Durdurmaya zorla"},
{"Reload external CSS styles", "Harici CSS stilini yeniden yükle"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Not:</b> burada yapılan ayarların hiçbiri kalıcı değildir ve ayar dosyalarınızı değiştirmez."},
{"Logging level", "Kayıt tutma seviyesi"},
{"Transit tunnels limit", "Transit tünel limiti"},
{"Change", "Değiştir"},
{"Change language", "Dil değiştir"},
{"no transit tunnels currently built", "kurulmuş bir transit tüneli bulunmamakta"},
{"SAM disabled", "SAM devre dışı"},
{"no sessions currently running", "hiçbir oturum şu anda çalışmıyor"},
{"SAM session not found", "SAM oturumu bulunamadı"},
{"SAM Session", "SAM oturumu"},
{"Server Tunnels", "Sunucu Tünelleri"},
{"Unknown page", "Bilinmeyen sayfa"},
{"Invalid token", "Geçersiz token"},
{"SUCCESS", "BAŞARILI"},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"%d days", {"%d gün", "%d gün"}},
{"%d hours", {"%d saat", "%d saat"}},
{"%d minutes", {"%d dakika", "%d dakika"}},
{"%d seconds", {"%d saniye", "%d saniye"}},
{"", {"", ""}},
};
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
{
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
}
} // language
} // i18n
} // i2p

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021-2023, The PurpleI2P Project * Copyright (c) 2021-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
* *
@@ -40,7 +40,6 @@ namespace turkmen // language namespace
{"established", "işleýär"}, {"established", "işleýär"},
{"unknown", "näbelli"}, {"unknown", "näbelli"},
{"exploratory", "gözleg"}, {"exploratory", "gözleg"},
{"Purple I2P Webconsole", "Web konsoly Purple I2P"},
{"<b>i2pd</b> webconsole", "Web konsoly <b>i2pd</b>"}, {"<b>i2pd</b> webconsole", "Web konsoly <b>i2pd</b>"},
{"Main page", "Esasy sahypa"}, {"Main page", "Esasy sahypa"},
{"Router commands", "Marşrutizator buýruklary"}, {"Router commands", "Marşrutizator buýruklary"},
@@ -58,6 +57,7 @@ namespace turkmen // language namespace
{"Unknown", "Näbelli"}, {"Unknown", "Näbelli"},
{"Proxy", "Proksi"}, {"Proxy", "Proksi"},
{"Mesh", "MESH-tor"}, {"Mesh", "MESH-tor"},
{"Error", "Ýalňyşlyk"},
{"Clock skew", "Takyk wagt däl"}, {"Clock skew", "Takyk wagt däl"},
{"Offline", "Awtonom"}, {"Offline", "Awtonom"},
{"Symmetric NAT", "Simmetriklik NAT"}, {"Symmetric NAT", "Simmetriklik NAT"},
@@ -116,6 +116,7 @@ namespace turkmen // language namespace
{"Gateway", "Derweze"}, {"Gateway", "Derweze"},
{"TunnelID", "Tuneliň ID"}, {"TunnelID", "Tuneliň ID"},
{"EndDate", "Gutarýar"}, {"EndDate", "Gutarýar"},
{"not floodfill", "fludfil däl"},
{"Queue size", "Nobatyň ululygy"}, {"Queue size", "Nobatyň ululygy"},
{"Run peer test", "Synag başlaň"}, {"Run peer test", "Synag başlaň"},
{"Decline transit tunnels", "Tranzit tunellerini ret ediň"}, {"Decline transit tunnels", "Tranzit tunellerini ret ediň"},
@@ -145,6 +146,8 @@ namespace turkmen // language namespace
{"Destination not found", "Niýetlenen ýeri tapylmady"}, {"Destination not found", "Niýetlenen ýeri tapylmady"},
{"StreamID can't be null", "StreamID boş bolup bilmez"}, {"StreamID can't be null", "StreamID boş bolup bilmez"},
{"Return to destination page", "Barmaly nokadynyň nokadyna gaýdyp geliň"}, {"Return to destination page", "Barmaly nokadynyň nokadyna gaýdyp geliň"},
{"You will be redirected in 5 seconds", "5 sekuntdan soň täzeden ugrukdyrylarsyňyz"},
{"Transit tunnels count must not exceed 65535", "Tranzit tagtalaryň sany 65535-den geçmeli däldir"},
{"Back to commands list", "Topar sanawyna dolan"}, {"Back to commands list", "Topar sanawyna dolan"},
{"Register at reg.i2p", "Reg.i2P-de hasaba duruň"}, {"Register at reg.i2p", "Reg.i2P-de hasaba duruň"},
{"Description", "Beýany"}, {"Description", "Beýany"},
@@ -162,24 +165,32 @@ namespace turkmen // language namespace
{"You may try to find this host on jump services below", "Aşakdaky böküş hyzmatlarynda bu öý eýesini tapmaga synanyşyp bilersiňiz"}, {"You may try to find this host on jump services below", "Aşakdaky böküş hyzmatlarynda bu öý eýesini tapmaga synanyşyp bilersiňiz"},
{"Invalid request", "Nädogry haýyş"}, {"Invalid request", "Nädogry haýyş"},
{"Proxy unable to parse your request", "Proksi haýyşyňyzy derňäp bilmeýär"}, {"Proxy unable to parse your request", "Proksi haýyşyňyzy derňäp bilmeýär"},
{"Invalid request URI", "Nädogry haýyş URI"}, {"addresshelper is not supported", "Salgylandyryjy goldanok"},
{"Host", "Adres"},
{"added to router's addressbook from helper", "marşruteriň adresini kömekçiden goşdy"},
{"Click here to proceed:", "Dowam etmek bu ýerde basyň:"},
{"Continue", "Dowam et"},
{"Addresshelper found", "Forgelper tapyldy"},
{"already in router's addressbook", "marşruteriň adres kitaby"},
{"Click here to update record:", "Recordazgyny täzelemek üçin bu ýerde basyň:"},
{"invalid request uri", "nädogry haýyş URI"},
{"Can't detect destination host from request", "Haýyşdan barmaly ýerini tapyp bilemok"}, {"Can't detect destination host from request", "Haýyşdan barmaly ýerini tapyp bilemok"},
{"Outproxy failure", "Daşarky proksi ýalňyşlyk"}, {"Outproxy failure", "Daşarky proksi ýalňyşlyk"},
{"Bad outproxy settings", "Daşarky Daşarky proksi sazlamalary nädogry"}, {"bad outproxy settings", "daşarky daşarky proksi sazlamalary nädogry"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Adres %s I2P torunda däl, ýöne daşarky proksi goşulmaýar"}, {"not inside I2P network, but outproxy is not enabled", "I2P torunda däl, ýöne daşarky proksi goşulmaýar"},
{"Unknown outproxy URL", "Näbelli daşarky proksi URL"}, {"unknown outproxy url", "näbelli daşarky proksi URL"},
{"Cannot resolve upstream proxy", "Has ýokary proksi kesgitläp bilmeýär"}, {"cannot resolve upstream proxy", "has ýokary proksi kesgitläp bilmeýär"},
{"Hostname is too long", "Hoster eýesi ady gaty uzyn"}, {"hostname too long", "hoster eýesi ady gaty uzyn"},
{"Cannot connect to upstream SOCKS proxy", "Ýokary jorap SOCKS proksi bilen birigip bolmaýar"}, {"cannot connect to upstream socks proxy", "ýokary jorap SOCKS proksi bilen birigip bolmaýar"},
{"Cannot negotiate with SOCKS proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"}, {"Cannot negotiate with socks proxy", "Iň ýokary jorap SOCKS proksi bilen ylalaşyp bilmeýärler"},
{"CONNECT error", "Bagyr haýyşy säwligi"}, {"CONNECT error", "Bagyr haýyşy säwligi"},
{"Failed to connect", "Birikdirip bilmedi"}, {"Failed to Connect", "Birikdirip bilmedi"},
{"SOCKS proxy error", "SOCKS proksi ýalňyşlygy"}, {"socks proxy error", "socks proksi ýalňyşlygy"},
{"Failed to send request to upstream", "Öý eýesi proksi üçin haýyş iberip bilmedi"}, {"failed to send request to upstream", "öý eýesi proksi üçin haýyş iberip bilmedi"},
{"No reply from SOCKS proxy", "Jorap SOCKS proksi serwerinden hiç hili jogap ýok"}, {"No Reply From socks proxy", "Jorap proksi serwerinden hiç hili jogap ýok"},
{"Cannot connect", "Birikdirip bilmedi"}, {"cannot connect", "birikdirip bilmedi"},
{"HTTP out proxy not implemented", "Daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"}, {"http out proxy not implemented", "daşarky HTTP proksi serwerini goldamak amala aşyrylmaýar"},
{"Cannot connect to upstream HTTP proxy", "Ýokary jorap HTTP proksi bilen birigip bolmaýar"}, {"cannot connect to upstream http proxy", "ýokary akym HTTP proksi serwerine birigip bilmedi"},
{"Host is down", "Salgy elýeterli däl"}, {"Host is down", "Salgy elýeterli däl"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Talap edilýän salgyda birikmäni gurup bilmedim, onlaýn bolup bilmez. Soňra haýyşy soň gaýtalamaga synanyşyň."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Talap edilýän salgyda birikmäni gurup bilmedim, onlaýn bolup bilmez. Soňra haýyşy soň gaýtalamaga synanyşyň."},
{"", ""}, {"", ""},

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021-2023, The PurpleI2P Project * Copyright (c) 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
* *
@@ -40,7 +40,6 @@ namespace ukrainian // language namespace
{"established", "працює"}, {"established", "працює"},
{"unknown", "невідомо"}, {"unknown", "невідомо"},
{"exploratory", "дослідницький"}, {"exploratory", "дослідницький"},
{"Purple I2P Webconsole", "Веб-консоль Purple I2P"},
{"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"}, {"<b>i2pd</b> webconsole", "Веб-консоль <b>i2pd</b>"},
{"Main page", "Головна"}, {"Main page", "Головна"},
{"Router commands", "Команди маршрутизатора"}, {"Router commands", "Команди маршрутизатора"},
@@ -58,11 +57,10 @@ namespace ukrainian // language namespace
{"Unknown", "Невідомо"}, {"Unknown", "Невідомо"},
{"Proxy", "Проксі"}, {"Proxy", "Проксі"},
{"Mesh", "MESH-мережа"}, {"Mesh", "MESH-мережа"},
{"Error", "Помилка"},
{"Clock skew", "Неточний час"}, {"Clock skew", "Неточний час"},
{"Offline", "Офлайн"}, {"Offline", "Офлайн"},
{"Symmetric NAT", "Симетричний NAT"}, {"Symmetric NAT", "Симетричний NAT"},
{"Full cone NAT", "Повний NAT"},
{"No Descriptors", "Немає Описів"},
{"Uptime", "У мережі"}, {"Uptime", "У мережі"},
{"Network status", "Мережевий статус"}, {"Network status", "Мережевий статус"},
{"Network status v6", "Мережевий статус v6"}, {"Network status v6", "Мережевий статус v6"},
@@ -118,10 +116,9 @@ namespace ukrainian // language namespace
{"Gateway", "Шлюз"}, {"Gateway", "Шлюз"},
{"TunnelID", "ID тунеля"}, {"TunnelID", "ID тунеля"},
{"EndDate", "Закінчується"}, {"EndDate", "Закінчується"},
{"floodfill mode is disabled", "режим floodfill вимкнено"}, {"not floodfill", "не флудфіл"},
{"Queue size", "Розмір черги"}, {"Queue size", "Розмір черги"},
{"Run peer test", "Запустити тестування"}, {"Run peer test", "Запустити тестування"},
{"Reload tunnels configuration", "Перезавантажити налаштування тунелів"},
{"Decline transit tunnels", "Відхиляти транзитні тунелі"}, {"Decline transit tunnels", "Відхиляти транзитні тунелі"},
{"Accept transit tunnels", "Ухвалювати транзитні тунелі"}, {"Accept transit tunnels", "Ухвалювати транзитні тунелі"},
{"Cancel graceful shutdown", "Скасувати плавну зупинку"}, {"Cancel graceful shutdown", "Скасувати плавну зупинку"},
@@ -149,8 +146,8 @@ namespace ukrainian // language namespace
{"Destination not found", "Точка призначення не знайдена"}, {"Destination not found", "Точка призначення не знайдена"},
{"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 5 seconds", "Ви будете переадресовані через 5 секунд"},
{"Transit tunnels count must not exceed %d", "Кількість транзитних тунелів не повинна перевищувати %d"}, {"Transit tunnels count must not exceed 65535", "Кількість транзитних тунелів не повинна перевищувати 65535"},
{"Back to commands list", "Повернутися до списку команд"}, {"Back to commands list", "Повернутися до списку команд"},
{"Register at reg.i2p", "Зареєструвати на reg.i2p"}, {"Register at reg.i2p", "Зареєструвати на reg.i2p"},
{"Description", "Опис"}, {"Description", "Опис"},
@@ -168,33 +165,32 @@ namespace ukrainian // language namespace
{"You may try to find this host on jump services below", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"}, {"You may try to find this host on jump services below", "Ви можете спробувати знайти дану адресу на джамп сервісах нижче"},
{"Invalid request", "Некоректний запит"}, {"Invalid request", "Некоректний запит"},
{"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"}, {"Proxy unable to parse your request", "Проксі не може розібрати ваш запит"},
{"Addresshelper is not supported", "Адресна книга не підтримується"}, {"addresshelper is not supported", "addresshelper не підтримується"},
{"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>.", "Хост %s <font color=red>вже в адресній книзі маршрутизатора</font>. <b>Будьте обережні: джерело цієї адреси може зашкодити!</b> Натисніть тут, щоб оновити запис: <a href=\"%s%s%s&update=true\">Продовжити</a>."}, {"Host", "Адреса"},
{"Addresshelper forced update rejected", "Адресна книга відхилила примусове оновлення"}, {"added to router's addressbook from helper", "доданий в адресну книгу маршрутизатора через хелпер"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Щоб додати хост <b>%s</b> в адресі маршрутизатора, натисніть тут: <a href=\"%s%s%s\"родовжити</a>."}, {"Click here to proceed:", "Натисніть тут щоб продовжити:"},
{"Addresshelper request", "Запит на адресну сторінку"}, {"Continue", "Продовжити"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Хост %s доданий в адресну книгу маршрутизатора від помічника. Натисніть тут, щоб продовжити: <a href=\"%s\">Продовжити</a>."}, {"Addresshelper found", "Знайдено addresshelper"},
{"Addresshelper adding", "Адреса додана"}, {"already in router's addressbook", "вже в адресній книзі маршрутизатора"},
{"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>.", "Хост %s <font color=red>вже в адресній книзі маршрутизатора</font>. Натисніть тут, щоб оновити запис: <a href=\"%s%s%s&update=true\">Продовжити</a>."}, {"Click here to update record:", "Натисніть тут щоб оновити запис:"},
{"Addresshelper update", "Оновлення адресної книги"}, {"invalid request uri", "некоректний URI запиту"},
{"Invalid request URI", "Некоректний URI запиту"},
{"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"}, {"Can't detect destination host from request", "Не вдалось визначити адресу призначення з запиту"},
{"Outproxy failure", "Помилка зовнішнього проксі"}, {"Outproxy failure", "Помилка зовнішнього проксі"},
{"Bad outproxy settings", "Некоректні налаштування зовнішнього проксі"}, {"bad outproxy settings", "некоректні налаштування зовнішнього проксі"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Адрес %s не в I2P мережі, але зовнішній проксі не включений"}, {"not inside I2P network, but outproxy is not enabled", "не в I2P мережі, але зовнішній проксі не включений"},
{"Unknown outproxy URL", "Невідомий URL зовнішнього проксі"}, {"unknown outproxy url", "невідомий URL зовнішнього проксі"},
{"Cannot resolve upstream proxy", "Не вдається визначити висхідний проксі"}, {"cannot resolve upstream proxy", "не вдається визначити висхідний проксі"},
{"Hostname is too long", "Ім'я вузла надто довге"}, {"hostname too long", "ім'я вузла надто довге"},
{"Cannot connect to upstream SOCKS proxy", "Не вдалося підключитися до висхідного SOCKS проксі сервера"}, {"cannot connect to upstream socks proxy", "не вдається підключитися до висхідного SOCKS проксі"},
{"Cannot negotiate with SOCKS proxy", "Не вдається домовитися з висхідним SOCKS проксі"}, {"Cannot negotiate with socks proxy", "Не вдається домовитися з висхідним SOCKS проксі"},
{"CONNECT error", "Помилка CONNECT запиту"}, {"CONNECT error", "Помилка CONNECT запиту"},
{"Failed to connect", "Не вдалося підключитися"}, {"Failed to Connect", "Не вдалося підключитися"},
{"SOCKS proxy error", "Помилка SOCKS проксі"}, {"socks proxy error", "помилка SOCKS проксі"},
{"Failed to send request to upstream", "Не вдалося відправити запит висхідному проксі"}, {"failed to send request to upstream", "не вдалося відправити запит висхідному проксі"},
{"No reply from SOCKS proxy", "Немає відповіді від SOCKS проксі сервера"}, {"No Reply From socks proxy", "Немає відповіді від SOCKS проксі сервера"},
{"Cannot connect", "Не вдалося підключитися"}, {"cannot connect", "не вдалося підключитися"},
{"HTTP out proxy not implemented", "Підтримка зовнішнього HTTP проксі сервера не реалізована"}, {"http out proxy not implemented", "підтримка зовнішнього HTTP проксі сервера не реалізована"},
{"Cannot connect to upstream HTTP proxy", "Не вдалося підключитися до висхідного HTTP проксі сервера"}, {"cannot connect to upstream http proxy", "не вдалося підключитися до висхідного HTTP проксі сервера"},
{"Host is down", "Вузол недоступний"}, {"Host is down", "Вузол недоступний"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Не вдалося встановити з'єднання до запитаного вузла, можливо він не в мережі. Спробуйте повторити запит пізніше."},
{"", ""}, {"", ""},

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021-2023, The PurpleI2P Project * Copyright (c) 2021-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
* *
@@ -40,7 +40,6 @@ namespace uzbek // language namespace
{"established", "aloqa o'rnatildi"}, {"established", "aloqa o'rnatildi"},
{"unknown", "noma'lum"}, {"unknown", "noma'lum"},
{"exploratory", "tadqiqiy"}, {"exploratory", "tadqiqiy"},
{"Purple I2P Webconsole", "Veb-konsoli Purple I2P"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> veb-konsoli"}, {"<b>i2pd</b> webconsole", "<b>i2pd</b> veb-konsoli"},
{"Main page", "Asosiy sahifa"}, {"Main page", "Asosiy sahifa"},
{"Router commands", "Router buyruqlari"}, {"Router commands", "Router buyruqlari"},
@@ -58,11 +57,10 @@ namespace uzbek // language namespace
{"Unknown", "Notanish"}, {"Unknown", "Notanish"},
{"Proxy", "Proksi"}, {"Proxy", "Proksi"},
{"Mesh", "Mesh To'r"}, {"Mesh", "Mesh To'r"},
{"Error", "Xato"},
{"Clock skew", "Aniq vaqt emas"}, {"Clock skew", "Aniq vaqt emas"},
{"Offline", "Oflayn"}, {"Offline", "Oflayn"},
{"Symmetric NAT", "Simmetrik NAT"}, {"Symmetric NAT", "Simmetrik NAT"},
{"Full cone NAT", "Full cone NAT"},
{"No Descriptors", "Deskriptorlar yo'q"},
{"Uptime", "Ish vaqti"}, {"Uptime", "Ish vaqti"},
{"Network status", "Tarmoq holati"}, {"Network status", "Tarmoq holati"},
{"Network status v6", "Tarmoq holati v6"}, {"Network status v6", "Tarmoq holati v6"},
@@ -118,10 +116,9 @@ namespace uzbek // language namespace
{"Gateway", "Kirish yo'li"}, {"Gateway", "Kirish yo'li"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Tugash Sanasi"}, {"EndDate", "Tugash Sanasi"},
{"floodfill mode is disabled", "floodfill rejimi o'chirilgan"}, {"not floodfill", "floodfill emas"},
{"Queue size", "Navbat hajmi"}, {"Queue size", "Navbat hajmi"},
{"Run peer test", "Sinovni boshlang"}, {"Run peer test", "Sinovni boshlang"},
{"Reload tunnels configuration", "Tunnel konfiguratsiyasini qayta yuklash"},
{"Decline transit tunnels", "Tranzit tunnellarini rad etish"}, {"Decline transit tunnels", "Tranzit tunnellarini rad etish"},
{"Accept transit tunnels", "Tranzit tunnellarni qabul qilish"}, {"Accept transit tunnels", "Tranzit tunnellarni qabul qilish"},
{"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qilish"}, {"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qilish"},
@@ -149,8 +146,8 @@ namespace uzbek // language namespace
{"Destination not found", "Yo'nalish topilmadi"}, {"Destination not found", "Yo'nalish topilmadi"},
{"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 5 seconds", "Siz 5 soniya ichida qayta yo'naltirilasiz"},
{"Transit tunnels count must not exceed %d", "Tranzit tunnellar soni %d dan oshmasligi kerak"}, {"Transit tunnels count must not exceed 65535", "Tranzit tunnellar soni 65535 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"},
{"Description", "Tavsif"}, {"Description", "Tavsif"},
@@ -168,33 +165,32 @@ namespace uzbek // language namespace
{"You may try to find this host on jump services below", "Siz xost quyida o'tish xizmatlari orqali topishga harakat qilishingiz mumkin"}, {"You may try to find this host on jump services below", "Siz xost quyida o'tish xizmatlari orqali topishga harakat qilishingiz mumkin"},
{"Invalid request", "Notogri sorov"}, {"Invalid request", "Notogri sorov"},
{"Proxy unable to parse your request", "Proksi sizning so'rovingizni aniqlab ololmayapti"}, {"Proxy unable to parse your request", "Proksi sizning so'rovingizni aniqlab ololmayapti"},
{"Addresshelper is not supported", "Addresshelper qo'llab-quvvatlanmaydi"}, {"addresshelper is not supported", "addresshelper qo'llab -quvvatlanmaydi"},
{"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>.", "%s xosti <font color=red>allaqachon routerning manzillar kitobida</font>. <b>Ehtiyot bo'ling: bu URL manbasi zararli bo'lishi mumkin!</b> Yozuvni yangilash uchun bu yerni bosing: <a href=\"%s%s%s&update=true\">Davom etish</a>."}, {"Host", "Xost"},
{"Addresshelper forced update rejected", "Addresshelperni majburiy yangilash rad etildi"}, {"added to router's addressbook from helper", "'helper'dan routerning 'addressbook'ga qo'shildi"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Routerning manzillar kitobiga <b>%s</b> xostini qo'shish uchun bu yerni bosing: <a href=\"%s%s%s\">Davom etish</a>."}, {"Click here to proceed:", "Davom etish uchun shu yerni bosing:"},
{"Addresshelper request", "Addresshelper so'rovi"}, {"Continue", "Davom etish"},
{"Host %s added to router's addressbook from helper. Click here to proceed: <a href=\"%s\">Continue</a>.", "Yordamchidan router manzillar kitobiga %s xost qoshildi. Davom etish uchun bu yerga bosing: <a href=\"%s\">Davom etish</a>."}, {"Addresshelper found", "Addresshelper topildi"},
{"Addresshelper adding", "Addresshelperni qo'shish"}, {"already in router's addressbook", "allaqachon 'addressbook'da yozilgan"},
{"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>.", "%s xosti <font color=red>allaqachon routerning manzillar kitobida</font>. Yozuvni yangilash uchun shu yerni bosing: <a href=\"%s%s%s&update=true\">Davom etish</a>."}, {"Click here to update record:", "Yozuvni yangilash uchun shu yerni bosing:"},
{"Addresshelper update", "Addresshelperni yangilash"}, {"invalid request uri", "noto'g'ri URI so'rovi"},
{"Invalid request URI", "Noto'g'ri URI so'rovi"},
{"Can't detect destination host from request", "Sorov orqali manzil xostini aniqlab bo'lmayapti"}, {"Can't detect destination host from request", "Sorov orqali manzil xostini aniqlab bo'lmayapti"},
{"Outproxy failure", "Tashqi proksi muvaffaqiyatsizligi"}, {"Outproxy failure", "Tashqi proksi muvaffaqiyatsizligi"},
{"Bad outproxy settings", "Noto'g'ri tashqi proksi-server sozlamalari"}, {"bad outproxy settings", "noto'g'ri tashqi proksi-server sozlamalari"},
{"Host %s is not inside I2P network, but outproxy is not enabled", "Xost %s I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"}, {"not inside I2P network, but outproxy is not enabled", "I2P tarmog'ida emas, lekin tashqi proksi yoqilmagan"},
{"Unknown outproxy URL", "Noma'lum outproxy URL"}, {"unknown outproxy url", "noma'lum outproxy url"},
{"Cannot resolve upstream proxy", "Yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"}, {"cannot resolve upstream proxy", "yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
{"Hostname is too long", "Xost nomi juda uzun"}, {"hostname too long", "xost nomi juda uzun"},
{"Cannot connect to upstream SOCKS proxy", "Yuqori 'SOCKS proxy'ga ulanib bo'lmayapti"}, {"cannot connect to upstream socks proxy", "yuqori 'socks proxy'ga ulanib bo'lmayapti"},
{"Cannot negotiate with SOCKS proxy", "'SOCKS proxy' bilan muzokara olib bo'lmaydi"}, {"Cannot negotiate with socks proxy", "'Socks proxy' bilan muzokara olib bo'lmaydi"},
{"CONNECT error", "CONNECT xatosi"}, {"CONNECT error", "CONNECT xatosi"},
{"Failed to connect", "Ulanib bo'lmayapti"}, {"Failed to Connect", "Ulanib bo'lmayapti"},
{"SOCKS proxy error", "'SOCKS proxy' xatosi"}, {"socks proxy error", "'socks proxy' xatosi"},
{"Failed to send request to upstream", "Yuqori proksi-serveriga so'rovni uborib bo'lmadi"}, {"failed to send request to upstream", "yuqori http proksi-serveriga so'rovni uborib bo'lmadi"},
{"No reply from SOCKS proxy", "'SOCKS proxy'dan javob yo'q"}, {"No Reply From socks proxy", "'Socks proxy'dan javob yo'q"},
{"Cannot connect", "Ulanib bo'lmaydi"}, {"cannot connect", "ulanib bo'lmaydi"},
{"HTTP out proxy not implemented", "Tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"}, {"http out proxy not implemented", "tashqi HTTP proksi-serverni qo'llab-quvvatlash amalga oshirilmagan"},
{"Cannot connect to upstream HTTP proxy", "Yuqori 'HTTP proxy'ga ulanib bo'lmayapti"}, {"cannot connect to upstream http proxy", "yuqori http 'proxy-server'iga ulanib bo'lmayapti"},
{"Host is down", "Xost ishlamayapti"}, {"Host is down", "Xost ishlamayapti"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Talab qilingan xost bilan aloqa o'rnatilmadi, u ishlamay qolishi mumkin. Iltimos keyinroq qayta urinib ko'ring."}, {"Can't create connection to requested host, it may be down. Please try again later.", "Talab qilingan xost bilan aloqa o'rnatilmadi, u ishlamay qolishi mumkin. Iltimos keyinroq qayta urinib ko'ring."},
{"", ""}, {"", ""},

View File

@@ -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
* *
@@ -45,7 +45,7 @@ namespace config {
("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)") ("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to") ("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
("host", value<std::string>()->default_value(""), "External IP") ("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
("ifname", value<std::string>()->default_value(""), "Network interface to bind to") ("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4") ("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6") ("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
@@ -95,7 +95,6 @@ namespace config {
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI") ("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )") ("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )")
("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )") ("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )")
("http.showTotalTCSR", value<bool>()->default_value(false), "Show additional value with total TCSR since router's start (default: false)")
; ;
options_description httpproxy("HTTP Proxy options"); options_description httpproxy("HTTP Proxy options");
@@ -149,8 +148,7 @@ namespace config {
sam.add_options() sam.add_options()
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge") ("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address") ("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen TCP port") ("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
("sam.portudp", value<uint16_t>()->default_value(0), "SAM listen UDP port")
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread") ("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread")
; ;
@@ -216,11 +214,10 @@ namespace config {
"https://reseed.onion.im/," "https://reseed.onion.im/,"
"https://i2pseed.creativecowpat.net:8443/," "https://i2pseed.creativecowpat.net:8443/,"
"https://reseed.i2pgit.org/," "https://reseed.i2pgit.org/,"
"https://i2p.novg.net/,"
"https://banana.incognet.io/," "https://banana.incognet.io/,"
"https://reseed-pl.i2pd.xyz/," "https://reseed-pl.i2pd.xyz/,"
"https://www2.mk16.de/," "https://www2.mk16.de/"
"https://i2p.ghativega.in/,"
"https://i2p.novg.net/"
), "Reseed URLs, separated by comma") ), "Reseed URLs, separated by comma")
("reseed.yggurls", value<std::string>()->default_value( ("reseed.yggurls", value<std::string>()->default_value(
"http://[324:71e:281a:9ed3::ace]:7070/," "http://[324:71e:281a:9ed3::ace]:7070/,"
@@ -287,7 +284,7 @@ namespace config {
options_description nettime("Time sync options"); options_description nettime("Time sync options");
nettime.add_options() nettime.add_options()
("nettime.enabled", value<bool>()->default_value(false), "Enable NTP time sync (default: disabled)") ("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
("nettime.ntpservers", value<std::string>()->default_value( ("nettime.ntpservers", value<std::string>()->default_value(
"0.pool.ntp.org," "0.pool.ntp.org,"
"1.pool.ntp.org," "1.pool.ntp.org,"

View File

@@ -399,11 +399,6 @@ namespace client
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len) void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
{ {
if (len < DATABASE_STORE_HEADER_SIZE)
{
LogPrint (eLogError, "Destination: Database store msg is too short ", len);
return;
}
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
size_t offset = DATABASE_STORE_HEADER_SIZE; size_t offset = DATABASE_STORE_HEADER_SIZE;
if (replyToken) if (replyToken)
@@ -411,11 +406,6 @@ namespace client
LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore"); LogPrint (eLogInfo, "Destination: Reply token is ignored for DatabaseStore");
offset += 36; offset += 36;
} }
if (offset > len || len > i2p::data::MAX_LS_BUFFER_SIZE + offset)
{
LogPrint (eLogError, "Destination: Database store message is too long ", len);
return;
}
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;
switch (buf[DATABASE_STORE_TYPE_OFFSET]) switch (buf[DATABASE_STORE_TYPE_OFFSET])
@@ -477,15 +467,12 @@ namespace client
{ {
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ()); it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
if (ls2->IsValid () && !ls2->IsExpired ()) if (ls2->IsValid ())
{ {
leaseSet = ls2;
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup m_RemoteLeaseSets[key] = ls2; // also store as key for next lookup
leaseSet = ls2;
} }
else
LogPrint (eLogError, "Destination: New remote encrypted LeaseSet2 failed");
} }
else else
LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2"); LogPrint (eLogInfo, "Destination: Couldn't find request for encrypted LeaseSet2");
@@ -775,20 +762,12 @@ namespace client
{ {
request->requestTime = ts; request->requestTime = ts;
if (!SendLeaseSetRequest (dest, floodfill, request)) if (!SendLeaseSetRequest (dest, floodfill, request))
{
// try another
LogPrint (eLogWarning, "Destination: Couldn't send LeaseSet request to ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another");
request->excluded.insert (floodfill->GetIdentHash ());
floodfill = i2p::data::netdb.GetClosestFloodfill (dest, request->excluded);
if (!SendLeaseSetRequest (dest, floodfill, request))
{ {
// request failed // request failed
LogPrint (eLogWarning, "Destination: LeaseSet request for ", dest.ToBase32 (), " was not sent");
m_LeaseSetRequests.erase (ret.first); m_LeaseSetRequests.erase (ret.first);
if (requestComplete) requestComplete (nullptr); if (requestComplete) requestComplete (nullptr);
} }
} }
}
else // duplicate else // duplicate
{ {
LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already"); LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already");
@@ -813,11 +792,11 @@ namespace client
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request) std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
{ {
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ()) if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false)); // outbound from floodfill request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true));
if (!request->replyTunnel) LogPrint (eLogWarning, "Destination: Can't send LeaseSet request, no compatible inbound tunnels found"); if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no inbound tunnels found");
if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ()) if (!request->outboundTunnel || !request->outboundTunnel->IsEstablished ())
request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true)); // inbound from floodfill request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false));
if (!request->outboundTunnel) LogPrint (eLogWarning, "Destination: Can't send LeaseSet request, no compatible outbound tunnels found"); if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no outbound tunnels found");
if (request->replyTunnel && request->outboundTunnel) if (request->replyTunnel && request->outboundTunnel)
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, 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
* *
@@ -335,7 +335,6 @@ namespace garlic
case eECIESx25519BlkAckRequest: case eECIESx25519BlkAckRequest:
{ {
LogPrint (eLogDebug, "Garlic: Ack request"); LogPrint (eLogDebug, "Garlic: Ack request");
if (receiveTagset)
m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index}); m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
break; break;
} }

View File

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

View File

@@ -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
* *
@@ -93,18 +93,15 @@ namespace http
std::size_t pos_c = 0; /* < work position */ std::size_t pos_c = 0; /* < work position */
if(url.at(0) != '/' || pos_p > 0) { if(url.at(0) != '/' || pos_p > 0) {
std::size_t pos_s = 0; std::size_t pos_s = 0;
/* schema */ /* schema */
pos_c = url.find("://"); pos_c = url.find("://");
if (pos_c != std::string::npos) { if (pos_c != std::string::npos) {
schema = url.substr(0, pos_c); schema = url.substr(0, pos_c);
pos_p = pos_c + 3; pos_p = pos_c + 3;
} }
/* user[:pass] */ /* user[:pass] */
pos_s = url.find('/', pos_p); /* find first slash */ pos_s = url.find('/', pos_p); /* find first slash */
pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */ pos_c = url.find('@', pos_p); /* find end of 'user' or 'user:pass' part */
if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) { if (pos_c != std::string::npos && (pos_s == std::string::npos || pos_s > pos_c)) {
std::size_t delim = url.find(':', pos_p); std::size_t delim = url.find(':', pos_p);
if (delim && delim != std::string::npos && delim < pos_c) { if (delim && delim != std::string::npos && delim < pos_c) {
@@ -116,28 +113,21 @@ namespace http
} }
pos_p = pos_c + 1; pos_p = pos_c + 1;
} }
/* hostname[:port][/path] */ /* hostname[:port][/path] */
if (url.at(pos_p) == '[') // ipv6 if (url[pos_p] == '[') // ipv6
{ {
auto pos_b = url.find(']', pos_p); auto pos_b = url.find(']', pos_p);
if (pos_b == std::string::npos) return false; if (pos_b == std::string::npos) return false;
ipv6 = true;
pos_c = url.find_first_of(":/", pos_b); pos_c = url.find_first_of(":/", pos_b);
} }
else else
pos_c = url.find_first_of(":/", pos_p); pos_c = url.find_first_of(":/", pos_p);
if (pos_c == std::string::npos) { if (pos_c == std::string::npos) {
/* only hostname, without post and path */ /* only hostname, without post and path */
host = ipv6 ? host = url.substr(pos_p, std::string::npos);
url.substr(pos_p + 1, url.length() - 1) :
url.substr(pos_p, std::string::npos);
return true; return true;
} else if (url.at(pos_c) == ':') { } else if (url.at(pos_c) == ':') {
host = ipv6 ? host = url.substr(pos_p, pos_c - pos_p);
url.substr(pos_p + 1, pos_c - pos_p - 2) :
url.substr(pos_p, pos_c - pos_p);
/* port[/path] */ /* port[/path] */
pos_p = pos_c + 1; pos_p = pos_c + 1;
pos_c = url.find('/', pos_p); pos_c = url.find('/', pos_p);
@@ -157,9 +147,7 @@ namespace http
pos_p = pos_c; pos_p = pos_c;
} else { } else {
/* start of path part found */ /* start of path part found */
host = ipv6 ? host = url.substr(pos_p, pos_c - pos_p);
url.substr(pos_p + 1, pos_c - pos_p - 2) :
url.substr(pos_p, pos_c - pos_p);
pos_p = pos_c; pos_p = pos_c;
} }
} }
@@ -172,7 +160,6 @@ namespace http
return true; return true;
} else if (url.at(pos_c) == '?') { } else if (url.at(pos_c) == '?') {
/* found query part */ /* found query part */
hasquery = true;
path = url.substr(pos_p, pos_c - pos_p); path = url.substr(pos_p, pos_c - pos_p);
pos_p = pos_c + 1; pos_p = pos_c + 1;
pos_c = url.find('#', pos_p); pos_c = url.find('#', pos_p);
@@ -224,25 +211,15 @@ namespace http
} else if (user != "") { } else if (user != "") {
out += user + "@"; out += user + "@";
} }
if (ipv6) {
if (port) {
out += "[" + host + "]:" + std::to_string(port);
} else {
out += "[" + host + "]";
}
} else {
if (port) { if (port) {
out += host + ":" + std::to_string(port); out += host + ":" + std::to_string(port);
} else { } else {
out += host; out += host;
} }
} }
}
out += path; out += path;
if (hasquery) // add query even if it was empty
out += "?";
if (query != "") if (query != "")
out += query; out += "?" + query;
if (frag != "") if (frag != "")
out += "#" + frag; out += "#" + frag;
return out; return out;
@@ -370,14 +347,6 @@ namespace http
return ""; return "";
} }
size_t HTTPReq::GetNumHeaders (const std::string& name) const
{
size_t num = 0;
for (auto& it : headers)
if (it.first == name) num++;
return num;
}
bool HTTPRes::is_chunked() const bool HTTPRes::is_chunked() const
{ {
auto it = headers.find("Transfer-Encoding"); auto it = headers.find("Transfer-Encoding");

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, 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
* *
@@ -33,12 +33,10 @@ namespace http
std::string host; std::string host;
unsigned short int port; unsigned short int port;
std::string path; std::string path;
bool hasquery;
std::string query; std::string query;
std::string frag; std::string frag;
bool ipv6;
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag(""), ipv6(false) {}; URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), query(""), frag("") {};
/** /**
* @brief Tries to parse url from string * @brief Tries to parse url from string
@@ -103,8 +101,6 @@ namespace http
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); }; void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); };
std::string GetHeader (const std::string& name) const; std::string GetHeader (const std::string& name) const;
size_t GetNumHeaders (const std::string& name) const;
size_t GetNumHeaders () const { return headers.size (); };
}; };
struct HTTPRes : HTTPMsg { struct HTTPRes : HTTPMsg {

View File

@@ -353,6 +353,21 @@ namespace i2p
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
} }
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{
if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
{
LogPrint (eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
g_MaxNumTransitTunnels = maxNumTransitTunnels;
}
}
uint16_t GetMaxNumTransitTunnels ()
{
return g_MaxNumTransitTunnels;
}
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{ {
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
@@ -364,7 +379,10 @@ namespace i2p
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false; if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false;
uint8_t retCode = 0; uint8_t retCode = 0;
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && !i2p::context.IsHighCongestion ()) if (i2p::context.AcceptsTunnels () &&
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded () &&
!i2p::transport::transports.IsTransitBandwidthExceeded ())
{ {
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
@@ -558,7 +576,10 @@ namespace i2p
// check if we accept this tunnel // check if we accept this tunnel
uint8_t retCode = 0; uint8_t retCode = 0;
if (!i2p::context.AcceptsTunnels () || i2p::context.IsHighCongestion ()) if (!i2p::context.AcceptsTunnels () ||
i2p::tunnel::tunnels.GetTransitTunnels ().size () > g_MaxNumTransitTunnels ||
i2p::transport::transports.IsBandwidthExceeded () ||
i2p::transport::transports.IsTransitBandwidthExceeded ())
retCode = 30; retCode = 30;
if (!retCode) if (!retCode)
{ {

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, 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
* *
@@ -308,6 +308,10 @@ namespace tunnel
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs; std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
}; };
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
uint16_t GetMaxNumTransitTunnels ();
} }
#endif #endif

View File

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

View File

@@ -1,372 +0,0 @@
/*
* Copyright (c) 2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*
*/
#include "KadDHT.h"
namespace i2p
{
namespace data
{
DHTNode::DHTNode ():
zero (nullptr), one (nullptr)
{
}
DHTNode::~DHTNode ()
{
if (zero) delete zero;
if (one) delete one;
}
void DHTNode::MoveRouterUp (bool fromOne)
{
DHTNode *& side = fromOne ? one : zero;
if (side)
{
if (router) router = nullptr; // shouldn't happen
router = side->router;
side->router = nullptr;
delete side;
side = nullptr;
}
}
DHTTable::DHTTable ():
m_Size (0)
{
m_Root = new DHTNode;
}
DHTTable::~DHTTable ()
{
delete m_Root;
}
void DHTTable::Clear ()
{
m_Size = 0;
delete m_Root;
m_Root = new DHTNode;
}
void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r)
{
if (!r) return;
return Insert (r, m_Root, 0);
}
void DHTTable::Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level)
{
if (root->router)
{
if (root->router->GetIdentHash () == r->GetIdentHash ())
{
root->router = r; // replace
return;
}
auto r2 = root->router;
root->router = nullptr; m_Size--;
int bit1, bit2;
do
{
bit1 = r->GetIdentHash ().GetBit (level);
bit2 = r2->GetIdentHash ().GetBit (level);
if (bit1 == bit2)
{
if (bit1)
{
if (root->one) return; // someting wrong
root->one = new DHTNode;
root = root->one;
}
else
{
if (root->zero) return; // someting wrong
root->zero = new DHTNode;
root = root->zero;
}
level++;
}
}
while (bit1 == bit2);
if (!root->zero)
root->zero = new DHTNode;
if (!root->one)
root->one = new DHTNode;
if (bit1)
{
Insert (r2, root->zero, level + 1);
Insert (r, root->one, level + 1);
}
else
{
Insert (r2, root->one, level + 1);
Insert (r, root->zero, level + 1);
}
}
else
{
if (!root->zero && !root->one)
{
root->router = r; m_Size++;
return;
}
int bit = r->GetIdentHash ().GetBit (level);
if (bit)
{
if (!root->one)
root->one = new DHTNode;
Insert (r, root->one, level + 1);
}
else
{
if (!root->zero)
root->zero = new DHTNode;
Insert (r, root->zero, level + 1);
}
}
}
bool DHTTable::Remove (const IdentHash& h)
{
return Remove (h, m_Root, 0);
}
bool DHTTable::Remove (const IdentHash& h, DHTNode * root, int level)
{
if (root)
{
if (root->router && root->router->GetIdentHash () == h)
{
root->router = nullptr;
m_Size--;
return true;
}
int bit = h.GetBit (level);
if (bit)
{
if (root->one && Remove (h, root->one, level + 1))
{
if (root->one->IsEmpty ())
{
delete root->one;
root->one = nullptr;
if (root->zero && root->zero->router)
root->MoveRouterUp (false);
}
else if (root->one->router && !root->zero)
root->MoveRouterUp (true);
return true;
}
}
else
{
if (root->zero && Remove (h, root->zero, level + 1))
{
if (root->zero->IsEmpty ())
{
delete root->zero;
root->zero = nullptr;
if (root->one && root->one->router)
root->MoveRouterUp (true);
}
else if (root->zero->router && !root->one)
root->MoveRouterUp (false);
return true;
}
}
}
return false;
}
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, const Filter& filter) const
{
if (filter) m_Filter = filter;
auto r = FindClosest (h, m_Root, 0);
m_Filter = nullptr;
return r;
}
std::shared_ptr<RouterInfo> DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level) const
{
bool split = false;
do
{
if (root->router)
return (!m_Filter || m_Filter (root->router)) ? root->router : nullptr;
split = root->zero && root->one;
if (!split)
{
if (root->zero) root = root->zero;
else if (root->one) root = root->one;
else return nullptr;
level++;
}
}
while (!split);
int bit = h.GetBit (level);
if (bit)
{
if (root->one)
{
auto r = FindClosest (h, root->one, level + 1);
if (r) return r;
}
if (root->zero)
{
auto r = FindClosest (h, root->zero, level + 1);
if (r) return r;
}
}
else
{
if (root->zero)
{
auto r = FindClosest (h, root->zero, level + 1);
if (r) return r;
}
if (root->one)
{
auto r = FindClosest (h, root->one, level + 1);
if (r) return r;
}
}
return nullptr;
}
std::vector<std::shared_ptr<RouterInfo> > DHTTable::FindClosest (const IdentHash& h, size_t num, const Filter& filter) const
{
std::vector<std::shared_ptr<RouterInfo> > vec;
if (num > 0)
{
if (filter) m_Filter = filter;
FindClosest (h, num, m_Root, 0, vec);
m_Filter = nullptr;
}
return vec;
}
void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const
{
if (hashes.size () >= num) return;
bool split = false;
do
{
if (root->router)
{
if (!m_Filter || m_Filter (root->router))
hashes.push_back (root->router);
return;
}
split = root->zero && root->one;
if (!split)
{
if (root->zero) root = root->zero;
else if (root->one) root = root->one;
else return;
level++;
}
}
while (!split);
int bit = h.GetBit (level);
if (bit)
{
if (root->one)
FindClosest (h, num, root->one, level + 1, hashes);
if (hashes.size () < num && root->zero)
FindClosest (h, num, root->zero, level + 1, hashes);
}
else
{
if (root->zero)
FindClosest (h, num, root->zero, level + 1, hashes);
if (hashes.size () < num && root->one)
FindClosest (h, num, root->one, level + 1, hashes);
}
}
void DHTTable::Cleanup (const Filter& filter)
{
if (filter)
{
m_Filter = filter;
Cleanup (m_Root);
m_Filter = nullptr;
}
else
Clear ();
}
void DHTTable::Cleanup (DHTNode * root)
{
if (!root) return;
if (root->router)
{
if (!m_Filter || !m_Filter (root->router))
{
m_Size--;
root->router = nullptr;
}
return;
}
if (root->zero)
{
Cleanup (root->zero);
if (root->zero->IsEmpty ())
{
delete root->zero;
root->zero = nullptr;
}
}
if (root->one)
{
Cleanup (root->one);
if (root->one->IsEmpty ())
{
delete root->one;
root->one = nullptr;
if (root->zero && root->zero->router)
root->MoveRouterUp (false);
}
else if (root->one->router && !root->zero)
root->MoveRouterUp (true);
}
}
void DHTTable::Print (std::stringstream& s)
{
Print (s, m_Root, 0);
}
void DHTTable::Print (std::stringstream& s, DHTNode * root, int level)
{
if (!root) return;
s << std::string (level, '-');
if (root->router)
{
if (!root->zero && !root->one)
s << '>' << GetIdentHashAbbreviation (root->router->GetIdentHash ());
else
s << "error";
}
s << std::endl;
if (root->zero)
{
s << std::string (level, '-') << "0" << std::endl;
Print (s, root->zero, level + 1);
}
if (root->one)
{
s << std::string (level, '-') << "1" << std::endl;
Print (s, root->one, level + 1);
}
}
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (c) 2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*
*/
#ifndef KADDHT_H__
#define KADDHT_H__
#include <memory>
#include <vector>
#include <sstream>
#include <functional>
#include "RouterInfo.h"
// Kademlia DHT (XOR distance)
namespace i2p
{
namespace data
{
struct DHTNode
{
DHTNode * zero, * one;
std::shared_ptr<RouterInfo> router;
DHTNode ();
~DHTNode ();
bool IsEmpty () const { return !zero && !one && !router; };
void MoveRouterUp (bool fromOne);
};
class DHTTable
{
typedef std::function<bool (const std::shared_ptr<RouterInfo>&)> Filter;
public:
DHTTable ();
~DHTTable ();
void Insert (const std::shared_ptr<RouterInfo>& r);
bool Remove (const IdentHash& h);
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, const Filter& filter = nullptr) const;
std::vector<std::shared_ptr<RouterInfo> > FindClosest (const IdentHash& h, size_t num, const Filter& filter = nullptr) const;
void Print (std::stringstream& s);
size_t GetSize () const { return m_Size; };
void Clear ();
void Cleanup (const Filter& filter);
private:
void Insert (const std::shared_ptr<RouterInfo>& r, DHTNode * root, int level); // recursive
bool Remove (const IdentHash& h, DHTNode * root, int level);
std::shared_ptr<RouterInfo> FindClosest (const IdentHash& h, DHTNode * root, int level) const;
void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<std::shared_ptr<RouterInfo> >& hashes) const;
void Cleanup (DHTNode * root);
void Print (std::stringstream& s, DHTNode * root, int level);
private:
DHTNode * m_Root;
size_t m_Size;
// transient
mutable Filter m_Filter;
};
}
}
#endif

View File

@@ -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
* *
@@ -315,7 +315,7 @@ namespace data
{ {
// standard LS2 header // standard LS2 header
std::shared_ptr<const IdentityEx> identity; std::shared_ptr<const IdentityEx> identity;
if (readIdentity || !GetIdentity ()) if (readIdentity)
{ {
identity = std::make_shared<IdentityEx>(buf, len); identity = std::make_shared<IdentityEx>(buf, len);
SetIdentity (identity); SetIdentity (identity);
@@ -366,8 +366,6 @@ namespace data
VerifySignature (identity, buf, len, offset); VerifySignature (identity, buf, len, offset);
SetIsValid (verified); SetIsValid (verified);
} }
else
SetIsValid (true);
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen (); offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
if (offset > len) { if (offset > len) {
LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len)); LogPrint (eLogWarning, "LeaseSet2: short buffer: wanted ", int(offset), "bytes, have ", int(len));

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, 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
* *
@@ -145,7 +145,6 @@ namespace data
{ {
public: public:
LeaseSet2 (uint8_t storeType): LeaseSet (true), m_StoreType (storeType) {}; // for update
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL);
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only
uint8_t GetStoreType () const { return m_StoreType; }; uint8_t GetStoreType () const { return m_StoreType; };

View File

@@ -693,20 +693,10 @@ namespace transport
SendTerminationAndTerminate (eNTCP2Message3Error); SendTerminationAndTerminate (eNTCP2Message3Error);
return; return;
} }
auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri.GetNTCP2V4Address () : auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri.GetYggdrasilAddress () : ri.GetNTCP2V6Address ()); if (!addr)
if (!addr || memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
{ {
LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed"); LogPrint (eLogError, "NTCP2: No NTCP2 address with static key found in SessionConfirmed");
Terminate ();
return;
}
if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
(!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
{
LogPrint (eLogError, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ());
Terminate (); Terminate ();
return; return;
} }
@@ -884,20 +874,8 @@ namespace transport
switch (blk) switch (blk)
{ {
case eNTCP2BlkDateTime: case eNTCP2BlkDateTime:
{
LogPrint (eLogDebug, "NTCP2: Datetime"); LogPrint (eLogDebug, "NTCP2: Datetime");
if (m_IsEstablished)
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
uint64_t tsA = bufbe32toh (frame + offset);
if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
{
LogPrint (eLogWarning, "NTCP2: Established session time difference ", (int)(ts - tsA), " exceeds clock skew");
SendTerminationAndTerminate (eNTCP2ClockSkew);
}
}
break; break;
}
case eNTCP2BlkOptions: case eNTCP2BlkOptions:
LogPrint (eLogDebug, "NTCP2: Options"); LogPrint (eLogDebug, "NTCP2: Options");
break; break;
@@ -1142,17 +1120,12 @@ namespace transport
{ {
if (!IsEstablished ()) return; if (!IsEstablished ()) return;
auto riLen = i2p::context.GetRouterInfo ().GetBufferLen (); auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime size_t payloadLen = riLen + 4; // 3 bytes block header + 1 byte RI flag
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 m_NextSendBuffer[2] = eNTCP2BlkRouterInfo;
m_NextSendBuffer[2] = eNTCP2BlkDateTime; htobe16buf (m_NextSendBuffer + 3, riLen + 1); // size
htobe16buf (m_NextSendBuffer + 3, 4); m_NextSendBuffer[5] = 0; // flag
htobe32buf (m_NextSendBuffer + 5, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); memcpy (m_NextSendBuffer + 6, i2p::context.GetRouterInfo ().GetBuffer (), riLen);
// RouterInfo block
m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
m_NextSendBuffer[12] = 0; // flag
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;
@@ -1457,7 +1430,7 @@ namespace transport
void NTCP2Server::HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error) void NTCP2Server::HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
{ {
if (!error && conn) if (!error)
{ {
boost::system::error_code ec; boost::system::error_code ec;
auto ep = conn->GetSocket ().remote_endpoint(ec); auto ep = conn->GetSocket ().remote_endpoint(ec);
@@ -1465,6 +1438,8 @@ namespace transport
{ {
LogPrint (eLogDebug, "NTCP2: Connected from ", ep); LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
if (!i2p::util::net::IsInReservedRange(ep.address ())) if (!i2p::util::net::IsInReservedRange(ep.address ()))
{
if (conn)
{ {
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second) if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
{ {
@@ -1475,6 +1450,7 @@ namespace transport
else else
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending"); LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
} }
}
else else
LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ()); LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
} }
@@ -1504,7 +1480,7 @@ namespace transport
void NTCP2Server::HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error) void NTCP2Server::HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
{ {
if (!error && conn) if (!error)
{ {
boost::system::error_code ec; boost::system::error_code ec;
auto ep = conn->GetSocket ().remote_endpoint(ec); auto ep = conn->GetSocket ().remote_endpoint(ec);
@@ -1513,6 +1489,8 @@ namespace transport
LogPrint (eLogDebug, "NTCP2: Connected from ", ep); LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
if (!i2p::util::net::IsInReservedRange(ep.address ()) || if (!i2p::util::net::IsInReservedRange(ep.address ()) ||
i2p::util::net::IsYggdrasilAddress (ep.address ())) i2p::util::net::IsYggdrasilAddress (ep.address ()))
{
if (conn)
{ {
if (m_PendingIncomingSessions.emplace (ep.address (), conn).second) if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
{ {
@@ -1523,6 +1501,7 @@ namespace transport
else else
LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending"); LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
} }
}
else else
LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ()); LogPrint (eLogError, "NTCP2: Incoming connection from invalid IP ", ep.address ());
} }

View File

@@ -36,7 +36,7 @@ namespace data
{ {
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true) NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false)
{ {
} }
@@ -55,7 +55,7 @@ namespace data
Load (); Load ();
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold || m_Floodfills.GetSize () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
{ {
Reseed (); Reseed ();
} }
@@ -66,13 +66,13 @@ namespace data
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
{ {
// remove own router // remove own router
m_Floodfills.Remove (it->second->GetIdentHash ()); m_Floodfills.remove (it->second);
m_RouterInfos.erase (it); m_RouterInfos.erase (it);
} }
// insert own router // insert own router
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ()); m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_Floodfills.Insert (i2p::context.GetSharedRouterInfo ()); m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles); i2p::config::GetOption("persist.profiles", m_PersistProfiles);
@@ -85,10 +85,11 @@ namespace data
if (m_IsRunning) if (m_IsRunning)
{ {
if (m_PersistProfiles) if (m_PersistProfiles)
SaveProfiles (); for (auto& it: m_RouterInfos)
it.second->SaveProfile ();
DeleteObsoleteProfiles (); DeleteObsoleteProfiles ();
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.Clear (); m_Floodfills.clear ();
if (m_Thread) if (m_Thread)
{ {
m_IsRunning = false; m_IsRunning = false;
@@ -106,7 +107,7 @@ namespace data
{ {
i2p::util::SetThreadName("NetDB"); i2p::util::SetThreadName("NetDB");
uint64_t lastSave = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch (); uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
int16_t profilesCleanupVariance = 0; int16_t profilesCleanupVariance = 0;
@@ -132,6 +133,9 @@ namespace data
case eI2NPDatabaseLookup: case eI2NPDatabaseLookup:
HandleDatabaseLookupMsg (msg); HandleDatabaseLookupMsg (msg);
break; break;
case eI2NPDeliveryStatus:
HandleDeliveryStatusMsg (msg);
break;
case eI2NPDummyMsg: case eI2NPDummyMsg:
// plain RouterInfo from NTCP2 with flags for now // plain RouterInfo from NTCP2 with flags for now
HandleNTCP2RouterInfoMsg (msg); HandleNTCP2RouterInfoMsg (msg);
@@ -149,13 +153,13 @@ namespace data
if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline if (!i2p::transport::transports.IsOnline ()) continue; // don't manage netdb when offline
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastManageRequest >= 15 || ts + 15 < lastManageRequest) // manage requests every 15 seconds if (ts - lastManageRequest >= 15) // manage requests every 15 seconds
{ {
m_Requests.ManageRequests (); m_Requests.ManageRequests ();
lastManageRequest = ts; lastManageRequest = ts;
} }
if (ts - lastSave >= 60 || ts + 60 < lastSave) // save routers, manage leasesets and validate subscriptions every minute if (ts - lastSave >= 60) // save routers, manage leasesets and validate subscriptions every minute
{ {
if (lastSave) if (lastSave)
{ {
@@ -165,23 +169,46 @@ namespace data
lastSave = ts; lastSave = ts;
} }
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT || if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
ts + i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT < lastDestinationCleanup)
{ {
i2p::context.CleanupDestination (); i2p::context.CleanupDestination ();
lastDestinationCleanup = ts; lastDestinationCleanup = ts;
} }
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance) || if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
ts + i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT < lastProfilesCleanup)
{ {
if (m_PersistProfiles) PersistProfiles ();
DeleteObsoleteProfiles (); DeleteObsoleteProfiles ();
lastProfilesCleanup = ts; lastProfilesCleanup = ts;
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE); profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
} }
if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds // publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{
bool publish = false;
if (m_PublishReplyToken)
{
// next publishing attempt
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
}
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
{
// new publish
m_PublishExcluded.clear ();
if (i2p::context.IsFloodfill ())
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
publish = true;
}
if (publish) // update timestamp and publish
{
i2p::context.UpdateTimestamp (ts);
Publish ();
lastPublish = ts;
}
}
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
{ {
auto numRouters = m_RouterInfos.size (); auto numRouters = m_RouterInfos.size ();
if (!numRouters) if (!numRouters)
@@ -194,7 +221,7 @@ namespace data
if (numRouters < 1) numRouters = 1; if (numRouters < 1) numRouters = 1;
if (numRouters > 9) numRouters = 9; if (numRouters > 9) numRouters = 9;
m_Requests.ManageRequests (); m_Requests.ManageRequests ();
if(!i2p::context.IsHidden ()) if(!m_HiddenMode)
Explore (numRouters); Explore (numRouters);
lastExploratory = ts; lastExploratory = ts;
} }
@@ -207,6 +234,12 @@ namespace data
} }
} }
void NetDb::SetHidden(bool hide)
{
// TODO: remove reachable addresses from router info
m_HiddenMode = hide;
}
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len) std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len)
{ {
bool updated; bool updated;
@@ -240,24 +273,7 @@ namespace data
bool wasFloodfill = r->IsFloodfill (); bool wasFloodfill = r->IsFloodfill ();
{ {
std::unique_lock<std::mutex> l(m_RouterInfosMutex); std::unique_lock<std::mutex> l(m_RouterInfosMutex);
if (!r->Update (buf, len)) r->Update (buf, len);
{
updated = false;
m_Requests.RequestComplete (ident, r);
return r;
}
if (r->IsUnreachable ())
{
// delete router as invalid after update
m_RouterInfos.erase (ident);
if (wasFloodfill)
{
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.Remove (r->GetIdentHash ());
}
m_Requests.RequestComplete (ident, nullptr);
return nullptr;
}
} }
LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64()); LogPrint (eLogInfo, "NetDb: RouterInfo updated: ", ident.ToBase64());
if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated if (wasFloodfill != r->IsFloodfill ()) // if floodfill status updated
@@ -265,9 +281,9 @@ namespace data
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
if (wasFloodfill) if (wasFloodfill)
m_Floodfills.Remove (r->GetIdentHash ()); m_Floodfills.remove (r);
else if (r->IsEligibleFloodfill ()) else if (r->IsEligibleFloodfill ())
m_Floodfills.Insert (r); m_Floodfills.push_back (r);
} }
} }
else else
@@ -279,7 +295,7 @@ namespace data
else else
{ {
r = std::make_shared<RouterInfo> (buf, len); r = std::make_shared<RouterInfo> (buf, len);
if (!r->IsUnreachable () && r->HasValidAddresses () && (!r->IsFloodfill () || !r->GetProfile ()->IsUnreachable ()) && if (!r->IsUnreachable () && r->HasValidAddresses () &&
i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp ()) i2p::util::GetMillisecondsSinceEpoch () + NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL > r->GetTimestamp ())
{ {
bool inserted = false; bool inserted = false;
@@ -293,7 +309,7 @@ namespace data
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.Insert (r); m_Floodfills.push_back (r);
} }
} }
else else
@@ -411,15 +427,7 @@ namespace data
{ {
auto it = m_RouterInfos.find (ident); auto it = m_RouterInfos.find (ident);
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
{ return it->second->SetUnreachable (unreachable);
it->second->SetUnreachable (unreachable);
if (unreachable)
{
auto profile = it->second->GetProfile ();
if (profile)
profile->Unreachable ();
}
}
} }
void NetDb::Reseed () void NetDb::Reseed ()
@@ -431,8 +439,8 @@ namespace data
} }
// try reseeding from floodfill first if specified // try reseeding from floodfill first if specified
std::string riPath; i2p::config::GetOption("reseed.floodfill", riPath); std::string riPath;
if (!riPath.empty()) if(i2p::config::GetOption("reseed.floodfill", riPath))
{ {
auto ri = std::make_shared<RouterInfo>(riPath); auto ri = std::make_shared<RouterInfo>(riPath);
if (ri->IsFloodfill()) if (ri->IsFloodfill())
@@ -494,7 +502,7 @@ namespace data
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second) if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{ {
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
m_Floodfills.Insert (r); m_Floodfills.push_back (r);
} }
} }
else else
@@ -578,7 +586,7 @@ namespace data
{ {
// make sure we cleanup netDb from previous attempts // make sure we cleanup netDb from previous attempts
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.Clear (); m_Floodfills.clear ();
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
std::vector<std::string> files; std::vector<std::string> files;
@@ -586,14 +594,14 @@ namespace data
for (const auto& path : files) for (const auto& path : files)
LoadRouterInfo (path, ts); LoadRouterInfo (path, ts);
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.GetSize (), " floodfils)"); LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
} }
void NetDb::SaveUpdated () void NetDb::SaveUpdated ()
{ {
int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0; int updatedCount = 0, deletedCount = 0, deletedFloodfillsCount = 0;
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
auto totalFloodfills = m_Floodfills.GetSize (); auto totalFloodfills = m_Floodfills.size ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
auto uptime = i2p::context.GetUptime (); auto uptime = i2p::context.GetUptime ();
@@ -611,25 +619,17 @@ namespace data
std::string ident = it.second->GetIdentHashBase64(); std::string ident = it.second->GetIdentHashBase64();
if (it.second->IsUpdated ()) if (it.second->IsUpdated ())
{ {
if (it.second->GetBuffer ())
{
// we have something to save
it.second->SaveToFile (m_Storage.Path(ident)); it.second->SaveToFile (m_Storage.Path(ident));
it.second->SetUpdated (false);
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
it.second->DeleteBuffer (); it.second->DeleteBuffer ();
}
it.second->SetUpdated (false);
updatedCount++; updatedCount++;
continue; continue;
} }
if (it.second->GetProfile ()->IsUnreachable ())
it.second->SetUnreachable (true);
// make router reachable back if too few routers or floodfills // make router reachable back if too few routers or floodfills
if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate || if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS || isLowRate ||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) (it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
if (!it.second->IsUnreachable ())
{
// find & mark expired routers // find & mark expired routers
if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & RouterInfo::eSSU2V4)) if (!it.second->IsReachable () && (it.second->GetCompatibleTransports (true) & RouterInfo::eSSU2V4))
// non-reachable router, but reachable by ipv4 SSU2 means introducers // non-reachable router, but reachable by ipv4 SSU2 means introducers
@@ -645,9 +645,6 @@ namespace data
LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds"); LogPrint (eLogWarning, "NetDb: RouterInfo is from future for ", (it.second->GetTimestamp () - ts)/1000LL, " seconds");
it.second->SetUnreachable (true); it.second->SetUnreachable (true);
} }
if (it.second->IsUnreachable () && i2p::transport::transports.IsConnected (it.second->GetIdentHash ()))
it.second->SetUnreachable (false); // don't expire connected router
}
if (it.second->IsUnreachable ()) if (it.second->IsUnreachable ())
{ {
@@ -674,21 +671,22 @@ namespace data
for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();) for (auto it = m_RouterInfos.begin (); it != m_RouterInfos.end ();)
{ {
if (it->second->IsUnreachable ()) if (it->second->IsUnreachable ())
it = m_RouterInfos.erase (it);
else
{ {
it->second->DropProfile (); if (m_PersistProfiles) it->second->SaveProfile ();
it++; it = m_RouterInfos.erase (it);
continue;
} }
++it;
} }
} }
// clean up expired floodfills or not floodfills anymore // clean up expired floodfills or not floodfills anymore
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.Cleanup ([](const std::shared_ptr<RouterInfo>& r)->bool for (auto it = m_Floodfills.begin (); it != m_Floodfills.end ();)
{ if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ())
return r && r->IsFloodfill () && !r->IsUnreachable (); it = m_Floodfills.erase (it);
}); else
++it;
} }
} }
} }
@@ -823,7 +821,7 @@ namespace data
} }
else // all others are considered as LeaseSet2 else // all others are considered as LeaseSet2
{ {
LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", int(storeType), " for ", ident.ToBase32()); LogPrint (eLogDebug, "NetDb: Store request: LeaseSet2 of type ", storeType, " for ", ident.ToBase32());
updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType); updated = AddLeaseSet2 (ident, buf + offset, len - offset, storeType);
} }
} }
@@ -1008,10 +1006,11 @@ namespace data
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP) lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
{ {
auto router = FindRouter (ident); auto router = FindRouter (ident);
if (router && !router->IsUnreachable ()) if (router)
{ {
LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found"); LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
if (PopulateRouterInfoBuffer (router)) PopulateRouterInfoBuffer (router);
if (router->GetBuffer ())
replyMsg = CreateDatabaseStoreMsg (router); replyMsg = CreateDatabaseStoreMsg (router);
} }
} }
@@ -1089,6 +1088,16 @@ namespace data
} }
} }
void NetDb::HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg)
{
if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
{
LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken);
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
}
}
void NetDb::Explore (int numDestinations) void NetDb::Explore (int numDestinations)
{ {
// new requests // new requests
@@ -1139,6 +1148,41 @@ namespace data
outbound->SendTunnelDataMsg (msgs); outbound->SendTunnelDataMsg (msgs);
} }
void NetDb::Publish ()
{
i2p::context.UpdateStats (); // for floodfill
if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
{
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
m_PublishExcluded.clear ();
}
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill)
{
uint32_t replyToken;
RAND_bytes ((uint8_t *)&replyToken, 4);
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken;
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
// send directly
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else
{
// otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (inbound && outbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
}
}
}
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg) void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
{ {
std::set<IdentHash> excluded; std::set<IdentHash> excluded;
@@ -1210,7 +1254,7 @@ namespace data
router->IsReachableFrom (*compatibleWith)) && router->IsReachableFrom (*compatibleWith)) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) && (router->GetCaps () & RouterInfo::eHighBandwidth) &&
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
router->IsECIES () && !router->IsHighCongestion (); router->IsECIES ();
}); });
} }
@@ -1278,39 +1322,79 @@ namespace data
} }
std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination, std::shared_ptr<const RouterInfo> NetDb::GetClosestFloodfill (const IdentHash& destination,
const std::set<IdentHash>& excluded) const const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{ {
std::shared_ptr<const RouterInfo> r;
XORMetric minMetric;
IdentHash destKey = CreateRoutingKey (destination); IdentHash destKey = CreateRoutingKey (destination);
if (closeThanUsOnly)
minMetric = destKey ^ i2p::context.GetIdentHash ();
else
minMetric.SetMax ();
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
return m_Floodfills.FindClosest (destKey, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool for (const auto& it: m_Floodfills)
{ {
return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () && if (!it->IsUnreachable ())
!excluded.count (r->GetIdentHash ()); {
}); XORMetric m = destKey ^ it->GetIdentHash ();
if (m < minMetric && !excluded.count (it->GetIdentHash ()))
{
minMetric = m;
r = it;
}
}
}
return r;
} }
std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> NetDb::GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly) const std::set<IdentHash>& excluded, bool closeThanUsOnly) const
{ {
std::vector<IdentHash> res; struct Sorted
IdentHash destKey = CreateRoutingKey (destination);
std::vector<std::shared_ptr<RouterInfo> > v;
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::shared_ptr<const RouterInfo> r;
v = m_Floodfills.FindClosest (destKey, num, [&excluded](const std::shared_ptr<RouterInfo>& r)->bool XORMetric metric;
{ bool operator< (const Sorted& other) const { return metric < other.metric; };
return r && !r->IsUnreachable () && !r->GetProfile ()->IsUnreachable () && };
!excluded.count (r->GetIdentHash ());
});
}
if (v.empty ()) return res;
std::set<Sorted> sorted;
IdentHash destKey = CreateRoutingKey (destination);
XORMetric ourMetric; XORMetric ourMetric;
if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash (); if (closeThanUsOnly) ourMetric = destKey ^ i2p::context.GetIdentHash ();
for (auto& it: v)
{ {
if (closeThanUsOnly && ourMetric < (destKey ^ it->GetIdentHash ())) break; std::unique_lock<std::mutex> l(m_FloodfillsMutex);
res.push_back (it->GetIdentHash ()); for (const auto& it: m_Floodfills)
{
if (!it->IsUnreachable ())
{
XORMetric m = destKey ^ it->GetIdentHash ();
if (closeThanUsOnly && ourMetric < m) continue;
if (sorted.size () < num)
sorted.insert ({it, m});
else if (m < sorted.rbegin ()->metric)
{
sorted.insert ({it, m});
sorted.erase (std::prev (sorted.end ()));
}
}
}
}
std::vector<IdentHash> res;
size_t i = 0;
for (const auto& it: sorted)
{
if (i < num)
{
const auto& ident = it.r->GetIdentHash ();
if (!excluded.count (ident))
{
res.push_back (ident);
i++;
}
}
else
break;
} }
return res; return res;
} }
@@ -1363,11 +1447,10 @@ namespace data
m_LeasesPool.CleanUpMt (); m_LeasesPool.CleanUpMt ();
} }
bool NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r) void NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
{ {
if (!r) return false; if (!r || r->GetBuffer ()) return;
if (r->GetBuffer ()) return true; r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
return r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
} }
} }
} }

View File

@@ -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
* *
@@ -12,6 +12,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <set> #include <set>
#include <unordered_map> #include <unordered_map>
#include <list>
#include <string> #include <string>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@@ -30,7 +31,6 @@
#include "Family.h" #include "Family.h"
#include "version.h" #include "version.h"
#include "util.h" #include "util.h"
#include "KadDHT.h"
namespace i2p namespace i2p
{ {
@@ -45,8 +45,11 @@ namespace data
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes const int NETDB_EXPIRATION_TIMEOUT_THRESHOLD = 2*60; // 2 minutes
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_PUBLISH_INTERVAL = 60 * 40;
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 38); // 0.9.38
const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 const int NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51
/** function for visiting a leaseset stored in a floodfill */ /** function for visiting a leaseset stored in a floodfill */
@@ -83,13 +86,14 @@ namespace data
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m); void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
void HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::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::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
@@ -98,12 +102,15 @@ namespace data
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide);
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; };
// for web interface // for web interface
int GetNumRouters () const { return m_RouterInfos.size (); }; int GetNumRouters () const { return m_RouterInfos.size (); };
int GetNumFloodfills () const { return m_Floodfills.GetSize (); }; int GetNumFloodfills () const { return m_Floodfills.size (); };
int GetNumLeaseSets () const { return m_LeaseSets.size (); }; int GetNumLeaseSets () const { return m_LeaseSets.size (); };
/** visit all lease sets we currently store */ /** visit all lease sets we currently store */
@@ -117,7 +124,7 @@ namespace data
void ClearRouterInfos () { m_RouterInfos.clear (); }; void ClearRouterInfos () { m_RouterInfos.clear (); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); }; std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
bool PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r); void 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 ()
{ {
@@ -137,6 +144,7 @@ namespace data
void SaveUpdated (); void SaveUpdated ();
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish ();
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg); void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
@@ -156,7 +164,7 @@ namespace data
mutable std::mutex m_RouterInfosMutex; mutable std::mutex m_RouterInfosMutex;
std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos; std::unordered_map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
DHTTable m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
@@ -175,6 +183,9 @@ namespace data
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/ /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
/** true if in hidden mode */
bool m_HiddenMode;
std::set<IdentHash> m_PublishExcluded; std::set<IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken = 0; uint32_t m_PublishReplyToken = 0;

View File

@@ -7,9 +7,6 @@
*/ */
#include <sys/stat.h> #include <sys/stat.h>
#include <unordered_map>
#include <list>
#include <thread>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp> #include <boost/property_tree/ini_parser.hpp>
#include "Base.h" #include "Base.h"
@@ -22,27 +19,24 @@ namespace i2p
{ {
namespace data namespace data
{ {
static i2p::fs::HashedStorage g_ProfilesStorage("peerProfiles", "p", "profile-", "txt"); i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
static std::mutex g_ProfilesMutex;
static boost::posix_time::ptime GetTime ()
{
return boost::posix_time::second_clock::local_time();
}
RouterProfile::RouterProfile (): RouterProfile::RouterProfile ():
m_LastUpdateTime (GetTime ()), m_IsUpdated (false), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
m_LastDeclineTime (0), m_LastUnreachableTime (0), m_LastDeclineTime (0),
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0), m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
m_NumTimesTaken (0), m_NumTimesRejected (0) m_NumTimesTaken (0), m_NumTimesRejected (0)
{ {
} }
boost::posix_time::ptime RouterProfile::GetTime () const
{
return boost::posix_time::second_clock::local_time();
}
void RouterProfile::UpdateTime () void RouterProfile::UpdateTime ()
{ {
m_LastUpdateTime = GetTime (); m_LastUpdateTime = GetTime ();
m_IsUpdated = true;
} }
void RouterProfile::Save (const IdentHash& identHash) void RouterProfile::Save (const IdentHash& identHash)
@@ -58,14 +52,12 @@ namespace data
// fill property tree // fill property tree
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime)); pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
if (m_LastUnreachableTime)
pt.put (PEER_PROFILE_LAST_UNREACHABLE_TIME, m_LastUnreachableTime);
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation); pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage); pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
// save to file // save to file
std::string ident = identHash.ToBase64 (); std::string ident = identHash.ToBase64 ();
std::string path = g_ProfilesStorage.Path(ident); std::string path = m_ProfilesStorage.Path(ident);
try { try {
boost::property_tree::write_ini (path, pt); boost::property_tree::write_ini (path, pt);
@@ -78,7 +70,7 @@ namespace data
void RouterProfile::Load (const IdentHash& identHash) void RouterProfile::Load (const IdentHash& identHash)
{ {
std::string ident = identHash.ToBase64 (); std::string ident = identHash.ToBase64 ();
std::string path = g_ProfilesStorage.Path(ident); std::string path = m_ProfilesStorage.Path(ident);
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
if (!i2p::fs::Exists(path)) if (!i2p::fs::Exists(path))
@@ -104,7 +96,6 @@ namespace data
m_LastUpdateTime = boost::posix_time::time_from_string (t); m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
{ {
m_LastUnreachableTime = pt.get (PEER_PROFILE_LAST_UNREACHABLE_TIME, 0);
try try
{ {
// read participations // read participations
@@ -161,12 +152,6 @@ namespace data
m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch (); m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
} }
void RouterProfile::Unreachable ()
{
m_LastUnreachableTime = i2p::util::GetSecondsSinceEpoch ();
UpdateTime ();
}
bool RouterProfile::IsLowPartcipationRate () const bool RouterProfile::IsLowPartcipationRate () const
{ {
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
@@ -182,15 +167,14 @@ namespace data
{ {
if (!m_LastDeclineTime) return false; if (!m_LastDeclineTime) return false;
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL || if (ts > m_LastDeclineTime + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL)
ts + PEER_PROFILE_DECLINED_RECENTLY_INTERVAL < m_LastDeclineTime)
m_LastDeclineTime = 0; m_LastDeclineTime = 0;
return (bool)m_LastDeclineTime; return m_LastDeclineTime;
} }
bool RouterProfile::IsBad () bool RouterProfile::IsBad ()
{ {
if (IsDeclinedRecently () || IsUnreachable ()) return true; if (IsDeclinedRecently ()) return true;
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/; auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1)) if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
{ {
@@ -204,98 +188,32 @@ namespace data
return isBad; return isBad;
} }
bool RouterProfile::IsUnreachable ()
{
if (!m_LastUnreachableTime) return false;
auto ts = i2p::util::GetSecondsSinceEpoch ();
if (ts > m_LastUnreachableTime + PEER_PROFILE_UNREACHABLE_INTERVAL ||
ts + PEER_PROFILE_UNREACHABLE_INTERVAL < m_LastUnreachableTime)
m_LastUnreachableTime = 0;
return (bool)m_LastUnreachableTime;
}
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash) std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
{ {
{
std::unique_lock<std::mutex> l(g_ProfilesMutex);
auto it = g_Profiles.find (identHash);
if (it != g_Profiles.end ())
return it->second;
}
auto profile = std::make_shared<RouterProfile> (); auto profile = std::make_shared<RouterProfile> ();
profile->Load (identHash); // if possible profile->Load (identHash); // if possible
std::unique_lock<std::mutex> l(g_ProfilesMutex);
g_Profiles.emplace (identHash, profile);
return profile; return profile;
} }
void InitProfilesStorage () void InitProfilesStorage ()
{ {
g_ProfilesStorage.SetPlace(i2p::fs::GetDataDir()); m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64); m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
}
void PersistProfiles ()
{
auto ts = GetTime ();
std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
{
std::unique_lock<std::mutex> l(g_ProfilesMutex);
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
{
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () > PEER_PROFILE_PERSIST_INTERVAL)
{
if (it->second->IsUpdated ())
tmp.push_back (std::make_pair (it->first, it->second));
it = g_Profiles.erase (it);
}
else
it++;
}
}
for (auto& it: tmp)
if (it.second) it.second->Save (it.first);
}
void SaveProfiles ()
{
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
{
std::unique_lock<std::mutex> l(g_ProfilesMutex);
tmp = g_Profiles;
g_Profiles.clear ();
}
auto ts = GetTime ();
for (auto& it: tmp)
if (it.second->IsUpdated () && (ts - it.second->GetLastUpdateTime ()).total_seconds () < PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
it.second->Save (it.first);
} }
void DeleteObsoleteProfiles () void DeleteObsoleteProfiles ()
{ {
{
auto ts = GetTime ();
std::unique_lock<std::mutex> l(g_ProfilesMutex);
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
{
if ((ts - it->second->GetLastUpdateTime ()).total_seconds () >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600)
it = g_Profiles.erase (it);
else
it++;
}
}
struct stat st; struct stat st;
std::time_t now = std::time(nullptr); std::time_t now = std::time(nullptr);
std::vector<std::string> files; std::vector<std::string> files;
g_ProfilesStorage.Traverse(files); m_ProfilesStorage.Traverse(files);
for (const auto& path: files) { for (const auto& path: files) {
if (stat(path.c_str(), &st) != 0) { if (stat(path.c_str(), &st) != 0) {
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path); LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
continue; continue;
} }
if (now - st.st_mtime >= PEER_PROFILE_EXPIRATION_TIMEOUT*3600) { if (((now - st.st_mtime) / 3600) >= PEER_PROFILE_EXPIRATION_TIMEOUT) {
LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path); LogPrint(eLogDebug, "Profiling: Removing expired peer profile: ", path);
i2p::fs::Remove(path); i2p::fs::Remove(path);
} }

View File

@@ -22,19 +22,16 @@ namespace data
const char PEER_PROFILE_SECTION_USAGE[] = "usage"; const char PEER_PROFILE_SECTION_USAGE[] = "usage";
// params // params
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
const char PEER_PROFILE_LAST_UNREACHABLE_TIME[] = "lastunreachabletime";
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed"; const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined"; const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied"; const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
const char PEER_PROFILE_USAGE_TAKEN[] = "taken"; const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected"; const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 36; // in hours (1.5 days) const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 6 * 3600; // in seconds (6 hours) const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3600; // in seconds (1 hour) const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes) const int PEER_PROFILE_DECLINED_RECENTLY_INTERVAL = 150; // in seconds (2.5 minutes)
const int PEER_PROFILE_PERSIST_INTERVAL = 3300; // in seconds (55 minutes)
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 2*3600; // on seconds (2 hours)
class RouterProfile class RouterProfile
{ {
@@ -47,18 +44,13 @@ namespace data
void Load (const IdentHash& identHash); void Load (const IdentHash& identHash);
bool IsBad (); bool IsBad ();
bool IsUnreachable ();
void TunnelBuildResponse (uint8_t ret); void TunnelBuildResponse (uint8_t ret);
void TunnelNonReplied (); void TunnelNonReplied ();
void Unreachable ();
boost::posix_time::ptime GetLastUpdateTime () const { return m_LastUpdateTime; };
bool IsUpdated () const { return m_IsUpdated; };
private: private:
boost::posix_time::ptime GetTime () const;
void UpdateTime (); void UpdateTime ();
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
@@ -69,8 +61,7 @@ namespace data
private: private:
boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono boost::posix_time::ptime m_LastUpdateTime; // TODO: use std::chrono
bool m_IsUpdated; uint64_t m_LastDeclineTime; // in seconds
uint64_t m_LastDeclineTime, m_LastUnreachableTime; // in seconds
// participation // participation
uint32_t m_NumTunnelsAgreed; uint32_t m_NumTunnelsAgreed;
uint32_t m_NumTunnelsDeclined; uint32_t m_NumTunnelsDeclined;
@@ -83,8 +74,6 @@ namespace data
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash); std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void InitProfilesStorage (); void InitProfilesStorage ();
void DeleteObsoleteProfiles (); void DeleteObsoleteProfiles ();
void SaveProfiles ();
void PersistProfiles ();
} }
} }

View File

@@ -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
* *
@@ -320,7 +320,7 @@ namespace data
uint16_t fileNameLength, extraFieldLength; uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2); s.read ((char *)&fileNameLength, 2);
fileNameLength = le16toh (fileNameLength); fileNameLength = le16toh (fileNameLength);
if ( fileNameLength >= 255 ) { if ( fileNameLength > 255 ) {
// too big // too big
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength); LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
return numFiles; return numFiles;
@@ -687,23 +687,12 @@ namespace data
while (it != end) while (it != end)
{ {
boost::asio::ip::tcp::endpoint ep = *it; boost::asio::ip::tcp::endpoint ep = *it;
if ( if ((ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
( (ep.address ().is_v6 () && i2p::context.SupportsV6 ()))
!i2p::util::net::IsInReservedRange(ep.address ()) && (
(ep.address ().is_v4 () && i2p::context.SupportsV4 ()) ||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())
)
) ||
(
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
i2p::context.SupportsMesh ()
)
)
{ {
s.lowest_layer().connect (ep, ecode); s.lowest_layer().connect (ep, ecode);
if (!ecode) if (!ecode)
{ {
LogPrint (eLogDebug, "Reseed: Resolved to ", ep.address ());
connected = true; connected = true;
break; break;
} }
@@ -791,45 +780,17 @@ namespace data
boost::asio::io_service service; boost::asio::io_service service;
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6()); boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
auto it = boost::asio::ip::tcp::resolver(service).resolve ( if (url.host.length () < 2) return ""; // assume []
boost::asio::ip::tcp::resolver::query (url.host, std::to_string(url.port)), ecode); auto host = url.host.substr (1, url.host.length () - 2);
LogPrint (eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port);
s.connect (boost::asio::ip::tcp::endpoint (boost::asio::ip::address_v6::from_string (host), url.port), ecode);
if (!ecode) if (!ecode)
{ {
bool connected = false; LogPrint (eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
boost::asio::ip::tcp::resolver::iterator end;
while (it != end)
{
boost::asio::ip::tcp::endpoint ep = *it;
if (
i2p::util::net::IsYggdrasilAddress (ep.address ()) &&
i2p::context.SupportsMesh ()
)
{
LogPrint (eLogDebug, "Reseed: Yggdrasil: Resolved to ", ep.address ());
s.connect (ep, ecode);
if (!ecode)
{
connected = true;
break;
}
}
it++;
}
if (!connected)
{
LogPrint(eLogError, "Reseed: Yggdrasil: Failed to connect to ", url.host);
return "";
}
}
if (!ecode)
{
LogPrint (eLogDebug, "Reseed: Yggdrasil: Connected to ", url.host, ":", url.port);
return ReseedRequest (s, url.to_string()); return ReseedRequest (s, url.to_string());
} }
else else
LogPrint (eLogError, "Reseed: Yggdrasil: Couldn't connect to ", url.host, ": ", ecode.message ()); LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ());
return ""; return "";
} }

View File

@@ -20,8 +20,6 @@
#include "Log.h" #include "Log.h"
#include "Family.h" #include "Family.h"
#include "ECIESX25519AEADRatchetSession.h" #include "ECIESX25519AEADRatchetSession.h"
#include "Transports.h"
#include "Tunnel.h"
#include "RouterContext.h" #include "RouterContext.h"
namespace i2p namespace i2p
@@ -31,8 +29,7 @@ namespace i2p
RouterContext::RouterContext (): RouterContext::RouterContext ():
m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false), m_LastUpdateTime (0), m_AcceptsTunnels (true), m_IsFloodfill (false),
m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown), m_ShareRatio (100), m_Status (eRouterStatusUnknown), m_StatusV6 (eRouterStatusUnknown),
m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID), m_Error (eRouterErrorNone), m_ErrorV6 (eRouterErrorNone), m_NetID (I2PD_NET_ID)
m_PublishReplyToken (0), m_IsHiddenMode (false)
{ {
} }
@@ -50,34 +47,6 @@ namespace i2p
m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState); m_ECIESSession = std::make_shared<i2p::garlic::RouterIncomingRatchetSession>(m_InitialNoiseState);
} }
void RouterContext::Start ()
{
if (!m_Service)
{
m_Service.reset (new RouterService);
m_Service->Start ();
if (!m_IsHiddenMode)
{
m_PublishTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
ScheduleInitialPublish ();
m_CongestionUpdateTimer.reset (new boost::asio::deadline_timer (m_Service->GetService ()));
ScheduleCongestionUpdate ();
}
}
}
void RouterContext::Stop ()
{
if (m_Service)
{
if (m_PublishTimer)
m_PublishTimer->cancel ();
if (m_CongestionUpdateTimer)
m_CongestionUpdateTimer->cancel ();
m_Service->Stop ();
}
}
void RouterContext::CreateNewRouter () void RouterContext::CreateNewRouter ()
{ {
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519,
@@ -116,103 +85,96 @@ namespace i2p
bool ssu2Published = false; bool ssu2Published = false;
if (ssu2) if (ssu2)
i2p::config::GetOption("ssu2.published", ssu2Published); i2p::config::GetOption("ssu2.published", ssu2Published);
uint8_t caps = 0; uint8_t caps = 0, addressCaps = 0;
if (ipv4) if (ipv4)
{ {
std::string host; std::string host = "127.0.0.1";
if (!nat) if (!i2p::config::IsDefault("host"))
i2p::config::GetOption("host", host);
else if (!nat)
{
// we have no NAT so set external address from local address // we have no NAT so set external address from local address
i2p::config::GetOption("address4", host); std::string address4; i2p::config::GetOption("address4", address4);
if (host.empty ()) i2p::config::GetOption("host", host); if (!address4.empty ()) host = address4;
}
if (ntcp2) if (ntcp2)
{ {
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); if (ntcp2Published)
if (!ntcp2Port) ntcp2Port = port; routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v4::from_string (host), port);
if (ntcp2Published && ntcp2Port) else // add non-published NTCP2 address
{ {
boost::asio::ip::address addr; addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
if (!host.empty ()) routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
addr = boost::asio::ip::address::from_string (host);
if (!addr.is_v4())
addr = boost::asio::ip::address_v4 ();
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
}
else
{
// add non-published NTCP2 address
uint8_t addressCaps = i2p::data::RouterInfo::AddressCaps::eV4;
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, addressCaps);
} }
} }
if (ssu2) if (ssu2)
{
if (ssu2Published)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!ssu2Port) ssu2Port = port; if (!ssu2Port) ssu2Port = port;
if (ssu2Published && ssu2Port) routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port);
{
boost::asio::ip::address addr;
if (!host.empty ())
addr = boost::asio::ip::address::from_string (host);
if (!addr.is_v4())
addr = boost::asio::ip::address_v4 ();
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
} }
else else
{ {
uint8_t addressCaps = i2p::data::RouterInfo::AddressCaps::eV4; addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6; routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, addressCaps);
} }
} }
} }
if (ipv6) if (ipv6)
{ {
std::string host; i2p::config::GetOption("address6", host); std::string host;
if (host.empty () && !ipv4) i2p::config::GetOption("host", host); // use host for ipv6 only if ipv4 is not presented if (!i2p::config::IsDefault("host") && !ipv4) // override if v6 only
i2p::config::GetOption("host", host);
else
{
std::string address6; i2p::config::GetOption("address6", address6);
if (!address6.empty ()) host = address6;
}
if (ntcp2) if (ntcp2)
{ {
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); bool added = false;
if (!ntcp2Port) ntcp2Port = port; if (ntcp2Published)
if (ntcp2Published && ntcp2Port)
{ {
std::string ntcp2Host; std::string ntcp2Host;
if (!i2p::config::IsDefault ("ntcp2.addressv6")) if (!i2p::config::IsDefault ("ntcp2.addressv6"))
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host); i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
else else
ntcp2Host = host; ntcp2Host = host;
boost::asio::ip::address addr; if (!ntcp2Host.empty () && port)
if (!ntcp2Host.empty ()) {
addr = boost::asio::ip::address::from_string (ntcp2Host); routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address_v6::from_string (ntcp2Host), port);
if (!addr.is_v6()) added = true;
addr = boost::asio::ip::address_v6 ();
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
} }
else }
if (!added)
{ {
if (!ipv4) // no other ntcp2 addresses yet if (!ipv4) // no other ntcp2 addresses yet
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::AddressCaps::eV6); routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
} }
} }
if (ssu2) if (ssu2)
{
bool added = false;
if (ssu2Published)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!ssu2Port) ssu2Port = port; if (!ssu2Port) ssu2Port = port;
if (ssu2Published && ssu2Port) if (!host.empty () && ssu2Port)
{ {
boost::asio::ip::address addr; routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port);
if (!host.empty ()) added = true;
addr = boost::asio::ip::address::from_string (host);
if (!addr.is_v6())
addr = boost::asio::ip::address_v6 ();
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
} }
else }
if (!added)
{ {
if (!ipv4) // no other ssu2 addresses yet if (!ipv4) // no other ssu2 addresses yet
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::AddressCaps::eV6); routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro);
addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
} }
} }
} }
@@ -223,6 +185,8 @@ namespace i2p
routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port); routerInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, yggaddr, port);
} }
if (addressCaps)
routerInfo.SetUnreachableAddressesTransportCaps (addressCaps);
routerInfo.UpdateCaps (caps); // caps + L routerInfo.UpdateCaps (caps); // caps + L
routerInfo.SetProperty ("netId", std::to_string (m_NetID)); routerInfo.SetProperty ("netId", std::to_string (m_NetID));
routerInfo.SetProperty ("router.version", I2P_VERSION); routerInfo.SetProperty ("router.version", I2P_VERSION);
@@ -233,13 +197,8 @@ namespace i2p
uint16_t RouterContext::SelectRandomPort () const uint16_t RouterContext::SelectRandomPort () const
{ {
uint16_t port; uint16_t port = rand () % (30777 - 9111) + 9111; // I2P network ports range
do if (port == 9150) port = 9151; // Tor browser
{
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
}
while(i2p::util::net::IsPortInReservedRange(port));
return port; return port;
} }
@@ -327,7 +286,7 @@ namespace i2p
bool updated = false; bool updated = false;
for (auto& address : *addresses) for (auto& address : *addresses)
{ {
if (address && address->port != port) if (address && address->port != port && address->transportStyle == i2p::data::RouterInfo::eTransportSSU2)
{ {
address->port = port; address->port = port;
updated = true; updated = true;
@@ -337,68 +296,66 @@ namespace i2p
UpdateRouterInfo (); UpdateRouterInfo ();
} }
void RouterContext::PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address,
int port, bool publish) const
{
if (!address) return;
if (!port && !address->port) port = SelectRandomPort ();
if (port) address->port = port;
address->published = publish;
memcpy (address->i, m_NTCP2Keys->iv, 16);
}
void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg) void RouterContext::PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg)
{ {
if (!m_NTCP2Keys) return; if (!m_NTCP2Keys) return;
auto addresses = m_RouterInfo.GetAddresses (); auto addresses = m_RouterInfo.GetAddresses ();
if (!addresses) return; if (!addresses) return;
bool updated = false; bool updated = false;
if (v4) for (auto& address : *addresses)
{ {
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V4Idx]; if (address && address->IsNTCP2 () && (address->port != port || address->published != publish))
if (addr && (addr->port != port || addr->published != publish))
{ {
PublishNTCP2Address (addr, port, publish); bool isAddr = v4 && address->IsV4 ();
if (!isAddr && (v6 || ygg))
{
if (i2p::util::net::IsYggdrasilAddress (address->host))
isAddr = ygg;
else
isAddr = v6 && address->IsV6 ();
}
if (isAddr)
{
if (!port && !address->port) port = SelectRandomPort ();
if (port) address->port = port;
address->published = publish;
memcpy (address->i, m_NTCP2Keys->iv, 16);
updated = true; updated = true;
} }
} }
if (v6)
{
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
if (addr && (addr->port != port || addr->published != publish))
{
PublishNTCP2Address (addr, port, publish);
updated = true;
} }
}
if (ygg)
{
auto addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx];
if (addr && (addr->port != port || addr->published != publish))
{
PublishNTCP2Address (addr, port, publish);
updated = true;
}
}
if (updated) if (updated)
UpdateRouterInfo (); UpdateRouterInfo ();
} }
void RouterContext::UpdateNTCP2Keys () void RouterContext::UpdateNTCP2Address (bool enable)
{ {
if (!m_NTCP2Keys) return;
auto addresses = m_RouterInfo.GetAddresses (); auto addresses = m_RouterInfo.GetAddresses ();
if (!addresses) return; if (!addresses) return;
bool found = false, updated = false;
for (auto& it: *addresses) for (auto& it: *addresses)
{ {
if (it && it->IsNTCP2 ()) if (it && it->IsNTCP2 ())
{
found = true;
if (enable)
{ {
it->s = m_NTCP2Keys->staticPublicKey; it->s = m_NTCP2Keys->staticPublicKey;
memcpy (it->i, m_NTCP2Keys->iv, 16); memcpy (it->i, m_NTCP2Keys->iv, 16);
} }
else
it.reset ();
updated = true;
} }
} }
if (enable && !found)
{
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv);
updated = true;
}
if (updated)
UpdateRouterInfo ();
}
void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6) void RouterContext::PublishSSU2Address (int port, bool publish, bool v4, bool v6)
{ {
@@ -436,20 +393,48 @@ namespace i2p
UpdateRouterInfo (); UpdateRouterInfo ();
} }
void RouterContext::UpdateSSU2Keys () void RouterContext::UpdateSSU2Address (bool enable)
{ {
if (!m_SSU2Keys) return;
auto addresses = m_RouterInfo.GetAddresses (); auto addresses = m_RouterInfo.GetAddresses ();
if (!addresses) return; if (!addresses) return;
for (auto& it: *addresses) bool found = false, updated = false;
for (auto& it : *addresses)
{ {
if (it && it->IsSSU2 ()) if (it && it->IsSSU2 ())
{
found = true;
if (enable)
{ {
it->s = m_SSU2Keys->staticPublicKey; it->s = m_SSU2Keys->staticPublicKey;
it->i = m_SSU2Keys->intro; it->i = m_SSU2Keys->intro;
} }
else
it.reset ();
updated = true;
} }
} }
if (enable && !found)
{
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool published; i2p::config::GetOption("ntcp2.published", published);
if (published)
{
if (ipv4) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV4);
if (ipv6) m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::AddressCaps::eV6);
}
else
{
uint8_t addressCaps = 0;
if (ipv4) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV4;
if (ipv6) addressCaps |= i2p::data::RouterInfo::AddressCaps::eV6;
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addressCaps);
}
updated = true;
}
if (updated)
UpdateRouterInfo ();
}
void RouterContext::UpdateAddress (const boost::asio::ip::address& host) void RouterContext::UpdateAddress (const boost::asio::ip::address& host)
{ {
@@ -743,68 +728,44 @@ namespace i2p
if (!port) port = SelectRandomPort (); if (!port) port = SelectRandomPort ();
} }
// NTCP2 // NTCP2
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2)
{
if (!foundNTCP2) if (!foundNTCP2)
{ {
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (!ntcp2Port) ntcp2Port = port;
bool added = false;
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published); bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2)
{
if (ntcp2Published) if (ntcp2Published)
{ {
std::string ntcp2Host; std::string ntcp2Host;
if (!i2p::config::IsDefault ("ntcp2.addressv6")) if (!i2p::config::IsDefault ("ntcp2.addressv6"))
i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host); i2p::config::GetOption ("ntcp2.addressv6", ntcp2Host);
else else
i2p::config::GetOption("host", ntcp2Host); ntcp2Host = "::1";
if (!ntcp2Host.empty () && ntcp2Port) uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
{ if (!ntcp2Port) ntcp2Port = port;
auto addr = boost::asio::ip::address::from_string (ntcp2Host); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (ntcp2Host), ntcp2Port);
if (addr.is_v6 ())
{
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
added = true;
}
}
}
if (!added)
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV6);
}
} }
else else
m_RouterInfo.RemoveNTCP2Address (false); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
}
}
// SSU2 // SSU2
if (!foundSSU2)
{
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2) if (ssu2)
{ {
if (!foundSSU2) bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
if (ssu2Published)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!ssu2Port) ssu2Port = port; if (!ssu2Port) ssu2Port = port;
bool added = false; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
if (ssu2Published && ssu2Port)
{
std::string host; i2p::config::GetOption("host", host);
if (!host.empty ())
{
auto addr = boost::asio::ip::address::from_string (host);
if (addr.is_v6 ())
{
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
added = true;
}
}
}
if (!added)
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV6);
}
} }
else else
m_RouterInfo.RemoveSSU2Address (false); m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
if (ntcp2 || ssu2) }
}
m_RouterInfo.EnableV6 (); m_RouterInfo.EnableV6 ();
} }
else else
@@ -814,9 +775,14 @@ namespace i2p
void RouterContext::SetSupportsV4 (bool supportsV4) void RouterContext::SetSupportsV4 (bool supportsV4)
{ {
// check if updates
if (supportsV4 && SupportsV4 ()) return;
if (!supportsV4 && !SupportsV4 ()) return;
// update
if (supportsV4) if (supportsV4)
{ {
bool foundNTCP2 = false, foundSSU2 = false; bool foundNTCP2 = false, foundSSU2 = false;
std::string host = "127.0.0.1";
uint16_t port = 0; uint16_t port = 0;
auto addresses = m_RouterInfo.GetAddresses (); auto addresses = m_RouterInfo.GetAddresses ();
if (addresses) if (addresses)
@@ -845,65 +811,39 @@ namespace i2p
if (!port) port = SelectRandomPort (); if (!port) port = SelectRandomPort ();
} }
// NTCP2 // NTCP2
if (!foundNTCP2)
{
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2) if (ntcp2)
{ {
if (!foundNTCP2) bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2Published)
{ {
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port); uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!ntcp2Port) ntcp2Port = port; if (!ntcp2Port) ntcp2Port = port;
bool added = false; m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port);
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2Published && ntcp2Port)
{
std::string host; i2p::config::GetOption("host", host);
if (!host.empty ())
{
auto addr = boost::asio::ip::address::from_string (host);
if (addr.is_v4 ())
{
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, addr, ntcp2Port);
added = true;
}
}
}
if (!added)
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV4);
}
} }
else else
m_RouterInfo.RemoveNTCP2Address (true); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
}
}
// SSU2 // SSU2
if (!foundSSU2)
{
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2) if (ssu2)
{ {
if (!foundSSU2) bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
if (ssu2Published)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!ssu2Port) ssu2Port = port; if (!ssu2Port) ssu2Port = port;
bool added = false; m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
std::string host; i2p::config::GetOption("host", host);
if (ssu2Published && ssu2Port)
{
std::string host; i2p::config::GetOption("host", host);
if (!host.empty ())
{
auto addr = boost::asio::ip::address::from_string (host);
if (addr.is_v4 ())
{
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port);
added = true;
}
}
}
if (!added)
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV4);
}
} }
else else
m_RouterInfo.RemoveSSU2Address (true); m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV4);
if (ntcp2 || ssu2) }
}
m_RouterInfo.EnableV4 (); m_RouterInfo.EnableV4 ();
} }
else else
@@ -958,18 +898,29 @@ namespace i2p
void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host) void RouterContext::UpdateNTCP2V6Address (const boost::asio::ip::address& host)
{ {
bool isYgg = i2p::util::net::IsYggdrasilAddress (host);
bool updated = false;
auto addresses = m_RouterInfo.GetAddresses (); auto addresses = m_RouterInfo.GetAddresses ();
if (!addresses) return; if (!addresses) return;
std::shared_ptr<i2p::data::RouterInfo::Address> addr; for (auto& addr: *addresses)
if (i2p::util::net::IsYggdrasilAddress (host)) // yggdrasil {
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6MeshIdx]; if (addr && addr->IsPublishedNTCP2 ())
else if (host.is_v6 ()) {
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx]; bool isYgg1 = i2p::util::net::IsYggdrasilAddress (addr->host);
if (addr && addr->IsPublishedNTCP2 () && addr->host != host) if (addr->IsV6 () && ((isYgg && isYgg1) || (!isYgg && !isYgg1)))
{
if (addr->host != host)
{ {
addr->host = host; addr->host = host;
UpdateRouterInfo (); updated = true;
} }
break;
}
}
}
if (updated)
UpdateRouterInfo ();
} }
void RouterContext::UpdateStats () void RouterContext::UpdateStats ()
@@ -1037,20 +988,6 @@ namespace i2p
} }
n2k.close (); n2k.close ();
} }
// read SSU2 keys if available
std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
if (s2k)
{
s2k.seekg (0, std::ios::end);
size_t len = s2k.tellg();
s2k.seekg (0, std::ios::beg);
if (len == sizeof (SSU2PrivateKeys))
{
m_SSU2Keys.reset (new SSU2PrivateKeys ());
s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
}
s2k.close ();
}
// read RouterInfo // read RouterInfo
m_RouterInfo.SetRouterIdentity (oldIdentity ? oldIdentity : GetIdentity ()); m_RouterInfo.SetRouterIdentity (oldIdentity ? oldIdentity : GetIdentity ());
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
@@ -1071,26 +1008,40 @@ namespace i2p
if (IsUnreachable ()) if (IsUnreachable ())
SetReachable (true, true); // we assume reachable until we discover firewall through peer tests SetReachable (true, true); // we assume reachable until we discover firewall through peer tests
bool updated = false; // read NTCP2
// create new NTCP2 keys if required
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg); bool ygg; i2p::config::GetOption("meshnets.yggdrasil", ygg);
if ((ntcp2 || ygg) && !m_NTCP2Keys) if (ntcp2 || ygg)
{ {
NewNTCP2Keys (); if (!m_NTCP2Keys) NewNTCP2Keys ();
UpdateNTCP2Keys (); UpdateNTCP2Address (true); // enable NTCP2
updated = true;
} }
// create new SSU2 keys if required else
UpdateNTCP2Address (false); // disable NTCP2
// read SSU2
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2 && !m_SSU2Keys) if (ssu2)
{ {
NewSSU2Keys (); // read SSU2 keys if available
UpdateSSU2Keys (); std::ifstream s2k (i2p::fs::DataDirPath (SSU2_KEYS), std::ifstream::in | std::ifstream::binary);
updated = true; if (s2k)
{
s2k.seekg (0, std::ios::end);
size_t len = s2k.tellg();
s2k.seekg (0, std::ios::beg);
if (len == sizeof (SSU2PrivateKeys))
{
m_SSU2Keys.reset (new SSU2PrivateKeys ());
s2k.read ((char *)m_SSU2Keys.get (), sizeof (SSU2PrivateKeys));
} }
if (updated) s2k.close ();
UpdateRouterInfo (); }
if (!m_SSU2Keys) NewSSU2Keys ();
UpdateSSU2Address (true); // enable SSU2
}
else
UpdateSSU2Address (false); // disable SSU2
return true; return true;
} }
@@ -1111,13 +1062,6 @@ namespace i2p
return i2p::tunnel::tunnels.GetExploratoryPool (); return i2p::tunnel::tunnels.GetExploratoryPool ();
} }
bool RouterContext::IsHighCongestion () const
{
return i2p::tunnel::tunnels.IsTooManyTransitTunnels () ||
i2p::transport::transports.IsBandwidthExceeded () ||
i2p::transport::transports.IsTransitBandwidthExceeded ();
}
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len) void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
{ {
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
@@ -1131,16 +1075,10 @@ namespace i2p
return true; return true;
} }
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (m_Service) std::unique_lock<std::mutex> l(m_GarlicMutex);
m_Service->GetService ().post (std::bind (&RouterContext::PostGarlicMessage, this, msg));
else
LogPrint (eLogError, "Router: service is NULL");
}
void RouterContext::PostGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
uint32_t len = bufbe32toh (buf); uint32_t len = bufbe32toh (buf);
if (len > msg->GetLength ()) if (len > msg->GetLength ())
@@ -1161,34 +1099,19 @@ namespace i2p
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg) void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (m_Service) if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
m_Service->GetService ().post (std::bind (&RouterContext::PostDeliveryStatusMessage, this, msg)); i2p::data::netdb.PostI2NPMsg (msg);
else else
LogPrint (eLogError, "Router: service is NULL");
}
void RouterContext::PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) std::unique_lock<std::mutex> l(m_GarlicMutex);
{
LogPrint (eLogInfo, "Router: Publishing confirmed. reply token=", m_PublishReplyToken);
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
SchedulePublish ();
}
else
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
} }
}
void RouterContext::CleanupDestination () void RouterContext::CleanupDestination ()
{ {
if (m_Service) std::unique_lock<std::mutex> l(m_GarlicMutex);
m_Service->GetService ().post ([this]() i2p::garlic::GarlicDestination::CleanupExpiredTags ();
{
this->i2p::garlic::GarlicDestination::CleanupExpiredTags ();
});
else
LogPrint (eLogError, "Router: service is NULL");
} }
uint32_t RouterContext::GetUptime () const uint32_t RouterContext::GetUptime () const
@@ -1263,143 +1186,4 @@ namespace i2p
} }
return *m_SSU2StaticKeys; return *m_SSU2StaticKeys;
} }
void RouterContext::ScheduleInitialPublish ()
{
if (m_PublishTimer)
{
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_INITIAL_PUBLISH_INTERVAL));
m_PublishTimer->async_wait (std::bind (&RouterContext::HandleInitialPublishTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Publish timer is NULL");
}
void RouterContext::HandleInitialPublishTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
if (m_RouterInfo.IsReachableBy (i2p::data::RouterInfo::eAllTransports))
HandlePublishTimer (ecode);
else
ScheduleInitialPublish ();
}
}
void RouterContext::SchedulePublish ()
{
if (m_PublishTimer)
{
m_PublishTimer->cancel ();
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_PUBLISH_INTERVAL +
rand () % ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE));
m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Publish timer is NULL");
}
void RouterContext::HandlePublishTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
m_PublishExcluded.clear ();
m_PublishReplyToken = 0;
if (IsFloodfill ())
{
UpdateStats (); // for floodfill
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // don't publish to ourselves
}
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
Publish ();
SchedulePublishResend ();
}
}
void RouterContext::Publish ()
{
if (!i2p::transport::transports.IsOnline ()) return;
if (m_PublishExcluded.size () > ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
{
LogPrint (eLogError, "Router: Couldn't publish our RouterInfo to ", ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
m_PublishExcluded.clear ();
UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
}
auto floodfill = i2p::data::netdb.GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill)
{
uint32_t replyToken;
RAND_bytes ((uint8_t *)&replyToken, 4);
LogPrint (eLogInfo, "Router: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
// send directly
i2p::transport::transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else
{
// otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (inbound && outbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
else
LogPrint (eLogInfo, "Router: Can't publish our RouterInfo. No tunnles. Try again in ", ROUTER_INFO_CONFIRMATION_TIMEOUT, " seconds");
}
m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken;
}
else
LogPrint (eLogInfo, "Router: Can't find floodfill to publish our RouterInfo");
}
void RouterContext::SchedulePublishResend ()
{
if (m_PublishTimer)
{
m_PublishTimer->cancel ();
m_PublishTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONFIRMATION_TIMEOUT));
m_PublishTimer->async_wait (std::bind (&RouterContext::HandlePublishResendTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Publish timer is NULL");
}
void RouterContext::HandlePublishResendTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
i2p::context.UpdateTimestamp (i2p::util::GetSecondsSinceEpoch ());
Publish ();
SchedulePublishResend ();
}
}
void RouterContext::ScheduleCongestionUpdate ()
{
if (m_CongestionUpdateTimer)
{
m_CongestionUpdateTimer->cancel ();
m_CongestionUpdateTimer->expires_from_now (boost::posix_time::seconds(ROUTER_INFO_CONGESTION_UPDATE_INTERVAL));
m_CongestionUpdateTimer->async_wait (std::bind (&RouterContext::HandleCongestionUpdateTimer,
this, std::placeholders::_1));
}
else
LogPrint (eLogError, "Router: Congestion update timer is NULL");
}
void RouterContext::HandleCongestionUpdateTimer (const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
{
if (m_RouterInfo.SetHighCongestion (IsHighCongestion ()))
UpdateRouterInfo ();
ScheduleCongestionUpdate ();
}
}
} }

View File

@@ -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
* *
@@ -12,13 +12,12 @@
#include <inttypes.h> #include <inttypes.h>
#include <string> #include <string>
#include <memory> #include <memory>
#include <mutex>
#include <chrono> #include <chrono>
#include <set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "Garlic.h" #include "Garlic.h"
#include "util.h"
namespace i2p namespace i2p
{ {
@@ -31,13 +30,7 @@ namespace garlic
const char ROUTER_KEYS[] = "router.keys"; const char ROUTER_KEYS[] = "router.keys";
const char NTCP2_KEYS[] = "ntcp2.keys"; const char NTCP2_KEYS[] = "ntcp2.keys";
const char SSU2_KEYS[] = "ssu2.keys"; const char SSU2_KEYS[] = "ssu2.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 30*60; // 30 minutes const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
const int ROUTER_INFO_PUBLISH_INTERVAL = 39*60; // in seconds
const int ROUTER_INFO_INITIAL_PUBLISH_INTERVAL = 10; // in seconds
const int ROUTER_INFO_PUBLISH_INTERVAL_VARIANCE = 105;// in seconds
const int ROUTER_INFO_CONFIRMATION_TIMEOUT = 5; // in seconds
const int ROUTER_INFO_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
const int ROUTER_INFO_CONGESTION_UPDATE_INTERVAL = 12*60; // in seconds
enum RouterStatus enum RouterStatus
{ {
@@ -77,22 +70,10 @@ namespace garlic
uint8_t intro[32]; uint8_t intro[32];
}; };
class RouterService: public i2p::util::RunnableServiceWithWork
{
public:
RouterService (): RunnableServiceWithWork ("Router") {};
boost::asio::io_service& GetService () { return GetIOService (); };
void Start () { StartIOService (); };
void Stop () { StopIOService (); };
};
public: public:
RouterContext (); RouterContext ();
void Init (); void Init ();
void Start ();
void Stop ();
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; }; i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; };
@@ -135,9 +116,11 @@ namespace garlic
bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data); bool DecryptTunnelShortRequestRecord (const uint8_t * encrypted, uint8_t * data);
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU2 or Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg); void PublishNTCP2Address (int port, bool publish, bool v4, bool v6, bool ygg);
void UpdateNTCP2Address (bool enable);
void PublishSSU2Address (int port, bool publish, bool v4, bool v6); void PublishSSU2Address (int port, bool publish, bool v4, bool v6);
void UpdateSSU2Address (bool enable);
bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4); bool AddSSU2Introducer (const i2p::data::RouterInfo::Introducer& introducer, bool v4);
void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4); void RemoveSSU2Introducer (const i2p::data::IdentHash& h, bool v4);
void ClearSSU2Introducers (bool v4); void ClearSSU2Introducers (bool v4);
@@ -153,7 +136,6 @@ namespace garlic
void SetShareRatio (int percents); // 0 - 100 void SetShareRatio (int percents); // 0 - 100
bool AcceptsTunnels () const { return m_AcceptsTunnels; }; bool AcceptsTunnels () const { return m_AcceptsTunnels; };
void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; void SetAcceptsTunnels (bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
bool IsHighCongestion () const;
bool SupportsV6 () const { return m_RouterInfo.IsV6 (); }; bool SupportsV6 () const { return m_RouterInfo.IsV6 (); };
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
bool SupportsMesh () const { return m_RouterInfo.IsMesh (); }; bool SupportsMesh () const { return m_RouterInfo.IsMesh (); };
@@ -161,8 +143,6 @@ namespace garlic
void SetSupportsV4 (bool supportsV4); void SetSupportsV4 (bool supportsV4);
void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host); void SetSupportsMesh (bool supportsmesh, const boost::asio::ip::address_v6& host);
void SetMTU (int mtu, bool v4); void SetMTU (int mtu, bool v4);
void SetHidden(bool hide) { m_IsHiddenMode = hide; };
bool IsHidden() const { return m_IsHiddenMode; };
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
@@ -197,26 +177,12 @@ namespace garlic
void UpdateRouterInfo (); void UpdateRouterInfo ();
void NewNTCP2Keys (); void NewNTCP2Keys ();
void NewSSU2Keys (); void NewSSU2Keys ();
void UpdateNTCP2Keys (); bool IsSSU2Only () const; // SSU2 and no SSU
void UpdateSSU2Keys ();
bool Load (); bool Load ();
void SaveKeys (); void SaveKeys ();
uint16_t SelectRandomPort () const; uint16_t SelectRandomPort () const;
void PublishNTCP2Address (std::shared_ptr<i2p::data::RouterInfo::Address> address, int port, bool publish) const;
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize); bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
void PostGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void PostDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void ScheduleInitialPublish ();
void HandleInitialPublishTimer (const boost::system::error_code& ecode);
void SchedulePublish ();
void HandlePublishTimer (const boost::system::error_code& ecode);
void Publish ();
void SchedulePublishResend ();
void HandlePublishResendTimer (const boost::system::error_code& ecode);
void ScheduleCongestionUpdate ();
void HandleCongestionUpdateTimer (const boost::system::error_code& ecode);
private: private:
@@ -232,17 +198,12 @@ namespace garlic
RouterStatus m_Status, m_StatusV6; RouterStatus m_Status, m_StatusV6;
RouterError m_Error, m_ErrorV6; RouterError m_Error, m_ErrorV6;
int m_NetID; int m_NetID;
std::mutex m_GarlicMutex;
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys; std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys; std::unique_ptr<SSU2PrivateKeys> m_SSU2Keys;
std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys; std::unique_ptr<i2p::crypto::X25519Keys> m_NTCP2StaticKeys, m_SSU2StaticKeys;
// for ECIESx25519 // for ECIESx25519
i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState; i2p::crypto::NoiseSymmetricState m_InitialNoiseState, m_CurrentNoiseState;
// publish
std::unique_ptr<RouterService> m_Service;
std::unique_ptr<boost::asio::deadline_timer> m_PublishTimer, m_CongestionUpdateTimer;
std::set<i2p::data::IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken;
bool m_IsHiddenMode; // not publish
}; };
extern RouterContext context; extern RouterContext context;

View File

@@ -43,7 +43,7 @@ namespace data
RouterInfo::RouterInfo (const std::string& fullPath): RouterInfo::RouterInfo (const std::string& fullPath):
m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false), m_FamilyID (0), m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0),m_ReachableTransports (0), m_SupportedTransports (0),m_ReachableTransports (0),
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion) m_Caps (0), m_Version (0)
{ {
m_Addresses = boost::make_shared<Addresses>(); // create empty list m_Addresses = boost::make_shared<Addresses>(); // create empty list
m_Buffer = NewBuffer (); // always RouterInfo's m_Buffer = NewBuffer (); // always RouterInfo's
@@ -53,7 +53,7 @@ namespace data
RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len): RouterInfo::RouterInfo (std::shared_ptr<Buffer>&& buf, size_t len):
m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false), m_FamilyID (0), m_IsUpdated (true), m_IsUnreachable (false),
m_SupportedTransports (0), m_ReachableTransports (0), m_SupportedTransports (0), m_ReachableTransports (0),
m_Caps (0), m_Version (0), m_Congestion (eLowCongestion) m_Caps (0), m_Version (0)
{ {
if (len <= MAX_RI_BUFFER_SIZE) if (len <= MAX_RI_BUFFER_SIZE)
{ {
@@ -79,12 +79,13 @@ namespace data
{ {
} }
bool RouterInfo::Update (const uint8_t * buf, size_t len) void RouterInfo::Update (const uint8_t * buf, size_t len)
{ {
if (len > MAX_RI_BUFFER_SIZE) if (len > MAX_RI_BUFFER_SIZE)
{ {
LogPrint (eLogWarning, "RouterInfo: Updated buffer is too long ", len, ". Not changed"); LogPrint (eLogError, "RouterInfo: Buffer is too long ", len);
return false; m_IsUnreachable = true;
return;
} }
// verify signature since we have identity already // verify signature since we have identity already
int l = len - m_RouterIdentity->GetSignatureLen (); int l = len - m_RouterIdentity->GetSignatureLen ();
@@ -98,21 +99,20 @@ namespace data
m_Caps = 0; m_Caps = 0;
// don't clean up m_Addresses, it will be replaced in ReadFromStream // don't clean up m_Addresses, it will be replaced in ReadFromStream
ClearProperties (); ClearProperties ();
// copy buffer
UpdateBuffer (buf, len);
// skip identity // skip identity
size_t identityLen = m_RouterIdentity->GetFullLen (); size_t identityLen = m_RouterIdentity->GetFullLen ();
// read new RI // read new RI
std::stringstream str (std::string ((char *)buf + identityLen, len - identityLen)); std::stringstream str (std::string ((char *)m_Buffer->data () + identityLen, m_BufferLen - identityLen));
ReadFromStream (str); ReadFromStream (str);
if (!m_IsUnreachable)
UpdateBuffer (buf, len); // save buffer
// don't delete buffer until saved to the file // don't delete buffer until saved to the file
} }
else else
{ {
LogPrint (eLogWarning, "RouterInfo: Updated signature verification failed. Not changed"); LogPrint (eLogError, "RouterInfo: Signature verification failed");
return false; m_IsUnreachable = true;
} }
return true;
} }
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity) void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
@@ -202,7 +202,7 @@ namespace data
void RouterInfo::ReadFromStream (std::istream& s) void RouterInfo::ReadFromStream (std::istream& s)
{ {
if (!s) return; if (!s) return;
m_Caps = 0; m_Congestion = eLowCongestion; m_Caps = 0;
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp)); s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
m_Timestamp = be64toh (m_Timestamp); m_Timestamp = be64toh (m_Timestamp);
// read addresses // read addresses
@@ -252,15 +252,7 @@ namespace data
{ {
boost::system::error_code ecode; boost::system::error_code ecode;
address->host = boost::asio::ip::address::from_string (value, ecode); address->host = boost::asio::ip::address::from_string (value, ecode);
if (!ecode && !address->host.is_unspecified ()) if (!ecode && !address->host.is_unspecified ()) isHost = true;
{
if (!i2p::util::net::IsInReservedRange (address->host) ||
i2p::util::net::IsYggdrasilAddress (address->host))
isHost = true;
else
// we consider such address as invalid
address->transportStyle = eTransportUnknown;
}
} }
else if (!strcmp (key, "port")) else if (!strcmp (key, "port"))
{ {
@@ -336,7 +328,11 @@ namespace data
address->ssu->introducers.resize (index + 1); address->ssu->introducers.resize (index + 1);
} }
Introducer& introducer = address->ssu->introducers.at (index); Introducer& introducer = address->ssu->introducers.at (index);
if (!strcmp (key, "itag")) if (!strcmp (key, "ihost"))
introducer.isH = false; // SSU1
else if (!strcmp (key, "iport"))
introducer.isH = false; // SSU1
else if (!strcmp (key, "itag"))
{ {
try try
{ {
@@ -348,7 +344,10 @@ namespace data
} }
} }
else if (!strcmp (key, "ih")) else if (!strcmp (key, "ih"))
{
Base64ToByteStream (value, strlen (value), introducer.iH, 32); Base64ToByteStream (value, strlen (value), introducer.iH, 32);
introducer.isH = true;
}
else if (!strcmp (key, "iexp")) else if (!strcmp (key, "iexp"))
{ {
try try
@@ -391,7 +390,7 @@ namespace data
{ {
if (address->IsV4 ()) supportedTransports |= eSSU2V4; if (address->IsV4 ()) supportedTransports |= eSSU2V4;
if (address->IsV6 ()) supportedTransports |= eSSU2V6; if (address->IsV6 ()) supportedTransports |= eSSU2V6;
if (isHost && address->port) if (address->port)
{ {
if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4; if (address->host.is_v4 ()) m_ReachableTransports |= eSSU2V4;
if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6; if (address->host.is_v6 ()) m_ReachableTransports |= eSSU2V6;
@@ -404,7 +403,7 @@ namespace data
int numValid = 0; int numValid = 0;
for (auto& it: address->ssu->introducers) for (auto& it: address->ssu->introducers)
{ {
if (it.iTag && ts < it.iExp) if (it.iTag && ts < it.iExp && it.isH)
numValid++; numValid++;
else else
it.iTag = 0; it.iTag = 0;
@@ -535,15 +534,6 @@ namespace data
case CAPS_FLAG_UNREACHABLE: case CAPS_FLAG_UNREACHABLE:
m_Caps |= Caps::eUnreachable; m_Caps |= Caps::eUnreachable;
break; break;
case CAPS_FLAG_MEDIUM_CONGESTION:
m_Congestion = eMediumCongestion;
break;
case CAPS_FLAG_HIGH_CONGESTION:
m_Congestion = eHighCongestion;
break;
case CAPS_FLAG_REJECT_ALL_CONGESTION:
m_Congestion = eRejectAll;
break;
default: ; default: ;
} }
cap++; cap++;
@@ -591,24 +581,20 @@ namespace data
{ {
if (LoadFile (fullPath)) if (LoadFile (fullPath))
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file"); LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
else
return nullptr;
} }
return m_Buffer->data (); return m_Buffer->data ();
} }
bool RouterInfo::SaveToFile (const std::string& fullPath) bool RouterInfo::SaveToFile (const std::string& fullPath)
{ {
if (m_IsUnreachable) return false; // don't save bad router
if (!m_Buffer) if (!m_Buffer)
{ {
LogPrint (eLogWarning, "RouterInfo: Can't save, m_Buffer == NULL"); LogPrint (eLogError, "RouterInfo: Can't save, m_Buffer == NULL");
return false; return false;
} }
std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out);
if (!f.is_open ()) if (!f.is_open ()) {
{ LogPrint(eLogError, "RouterInfo: Can't save to ", fullPath);
LogPrint (eLogError, "RouterInfo: Can't save to ", fullPath);
return false; return false;
} }
f.write ((char *)m_Buffer->data (), m_BufferLen); f.write ((char *)m_Buffer->data (), m_BufferLen);
@@ -634,49 +620,22 @@ namespace data
return l+1; return l+1;
} }
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps)
{
auto addr = std::make_shared<Address>();
addr->port = port;
addr->transportStyle = eTransportNTCP2;
addr->caps = caps;
addr->date = 0;
addr->published = false;
memcpy (addr->s, staticKey, 32);
memcpy (addr->i, iv, 16);
if (addr->IsV4 ())
{
m_SupportedTransports |= eNTCP2V4;
(*m_Addresses)[eNTCP2V4Idx] = addr;
}
if (addr->IsV6 ())
{
m_SupportedTransports |= eNTCP2V6;
(*m_Addresses)[eNTCP2V6Idx] = addr;
}
}
void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, void RouterInfo::AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host, int port) const boost::asio::ip::address& host, int port, uint8_t caps)
{ {
auto addr = std::make_shared<Address>(); auto addr = std::make_shared<Address>();
addr->host = host; addr->host = host;
addr->port = port; addr->port = port;
addr->transportStyle = eTransportNTCP2; addr->transportStyle = eTransportNTCP2;
addr->caps = caps;
addr->date = 0; addr->date = 0;
addr->published = true; if (port) addr->published = true;
memcpy (addr->s, staticKey, 32); memcpy (addr->s, staticKey, 32);
memcpy (addr->i, iv, 16); memcpy (addr->i, iv, 16);
addr->caps = 0;
if (host.is_unspecified ())
{
if (host.is_v4 ()) addr->caps |= eV4;
if (host.is_v6 ()) addr->caps |= eV6;
}
if (addr->IsV4 ()) if (addr->IsV4 ())
{ {
m_SupportedTransports |= eNTCP2V4; m_SupportedTransports |= eNTCP2V4;
m_ReachableTransports |= eNTCP2V4; if (addr->published) m_ReachableTransports |= eNTCP2V4;
(*m_Addresses)[eNTCP2V4Idx] = addr; (*m_Addresses)[eNTCP2V4Idx] = addr;
} }
if (addr->IsV6 ()) if (addr->IsV6 ())
@@ -690,34 +649,17 @@ namespace data
else else
{ {
m_SupportedTransports |= eNTCP2V6; m_SupportedTransports |= eNTCP2V6;
m_ReachableTransports |= eNTCP2V6; if (addr->published) m_ReachableTransports |= eNTCP2V6;
(*m_Addresses)[eNTCP2V6Idx] = addr; (*m_Addresses)[eNTCP2V6Idx] = addr;
} }
} }
} }
void RouterInfo::RemoveNTCP2Address (bool v4) void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps)
{
if (v4)
{
if ((*m_Addresses)[eNTCP2V6Idx])
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4;
(*m_Addresses)[eNTCP2V4Idx].reset ();
}
else
{
if ((*m_Addresses)[eNTCP2V4Idx])
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6;
(*m_Addresses)[eNTCP2V6Idx].reset ();
}
UpdateSupportedTransports ();
}
void RouterInfo::AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps)
{ {
auto addr = std::make_shared<Address>(); auto addr = std::make_shared<Address>();
addr->transportStyle = eTransportSSU2; addr->transportStyle = eTransportSSU2;
addr->port = port; addr->port = 0;
addr->caps = caps; addr->caps = caps;
addr->date = 0; addr->date = 0;
addr->ssu.reset (new SSUExt ()); addr->ssu.reset (new SSUExt ());
@@ -744,19 +686,12 @@ namespace data
addr->host = host; addr->host = host;
addr->port = port; addr->port = port;
addr->published = true; addr->published = true;
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
addr->date = 0; addr->date = 0;
addr->ssu.reset (new SSUExt ()); addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = 0; addr->ssu->mtu = 0;
memcpy (addr->s, staticKey, 32); memcpy (addr->s, staticKey, 32);
memcpy (addr->i, introKey, 32); memcpy (addr->i, introKey, 32);
if (!host.is_unspecified ())
addr->caps = i2p::data::RouterInfo::eSSUTesting | i2p::data::RouterInfo::eSSUIntroducer; // BC;
else
{
addr->caps = 0;
if (host.is_v4 ()) addr->caps |= eV4;
if (host.is_v6 ()) addr->caps |= eV6;
}
if (addr->IsV4 ()) if (addr->IsV4 ())
{ {
m_SupportedTransports |= eSSU2V4; m_SupportedTransports |= eSSU2V4;
@@ -771,23 +706,6 @@ namespace data
} }
} }
void RouterInfo::RemoveSSU2Address (bool v4)
{
if (v4)
{
if ((*m_Addresses)[eSSU2V6Idx])
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4;
(*m_Addresses)[eSSU2V4Idx].reset ();
}
else
{
if ((*m_Addresses)[eSSU2V4Idx])
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6;
(*m_Addresses)[eSSU2V6Idx].reset ();
}
UpdateSupportedTransports ();
}
bool RouterInfo::IsNTCP2 (bool v4only) const bool RouterInfo::IsNTCP2 (bool v4only) const
{ {
if (v4only) if (v4only)
@@ -826,14 +744,14 @@ namespace data
{ {
if ((*m_Addresses)[eNTCP2V6Idx]) if ((*m_Addresses)[eNTCP2V6Idx])
{ {
if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 () && (*m_Addresses)[eNTCP2V4Idx]) if ((*m_Addresses)[eNTCP2V6Idx]->IsV4 ())
(*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV6; (*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV6;
(*m_Addresses)[eNTCP2V6Idx].reset (); (*m_Addresses)[eNTCP2V6Idx].reset ();
} }
if ((*m_Addresses)[eSSU2V6Idx]) if ((*m_Addresses)[eSSU2V6Idx])
{ {
if ((*m_Addresses)[eSSU2V6Idx]->IsV4 () && (*m_Addresses)[eSSU2V4Idx]) if ((*m_Addresses)[eSSU2V6Idx]->IsV4 ())
(*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV6; (*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV6;
(*m_Addresses)[eSSU2V6Idx].reset (); (*m_Addresses)[eSSU2V6Idx].reset ();
} }
UpdateSupportedTransports (); UpdateSupportedTransports ();
@@ -846,14 +764,14 @@ namespace data
{ {
if ((*m_Addresses)[eNTCP2V4Idx]) if ((*m_Addresses)[eNTCP2V4Idx])
{ {
if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 () && (*m_Addresses)[eNTCP2V6Idx]) if ((*m_Addresses)[eNTCP2V4Idx]->IsV6 ())
(*m_Addresses)[eNTCP2V6Idx]->caps &= ~AddressCaps::eV4; (*m_Addresses)[eNTCP2V4Idx]->caps &= ~AddressCaps::eV4;
(*m_Addresses)[eNTCP2V4Idx].reset (); (*m_Addresses)[eNTCP2V4Idx].reset ();
} }
if ((*m_Addresses)[eSSU2V4Idx]) if ((*m_Addresses)[eSSU2V4Idx])
{ {
if ((*m_Addresses)[eSSU2V4Idx]->IsV6 () && (*m_Addresses)[eSSU2V6Idx]) if ((*m_Addresses)[eSSU2V4Idx]->IsV6 ())
(*m_Addresses)[eSSU2V6Idx]->caps &= ~AddressCaps::eV4; (*m_Addresses)[eSSU2V4Idx]->caps &= ~AddressCaps::eV4;
(*m_Addresses)[eSSU2V4Idx].reset (); (*m_Addresses)[eSSU2V4Idx].reset ();
} }
UpdateSupportedTransports (); UpdateSupportedTransports ();
@@ -928,14 +846,23 @@ namespace data
return nullptr; return nullptr;
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V4Address () const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2AddressWithStaticKey (const uint8_t * key) const
{ {
return (*GetAddresses ())[eNTCP2V4Idx]; if (!key) return nullptr;
return GetAddress (
[key](std::shared_ptr<const RouterInfo::Address> address)->bool
{
return address->IsNTCP2 () && !memcmp (address->s, key, 32);
});
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCP2V6Address () const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const
{ {
return (*GetAddresses ())[eNTCP2V6Idx]; if (!key) return nullptr;
auto addr = (*GetAddresses ())[isV6 ? eSSU2V6Idx : eSSU2V4Idx];
if (addr && !memcmp (addr->s, key, 32))
return addr;
return nullptr;
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetPublishedNTCP2V4Address () const
@@ -959,13 +886,9 @@ namespace data
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
{ {
auto profile = m_Profile; if (!m_Profile)
if (!profile) m_Profile = GetRouterProfile (GetIdentHash ());
{ return m_Profile;
profile = GetRouterProfile (GetIdentHash ());
m_Profile = profile;
}
return profile;
} }
void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted) const void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted) const
@@ -1066,21 +989,6 @@ namespace data
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
} }
bool RouterInfo::IsHighCongestion () const
{
if (m_Congestion == eLowCongestion || m_Congestion == eMediumCongestion) return false;
if (m_Congestion == eRejectAll) return true;
if (m_Congestion == eHighCongestion)
return (i2p::util::GetMillisecondsSinceEpoch () < m_Timestamp + HIGH_CONGESTION_INTERVAL*1000LL) ? true : false;
return false;
}
LocalRouterInfo::LocalRouterInfo (const std::string& fullPath):
RouterInfo (fullPath)
{
SetHighCongestion (false); // drop congestion
}
void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys) void LocalRouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
{ {
RefreshTimestamp (); RefreshTimestamp ();
@@ -1132,35 +1040,9 @@ namespace data
if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable if (c & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable if (c & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
switch (GetCongestion ())
{
case eMediumCongestion:
caps += CAPS_FLAG_MEDIUM_CONGESTION;
break;
case eHighCongestion:
caps += CAPS_FLAG_HIGH_CONGESTION;
break;
case eRejectAll:
caps += CAPS_FLAG_REJECT_ALL_CONGESTION;
break;
default: ;
};
SetProperty ("caps", caps); SetProperty ("caps", caps);
} }
bool LocalRouterInfo::SetHighCongestion (bool highCongestion)
{
Congestion c = highCongestion ? eHighCongestion : eLowCongestion;
if (c != GetCongestion ())
{
SetCongestion (c);
UpdateCapsProperty ();
return true;
}
return false;
}
void LocalRouterInfo::WriteToStream (std::ostream& s) const void LocalRouterInfo::WriteToStream (std::ostream& s) const
{ {
auto addresses = GetAddresses (); auto addresses = GetAddresses ();

View File

@@ -44,10 +44,6 @@ namespace data
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */ const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
// congesion flags
const char CAPS_FLAG_MEDIUM_CONGESTION = 'D';
const char CAPS_FLAG_HIGH_CONGESTION = 'E';
const char CAPS_FLAG_REJECT_ALL_CONGESTION = 'G';
const char CAPS_FLAG_V4 = '4'; const char CAPS_FLAG_V4 = '4';
const char CAPS_FLAG_V6 = '6'; const char CAPS_FLAG_V6 = '6';
@@ -60,8 +56,6 @@ namespace data
const uint8_t COST_SSU2_NON_PUBLISHED = 15; const uint8_t COST_SSU2_NON_PUBLISHED = 15;
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
const int HIGH_CONGESTION_INTERVAL = 15*60; // in seconds, 15 minutes
class RouterInfo: public RoutingDestination class RouterInfo: public RoutingDestination
{ {
public: public:
@@ -99,14 +93,6 @@ namespace data
eUnreachable = 0x20 eUnreachable = 0x20
}; };
enum Congestion
{
eLowCongestion = 0,
eMediumCongestion,
eHighCongestion,
eRejectAll
};
enum AddressCaps enum AddressCaps
{ {
eV4 = 0x01, eV4 = 0x01,
@@ -124,10 +110,11 @@ namespace data
struct Introducer struct Introducer
{ {
Introducer (): iTag (0), iExp (0) {}; Introducer (): iTag (0), iExp (0), isH (false) {};
IdentHash iH; IdentHash iH;
uint32_t iTag; uint32_t iTag;
uint32_t iExp; uint32_t iExp;
bool isH; // TODO: remove later
}; };
struct SSUExt struct SSUExt
@@ -202,8 +189,8 @@ namespace data
virtual void SetProperty (const std::string& key, const std::string& value) {}; virtual void SetProperty (const std::string& key, const std::string& value) {};
virtual void ClearProperties () {}; virtual void ClearProperties () {};
boost::shared_ptr<Addresses> GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr boost::shared_ptr<Addresses> GetAddresses () const; // should be called for local RI only, otherwise must return shared_ptr
std::shared_ptr<const Address> GetNTCP2V4Address () const; std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey (const uint8_t * key) const;
std::shared_ptr<const Address> GetNTCP2V6Address () const; std::shared_ptr<const Address> GetSSU2AddressWithStaticKey (const uint8_t * key, bool isV6) const;
std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const; std::shared_ptr<const Address> GetPublishedNTCP2V4Address () const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const; std::shared_ptr<const Address> GetPublishedNTCP2V6Address () const;
std::shared_ptr<const Address> GetYggdrasilAddress () const; std::shared_ptr<const Address> GetYggdrasilAddress () const;
@@ -211,14 +198,11 @@ namespace data
std::shared_ptr<const Address> GetSSU2V6Address () const; std::shared_ptr<const Address> GetSSU2V6Address () const;
std::shared_ptr<const Address> GetSSU2Address (bool v4) const; std::shared_ptr<const Address> GetSSU2Address (bool v4) const;
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,int port, uint8_t caps); // non published
void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv, void AddNTCP2Address (const uint8_t * staticKey, const uint8_t * iv,
const boost::asio::ip::address& host, int port); // published const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0);
void RemoveNTCP2Address (bool v4); void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, uint8_t caps = 0); // non published
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, int port, uint8_t caps); // non published
void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey, void AddSSU2Address (const uint8_t * staticKey, const uint8_t * introKey,
const boost::asio::ip::address& host, int port); // published const boost::asio::ip::address& host, int port); // published
void RemoveSSU2Address (bool v4);
void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps void SetUnreachableAddressesTransportCaps (uint8_t transports); // bitmask of AddressCaps
void UpdateSupportedTransports (); void UpdateSupportedTransports ();
bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; }; bool IsFloodfill () const { return m_Caps & Caps::eFloodfill; };
@@ -248,17 +232,14 @@ namespace data
bool IsEligibleFloodfill () const; bool IsEligibleFloodfill () const;
bool IsSSU2PeerTesting (bool v4) const; bool IsSSU2PeerTesting (bool v4) const;
bool IsSSU2Introducer (bool v4) const; bool IsSSU2Introducer (bool v4) const;
bool IsHighCongestion () const;
uint8_t GetCaps () const { return m_Caps; }; uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps) { m_Caps = caps; }; void SetCaps (uint8_t caps) { m_Caps = caps; };
Congestion GetCongestion () const { return m_Congestion; };
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; }; bool IsUnreachable () const { return m_IsUnreachable; };
const uint8_t * GetBuffer () const { return m_Buffer ? m_Buffer->data () : nullptr; }; const uint8_t * GetBuffer () const { return m_Buffer->data (); };
const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary const uint8_t * LoadBuffer (const std::string& fullPath); // load if necessary
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
@@ -267,9 +248,9 @@ namespace data
bool SaveToFile (const std::string& fullPath); bool SaveToFile (const std::string& fullPath);
std::shared_ptr<RouterProfile> GetProfile () const; std::shared_ptr<RouterProfile> GetProfile () const;
void DropProfile () { m_Profile = nullptr; }; void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
bool Update (const uint8_t * buf, size_t len); void Update (const uint8_t * buf, size_t len);
void DeleteBuffer () { m_Buffer = nullptr; }; void DeleteBuffer () { m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const; bool IsNewer (const uint8_t * buf, size_t len) const;
@@ -291,7 +272,6 @@ namespace data
void RefreshTimestamp (); void RefreshTimestamp ();
CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; }; CompatibleTransports GetReachableTransports () const { return m_ReachableTransports; };
void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; }; void SetReachableTransports (CompatibleTransports transports) { m_ReachableTransports = transports; };
void SetCongestion (Congestion c) { m_Congestion = c; };
private: private:
@@ -320,7 +300,6 @@ namespace data
CompatibleTransports m_SupportedTransports, m_ReachableTransports; CompatibleTransports m_SupportedTransports, m_ReachableTransports;
uint8_t m_Caps; uint8_t m_Caps;
int m_Version; int m_Version;
Congestion m_Congestion;
mutable std::shared_ptr<RouterProfile> m_Profile; mutable std::shared_ptr<RouterProfile> m_Profile;
}; };
@@ -329,10 +308,9 @@ namespace data
public: public:
LocalRouterInfo () = default; LocalRouterInfo () = default;
LocalRouterInfo (const std::string& fullPath); LocalRouterInfo (const std::string& fullPath): RouterInfo (fullPath) {};
void CreateBuffer (const PrivateKeys& privateKeys); void CreateBuffer (const PrivateKeys& privateKeys);
void UpdateCaps (uint8_t caps); void UpdateCaps (uint8_t caps);
bool SetHighCongestion (bool highCongestion); // returns true if updated
void SetProperty (const std::string& key, const std::string& value) override; void SetProperty (const std::string& key, const std::string& value) override;
void DeleteProperty (const std::string& key); void DeleteProperty (const std::string& key);

View File

@@ -212,8 +212,6 @@ namespace transport
boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4; boost::asio::ip::udp::socket& socket = localEndpoint.address ().is_v6 () ? m_SocketV6 : m_SocketV4;
try try
{ {
if (socket.is_open ())
socket.close ();
socket.open (localEndpoint.protocol ()); socket.open (localEndpoint.protocol ());
if (localEndpoint.address ().is_v6 ()) if (localEndpoint.address ().is_v6 ())
socket.set_option (boost::asio::ip::v6_only (true)); socket.set_option (boost::asio::ip::v6_only (true));
@@ -918,7 +916,7 @@ namespace transport
} }
uint64_t token; uint64_t token;
RAND_bytes ((uint8_t *)&token, 8); RAND_bytes ((uint8_t *)&token, 8);
m_IncomingTokens.emplace (ep, std::make_pair (token, uint32_t(ts + SSU2_TOKEN_EXPIRATION_TIMEOUT))); m_IncomingTokens.emplace (ep, std::make_pair (token, ts + SSU2_TOKEN_EXPIRATION_TIMEOUT));
return token; return token;
} }
@@ -927,7 +925,7 @@ namespace transport
m_IncomingTokens.erase (ep); // drop previous m_IncomingTokens.erase (ep); // drop previous
uint64_t token; uint64_t token;
RAND_bytes ((uint8_t *)&token, 8); RAND_bytes ((uint8_t *)&token, 8);
auto ret = std::make_pair (token, uint32_t(i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT)); auto ret = std::make_pair (token, i2p::util::GetSecondsSinceEpoch () + SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT);
m_IncomingTokens.emplace (ep, ret); m_IncomingTokens.emplace (ep, ret);
return ret; return ret;
} }
@@ -1017,6 +1015,7 @@ namespace transport
i2p::data::RouterInfo::Introducer introducer; i2p::data::RouterInfo::Introducer introducer;
introducer.iTag = it->GetRelayTag (); introducer.iTag = it->GetRelayTag ();
introducer.iH = it->GetRemoteIdentity ()->GetIdentHash (); introducer.iH = it->GetRemoteIdentity ()->GetIdentHash ();
introducer.isH = true;
introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION; introducer.iExp = it->GetCreationTime () + SSU2_TO_INTRODUCER_SESSION_EXPIRATION;
excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ()); excluded.insert (it->GetRemoteIdentity ()->GetIdentHash ());
if (i2p::context.AddSSU2Introducer (introducer, v4)) if (i2p::context.AddSSU2Introducer (introducer, v4))

View File

@@ -83,9 +83,9 @@ namespace transport
TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT),
m_Server (server), m_Address (addr), m_RemoteTransports (0), m_Server (server), m_Address (addr), m_RemoteTransports (0),
m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown),
m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false),
m_IsDataReceived (false), m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_WindowSize (SSU2_MIN_WINDOW_SIZE), m_RTT (SSU2_RESEND_INTERVAL),
m_RTT (SSU2_RESEND_INTERVAL), m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0), m_RTO (SSU2_RESEND_INTERVAL*SSU2_kAPPA), m_RelayTag (0),
m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose), m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose),
m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32) // min size
{ {
@@ -1041,18 +1041,10 @@ namespace transport
LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block"); LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
return false; return false;
} }
m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address (); m_Address = ri->GetSSU2AddressWithStaticKey (S, m_RemoteEndpoint.address ().is_v6 ());
if (!m_Address || memcmp (S, m_Address->s, 32)) if (!m_Address)
{ {
LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ())); LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
return false;
}
if (m_Address->published && m_RemoteEndpoint.address () != m_Address->host &&
(!m_RemoteEndpoint.address ().is_v6 () ||
memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address
{
LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host,
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
return false; return false;
} }
// update RouterInfo in netdb // update RouterInfo in netdb
@@ -1617,7 +1609,6 @@ namespace transport
{ {
case eSSU2SessionStateSessionRequestReceived: case eSSU2SessionStateSessionRequestReceived:
case eSSU2SessionStateTokenRequestReceived: case eSSU2SessionStateTokenRequestReceived:
case eSSU2SessionStateEstablished:
if (std::abs (offset) > SSU2_CLOCK_SKEW) if (std::abs (offset) > SSU2_CLOCK_SKEW)
m_TerminationReason = eSSU2TerminationReasonClockSkew; m_TerminationReason = eSSU2TerminationReasonClockSkew;
break; break;
@@ -1661,7 +1652,7 @@ namespace transport
// ranges // ranges
len -= 5; len -= 5;
const uint8_t * ranges = buf + 5; const uint8_t * ranges = buf + 5;
while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS) while (len > 0 && firstPacketNum)
{ {
uint32_t lastPacketNum = firstPacketNum - 1; uint32_t lastPacketNum = firstPacketNum - 1;
if (*ranges > lastPacketNum) break; if (*ranges > lastPacketNum) break;
@@ -1872,9 +1863,10 @@ namespace transport
// send relay intro to Charlie // send relay intro to Charlie
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; if (r)
if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); i2p::data::netdb.PopulateRouterInfoBuffer (r);
else
LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r) if (!payloadSize && r)
@@ -2068,7 +2060,7 @@ namespace transport
auto packet = m_Server.GetSentPacketsPool ().AcquireShared (); auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
// Alice's RouterInfo // Alice's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0; packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!packet->payloadSize && r) if (!packet->payloadSize && r)
session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
@@ -2172,7 +2164,7 @@ namespace transport
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
// Charlie's RouterInfo // Charlie's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr; if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0; size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r) if (!payloadSize && r)
it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
@@ -2296,9 +2288,9 @@ namespace transport
m_Server.RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce)); m_Server.RemoveSession (~htobe64 (((uint64_t)nonce << 32) | nonce));
break; break;
case 7: // Alice from Charlie 2 case 7: // Alice from Charlie 2
m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce));
if (m_Address->IsV6 ()) if (m_Address->IsV6 ())
i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2 i2p::context.SetStatusV6 (eRouterStatusOK); // set status OK for ipv6 even if from SSU2
m_Server.RemoveSession (htobe64 (((uint64_t)nonce << 32) | nonce));
break; break;
default: default:
LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]); LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]);
@@ -2308,7 +2300,7 @@ namespace transport
void SSU2Session::HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg) void SSU2Session::HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg)
{ {
if (!msg) return; if (!msg) return;
uint32_t msgID = msg->GetMsgID (); int32_t msgID = msg->GetMsgID ();
if (!msg->IsExpired ()) if (!msg->IsExpired ())
{ {
// m_LastActivityTimestamp is updated in ProcessData before // m_LastActivityTimestamp is updated in ProcessData before
@@ -2463,24 +2455,21 @@ namespace transport
if (ackThrough) if (ackThrough)
{ {
if (m_OutOfSequencePackets.empty ()) if (m_OutOfSequencePackets.empty ())
acnt = std::min ((int)ackThrough, SSU2_MAX_NUM_ACNT); // no gaps acnt = std::min ((int)ackThrough, 255); // no gaps
else else
{ {
auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num
while (it != m_OutOfSequencePackets.rend () && *it == ackThrough - acnt - 1) while (it != m_OutOfSequencePackets.rend () && *it == ackThrough - acnt - 1)
{ {
acnt++; acnt++;
if (acnt >= SSU2_MAX_NUM_ACK_PACKETS)
break;
else
it++; it++;
} }
// ranges // ranges
uint32_t lastNum = ackThrough - acnt; uint32_t lastNum = ackThrough - acnt;
if (acnt > SSU2_MAX_NUM_ACNT) if (acnt > 255)
{ {
auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT); auto d = std::div (acnt - 255, 255);
acnt = SSU2_MAX_NUM_ACNT; acnt = 255;
if (d.quot > maxNumRanges) if (d.quot > maxNumRanges)
{ {
d.quot = maxNumRanges; d.quot = maxNumRanges;
@@ -2489,7 +2478,7 @@ namespace transport
// Acks only ranges for acnt // Acks only ranges for acnt
for (int i = 0; i < d.quot; i++) for (int i = 0; i < d.quot; i++)
{ {
buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255 buf[8 + numRanges*2] = 0; buf[8 + numRanges*2 + 1] = 255; // NACKs 0, Acks 255
numRanges++; numRanges++;
} }
if (d.rem > 0) if (d.rem > 0)
@@ -2498,25 +2487,21 @@ namespace transport
numRanges++; numRanges++;
} }
} }
int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT; while (it != m_OutOfSequencePackets.rend () && numRanges < maxNumRanges)
while (it != m_OutOfSequencePackets.rend () &&
numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
{ {
if (lastNum - (*it) > SSU2_MAX_NUM_ACNT) if (lastNum - (*it) > 255)
{ {
// NACKs only ranges // NACKs only ranges
if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs if (lastNum > (*it) + 255*(maxNumRanges - numRanges)) break; // too many NACKs
while (lastNum - (*it) > SSU2_MAX_NUM_ACNT) while (lastNum - (*it) > 255)
{ {
buf[8 + numRanges*2] = SSU2_MAX_NUM_ACNT; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0 buf[8 + numRanges*2] = 255; buf[8 + numRanges*2 + 1] = 0; // NACKs 255, Acks 0
lastNum -= SSU2_MAX_NUM_ACNT; lastNum -= 255;
numRanges++; numRanges++;
numPackets += SSU2_MAX_NUM_ACNT;
} }
} }
// NACKs and Acks ranges // NACKs and Acks ranges
buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs buf[8 + numRanges*2] = lastNum - (*it) - 1; // NACKs
numPackets += buf[8 + numRanges*2];
lastNum = *it; it++; lastNum = *it; it++;
int numAcks = 1; int numAcks = 1;
while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1) while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1)
@@ -2524,31 +2509,28 @@ namespace transport
numAcks++; lastNum--; numAcks++; lastNum--;
it++; it++;
} }
while (numAcks > SSU2_MAX_NUM_ACNT) while (numAcks > 255)
{ {
// Acks only ranges // Acks only ranges
buf[8 + numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255 buf[8 + numRanges*2 + 1] = 255; // Acks 255
numAcks -= SSU2_MAX_NUM_ACNT; numAcks -= 255;
numRanges++; numRanges++;
numPackets += SSU2_MAX_NUM_ACNT;
buf[8 + numRanges*2] = 0; // NACKs 0 buf[8 + numRanges*2] = 0; // NACKs 0
if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break; if (numRanges >= maxNumRanges) break;
} }
if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT; if (numAcks > 255) numAcks = 255;
buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks buf[8 + numRanges*2 + 1] = (uint8_t)numAcks; // Acks
numPackets += numAcks;
numRanges++; numRanges++;
} }
if (it == m_OutOfSequencePackets.rend () && if (numRanges < maxNumRanges && it == m_OutOfSequencePackets.rend ())
numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
{ {
// add range between out-of-sequence and received // add range between out-of-sequence and received
int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1; int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1;
if (nacks > 0) if (nacks > 0)
{ {
if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT; if (nacks > 255) nacks = 255;
buf[8 + numRanges*2] = nacks; buf[8 + numRanges*2] = nacks;
buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT); buf[8 + numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, 255);
numRanges++; numRanges++;
} }
} }
@@ -2775,26 +2757,16 @@ namespace transport
if (packetNum <= m_ReceivePacketNum) return false; // duplicate if (packetNum <= m_ReceivePacketNum) return false; // duplicate
if (packetNum == m_ReceivePacketNum + 1) if (packetNum == m_ReceivePacketNum + 1)
{ {
if (!m_OutOfSequencePackets.empty ()) for (auto it = m_OutOfSequencePackets.begin (); it != m_OutOfSequencePackets.end ();)
{
auto it = m_OutOfSequencePackets.begin ();
if (*it == packetNum + 1)
{
// first out of sequence packet is in sequence now
packetNum++; it++;
while (it != m_OutOfSequencePackets.end ())
{ {
if (*it == packetNum + 1) if (*it == packetNum + 1)
{ {
packetNum++; packetNum++;
it++; it = m_OutOfSequencePackets.erase (it);
} }
else // next out of sequence else
break; break;
} }
m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it);
}
}
m_ReceivePacketNum = packetNum; m_ReceivePacketNum = packetNum;
} }
else else
@@ -2805,16 +2777,7 @@ namespace transport
void SSU2Session::SendQuickAck () void SSU2Session::SendQuickAck ()
{ {
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = 0; size_t payloadSize = CreateAckBlock (payload, m_MaxPayloadSize);
if (m_SendPacketNum > m_LastDatetimeSentPacketNum + SSU2_SEND_DATETIME_NUM_PACKETS)
{
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
payloadSize += 7;
m_LastDatetimeSentPacketNum = m_SendPacketNum;
}
payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
} }
@@ -2888,10 +2851,8 @@ namespace transport
} }
if (!m_OutOfSequencePackets.empty ()) if (!m_OutOfSequencePackets.empty ())
{ {
int ranges = 0; if (m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
while (ranges < 8 && !m_OutOfSequencePackets.empty () && *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + 255*8)
(m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
*m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + SSU2_MAX_NUM_ACK_PACKETS))
{ {
uint32_t packet = *m_OutOfSequencePackets.begin (); uint32_t packet = *m_OutOfSequencePackets.begin ();
if (packet > m_ReceivePacketNum + 1) if (packet > m_ReceivePacketNum + 1)
@@ -2900,13 +2861,9 @@ namespace transport
packet--; packet--;
m_ReceivePacketNum = packet - 1; m_ReceivePacketNum = packet - 1;
UpdateReceivePacketNum (packet); UpdateReceivePacketNum (packet);
ranges++;
} }
else else
{
LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum); LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum);
break;
}
} }
if (m_OutOfSequencePackets.size () > 255*4) if (m_OutOfSequencePackets.size () > 255*4)
{ {

View File

@@ -48,11 +48,8 @@ namespace transport
const size_t SSU2_MAX_RTO = 2500; // in milliseconds const size_t SSU2_MAX_RTO = 2500; // in milliseconds
const float SSU2_kAPPA = 1.8; const float SSU2_kAPPA = 1.8;
const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages const size_t SSU2_MAX_OUTGOING_QUEUE_SIZE = 500; // in messages
const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks
const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
const int SSU2_SEND_DATETIME_NUM_PACKETS = 256;
// flags // flags
const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;
@@ -345,7 +342,7 @@ namespace transport
uint64_t m_DestConnID, m_SourceConnID; uint64_t m_DestConnID, m_SourceConnID;
SSU2SessionState m_State; SSU2SessionState m_State;
uint8_t m_KeyDataSend[64], m_KeyDataReceive[64]; uint8_t m_KeyDataSend[64], m_KeyDataReceive[64];
uint32_t m_SendPacketNum, m_ReceivePacketNum, m_LastDatetimeSentPacketNum; uint32_t m_SendPacketNum, m_ReceivePacketNum;
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet
std::unordered_map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // msgID -> I2NP std::unordered_map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // msgID -> I2NP

View File

@@ -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
* *
@@ -51,8 +51,8 @@ namespace stream
{ {
// partially // partially
rem = len - offset; rem = len - offset;
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem); memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
nextBuffer->offset += rem; nextBuffer->offset += (len - offset);
offset = len; // break offset = len; // break
} }
} }
@@ -139,16 +139,7 @@ namespace stream
{ {
m_NumReceivedBytes += packet->GetLength (); m_NumReceivedBytes += packet->GetLength ();
if (!m_SendStreamID) if (!m_SendStreamID)
{
m_SendStreamID = packet->GetReceiveStreamID (); m_SendStreamID = packet->GetReceiveStreamID ();
if (!m_RemoteIdentity && packet->GetNACKCount () == 8 && // first incoming packet
memcmp (packet->GetNACKs (), m_LocalDestination.GetOwner ()->GetIdentHash (), 32))
{
LogPrint (eLogWarning, "Streaming: Destination mismatch for ", m_LocalDestination.GetOwner ()->GetIdentHash ().ToBase32 ());
m_LocalDestination.DeletePacket (packet);
return;
}
}
if (!packet->IsNoAck ()) // ack received if (!packet->IsNoAck ()) // ack received
ProcessAck (packet); ProcessAck (packet);
@@ -393,7 +384,7 @@ namespace stream
memset (p.buf, 0, 22); // minimal header all zeroes memset (p.buf, 0, 22); // minimal header all zeroes
memcpy (p.buf + 4, packet->buf, 4); // but receiveStreamID is the sendStreamID from the ping memcpy (p.buf + 4, packet->buf, 4); // but receiveStreamID is the sendStreamID from the ping
htobe16buf (p.buf + 18, PACKET_FLAG_ECHO); // and echo flag htobe16buf (p.buf + 18, PACKET_FLAG_ECHO); // and echo flag
auto payloadLen = int(packet->len) - (packet->GetPayload () - packet->buf); ssize_t payloadLen = packet->len - (packet->GetPayload () - packet->buf);
if (payloadLen > 0) if (payloadLen > 0)
memcpy (p.buf + 22, packet->GetPayload (), payloadLen); memcpy (p.buf + 22, packet->GetPayload (), payloadLen);
else else
@@ -569,19 +560,8 @@ namespace stream
else else
htobe32buf (packet + size, m_LastReceivedSequenceNumber); htobe32buf (packet + size, m_LastReceivedSequenceNumber);
size += 4; // ack Through size += 4; // ack Through
if (m_Status == eStreamStatusNew && !m_SendStreamID && m_RemoteIdentity)
{
// first SYN packet
packet[size] = 8;
size++; // NACK count
memcpy (packet + size, m_RemoteIdentity->GetIdentHash (), 32);
size += 32;
}
else
{
packet[size] = 0; packet[size] = 0;
size++; // NACK count size++; // NACK count
}
packet[size] = m_RTO/1000; packet[size] = m_RTO/1000;
size++; // resend delay size++; // resend delay
if (m_Status == eStreamStatusNew) if (m_Status == eStreamStatusNew)

View File

@@ -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
* *
@@ -80,7 +80,6 @@ namespace stream
uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); }; uint32_t GetAckThrough () const { return bufbe32toh (buf + 12); };
uint8_t GetNACKCount () const { return buf[16]; }; uint8_t GetNACKCount () const { return buf[16]; };
uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); }; uint32_t GetNACK (int i) const { return bufbe32toh (buf + 17 + 4 * i); };
const uint8_t * GetNACKs () const { return buf + 17; };
const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags const uint8_t * GetOption () const { return buf + 17 + GetNACKCount ()*4 + 3; }; // 3 = resendDelay + flags
uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); }; uint16_t GetFlags () const { return bufbe16toh (GetOption () - 2); };
uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); }; uint16_t GetOptionSize () const { return bufbe16toh (GetOption ()); };

View File

@@ -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
* *
@@ -80,13 +80,6 @@ namespace data {
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
} }
uint8_t GetBit (int i) const
{
int pos = i >> 3; // /8
if (pos >= (int)sz) return 0;
return m_Buf[pos] & (0x80 >> (i & 0x07));
}
private: private:
union // 8 bytes aligned union // 8 bytes aligned

View File

@@ -107,10 +107,7 @@ namespace transport
int GetTerminationTimeout () const { return m_TerminationTimeout; }; int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; }; void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const bool IsTerminationTimeoutExpired (uint64_t ts) const
{ { return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
return ts >= m_LastActivityTimestamp + GetTerminationTimeout () ||
ts + GetTerminationTimeout () < m_LastActivityTimestamp;
};
uint32_t GetCreationTime () const { return m_CreationTime; }; uint32_t GetCreationTime () const { return m_CreationTime; };
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers

View File

@@ -476,7 +476,7 @@ namespace transport
bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer) bool Transports::ConnectToPeer (const i2p::data::IdentHash& ident, Peer& peer)
{ {
if (!peer.router) // reconnect if (!peer.router) // reconnect
peer.SetRouter (netdb.FindRouter (ident)); // try to get new one from netdb peer.router = netdb.FindRouter (ident); // try to get new one from netdb
if (peer.router) // we have RI already if (peer.router) // we have RI already
{ {
if (peer.priority.empty ()) if (peer.priority.empty ())
@@ -539,8 +539,7 @@ namespace transport
} }
LogPrint (eLogInfo, "Transports: No compatible addresses available"); LogPrint (eLogInfo, "Transports: No compatible addresses available");
if (peer.router->IsReachableFrom (i2p::context.GetRouterInfo ())) i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed but router claimed them
peer.Done (); peer.Done ();
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident); m_Peers.erase (ident);
@@ -599,7 +598,7 @@ namespace transport
if (r) if (r)
{ {
LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect"); LogPrint (eLogDebug, "Transports: RouterInfo for ", ident.ToBase64 (), " found, trying to connect");
it->second.SetRouter (r); it->second.router = r;
ConnectToPeer (ident, it->second); ConnectToPeer (ident, it->second);
} }
else else
@@ -816,101 +815,20 @@ namespace transport
} }
} }
template<typename Filter> std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer () const
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
{ {
if (m_Peers.empty()) return nullptr; if (m_Peers.empty ()) return nullptr;
bool found = false;
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
{ {
uint16_t inds[3];
RAND_bytes ((uint8_t *)inds, sizeof (inds));
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
inds[0] %= m_Peers.size ();
auto it = m_Peers.begin (); auto it = m_Peers.begin ();
std::advance (it, inds[0]); std::advance (it, rand () % m_Peers.size ());
// try random peer if (it == m_Peers.end () || it->second.router || it->second.sessions.empty () ||
if (it != m_Peers.end () && filter (it->second)) it->second.sessions.front ()->GetSendQueueSize () > PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE)
{ return nullptr; // not connected or overloaded
ident = it->first; ident = it->first;
found = true;
} }
else return i2p::data::netdb.FindRouter (ident);
{
// try some peers around
auto it1 = m_Peers.begin ();
if (inds[0])
{
// before
inds[1] %= inds[0];
std::advance (it1, (inds[1] + inds[0])/2);
}
else
it1 = it;
auto it2 = it;
if (inds[0] < m_Peers.size () - 1)
{
// after
inds[2] %= (m_Peers.size () - 1 - inds[0]); inds[2] /= 2;
std::advance (it2, inds[2]);
}
// it1 - from, it2 - to
it = it1;
while (it != it2 && it != m_Peers.end ())
{
if (filter (it->second))
{
ident = it->first;
found = true;
break;
}
it++;
}
if (!found)
{
// still not found, try from the beginning
it = m_Peers.begin ();
while (it != it1 && it != m_Peers.end ())
{
if (filter (it->second))
{
ident = it->first;
found = true;
break;
}
it++;
}
if (!found)
{
// still not found, try to the beginning
it = it2;
while (it != m_Peers.end ())
{
if (filter (it->second))
{
ident = it->first;
found = true;
break;
}
it++;
}
}
}
}
}
return found ? i2p::data::netdb.FindRouter (ident) : nullptr;
}
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
{
return GetRandomPeer (
[isHighBandwidth](const Peer& peer)->bool
{
// connected and not overloaded
return !peer.router && !peer.sessions.empty () &&
peer.sessions.front ()->GetSendQueueSize () <= PEER_ROUTER_INFO_OVERLOAD_QUEUE_SIZE &&
(!isHighBandwidth || peer.isHighBandwidth);
});
} }
void Transports::RestrictRoutesToFamilies(const std::set<std::string>& families) void Transports::RestrictRoutesToFamilies(const std::set<std::string>& families)

View File

@@ -72,15 +72,11 @@ namespace transport
uint64_t creationTime, nextRouterInfoUpdateTime; uint64_t creationTime, nextRouterInfoUpdateTime;
std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages; std::vector<std::shared_ptr<i2p::I2NPMessage> > delayedMessages;
std::vector<i2p::data::RouterInfo::SupportedTransports> priority; std::vector<i2p::data::RouterInfo::SupportedTransports> priority;
bool isHighBandwidth;
Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts): Peer (std::shared_ptr<const i2p::data::RouterInfo> r, uint64_t ts):
numAttempts (0), router (r), creationTime (ts), numAttempts (0), router (r), creationTime (ts),
nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL), nextRouterInfoUpdateTime (ts + PEER_ROUTER_INFO_UPDATE_INTERVAL)
isHighBandwidth (false)
{ {
if (router)
isHighBandwidth = router->IsHighBandwidth ();
} }
void Done () void Done ()
@@ -88,13 +84,6 @@ namespace transport
for (auto& it: sessions) for (auto& it: sessions)
it->Done (); it->Done ();
} }
void SetRouter (std::shared_ptr<const i2p::data::RouterInfo> r)
{
router = r;
if (router)
isHighBandwidth = router->IsHighBandwidth ();
}
}; };
const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds const uint64_t SESSION_CREATION_TIMEOUT = 15; // in seconds
@@ -142,7 +131,7 @@ namespace transport
bool IsBandwidthExceeded () const; bool IsBandwidthExceeded () const;
bool IsTransitBandwidthExceeded () const; bool IsTransitBandwidthExceeded () const;
size_t GetNumPeers () const { return m_Peers.size (); }; size_t GetNumPeers () const { return m_Peers.size (); };
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (bool isHighBandwidth) const; std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
/** get a trusted first hop for restricted routes */ /** get a trusted first hop for restricted routes */
std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const; std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const;
@@ -174,9 +163,6 @@ namespace transport
void DetectExternalIP (); void DetectExternalIP ();
template<typename Filter>
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (Filter filter) const;
private: private:
volatile bool m_IsOnline; volatile bool m_IsOnline;

View File

@@ -331,15 +331,12 @@ namespace tunnel
Tunnels tunnels; Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), m_MaxNumTransitTunnels (DEFAULT_MAX_NUM_TRANSIT_TUNNELS), Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr),
m_TotalNumSuccesiveTunnelCreations (0), m_TotalNumFailedTunnelCreations (0), // for normal avarage m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0) {
m_TunnelCreationSuccessRate (TCSR_START_VALUE), m_TunnelCreationAttemptsNum(0)
{
} }
Tunnels::~Tunnels () Tunnels::~Tunnels ()
{ {
DeleteTunnelPool(m_ExploratoryPool);
} }
std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID) std::shared_ptr<TunnelBase> Tunnels::GetTunnel (uint32_t tunnelID)
@@ -538,20 +535,17 @@ namespace tunnel
if (i2p::transport::transports.IsOnline()) if (i2p::transport::transports.IsOnline())
{ {
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastTs >= TUNNEL_MANAGE_INTERVAL || // manage tunnels every 15 seconds if (ts - lastTs >= TUNNEL_MANAGE_INTERVAL) // manage tunnels every 15 seconds
ts + TUNNEL_MANAGE_INTERVAL < lastTs)
{ {
ManageTunnels (ts); ManageTunnels ();
lastTs = ts; lastTs = ts;
} }
if (ts - lastPoolsTs >= TUNNEL_POOLS_MANAGE_INTERVAL || // manage pools every 5 secondsts if (ts - lastPoolsTs >= TUNNEL_POOLS_MANAGE_INTERVAL) // manage pools every 5 seconds
ts + TUNNEL_POOLS_MANAGE_INTERVAL < lastPoolsTs)
{ {
ManageTunnelPools (ts); ManageTunnelPools (ts);
lastPoolsTs = ts; lastPoolsTs = ts;
} }
if (ts - lastMemoryPoolTs >= TUNNEL_MEMORY_POOL_MANAGE_INTERVAL || if (ts - lastMemoryPoolTs >= TUNNEL_MEMORY_POOL_MANAGE_INTERVAL) // manage memory pool every 2 minutes
ts + TUNNEL_MEMORY_POOL_MANAGE_INTERVAL < lastMemoryPoolTs) // manage memory pool every 2 minutes
{ {
m_I2NPTunnelEndpointMessagesMemoryPool.CleanUpMt (); m_I2NPTunnelEndpointMessagesMemoryPool.CleanUpMt ();
m_I2NPTunnelMessagesMemoryPool.CleanUpMt (); m_I2NPTunnelMessagesMemoryPool.CleanUpMt ();
@@ -593,32 +587,32 @@ namespace tunnel
tunnel->SendTunnelDataMsg (msg); tunnel->SendTunnelDataMsg (msg);
} }
void Tunnels::ManageTunnels (uint64_t ts) void Tunnels::ManageTunnels ()
{ {
ManagePendingTunnels (ts); ManagePendingTunnels ();
ManageInboundTunnels (ts); ManageInboundTunnels ();
ManageOutboundTunnels (ts); ManageOutboundTunnels ();
ManageTransitTunnels (ts); ManageTransitTunnels ();
} }
void Tunnels::ManagePendingTunnels (uint64_t ts) void Tunnels::ManagePendingTunnels ()
{ {
ManagePendingTunnels (m_PendingInboundTunnels, ts); ManagePendingTunnels (m_PendingInboundTunnels);
ManagePendingTunnels (m_PendingOutboundTunnels, ts); ManagePendingTunnels (m_PendingOutboundTunnels);
} }
template<class PendingTunnels> template<class PendingTunnels>
void Tunnels::ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts) void Tunnels::ManagePendingTunnels (PendingTunnels& pendingTunnels)
{ {
// check pending tunnel. delete failed or timeout // check pending tunnel. delete failed or timeout
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();) for (auto it = pendingTunnels.begin (); it != pendingTunnels.end ();)
{ {
auto tunnel = it->second; auto tunnel = it->second;
switch (tunnel->GetState ()) switch (tunnel->GetState ())
{ {
case eTunnelStatePending: case eTunnelStatePending:
if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT || if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
ts + TUNNEL_CREATION_TIMEOUT < tunnel->GetCreationTime ())
{ {
LogPrint (eLogDebug, "Tunnel: Pending build request ", it->first, " timeout, deleted"); LogPrint (eLogDebug, "Tunnel: Pending build request ", it->first, " timeout, deleted");
// update stats // update stats
@@ -661,7 +655,9 @@ namespace tunnel
} }
} }
void Tunnels::ManageOutboundTunnels (uint64_t ts) void Tunnels::ManageOutboundTunnels ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
{ {
for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();) for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();)
{ {
@@ -695,6 +691,7 @@ namespace tunnel
++it; ++it;
} }
} }
}
if (m_OutboundTunnels.size () < 3) if (m_OutboundTunnels.size () < 3)
{ {
@@ -712,13 +709,14 @@ namespace tunnel
} }
} }
void Tunnels::ManageInboundTunnels (uint64_t ts) void Tunnels::ManageInboundTunnels ()
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
{ {
for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();) for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();)
{ {
auto tunnel = *it; auto tunnel = *it;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
{ {
LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired"); LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
auto pool = tunnel->GetTunnelPool (); auto pool = tunnel->GetTunnelPool ();
@@ -750,6 +748,7 @@ namespace tunnel
it++; it++;
} }
} }
}
if (m_InboundTunnels.empty ()) if (m_InboundTunnels.empty ())
{ {
@@ -786,13 +785,13 @@ namespace tunnel
} }
} }
void Tunnels::ManageTransitTunnels (uint64_t ts) void Tunnels::ManageTransitTunnels ()
{ {
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();) for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();)
{ {
auto tunnel = *it; auto tunnel = *it;
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT || if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
{ {
LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired"); LogPrint (eLogDebug, "Tunnel: Transit tunnel with id ", tunnel->GetTunnelID (), " expired");
m_Tunnels.erase (tunnel->GetTunnelID ()); m_Tunnels.erase (tunnel->GetTunnelID ());
@@ -971,14 +970,5 @@ namespace tunnel
// TODO: locking // TODO: locking
return m_OutboundTunnels.size(); return m_OutboundTunnels.size();
} }
void Tunnels::SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{
if (maxNumTransitTunnels > 0 && m_MaxNumTransitTunnels != maxNumTransitTunnels)
{
LogPrint (eLogDebug, "Tunnel: Max number of transit tunnels set to ", maxNumTransitTunnels);
m_MaxNumTransitTunnels = maxNumTransitTunnels;
}
}
} }
} }

View File

@@ -41,7 +41,6 @@ namespace tunnel
const int MAX_NUM_RECORDS = 8; const int MAX_NUM_RECORDS = 8;
const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds const int HIGH_LATENCY_PER_HOP = 250; // in milliseconds
const int MAX_TUNNEL_MSGS_BATCH_SIZE = 100; // handle messages without interrupt const int MAX_TUNNEL_MSGS_BATCH_SIZE = 100; // handle messages without interrupt
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 5000;
const int TUNNEL_MANAGE_INTERVAL = 15; // in seconds const int TUNNEL_MANAGE_INTERVAL = 15; // in seconds
const int TUNNEL_POOLS_MANAGE_INTERVAL = 5; // in seconds const int TUNNEL_POOLS_MANAGE_INTERVAL = 5; // in seconds
const int TUNNEL_MEMORY_POOL_MANAGE_INTERVAL = 120; // in seconds const int TUNNEL_MEMORY_POOL_MANAGE_INTERVAL = 120; // in seconds
@@ -230,10 +229,6 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint);
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
uint16_t GetMaxNumTransitTunnels () const { return m_MaxNumTransitTunnels; };
bool IsTooManyTransitTunnels () const { return m_TransitTunnels.size () >= m_MaxNumTransitTunnels; };
private: private:
template<class TTunnel> template<class TTunnel>
@@ -246,36 +241,18 @@ namespace tunnel
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg); void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
void Run (); void Run ();
void ManageTunnels (uint64_t ts); void ManageTunnels ();
void ManageOutboundTunnels (uint64_t ts); void ManageOutboundTunnels ();
void ManageInboundTunnels (uint64_t ts); void ManageInboundTunnels ();
void ManageTransitTunnels (uint64_t ts); void ManageTransitTunnels ();
void ManagePendingTunnels (uint64_t ts); void ManagePendingTunnels ();
template<class PendingTunnels> template<class PendingTunnels>
void ManagePendingTunnels (PendingTunnels& pendingTunnels, uint64_t ts); void ManagePendingTunnels (PendingTunnels& pendingTunnels);
void ManageTunnelPools (uint64_t ts); void ManageTunnelPools (uint64_t ts);
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool); std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel (std::shared_ptr<TunnelPool> pool);
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel (std::shared_ptr<TunnelPool> pool); std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel (std::shared_ptr<TunnelPool> pool);
// Calculating of tunnel creation success rate
void SuccesiveTunnelCreation()
{
// total TCSR
m_TotalNumSuccesiveTunnelCreations++;
// A modified version of the EWMA algorithm, where alpha is increased at the beginning to accelerate similarity
double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
m_TunnelCreationSuccessRate = alpha * 1 + (1 - alpha) * m_TunnelCreationSuccessRate;
}
void FailedTunnelCreation()
{
m_TotalNumFailedTunnelCreations++;
double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
m_TunnelCreationSuccessRate = alpha * 0 + (1 - alpha) * m_TunnelCreationSuccessRate;
}
private: private:
bool m_IsRunning; bool m_IsRunning;
@@ -292,9 +269,18 @@ namespace tunnel
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue; i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool; i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_ENPOINT_MESSAGE_SIZE> > m_I2NPTunnelEndpointMessagesMemoryPool;
i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool; i2p::util::MemoryPoolMt<I2NPMessageBuffer<I2NP_TUNNEL_MESSAGE_SIZE> > m_I2NPTunnelMessagesMemoryPool;
uint16_t m_MaxNumTransitTunnels;
// count of tunnels for total TCSR algorithm // Calculating of tunnel creation success rate
int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; // A modified version of the EWMA algorithm, where alpha is increased at the beginning to accelerate similarity
void SuccesiveTunnelCreation() {
double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
m_TunnelCreationSuccessRate = alpha * 1 + (1 - alpha) * m_TunnelCreationSuccessRate;
};
void FailedTunnelCreation() {
double alpha = TCSR_SMOOTHING_CONSTANT + (1 - TCSR_SMOOTHING_CONSTANT)/++m_TunnelCreationAttemptsNum;
m_TunnelCreationSuccessRate = alpha * 0 + (1 - alpha) * m_TunnelCreationSuccessRate;
};
double m_TunnelCreationSuccessRate; double m_TunnelCreationSuccessRate;
int m_TunnelCreationAttemptsNum; int m_TunnelCreationAttemptsNum;
@@ -311,11 +297,6 @@ namespace tunnel
int GetQueueSize () { return m_Queue.GetSize (); }; int GetQueueSize () { return m_Queue.GetSize (); };
int GetTunnelCreationSuccessRate () const { return std::round(m_TunnelCreationSuccessRate * 100); } // in percents int GetTunnelCreationSuccessRate () const { return std::round(m_TunnelCreationSuccessRate * 100); } // in percents
int GetTotalTunnelCreationSuccessRate () const // in percents
{
int totalNum = m_TotalNumSuccesiveTunnelCreations + m_TotalNumFailedTunnelCreations;
return totalNum ? m_TotalNumSuccesiveTunnelCreations*100/totalNum : 0;
}
}; };
extern Tunnels tunnels; extern Tunnels tunnels;

View File

@@ -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
* *
@@ -480,7 +480,7 @@ namespace tunnel
return hop; return hop;
} }
bool TunnelPool::StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop) bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop)
{ {
int start = 0; int start = 0;
std::shared_ptr<const i2p::data::RouterInfo> prevHop = i2p::context.GetSharedRouterInfo (); std::shared_ptr<const i2p::data::RouterInfo> prevHop = i2p::context.GetSharedRouterInfo ();
@@ -496,7 +496,7 @@ namespace tunnel
else if (i2p::transport::transports.GetNumPeers () > 100 || else if (i2p::transport::transports.GetNumPeers () > 100 ||
(inbound && i2p::transport::transports.GetNumPeers () > 25)) (inbound && i2p::transport::transports.GetNumPeers () > 25))
{ {
auto r = i2p::transport::transports.GetRandomPeer (!IsExploratory ()); auto r = i2p::transport::transports.GetRandomPeer ();
if (r && r->IsECIES () && !r->GetProfile ()->IsBad () && if (r && r->IsECIES () && !r->GetProfile ()->IsBad () &&
(numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable (numHops > 1 || (r->IsV4 () && (!inbound || r->IsReachable ())))) // first inbound must be reachable
{ {
@@ -512,7 +512,7 @@ namespace tunnel
if (!hop && !i) // if no suitable peer found for first hop, try already connected if (!hop && !i) // if no suitable peer found for first hop, try already connected
{ {
LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected"); LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected");
hop = i2p::transport::transports.GetRandomPeer (false); hop = i2p::transport::transports.GetRandomPeer ();
if (hop && !hop->IsECIES ()) hop = nullptr; if (hop && !hop->IsECIES ()) hop = nullptr;
} }
if (!hop) if (!hop)

View File

@@ -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
* *
@@ -54,9 +54,12 @@ namespace tunnel
virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0; virtual bool SelectPeers(Path & peers, int hops, bool isInbound) = 0;
}; };
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc;
bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination class TunnelPool: public std::enable_shared_from_this<TunnelPool> // per local destination
{ {
typedef std::function<std::shared_ptr<const i2p::data::RouterInfo>(std::shared_ptr<const i2p::data::RouterInfo>, bool)> SelectHopFunc;
public: public:
TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels,
@@ -113,7 +116,6 @@ namespace tunnel
// for overriding tunnel peer selection // for overriding tunnel peer selection
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const; std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, bool reverse) const;
bool StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop);
private: private:

View File

@@ -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
* *
@@ -67,15 +67,11 @@ namespace api
i2p::transport::transports.Start(); i2p::transport::transports.Start();
LogPrint(eLogInfo, "API: Starting Tunnels"); LogPrint(eLogInfo, "API: Starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
LogPrint(eLogInfo, "API: Starting Router context");
i2p::context.Start();
} }
void StopI2P () void StopI2P ()
{ {
LogPrint(eLogInfo, "API: Shutting down"); LogPrint(eLogInfo, "API: Shutting down");
LogPrint(eLogInfo, "API: Stopping Router context");
i2p::context.Stop();
LogPrint(eLogInfo, "API: Stopping Tunnels"); LogPrint(eLogInfo, "API: Stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();
LogPrint(eLogInfo, "API: Stopping Transports"); LogPrint(eLogInfo, "API: Stopping Transports");

View File

@@ -8,14 +8,13 @@
#include <cstdlib> #include <cstdlib>
#include <string> #include <string>
#include <unordered_set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include "util.h" #include "util.h"
#include "Log.h" #include "Log.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#if !defined (__FreeBSD__) && !defined(_MSC_VER) #if not defined (__FreeBSD__)
#include <pthread.h> #include <pthread.h>
#endif #endif
@@ -37,19 +36,6 @@
#include <iphlpapi.h> #include <iphlpapi.h>
#include <shlobj.h> #include <shlobj.h>
#if defined(_MSC_VER)
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
} THREADNAME_INFO;
#pragma pack(pop)
#endif
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
@@ -88,8 +74,7 @@ const char *inet_ntop_xp(int af, const void *src, char *dst, socklen_t size)
ZeroMemory(&ss, sizeof(ss)); ZeroMemory(&ss, sizeof(ss));
ss.ss_family = af; ss.ss_family = af;
switch (af) switch(af) {
{
case AF_INET: case AF_INET:
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
break; break;
@@ -175,23 +160,7 @@ namespace util
#elif defined(__NetBSD__) #elif defined(__NetBSD__)
pthread_setname_np(pthread_self(), "%s", (void *)name); pthread_setname_np(pthread_self(), "%s", (void *)name);
#elif !defined(__gnu_hurd__) #elif !defined(__gnu_hurd__)
#if defined(_MSC_VER)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = -1;
info.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable: 6320 6322)
__try {
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
}
#pragma warning(pop)
#else
pthread_setname_np(pthread_self(), name); pthread_setname_np(pthread_self(), name);
#endif
#endif #endif
} }
@@ -209,7 +178,7 @@ namespace net
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if (GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW) == ERROR_BUFFER_OVERFLOW)
{ {
FREE(pAddresses); FREE(pAddresses);
@@ -220,7 +189,7 @@ namespace net
AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
); );
if (dwRetVal != NO_ERROR) if(dwRetVal != NO_ERROR)
{ {
LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed"); LogPrint(eLogError, "NetIface: GetMTU: Enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses); FREE(pAddresses);
@@ -228,17 +197,19 @@ namespace net
} }
pCurrAddresses = pAddresses; pCurrAddresses = pAddresses;
while (pCurrAddresses) while(pCurrAddresses)
{ {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress;
if (pUnicast == nullptr) if(pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported"); LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv4 address, this is not supported");
while (pUnicast != nullptr) for(int i = 0; pUnicast != nullptr; ++i)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr; sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr;
if (localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr)
{ {
char addr[INET_ADDRSTRLEN]; char addr[INET_ADDRSTRLEN];
inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN); inetntop(AF_INET, &(((struct sockaddr_in *)localInterfaceAddress)->sin_addr), addr, INET_ADDRSTRLEN);
@@ -292,11 +263,12 @@ namespace net
pCurrAddresses = pAddresses; pCurrAddresses = pAddresses;
while (pCurrAddresses) while (pCurrAddresses)
{ {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress;
if (pUnicast == nullptr) if (pUnicast == nullptr)
LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported"); LogPrint(eLogError, "NetIface: GetMTU: Not a unicast IPv6 address, this is not supported");
while (pUnicast != nullptr) for (int i = 0; pUnicast != nullptr; ++i)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
@@ -344,13 +316,13 @@ namespace net
IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton"); IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found
if (localAddress.is_v4()) if(localAddress.is_v4())
{ {
sockaddr_in inputAddress; sockaddr_in inputAddress;
inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr)); inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
return GetMTUWindowsIpv4(inputAddress, fallback); return GetMTUWindowsIpv4(inputAddress, fallback);
} }
else if (localAddress.is_v6()) else if(localAddress.is_v6())
{ {
sockaddr_in6 inputAddress; sockaddr_in6 inputAddress;
inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr)); inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
@@ -366,7 +338,7 @@ namespace net
int GetMTUUnix (const boost::asio::ip::address& localAddress, int fallback) int GetMTUUnix (const boost::asio::ip::address& localAddress, int fallback)
{ {
ifaddrs* ifaddr, *ifa = nullptr; ifaddrs* ifaddr, *ifa = nullptr;
if (getifaddrs(&ifaddr) == -1) if(getifaddrs(&ifaddr) == -1)
{ {
LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno)); LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno));
return fallback; return fallback;
@@ -374,34 +346,34 @@ namespace net
int family = 0; int family = 0;
// look for interface matching local address // look for interface matching local address
for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{ {
if (!ifa->ifa_addr) if(!ifa->ifa_addr)
continue; continue;
family = ifa->ifa_addr->sa_family; family = ifa->ifa_addr->sa_family;
if (family == AF_INET && localAddress.is_v4()) if(family == AF_INET && localAddress.is_v4())
{ {
sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr; sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr;
if (!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4)) if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
break; // address matches break; // address matches
} }
else if (family == AF_INET6 && localAddress.is_v6()) else if(family == AF_INET6 && localAddress.is_v6())
{ {
sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr; sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr;
if (!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16)) if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
break; // address matches break; // address matches
} }
} }
int mtu = fallback; int mtu = fallback;
if (ifa && family) if(ifa && family)
{ // interface found? { // interface found?
int fd = socket(family, SOCK_DGRAM, 0); int fd = socket(family, SOCK_DGRAM, 0);
if (fd > 0) if(fd > 0)
{ {
ifreq ifr; ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ-1); // set interface for query strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ-1); // set interface for query
if (ioctl(fd, SIOCGIFMTU, &ifr) >= 0) if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU mtu = ifr.ifr_mtu; // MTU
else else
LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno)); LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno));
@@ -434,7 +406,7 @@ namespace net
{ {
#ifdef _WIN32 #ifdef _WIN32
LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32"); LogPrint(eLogError, "NetIface: Cannot get address by interface name, not implemented on WIN32");
if (ipv6) if(ipv6)
return boost::asio::ip::address::from_string("::1"); return boost::asio::ip::address::from_string("::1");
else else
return boost::asio::ip::address::from_string("127.0.0.1"); return boost::asio::ip::address::from_string("127.0.0.1");
@@ -453,7 +425,7 @@ namespace net
// match // match
char addr[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
memset (addr, 0, INET6_ADDRSTRLEN); memset (addr, 0, INET6_ADDRSTRLEN);
if (af == AF_INET) if(af == AF_INET)
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN); inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
else else
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN); inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
@@ -469,9 +441,9 @@ namespace net
LogPrint(eLogError, "NetIface: Exception while searching address using ifaddr: ", ex.what()); LogPrint(eLogError, "NetIface: Exception while searching address using ifaddr: ", ex.what());
} }
if (addrs) freeifaddrs(addrs); if(addrs) freeifaddrs(addrs);
std::string fallback; std::string fallback;
if (ipv6) if(ipv6)
{ {
fallback = "::1"; fallback = "::1";
LogPrint(eLogWarning, "NetIface: Cannot find IPv6 address for interface ", ifname); LogPrint(eLogWarning, "NetIface: Cannot find IPv6 address for interface ", ifname);
@@ -515,22 +487,6 @@ namespace net
return IsYggdrasilAddress (addr.to_v6 ().to_bytes ().data ()); return IsYggdrasilAddress (addr.to_v6 ().to_bytes ().data ());
} }
bool IsPortInReservedRange (const uint16_t port) noexcept
{
// https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers (Feb. 3, 2023) + Tor browser (9150)
static const std::unordered_set<uint16_t> reservedPorts{
9119,9150,9306,9312,9389,9418,9535,9536,9695,
9800,9899,10000,10050,10051,10110,10212,
10933,11001,11112,11235,11371,12222,12223,
13075,13400,13720,13721,13724,13782,13783,
13785,13786,15345,17224,17225,17500,18104,
19788,19812,19813,19814,19999,20000,24465,
24554,26000,27000,27001,27002,27003,27004,
27005,27006,27007,27008,27009,28000};
return (reservedPorts.find(port) != reservedPorts.end());
}
boost::asio::ip::address_v6 GetYggdrasilAddress () boost::asio::ip::address_v6 GetYggdrasilAddress ()
{ {
#if defined(_WIN32) #if defined(_WIN32)
@@ -539,7 +495,7 @@ namespace net
PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr;
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr;
if (GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen)
== ERROR_BUFFER_OVERFLOW) == ERROR_BUFFER_OVERFLOW)
{ {
FREE(pAddresses); FREE(pAddresses);
@@ -550,7 +506,7 @@ namespace net
AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen
); );
if (dwRetVal != NO_ERROR) if(dwRetVal != NO_ERROR)
{ {
LogPrint(eLogError, "NetIface: GetYggdrasilAddress(): enclosed GetAdaptersAddresses() call has failed"); LogPrint(eLogError, "NetIface: GetYggdrasilAddress(): enclosed GetAdaptersAddresses() call has failed");
FREE(pAddresses); FREE(pAddresses);
@@ -558,11 +514,12 @@ namespace net
} }
pCurrAddresses = pAddresses; pCurrAddresses = pAddresses;
while (pCurrAddresses) while(pCurrAddresses)
{ {
PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress;
pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast = pCurrAddresses->FirstUnicastAddress;
while (pUnicast != nullptr) for(int i = 0; pUnicast != nullptr; ++i)
{ {
LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr;
sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr;
@@ -606,7 +563,7 @@ namespace net
LogPrint(eLogError, "NetIface: Exception while searching Yggdrasill address using ifaddr: ", ex.what()); LogPrint(eLogError, "NetIface: Exception while searching Yggdrasill address using ifaddr: ", ex.what());
} }
LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found"); LogPrint(eLogWarning, "NetIface: Interface with Yggdrasil network address not found");
if (addrs) freeifaddrs(addrs); if(addrs) freeifaddrs(addrs);
return boost::asio::ip::address_v6 (); return boost::asio::ip::address_v6 ();
#endif #endif
} }
@@ -626,7 +583,7 @@ namespace net
{ {
// https://en.wikipedia.org/wiki/Reserved_IP_addresses // https://en.wikipedia.org/wiki/Reserved_IP_addresses
if (host.is_unspecified ()) return false; if (host.is_unspecified ()) return false;
if (host.is_v4()) if(host.is_v4())
{ {
static const std::vector< std::pair<uint32_t, uint32_t> > reservedIPv4Ranges { static const std::vector< std::pair<uint32_t, uint32_t> > reservedIPv4Ranges {
address_pair_v4("0.0.0.0", "0.255.255.255"), address_pair_v4("0.0.0.0", "0.255.255.255"),
@@ -646,12 +603,12 @@ namespace net
}; };
uint32_t ipv4_address = host.to_v4 ().to_ulong (); uint32_t ipv4_address = host.to_v4 ().to_ulong ();
for (const auto& it : reservedIPv4Ranges) { for(const auto& it : reservedIPv4Ranges) {
if (ipv4_address >= it.first && ipv4_address <= it.second) if (ipv4_address >= it.first && ipv4_address <= it.second)
return true; return true;
} }
} }
if (host.is_v6()) if(host.is_v6())
{ {
static const std::vector< std::pair<boost::asio::ip::address_v6::bytes_type, boost::asio::ip::address_v6::bytes_type> > reservedIPv6Ranges { static const std::vector< std::pair<boost::asio::ip::address_v6::bytes_type, boost::asio::ip::address_v6::bytes_type> > reservedIPv6Ranges {
address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"), address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"),
@@ -663,7 +620,7 @@ namespace net
}; };
boost::asio::ip::address_v6::bytes_type ipv6_address = host.to_v6 ().to_bytes (); boost::asio::ip::address_v6::bytes_type ipv6_address = host.to_v6 ().to_bytes ();
for (const auto& it : reservedIPv6Ranges) { for(const auto& it : reservedIPv6Ranges) {
if (ipv6_address >= it.first && ipv6_address <= it.second) if (ipv6_address >= it.first && ipv6_address <= it.second)
return true; return true;
} }

View File

@@ -224,7 +224,6 @@ namespace util
bool IsLocalAddress (const boost::asio::ip::address& addr); bool IsLocalAddress (const boost::asio::ip::address& addr);
bool IsInReservedRange (const boost::asio::ip::address& host); bool IsInReservedRange (const boost::asio::ip::address& host);
bool IsYggdrasilAddress (const boost::asio::ip::address& addr); bool IsYggdrasilAddress (const boost::asio::ip::address& addr);
bool IsPortInReservedRange (const uint16_t port) noexcept;
} }
} }
} }

View File

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

View File

@@ -63,19 +63,18 @@ namespace client
if (sam) if (sam)
{ {
std::string samAddr; i2p::config::GetOption("sam.address", samAddr); std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
uint16_t samPortTCP; i2p::config::GetOption("sam.port", samPortTCP); uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
uint16_t samPortUDP; i2p::config::GetOption("sam.portudp", samPortUDP);
bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread); bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread);
LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP, "]"); LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":", samPort);
try try
{ {
m_SamBridge = new SAMBridge (samAddr, samPortTCP, samPortUDP, singleThread); m_SamBridge = new SAMBridge (samAddr, samPort, singleThread);
m_SamBridge->Start (); m_SamBridge->Start ();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what()); LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP,"]: ", e.what ()); ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ());
} }
} }

View File

@@ -113,7 +113,7 @@ namespace proxy {
i2p::http::URL m_ProxyURL; i2p::http::URL m_ProxyURL;
i2p::http::URL m_RequestURL; i2p::http::URL m_RequestURL;
uint8_t m_socks_buf[255+8]; // for socks request/response uint8_t m_socks_buf[255+8]; // for socks request/response
int m_req_len; ssize_t m_req_len;
i2p::http::URL m_ClientRequestURL; i2p::http::URL m_ClientRequestURL;
i2p::http::HTTPReq m_ClientRequest; i2p::http::HTTPReq m_ClientRequest;
i2p::http::HTTPRes m_ClientResponse; i2p::http::HTTPRes m_ClientResponse;
@@ -238,33 +238,9 @@ namespace proxy {
std::string value = params["i2paddresshelper"]; std::string value = params["i2paddresshelper"];
len += value.length(); len += value.length();
b64 = i2p::http::UrlDecode(value); b64 = i2p::http::UrlDecode(value);
// if we need update exists, request formed with update param // if we need update exists, request formed with update param
if (params["update"] == "true") if (params["update"] == "true") { len += std::strlen("&update=true"); confirm = true; }
{ if (pos != 0 && url.query[pos-1] == '&') { pos--; len++; } // if helper is not only one query option
len += std::strlen("&update=true");
confirm = true;
}
// if helper is not only one query option and it placed after user's query
if (pos != 0 && url.query[pos-1] == '&')
{
pos--;
len++;
}
// if helper is not only one query option and it placed before user's query
else if (pos == 0 && url.query.length () > len && url.query[len] == '&')
{
// we don't touch the '?' but remove the trailing '&'
len++;
}
else
{
// there is no more query options, resetting hasquery flag
url.hasquery = false;
}
// reset hasquery flag and remove addresshelper from URL
url.query.replace(pos, len, ""); url.query.replace(pos, len, "");
return true; return true;
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, 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
* *
@@ -72,7 +72,7 @@ namespace client
bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound) bool MatchedTunnelDestination::SelectPeers(i2p::tunnel::Path & path, int hops, bool inbound)
{ {
auto pool = GetTunnelPool(); auto pool = GetTunnelPool();
if(!pool || !pool->StandardSelectPeers(path, hops, inbound, if(!i2p::tunnel::StandardSelectPeers(path, hops, inbound,
std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1, std::placeholders::_2))) std::bind(&i2p::tunnel::TunnelPool::SelectNextHop, pool, std::placeholders::_1, std::placeholders::_2)))
return false; return false;
// more here for outbound tunnels // more here for outbound tunnels

View File

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

View File

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

12
tests/.gitignore vendored
View File

@@ -1,12 +0,0 @@
/test-http-merge_chunked
/test-http-req
/test-http-res
/test-http-url
/test-http-url_decode
/test-gost
/test-gost-sig
/test-base-64
/test-x25519
/test-aeadchacha20poly1305
/test-blinding
/test-elligator

View File

@@ -4,9 +4,9 @@ include_directories(${CHECK_INCLUDE_DIRS})
# Compiler flags: # Compiler flags:
if(APPLE) if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -Wl,-undefined,dynamic_lookup") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -Wl,-undefined,dynamic_lookup")
else() else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -Wl,--unresolved-symbols=ignore-in-object-files") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -D_GLIBCXX_USE_NANOSLEEP=1 -Wl,--unresolved-symbols=ignore-in-object-files")
endif() endif()
set(TEST_PATH ${CMAKE_CURRENT_BINARY_DIR}) set(TEST_PATH ${CMAKE_CURRENT_BINARY_DIR})
@@ -18,50 +18,80 @@ include_directories(
) )
set(test-http-merge_chunked_SRCS set(test-http-merge_chunked_SRCS
../libi2pd/HTTP.cpp
test-http-merge_chunked.cpp test-http-merge_chunked.cpp
) )
set(test-http-req_SRCS set(test-http-req_SRCS
../libi2pd/HTTP.cpp
test-http-req.cpp test-http-req.cpp
) )
set(test-http-res_SRCS set(test-http-res_SRCS
../libi2pd/HTTP.cpp
test-http-res.cpp test-http-res.cpp
) )
set(test-http-url_decode_SRCS set(test-http-url_decode_SRCS
../libi2pd/HTTP.cpp
test-http-url_decode.cpp test-http-url_decode.cpp
) )
set(test-http-url_SRCS set(test-http-url_SRCS
../libi2pd/HTTP.cpp
test-http-url.cpp test-http-url.cpp
) )
set(test-base-64_SRCS set(test-base-64_SRCS
../libi2pd/Base.cpp
test-base-64.cpp test-base-64.cpp
) )
set(test-gost_SRCS set(test-gost_SRCS
../libi2pd/Gost.cpp
../libi2pd/I2PEndian.cpp
test-gost.cpp test-gost.cpp
) )
set(test-gost-sig_SRCS set(test-gost-sig_SRCS
../libi2pd/Gost.cpp
../libi2pd/I2PEndian.cpp
../libi2pd/Crypto.cpp
../libi2pd/Log.cpp
test-gost-sig.cpp test-gost-sig.cpp
) )
set(test-x25519_SRCS set(test-x25519_SRCS
../libi2pd/Ed25519.cpp
../libi2pd/I2PEndian.cpp
../libi2pd/Log.cpp
../libi2pd/Crypto.cpp
test-x25519.cpp test-x25519.cpp
) )
set(test-aeadchacha20poly1305_SRCS set(test-aeadchacha20poly1305_SRCS
../libi2pd/Crypto.cpp
../libi2pd/ChaCha20.cpp
../libi2pd/Poly1305.cpp
test-aeadchacha20poly1305.cpp test-aeadchacha20poly1305.cpp
) )
set(test-blinding_SRCS set(test-blinding_SRCS
../libi2pd/Crypto.cpp
../libi2pd/Blinding.cpp
../libi2pd/Ed25519.cpp
../libi2pd/I2PEndian.cpp
../libi2pd/Log.cpp
../libi2pd/util.cpp
../libi2pd/Identity.cpp
../libi2pd/Signature.cpp
../libi2pd/Timestamp.cpp
test-blinding.cpp test-blinding.cpp
) )
SET(test-elligator_SRCS SET(test-elligator_SRCS
../libi2pd/Elligator.cpp
../libi2pd/Crypto.cpp
test-elligator.cpp test-elligator.cpp
) )
@@ -79,23 +109,15 @@ add_executable(test-blinding ${test-blinding_SRCS})
add_executable(test-elligator ${test-elligator_SRCS}) add_executable(test-elligator ${test-elligator_SRCS})
set(LIBS set(LIBS
libi2pd
${Boost_LIBRARIES} ${Boost_LIBRARIES}
OpenSSL::SSL
OpenSSL::Crypto
ZLIB::ZLIB
Threads::Threads
${CHECK_LDFLAGS} ${CHECK_LDFLAGS}
${CMAKE_REQUIRED_LIBRARIES} ${CMAKE_REQUIRED_LIBRARIES}
OpenSSL::SSL
OpenSSL::Crypto
Threads::Threads
) )
target_link_libraries(test-http-merge_chunked ${LIBS}) target_link_libraries(test-gost OpenSSL::Crypto Threads::Threads)
target_link_libraries(test-http-req ${LIBS})
target_link_libraries(test-http-res ${LIBS})
target_link_libraries(test-http-url_decode ${LIBS})
target_link_libraries(test-http-url ${LIBS})
target_link_libraries(test-base-64 ${LIBS})
target_link_libraries(test-gost ${LIBS})
target_link_libraries(test-gost-sig ${LIBS}) target_link_libraries(test-gost-sig ${LIBS})
target_link_libraries(test-x25519 ${LIBS}) target_link_libraries(test-x25519 ${LIBS})
target_link_libraries(test-aeadchacha20poly1305 ${LIBS}) target_link_libraries(test-aeadchacha20poly1305 ${LIBS})

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