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
76 changed files with 1171 additions and 2454 deletions

View File

@@ -5,7 +5,7 @@ on: [push, pull_request]
jobs: jobs:
build-make: build-make:
name: Make with USE_UPNP=${{ matrix.with_upnp }} name: Make with USE_UPNP=${{ matrix.with_upnp }}
runs-on: ubuntu-18.04 runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
@@ -14,14 +14,13 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install packages - name: install packages
run: | run: |
sudo add-apt-repository ppa:mhier/libboost-latest
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev sudo apt-get install build-essential libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application - name: build application
run: make USE_UPNP=${{ matrix.with_upnp }} -j3 run: make USE_UPNP=${{ matrix.with_upnp }} -j3
build-cmake: build-cmake:
name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }} name: CMake with -DWITH_UPNP=${{ matrix.with_upnp }}
runs-on: ubuntu-18.04 runs-on: ubuntu-20.04
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
@@ -30,11 +29,26 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: install packages - name: install packages
run: | run: |
sudo add-apt-repository ppa:mhier/libboost-latest
sudo apt-get update sudo apt-get update
sudo apt-get install build-essential cmake libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev sudo apt-get install build-essential cmake libboost-all-dev libminiupnpc-dev libssl-dev zlib1g-dev
- name: build application - name: build application
run: | run: |
cd build cd build
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

@@ -57,7 +57,6 @@ 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:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -91,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,44 +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.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
@@ -47,7 +9,7 @@
- Set rejection code 30 if tunnel with id already exists - Set rejection code 30 if tunnel with id already exists
- Network status is always OK if peer test msg 5 received - Network status is always OK if peer test msg 5 received
### Fixed ### Fixed
- UPnP crash if SSU2 or NTCP2 is disabled - UPnP crash if SSU2 or NTCP2 is disabled
- Crash on termination for some platforms - Crash on termination for some platforms
## [2.45.0] - 2023-01-03 ## [2.45.0] - 2023-01-03

View File

@@ -118,9 +118,9 @@ obj/%.o: %.cpp | mk_obj_dir
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(ARLIB_LANG)
$(CXX) -o $@ $(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

@@ -33,34 +33,23 @@ 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)
LDLIBS += -lminiupnpc
NEEDED_CXXFLAGS += -DUSE_UPNP NEEDED_CXXFLAGS += -DUSE_UPNP
endif 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
ifeq ($(USE_AESNI),yes) ifeq ($(USE_AESNI),yes)
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
NEEDED_CXXFLAGS += -D__AES__ -maes NEEDED_CXXFLAGS += -D__AES__ -maes

3
build/.gitignore vendored
View File

@@ -1,7 +1,5 @@
# Various generated files # Various generated files
/CMakeFiles/ /CMakeFiles/
/Testing/
/tests/
/i2pd /i2pd
/libi2pd.a /libi2pd.a
/libi2pdclient.a /libi2pdclient.a
@@ -10,7 +8,6 @@
/CMakeCache.txt /CMakeCache.txt
/CPackConfig.cmake /CPackConfig.cmake
/CPackSourceConfig.cmake /CPackSourceConfig.cmake
/CTestTestfile.cmake
/install_manifest.txt /install_manifest.txt
/arch.c /arch.c
# windows build script # windows build script

View File

@@ -178,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()

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

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]

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.46.1 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,12 +158,6 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* 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,6 +1,6 @@
Name: i2pd Name: i2pd
Version: 2.46.1 Version: 2.45.1
Release: 2%{?dist} Release: 1%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@@ -155,12 +155,6 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* 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

@@ -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())
@@ -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++;
} }

20
debian/changelog vendored
View File

@@ -1,26 +1,8 @@
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", "Գաղտնագրի տեսակը"},
@@ -113,10 +112,11 @@ namespace armenian // language namespace
{"Invalid", "Անվավեր"}, {"Invalid", "Անվավեր"},
{"Store type", "Պահեստավորման տեսակը"}, {"Store type", "Պահեստավորման տեսակը"},
{"Expires", "Սպառվում է"}, {"Expires", "Սպառվում է"},
{"Non Expired Leases", "Չսպառված Lease-եր"}, {"Non Expired Leases", "Չսպառված Lease-եր"},
{"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,6 +58,7 @@ 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"},
@@ -116,6 +117,7 @@ namespace german // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Enddatum"}, {"EndDate", "Enddatum"},
{"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"},
{"Decline transit tunnels", "Transittunnel ablehnen"}, {"Decline transit tunnels", "Transittunnel ablehnen"},
@@ -145,6 +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 5 seconds", "Du wirst in 5 Sekunden weitergeleitet"},
{"Transit tunnels count must not exceed 65535", "Es darf maximal 65535 Transittunnel geben"},
{"Back to commands list", "Zurück zur Befehlsliste"}, {"Back to commands list", "Zurück zur Befehlsliste"},
{"Register at reg.i2p", "Auf reg.i2p registrieren"}, {"Register at reg.i2p", "Auf reg.i2p registrieren"},
{"Description", "Beschreibung"}, {"Description", "Beschreibung"},
@@ -162,24 +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"},
{"Invalid request URI", "Ungültige Anfrage-URI"}, {"addresshelper is not supported", "Addresshelfer wird nicht unterstützt"},
{"Host", "Host"},
{"added to router's addressbook from helper", "vom Helfer zum Router-Adressbuch hinzugefügt"},
{"Click here to proceed:", "Klicke hier um fortzufahren:"},
{"Continue", "Fortsetzen"},
{"Addresshelper found", "Adresshelfer gefunden"},
{"already in router's addressbook", "bereits im Adressbuch des Routers"},
{"Click here to update record:", "Klicke hier, um den Eintrag zu aktualisieren:"},
{"invalid request uri", "ungültige Anfrage-URI"},
{"Can't detect destination host from request", "Kann 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

@@ -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
* *
@@ -23,23 +23,20 @@ namespace i18n
}; };
// Add localization here with language name as namespace // Add localization here with language name as namespace
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace czech { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace czech { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
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 russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace portuguese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace spanish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace swedish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace turkish { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
/** /**
* That map contains international language name lower-case, name in it's language and it's code * That map contains international language name lower-case, name in it's language and it's code
@@ -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,6 +58,7 @@ 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"},
@@ -116,9 +117,9 @@ namespace italian // language namespace
{"Gateway", "Gateway"}, {"Gateway", "Gateway"},
{"TunnelID", "TunnelID"}, {"TunnelID", "TunnelID"},
{"EndDate", "Data di fine"}, {"EndDate", "Data di fine"},
{"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"},
@@ -146,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"},
@@ -165,26 +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"},
{"To add host <b>%s</b> in router's addressbook, click here: <a href=\"%s%s%s\">Continue</a>.", "Per aggiungere host <b>%s</b> nella rubrica del router, clicca qui: <a href=\"%s%s%s\">Continua</a>."}, {"addresshelper is not supported", "addresshelper non è supportato"},
{"Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href=\"%s%s%s&update=true\">Continue</a>.", "L'host %s è <font color=red>già nella rubrica del router</font>. Clicca qui per aggiornare il record: <a href=\"%s%s%s&update=true\">Continua</a>."}, {"Host", "Host"},
{"Invalid request URI", "URI della richiesta non valido"}, {"added to router's addressbook from helper", "aggiunto alla rubrica tramite l'helper"},
{"Click here to proceed:", "Clicca qui per procedere:"},
{"Continue", "Continua"},
{"Addresshelper found", "Addresshelper trovato"},
{"already in router's addressbook", "già presente nella rubrica del router"},
{"Click here to update record:", "Clicca qui per aggiornare l'elemento:"},
{"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", "Caminho 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únel de trânsito"},
{"Accept transit tunnels", "Aceitar túnel 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 nos 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");
@@ -285,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");
@@ -776,17 +763,9 @@ namespace client
request->requestTime = ts; request->requestTime = ts;
if (!SendLeaseSetRequest (dest, floodfill, request)) if (!SendLeaseSetRequest (dest, floodfill, request))
{ {
// try another // request failed
LogPrint (eLogWarning, "Destination: Couldn't send LeaseSet request to ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another"); m_LeaseSetRequests.erase (ret.first);
request->excluded.insert (floodfill->GetIdentHash ()); if (requestComplete) requestComplete (nullptr);
floodfill = i2p::data::netdb.GetClosestFloodfill (dest, request->excluded);
if (!SendLeaseSetRequest (dest, floodfill, request))
{
// request failed
LogPrint (eLogWarning, "Destination: LeaseSet request for ", dest.ToBase32 (), " was not sent");
m_LeaseSetRequests.erase (ret.first);
if (requestComplete) requestComplete (nullptr);
}
} }
} }
else // duplicate else // duplicate
@@ -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)
{ {
@@ -1173,11 +1152,11 @@ namespace client
}, },
dest, port); dest, port);
while (!done) while (!done)
{ {
std::unique_lock<std::mutex> l(streamRequestCompleteMutex); std::unique_lock<std::mutex> l(streamRequestCompleteMutex);
if (!done) if (!done)
streamRequestComplete.wait (l); streamRequestComplete.wait (l);
} }
return stream; return stream;
} }

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,8 +335,7 @@ 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;
} }
case eECIESx25519BlkTermination: case eECIESx25519BlkTermination:

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
* *
@@ -160,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);
@@ -219,10 +218,8 @@ namespace http
} }
} }
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;
@@ -350,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,11 +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;
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag("") {}; URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), query(""), frag("") {};
/** /**
* @brief Tries to parse url from string * @brief Tries to parse url from string
@@ -102,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

@@ -1,271 +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), hash (nullptr)
{
}
DHTNode::~DHTNode ()
{
if (zero) delete zero;
if (one) delete one;
if (hash) delete hash;
}
void DHTNode::MoveHashUp (bool fromOne)
{
DHTNode *& side = fromOne ? one : zero;
if (side)
{
if (hash) delete hash; // shouldn't happen
hash = side->hash;
side->hash = nullptr;
delete side;
side = nullptr;
}
}
DHTTable::DHTTable ():
m_Size (0)
{
m_Root = new DHTNode;
}
DHTTable::~DHTTable ()
{
delete m_Root;
}
DHTNode * DHTTable::Insert (const IdentHash& h)
{
return Insert (new IdentHash (h), m_Root, 0);
}
DHTNode * DHTTable::Insert (IdentHash * h, DHTNode * root, int level)
{
if (root->hash)
{
if (*(root->hash) == *h)
{
delete h;
return root;
}
auto h2 = root->hash;
root->hash = nullptr; m_Size--;
int bit1, bit2;
do
{
bit1 = h->GetBit (level);
bit2 = h2->GetBit (level);
if (bit1 == bit2)
{
if (bit1)
{
if (root->one) return nullptr; // someting wrong
root->one = new DHTNode;
root = root->one;
}
else
{
if (root->zero) return nullptr; // 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 (h2, root->zero, level + 1);
return Insert (h, root->one, level + 1);
}
else
{
Insert (h2, root->one, level + 1);
return Insert (h, root->zero, level + 1);
}
}
else
{
if (!root->zero && !root->one)
{
root->hash = h; m_Size++;
return root;
}
int bit = h->GetBit (level);
if (bit)
{
if (!root->one)
root->one = new DHTNode;
return Insert (h, root->one, level + 1);
}
else
{
if (!root->zero)
root->zero = new DHTNode;
return Insert (h, root->zero, level + 1);
}
}
return nullptr;
}
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->hash && *(root->hash) == h)
{
delete root->hash; root->hash = 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->hash)
root->MoveHashUp (false);
}
else if (root->one->hash && !root->zero)
root->MoveHashUp (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->hash)
root->MoveHashUp (true);
}
else if (root->zero->hash && !root->one)
root->MoveHashUp (false);
return true;
}
}
}
return false;
}
IdentHash * DHTTable::FindClosest (const IdentHash& h)
{
return FindClosest (h, m_Root, 0);
}
IdentHash * DHTTable::FindClosest (const IdentHash& h, DHTNode * root, int level)
{
if (root->hash) return root->hash;
int bit = h.GetBit (level);
if (bit)
{
if (root->one)
return FindClosest (h, root->one, level + 1);
if (root->zero)
return FindClosest (h, root->zero, level + 1);
}
else
{
if (root->zero)
return FindClosest (h, root->zero, level + 1);
if (root->one)
return FindClosest (h, root->one, level + 1);
}
return nullptr;
}
std::vector<IdentHash *> DHTTable::FindClosest (const IdentHash& h, size_t num)
{
std::vector<IdentHash *> vec;
if (num > 0)
FindClosest (h, num, m_Root, 0, vec);
return vec;
}
void DHTTable::FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<IdentHash *>& hashes)
{
if (hashes.size () >= num) return;
if (root->hash)
{
hashes.push_back (root->hash);
return;
}
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::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->hash)
{
if (!root->zero && !root->one)
s << '>' << GetIdentHashAbbreviation (*(root->hash));
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,67 +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 "Identity.h"
// Kademlia DHT (XOR distance)
namespace i2p
{
namespace data
{
struct DHTNode
{
DHTNode * zero, * one;
IdentHash * hash;
DHTNode ();
~DHTNode ();
bool IsEmpty () const { return !zero && !one && !hash; };
void MoveHashUp (bool fromOne);
};
class DHTTable
{
public:
DHTTable ();
~DHTTable ();
DHTNode * Insert (const IdentHash& h);
bool Remove (const IdentHash& h);
IdentHash * FindClosest (const IdentHash& h);
std::vector<IdentHash *> FindClosest (const IdentHash& h, size_t num);
void Print (std::stringstream& s);
size_t GetSize () const { return m_Size; };
private:
DHTNode * Insert (IdentHash * h, DHTNode * root, int level); // recursive
bool Remove (const IdentHash& h, DHTNode * root, int level);
IdentHash * FindClosest (const IdentHash& h, DHTNode * root, int level);
void FindClosest (const IdentHash& h, size_t num, DHTNode * root, int level, std::vector<IdentHash *>& hashes);
void Print (std::stringstream& s, DHTNode * root, int level);
private:
DHTNode * m_Root;
size_t m_Size;
};
}
}
#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) break;
{
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;
}
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;

View File

@@ -85,7 +85,8 @@ 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 ();
@@ -152,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)
{ {
@@ -168,17 +169,14 @@ 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);
@@ -194,8 +192,7 @@ namespace data
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true; if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
} }
else if (i2p::context.GetLastUpdateTime () > lastPublish || else if (i2p::context.GetLastUpdateTime () > lastPublish ||
ts - lastPublish >= NETDB_PUBLISH_INTERVAL || ts - lastPublish >= NETDB_PUBLISH_INTERVAL)
ts + NETDB_PUBLISH_INTERVAL < lastPublish)
{ {
// new publish // new publish
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
@@ -211,7 +208,7 @@ namespace data
} }
} }
if (ts - lastExploratory >= 30 || ts + 30 < lastExploratory) // exploratory every 30 seconds if (ts - lastExploratory >= 30) // exploratory every 30 seconds
{ {
auto numRouters = m_RouterInfos.size (); auto numRouters = m_RouterInfos.size ();
if (!numRouters) if (!numRouters)
@@ -276,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);
}
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
@@ -315,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;
@@ -447,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 ()
@@ -647,19 +619,13 @@ 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 ()) it.second->SaveToFile (m_Storage.Path(ident));
{
// we have something to save
it.second->SaveToFile (m_Storage.Path(ident));
it.second->SetUnreachable (false);
it.second->DeleteBuffer ();
}
it.second->SetUpdated (false); it.second->SetUpdated (false);
it.second->SetUnreachable (false);
it.second->DeleteBuffer ();
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)))
@@ -705,12 +671,12 @@ 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 ())
{
if (m_PersistProfiles) it->second->SaveProfile ();
it = m_RouterInfos.erase (it); it = m_RouterInfos.erase (it);
else continue;
{ }
it->second->DropProfile (); ++it;
it++;
}
} }
} }
// clean up expired floodfills or not floodfills anymore // clean up expired floodfills or not floodfills anymore
@@ -720,7 +686,7 @@ namespace data
if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ()) if ((*it)->IsUnreachable () || !(*it)->IsFloodfill ())
it = m_Floodfills.erase (it); it = m_Floodfills.erase (it);
else else
it++; ++it;
} }
} }
} }
@@ -845,7 +811,7 @@ namespace data
{ {
LogPrint (eLogError, "NetDb: Database store message is too long ", len); LogPrint (eLogError, "NetDb: Database store message is too long ", len);
return; return;
} }
if (!m->from) // unsolicited LS must be received directly if (!m->from) // unsolicited LS must be received directly
{ {
if (storeType == NETDB_STORE_TYPE_LEASESET) // 1 if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
@@ -855,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);
} }
} }
@@ -1040,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);
} }
} }
@@ -1367,7 +1334,7 @@ namespace data
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) for (const auto& it: m_Floodfills)
{ {
if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ()) if (!it->IsUnreachable ())
{ {
XORMetric m = destKey ^ it->GetIdentHash (); XORMetric m = destKey ^ it->GetIdentHash ();
if (m < minMetric && !excluded.count (it->GetIdentHash ())) if (m < minMetric && !excluded.count (it->GetIdentHash ()))
@@ -1398,7 +1365,7 @@ namespace data
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
for (const auto& it: m_Floodfills) for (const auto& it: m_Floodfills)
{ {
if (!it->IsUnreachable () && !it->GetProfile ()->IsUnreachable ()) if (!it->IsUnreachable ())
{ {
XORMetric m = destKey ^ it->GetIdentHash (); XORMetric m = destKey ^ it->GetIdentHash ();
if (closeThanUsOnly && ourMetric < m) continue; if (closeThanUsOnly && ourMetric < m) continue;
@@ -1480,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
* *
@@ -48,8 +48,8 @@ namespace data
const int NETDB_PUBLISH_INTERVAL = 60 * 40; const int NETDB_PUBLISH_INTERVAL = 60 * 40;
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 51); // 0.9.51 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, 51); // 0.9.51 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 */
@@ -124,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 ()
{ {

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
@@ -142,15 +133,15 @@ namespace data
{ {
UpdateTime (); UpdateTime ();
if (ret > 0) if (ret > 0)
{ {
m_NumTunnelsDeclined++; m_NumTunnelsDeclined++;
m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch (); m_LastDeclineTime = i2p::util::GetSecondsSinceEpoch ();
} }
else else
{ {
m_NumTunnelsAgreed++; m_NumTunnelsAgreed++;
m_LastDeclineTime = 0; m_LastDeclineTime = 0;
} }
} }
void RouterProfile::TunnelNonReplied () void RouterProfile::TunnelNonReplied ()
@@ -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

@@ -85,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)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); if (ssu2Published)
if (!ssu2Port) ssu2Port = port;
if (ssu2Published && ssu2Port)
{ {
boost::asio::ip::address addr; uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!host.empty ()) if (!ssu2Port) ssu2Port = port;
addr = boost::asio::ip::address::from_string (host); routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v4::from_string (host), ssu2Port);
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)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port); bool added = false;
if (!ssu2Port) ssu2Port = port; if (ssu2Published)
if (ssu2Published && ssu2Port)
{ {
boost::asio::ip::address addr; uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!host.empty ()) if (!ssu2Port) ssu2Port = port;
addr = boost::asio::ip::address::from_string (host); if (!host.empty () && ssu2Port)
if (!addr.is_v6()) {
addr = boost::asio::ip::address_v6 (); routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address_v6::from_string (host), ssu2Port);
routerInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, addr, ssu2Port); added = true;
}
} }
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;
} }
} }
} }
@@ -192,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);
@@ -202,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;
} }
@@ -260,7 +250,7 @@ namespace i2p
break; break;
case eRouterStatusTesting: case eRouterStatusTesting:
m_Error = eRouterErrorNone; m_Error = eRouterErrorNone;
break; break;
default: default:
; ;
} }
@@ -282,7 +272,7 @@ namespace i2p
break; break;
case eRouterStatusTesting: case eRouterStatusTesting:
m_ErrorV6 = eRouterErrorNone; m_ErrorV6 = eRouterErrorNone;
break; break;
default: default:
; ;
} }
@@ -296,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;
@@ -306,67 +296,65 @@ 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 ();
updated = true; 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;
}
} }
} }
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 ())
{ {
it->s = m_NTCP2Keys->staticPublicKey; found = true;
memcpy (it->i, m_NTCP2Keys->iv, 16); if (enable)
{
it->s = m_NTCP2Keys->staticPublicKey;
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)
@@ -405,19 +393,47 @@ 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 ())
{ {
it->s = m_SSU2Keys->staticPublicKey; found = true;
it->i = m_SSU2Keys->intro; if (enable)
{
it->s = m_SSU2Keys->staticPublicKey;
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)
@@ -712,69 +728,45 @@ namespace i2p
if (!port) port = SelectRandomPort (); if (!port) port = SelectRandomPort ();
} }
// NTCP2 // NTCP2
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (!foundNTCP2)
if (ntcp2)
{ {
if (!foundNTCP2) bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2)
{ {
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!ntcp2Port) ntcp2Port = port;
bool added = false;
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
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) else
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV6); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV6);
} }
} }
else
m_RouterInfo.RemoveNTCP2Address (false);
// SSU2 // SSU2
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); if (!foundSSU2)
if (ssu2)
{ {
if (!foundSSU2) bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!ssu2Port) ssu2Port = port;
bool added = false;
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published); bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
if (ssu2Published && ssu2Port) if (ssu2Published)
{ {
std::string host; i2p::config::GetOption("host", host); uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!host.empty ()) if (!ssu2Port) ssu2Port = port;
{ m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("::1"), ssu2Port);
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) else
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV6); m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV6);
} }
} }
else m_RouterInfo.EnableV6 ();
m_RouterInfo.RemoveSSU2Address (false);
if (ntcp2 || ssu2)
m_RouterInfo.EnableV6 ();
} }
else else
m_RouterInfo.DisableV6 (); m_RouterInfo.DisableV6 ();
@@ -783,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)
@@ -814,66 +811,40 @@ namespace i2p
if (!port) port = SelectRandomPort (); if (!port) port = SelectRandomPort ();
} }
// NTCP2 // NTCP2
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (!foundNTCP2)
if (ntcp2)
{ {
if (!foundNTCP2) bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2)
{ {
uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!ntcp2Port) ntcp2Port = port;
bool added = false;
bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published); bool ntcp2Published; i2p::config::GetOption("ntcp2.published", ntcp2Published);
if (ntcp2Published && ntcp2Port) if (ntcp2Published)
{ {
std::string host; i2p::config::GetOption("host", host); uint16_t ntcp2Port; i2p::config::GetOption ("ntcp2.port", ntcp2Port);
if (!host.empty ()) if (!ntcp2Port) ntcp2Port = port;
{ m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address::from_string (host), ntcp2Port);
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) else
m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, ntcp2Port, i2p::data::RouterInfo::eV4); m_RouterInfo.AddNTCP2Address (m_NTCP2Keys->staticPublicKey, m_NTCP2Keys->iv, boost::asio::ip::address(), 0, i2p::data::RouterInfo::eV4);
} }
} }
else
m_RouterInfo.RemoveNTCP2Address (true);
// SSU2 // SSU2
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2); if (!foundSSU2)
if (ssu2)
{ {
if (!foundSSU2) bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{ {
uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!ssu2Port) ssu2Port = port;
bool added = false;
bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published); bool ssu2Published; i2p::config::GetOption("ssu2.published", ssu2Published);
std::string host; i2p::config::GetOption("host", host); if (ssu2Published)
if (ssu2Published && ssu2Port)
{ {
std::string host; i2p::config::GetOption("host", host); uint16_t ssu2Port; i2p::config::GetOption ("ssu2.port", ssu2Port);
if (!host.empty ()) if (!ssu2Port) ssu2Port = port;
{ m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, boost::asio::ip::address::from_string ("127.0.0.1"), ssu2Port);
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) else
m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, ssu2Port, i2p::data::RouterInfo::eV4); m_RouterInfo.AddSSU2Address (m_SSU2Keys->staticPublicKey, m_SSU2Keys->intro, i2p::data::RouterInfo::eV4);
} }
} }
else m_RouterInfo.EnableV4 ();
m_RouterInfo.RemoveSSU2Address (true);
if (ntcp2 || ssu2)
m_RouterInfo.EnableV4 ();
} }
else else
m_RouterInfo.DisableV4 (); m_RouterInfo.DisableV4 ();
@@ -927,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];
else if (host.is_v6 ())
addr = (*addresses)[i2p::data::RouterInfo::eNTCP2V6Idx];
if (addr && addr->IsPublishedNTCP2 () && addr->host != host)
{ {
addr->host = host; if (addr && addr->IsPublishedNTCP2 ())
UpdateRouterInfo (); {
bool isYgg1 = i2p::util::net::IsYggdrasilAddress (addr->host);
if (addr->IsV6 () && ((isYgg && isYgg1) || (!isYgg && !isYgg1)))
{
if (addr->host != host)
{
addr->host = host;
updated = true;
}
break;
}
}
} }
if (updated)
UpdateRouterInfo ();
} }
void RouterContext::UpdateStats () void RouterContext::UpdateStats ()
@@ -1006,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));
@@ -1040,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));
}
s2k.close ();
}
if (!m_SSU2Keys) NewSSU2Keys ();
UpdateSSU2Address (true); // enable SSU2
} }
if (updated) else
UpdateRouterInfo (); UpdateSSU2Address (false); // disable SSU2
return true; return true;
} }
@@ -1087,18 +1069,13 @@ namespace i2p
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID)
{ {
if (typeID == eI2NPGarlic)
{
// TODO: implement
LogPrint (eLogWarning, "Router: garlic message in garlic clove. Dropped");
return false;
}
auto msg = CreateI2NPMessage (typeID, payload, len, msgID); auto msg = CreateI2NPMessage (typeID, payload, len, msgID);
if (!msg) return false; if (!msg) return false;
i2p::HandleI2NPMessage (msg); i2p::HandleI2NPMessage (msg);
return true; return true;
} }
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
std::unique_lock<std::mutex> l(m_GarlicMutex); std::unique_lock<std::mutex> l(m_GarlicMutex);

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
* *
@@ -116,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);
@@ -175,12 +177,10 @@ 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);

View File

@@ -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)
@@ -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"))
{ {
@@ -398,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;
@@ -589,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);
@@ -632,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 ())
@@ -688,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 ());
@@ -742,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;
@@ -769,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)
@@ -824,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 ();
@@ -844,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 ();
@@ -926,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
@@ -957,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
@@ -1052,13 +977,13 @@ namespace data
std::shared_ptr<RouterInfo::Address> RouterInfo::NewAddress () const std::shared_ptr<RouterInfo::Address> RouterInfo::NewAddress () const
{ {
return netdb.NewRouterInfoAddress (); return netdb.NewRouterInfoAddress ();
} }
boost::shared_ptr<RouterInfo::Addresses> RouterInfo::NewAddresses () const boost::shared_ptr<RouterInfo::Addresses> RouterInfo::NewAddresses () const
{ {
return netdb.NewRouterInfoAddresses (); return netdb.NewRouterInfoAddresses ();
} }
void RouterInfo::RefreshTimestamp () void RouterInfo::RefreshTimestamp ()
{ {
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
@@ -1344,12 +1269,12 @@ namespace data
{ {
return std::make_shared<Address> (); return std::make_shared<Address> ();
} }
boost::shared_ptr<RouterInfo::Addresses> LocalRouterInfo::NewAddresses () const boost::shared_ptr<RouterInfo::Addresses> LocalRouterInfo::NewAddresses () const
{ {
return boost::make_shared<Addresses> (); return boost::make_shared<Addresses> ();
} }
bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4) bool LocalRouterInfo::AddSSU2Introducer (const Introducer& introducer, bool v4)
{ {
auto addresses = GetAddresses (); auto addresses = GetAddresses ();

View File

@@ -189,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;
@@ -198,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; };
@@ -242,7 +239,7 @@ namespace data
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; };
@@ -251,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;

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));
@@ -821,7 +819,7 @@ namespace transport
m_CleanupTimer.async_wait (std::bind (&SSU2Server::HandleCleanupTimer, m_CleanupTimer.async_wait (std::bind (&SSU2Server::HandleCleanupTimer,
this, std::placeholders::_1)); this, std::placeholders::_1));
} }
void SSU2Server::HandleCleanupTimer (const boost::system::error_code& ecode) void SSU2Server::HandleCleanupTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
@@ -850,15 +848,15 @@ namespace transport
else else
it++; it++;
} }
m_PacketsPool.CleanUpMt (); m_PacketsPool.CleanUpMt ();
m_SentPacketsPool.CleanUp (); m_SentPacketsPool.CleanUp ();
m_IncompleteMessagesPool.CleanUp (); m_IncompleteMessagesPool.CleanUp ();
m_FragmentsPool.CleanUp (); m_FragmentsPool.CleanUp ();
ScheduleCleanup (); ScheduleCleanup ();
} }
} }
void SSU2Server::ScheduleResend (bool more) void SSU2Server::ScheduleResend (bool more)
{ {
m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT : m_ResendTimer.expires_from_now (boost::posix_time::milliseconds (more ? SSU2_RESEND_CHECK_MORE_TIMEOUT :

View File

@@ -100,7 +100,7 @@ namespace transport
i2p::util::MemoryPool<SSU2SentPacket>& GetSentPacketsPool () { return m_SentPacketsPool; }; i2p::util::MemoryPool<SSU2SentPacket>& GetSentPacketsPool () { return m_SentPacketsPool; };
i2p::util::MemoryPool<SSU2IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; }; i2p::util::MemoryPool<SSU2IncompleteMessage>& GetIncompleteMessagesPool () { return m_IncompleteMessagesPool; };
i2p::util::MemoryPool<SSU2IncompleteMessage::Fragment>& GetFragmentsPool () { return m_FragmentsPool; }; i2p::util::MemoryPool<SSU2IncompleteMessage::Fragment>& GetFragmentsPool () { return m_FragmentsPool; };
private: private:
boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint); boost::asio::ip::udp::socket& OpenSocket (const boost::asio::ip::udp::endpoint& localEndpoint);
@@ -116,7 +116,7 @@ namespace transport
void ScheduleCleanup (); void ScheduleCleanup ();
void HandleCleanupTimer (const boost::system::error_code& ecode); void HandleCleanupTimer (const boost::system::error_code& ecode);
void ScheduleResend (bool more); void ScheduleResend (bool more);
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);

View File

@@ -36,34 +36,34 @@ namespace transport
{ {
bool isLast = false; bool isLast = false;
while (outOfSequenceFragments) while (outOfSequenceFragments)
{ {
if (outOfSequenceFragments->fragmentNum == nextFragmentNum) if (outOfSequenceFragments->fragmentNum == nextFragmentNum)
{ {
AttachNextFragment (outOfSequenceFragments->buf, outOfSequenceFragments->len); AttachNextFragment (outOfSequenceFragments->buf, outOfSequenceFragments->len);
isLast = outOfSequenceFragments->isLast; isLast = outOfSequenceFragments->isLast;
if (isLast) if (isLast)
outOfSequenceFragments = nullptr; outOfSequenceFragments = nullptr;
else else
outOfSequenceFragments = outOfSequenceFragments->next; outOfSequenceFragments = outOfSequenceFragments->next;
} }
else else
break; break;
} }
return isLast; return isLast;
} }
void SSU2IncompleteMessage::AddOutOfSequenceFragment (std::shared_ptr<SSU2IncompleteMessage::Fragment> fragment) void SSU2IncompleteMessage::AddOutOfSequenceFragment (std::shared_ptr<SSU2IncompleteMessage::Fragment> fragment)
{ {
if (!fragment || !fragment->fragmentNum) return; // fragment 0 not allowed if (!fragment || !fragment->fragmentNum) return; // fragment 0 not allowed
if (fragment->fragmentNum < nextFragmentNum) return; // already processed if (fragment->fragmentNum < nextFragmentNum) return; // already processed
if (!outOfSequenceFragments) if (!outOfSequenceFragments)
outOfSequenceFragments = fragment; outOfSequenceFragments = fragment;
else else
{ {
auto frag = outOfSequenceFragments; auto frag = outOfSequenceFragments;
std::shared_ptr<Fragment> prev; std::shared_ptr<Fragment> prev;
do do
{ {
if (fragment->fragmentNum < frag->fragmentNum) break; // found if (fragment->fragmentNum < frag->fragmentNum) break; // found
if (fragment->fragmentNum == frag->fragmentNum) return; // duplicate if (fragment->fragmentNum == frag->fragmentNum) return; // duplicate
prev = frag; frag = frag->next; prev = frag; frag = frag->next;
@@ -71,21 +71,21 @@ namespace transport
while (frag); while (frag);
fragment->next = frag; fragment->next = frag;
if (prev) if (prev)
prev->next = fragment; prev->next = fragment;
else else
outOfSequenceFragments = fragment; outOfSequenceFragments = fragment;
} }
lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
} }
SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter, SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr): std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
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;
@@ -1804,7 +1795,7 @@ namespace transport
{ {
LogPrint (eLogWarning, "SSU2: Invalid follow-on fragment num ", fragmentNum); LogPrint (eLogWarning, "SSU2: Invalid follow-on fragment num ", fragmentNum);
return; return;
} }
bool isLast = buf[0] & 0x01; bool isLast = buf[0] & 0x01;
uint32_t msgID; memcpy (&msgID, buf + 1, 4); uint32_t msgID; memcpy (&msgID, buf + 1, 4);
auto it = m_IncompleteMessages.find (msgID); auto it = m_IncompleteMessages.find (msgID);
@@ -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]);
@@ -2306,21 +2298,21 @@ 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
if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)m_LastActivityTimestamp).second) if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)m_LastActivityTimestamp).second)
m_Handler.PutNextMessage (std::move (msg)); m_Handler.PutNextMessage (std::move (msg));
else else
LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received"); LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received");
} }
else else
LogPrint (eLogDebug, "SSU2: Message ", msgID, " expired"); LogPrint (eLogDebug, "SSU2: Message ", msgID, " expired");
} }
bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep) bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep)
{ {
if (size < 2) return false; if (size < 2) return false;
@@ -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) it++;
break;
else
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,25 +2757,15 @@ 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) if (*it == packetNum + 1)
{ {
// first out of sequence packet is in sequence now packetNum++;
packetNum++; it++; it = m_OutOfSequencePackets.erase (it);
while (it != m_OutOfSequencePackets.end ())
{
if (*it == packetNum + 1)
{
packetNum++;
it++;
}
else // next out of sequence
break;
}
m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it);
} }
else
break;
} }
m_ReceivePacketNum = packetNum; m_ReceivePacketNum = packetNum;
} }
@@ -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,12 +48,9 @@ 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 = 510; // 2*255 ack + nack
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
const int SSU2_SEND_DATETIME_NUM_PACKETS = 250;
// flags // flags
const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01;
@@ -318,7 +315,7 @@ namespace transport
void HandleRelayResponse (const uint8_t * buf, size_t len); void HandleRelayResponse (const uint8_t * buf, size_t len);
void HandlePeerTest (const uint8_t * buf, size_t len); void HandlePeerTest (const uint8_t * buf, size_t len);
void HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg); void HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg);
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r); size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
size_t CreateAckBlock (uint8_t * buf, size_t len); size_t CreateAckBlock (uint8_t * buf, size_t len);
@@ -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
* *
@@ -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
{
// 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; return i2p::data::netdb.FindRouter (ident);
}
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

@@ -332,9 +332,7 @@ namespace tunnel
Tunnels tunnels; Tunnels tunnels;
Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), 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 ()
@@ -439,11 +437,11 @@ namespace tunnel
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second) if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
m_TransitTunnels.push_back (tunnel); m_TransitTunnels.push_back (tunnel);
else else
{ {
LogPrint (eLogError, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists"); LogPrint (eLogError, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " already exists");
return false; return false;
} }
return true; return true;
} }
void Tunnels::Start () void Tunnels::Start ()
@@ -537,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 ();
@@ -592,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
@@ -660,38 +655,41 @@ namespace tunnel
} }
} }
void Tunnels::ManageOutboundTunnels (uint64_t ts) void Tunnels::ManageOutboundTunnels ()
{ {
for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();) uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
{ {
auto tunnel = *it; for (auto it = m_OutboundTunnels.begin (); it != m_OutboundTunnels.end ();)
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{ {
LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired"); auto tunnel = *it;
auto pool = tunnel->GetTunnelPool (); if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
if (pool)
pool->TunnelExpired (tunnel);
// we don't have outbound tunnels in m_Tunnels
it = m_OutboundTunnels.erase (it);
}
else
{
if (tunnel->IsEstablished ())
{ {
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
{ auto pool = tunnel->GetTunnelPool ();
auto pool = tunnel->GetTunnelPool (); if (pool)
// let it die if the tunnel pool has been reconfigured and this is old pool->TunnelExpired (tunnel);
if (pool && tunnel->GetNumHops() == pool->GetNumOutboundHops()) // we don't have outbound tunnels in m_Tunnels
{ it = m_OutboundTunnels.erase (it);
tunnel->SetRecreated (true); }
pool->RecreateOutboundTunnel (tunnel); else
} {
} if (tunnel->IsEstablished ())
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) {
tunnel->SetState (eTunnelStateExpiring); if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
{
auto pool = tunnel->GetTunnelPool ();
// let it die if the tunnel pool has been reconfigured and this is old
if (pool && tunnel->GetNumHops() == pool->GetNumOutboundHops())
{
tunnel->SetRecreated (true);
pool->RecreateOutboundTunnel (tunnel);
}
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
}
++it;
} }
++it;
} }
} }
@@ -711,42 +709,44 @@ namespace tunnel
} }
} }
void Tunnels::ManageInboundTunnels (uint64_t ts) void Tunnels::ManageInboundTunnels ()
{ {
for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();) uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
{ {
auto tunnel = *it; for (auto it = m_InboundTunnels.begin (); it != m_InboundTunnels.end ();)
if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT ||
ts + TUNNEL_EXPIRATION_TIMEOUT < tunnel->GetCreationTime ())
{ {
LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired"); auto tunnel = *it;
auto pool = tunnel->GetTunnelPool (); if (ts > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
if (pool)
pool->TunnelExpired (tunnel);
m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_InboundTunnels.erase (it);
}
else
{
if (tunnel->IsEstablished ())
{ {
if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) LogPrint (eLogDebug, "Tunnel: Tunnel with id ", tunnel->GetTunnelID (), " expired");
{ auto pool = tunnel->GetTunnelPool ();
auto pool = tunnel->GetTunnelPool (); if (pool)
// let it die if the tunnel pool was reconfigured and has different number of hops pool->TunnelExpired (tunnel);
if (pool && tunnel->GetNumHops() == pool->GetNumInboundHops()) m_Tunnels.erase (tunnel->GetTunnelID ());
{ it = m_InboundTunnels.erase (it);
tunnel->SetRecreated (true); }
pool->RecreateInboundTunnel (tunnel); else
} {
} if (tunnel->IsEstablished ())
{
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) if (!tunnel->IsRecreated () && ts + TUNNEL_RECREATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring); {
else // we don't need to cleanup expiring tunnels auto pool = tunnel->GetTunnelPool ();
tunnel->Cleanup (); // let it die if the tunnel pool was reconfigured and has different number of hops
if (pool && tunnel->GetNumHops() == pool->GetNumInboundHops())
{
tunnel->SetRecreated (true);
pool->RecreateInboundTunnel (tunnel);
}
}
if (ts + TUNNEL_EXPIRATION_THRESHOLD > tunnel->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT)
tunnel->SetState (eTunnelStateExpiring);
else // we don't need to cleanup expiring tunnels
tunnel->Cleanup ();
}
it++;
} }
it++;
} }
} }
@@ -785,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 ());

View File

@@ -241,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;
@@ -287,8 +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;
// count of tunnels for total TCSR algorithm
int m_TotalNumSuccesiveTunnelCreations, m_TotalNumFailedTunnelCreations; // Calculating of tunnel creation success rate
// 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;
@@ -305,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

@@ -8,7 +8,6 @@
#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"
@@ -488,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)

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

@@ -16,7 +16,7 @@
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 46 #define I2PD_VERSION_MINOR 45
#define I2PD_VERSION_MICRO 1 #define I2PD_VERSION_MICRO 1
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#ifdef GITVER #ifdef GITVER

View File

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

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})

View File

@@ -1,62 +1,36 @@
SYS := $(shell $(CXX) -dumpmachine) CXXFLAGS += -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -pthread -Wl,--unresolved-symbols=ignore-in-object-files
CXXFLAGS += -Wall -Wno-unused-parameter -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -DOPENSSL_SUPPRESS_DEPRECATED -pthread -Wl,--unresolved-symbols=ignore-in-object-files
INCFLAGS += -I../libi2pd INCFLAGS += -I../libi2pd
LIBI2PD = ../libi2pd.a TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding test-elligator
TESTS = \
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
ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
CXXFLAGS += -DWIN32_LEAN_AND_MEAN
LDFLAGS += -mwindows -static
BOOST_SUFFIX = -mt
NEEDED_LDLIBS = -lwsock32 -lws2_32 -lgdi32 -liphlpapi -lole32
endif
LDLIBS = \
-lboost_filesystem$(BOOST_SUFFIX) \
-lboost_program_options$(BOOST_SUFFIX) \
-lssl \
-lcrypto \
-lz \
$(NEEDED_LDLIBS) \
-lpthread
all: $(TESTS) run all: $(TESTS) run
$(LIBI2PD): test-http-%: ../libi2pd/HTTP.cpp test-http-%.cpp
@echo "Building libi2pd.a ..." && cd .. && $(MAKE) libi2pd.a $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^
test-http-%: test-http-%.cpp $(LIBI2PD) test-base-%: ../libi2pd/Base.cpp test-base-%.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^
test-base-%: test-base-%.cpp $(LIBI2PD) test-gost: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp test-gost.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto
test-gost: test-gost.cpp $(LIBI2PD) test-gost-sig: ../libi2pd/Gost.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Crypto.cpp ../libi2pd/Log.cpp test-gost-sig.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
test-gost-sig: test-gost-sig.cpp $(LIBI2PD) test-x25519: ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/Crypto.cpp test-x25519.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
test-x25519: test-x25519.cpp $(LIBI2PD) test-aeadchacha20poly1305: ../libi2pd/Crypto.cpp ../libi2pd/ChaCha20.cpp ../libi2pd/Poly1305.cpp test-aeadchacha20poly1305.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD) test-blinding: ../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
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
test-blinding: test-blinding.cpp $(LIBI2PD) test-elligator: ../libi2pd/Elligator.cpp ../libi2pd/Crypto.cpp test-elligator.cpp
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
test-elligator: test-elligator.cpp $(LIBI2PD)
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
run: $(TESTS) run: $(TESTS)
@for TEST in $(TESTS); do echo Running $$TEST; ./$$TEST ; done @for TEST in $(TESTS); do ./$$TEST ; done
clean: clean:
rm -f $(TESTS) rm -f $(TESTS)

View File

@@ -7,28 +7,28 @@
char text[] = "Ladies and Gentlemen of the class of '99: If I could offer you " char text[] = "Ladies and Gentlemen of the class of '99: If I could offer you "
"only one tip for the future, sunscreen would be it."; // 114 bytes "only one tip for the future, sunscreen would be it."; // 114 bytes
uint8_t key[32] = uint8_t key[32] =
{ {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
}; };
uint8_t ad[12] = uint8_t ad[12] =
{ {
0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
}; };
uint8_t nonce[12] = uint8_t nonce[12] =
{ {
0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47
}; };
uint8_t tag[16] = uint8_t tag[16] =
{ {
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
}; };
uint8_t encrypted[114] = uint8_t encrypted[114] =
{ {
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
@@ -53,7 +53,7 @@ int main ()
assert (memcmp (buf1, text, 114) == 0); assert (memcmp (buf1, text, 114) == 0);
// test encryption of multiple buffers // test encryption of multiple buffers
memcpy (buf, text, 114); memcpy (buf, text, 114);
std::vector<std::pair<uint8_t*, std::size_t> > bufs{ std::make_pair (buf, 20), std::make_pair (buf + 20, 10), std::make_pair (buf + 30, 70), std::make_pair (buf + 100, 14) }; std::vector<std::pair<uint8_t*, std::size_t> > bufs{ std::make_pair (buf, 20), std::make_pair (buf + 20, 10), std::make_pair (buf + 30, 70), std::make_pair (buf + 100, 14) };
i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114); i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false); i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
assert (memcmp (buf1, text, 114) == 0); assert (memcmp (buf1, text, 114) == 0);

View File

@@ -13,12 +13,12 @@ void BlindTest (SigningKeyType sigType)
{ {
auto keys = PrivateKeys::CreateRandomKeys (sigType); auto keys = PrivateKeys::CreateRandomKeys (sigType);
BlindedPublicKey blindedKey (keys.GetPublic ()); BlindedPublicKey blindedKey (keys.GetPublic ());
auto timestamp = GetSecondsSinceEpoch (); auto timestamp = GetSecondsSinceEpoch ();
char date[9]; char date[9];
GetDateString (timestamp, date); GetDateString (timestamp, date);
uint8_t blindedPriv[32], blindedPub[32]; uint8_t blindedPriv[32], blindedPub[32];
auto publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub); auto publicKeyLen = blindedKey.BlindPrivateKey (keys.GetSigningPrivateKey (), date, blindedPriv, blindedPub);
uint8_t blindedPub1[32]; uint8_t blindedPub1[32];
blindedKey.GetBlindedKey (date, blindedPub1); blindedKey.GetBlindedKey (date, blindedPub1);
// check if public key produced from private blinded key matches blided public key // check if public key produced from private blinded key matches blided public key
assert (!memcmp (blindedPub, blindedPub1, publicKeyLen)); assert (!memcmp (blindedPub, blindedPub1, publicKeyLen));
@@ -26,16 +26,16 @@ void BlindTest (SigningKeyType sigType)
std::unique_ptr<Signer> blindedSigner (PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv)); std::unique_ptr<Signer> blindedSigner (PrivateKeys::CreateSigner (blindedKey.GetBlindedSigType (), blindedPriv));
uint8_t buf[100], signature[64]; uint8_t buf[100], signature[64];
memset (buf, 1, 100); memset (buf, 1, 100);
blindedSigner->Sign (buf, 100, signature); blindedSigner->Sign (buf, 100, signature);
std::unique_ptr<Verifier> blindedVerifier (IdentityEx::CreateVerifier (blindedKey.GetBlindedSigType ())); std::unique_ptr<Verifier> blindedVerifier (IdentityEx::CreateVerifier (blindedKey.GetBlindedSigType ()));
blindedVerifier->SetPublicKey (blindedPub); blindedVerifier->SetPublicKey (blindedPub);
assert (blindedVerifier->Verify (buf, 100, signature)); assert (blindedVerifier->Verify (buf, 100, signature));
} }
int main () int main ()
{ {
// EdDSA test // EdDSA test
BlindTest (SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); BlindTest (SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
// RedDSA test // RedDSA test
BlindTest (SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519); BlindTest (SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519);
} }

View File

@@ -4,19 +4,19 @@
#include "Elligator.h" #include "Elligator.h"
const uint8_t key[32] = const uint8_t key[32] =
{ {
0x33, 0x95, 0x19, 0x64, 0x00, 0x3c, 0x94, 0x08, 0x78, 0x06, 0x3c, 0xcf, 0xd0, 0x34, 0x8a, 0xf4, 0x33, 0x95, 0x19, 0x64, 0x00, 0x3c, 0x94, 0x08, 0x78, 0x06, 0x3c, 0xcf, 0xd0, 0x34, 0x8a, 0xf4,
0x21, 0x50, 0xca, 0x16, 0xd2, 0x64, 0x6f, 0x2c, 0x58, 0x56, 0xe8, 0x33, 0x83, 0x77, 0xd8, 0x80 0x21, 0x50, 0xca, 0x16, 0xd2, 0x64, 0x6f, 0x2c, 0x58, 0x56, 0xe8, 0x33, 0x83, 0x77, 0xd8, 0x80
}; };
const uint8_t encoded_key[32] = const uint8_t encoded_key[32] =
{ {
0x28, 0x20, 0xb6, 0xb2, 0x41, 0xe0, 0xf6, 0x8a, 0x6c, 0x4a, 0x7f, 0xee, 0x3d, 0x97, 0x82, 0x28, 0x28, 0x20, 0xb6, 0xb2, 0x41, 0xe0, 0xf6, 0x8a, 0x6c, 0x4a, 0x7f, 0xee, 0x3d, 0x97, 0x82, 0x28,
0xef, 0x3a, 0xe4, 0x55, 0x33, 0xcd, 0x41, 0x0a, 0xa9, 0x1a, 0x41, 0x53, 0x31, 0xd8, 0x61, 0x2d 0xef, 0x3a, 0xe4, 0x55, 0x33, 0xcd, 0x41, 0x0a, 0xa9, 0x1a, 0x41, 0x53, 0x31, 0xd8, 0x61, 0x2d
}; };
const uint8_t encoded_key_high_y[32] = const uint8_t encoded_key_high_y[32] =
{ {
0x3c, 0xfb, 0x87, 0xc4, 0x6c, 0x0b, 0x45, 0x75, 0xca, 0x81, 0x75, 0xe0, 0xed, 0x1c, 0x0a, 0xe9, 0x3c, 0xfb, 0x87, 0xc4, 0x6c, 0x0b, 0x45, 0x75, 0xca, 0x81, 0x75, 0xe0, 0xed, 0x1c, 0x0a, 0xe9,
0xda, 0xe7, 0x9d, 0xb7, 0x8d, 0xf8, 0x69, 0x97, 0xc4, 0x84, 0x7b, 0x9f, 0x20, 0xb2, 0x77, 0x18 0xda, 0xe7, 0x9d, 0xb7, 0x8d, 0xf8, 0x69, 0x97, 0xc4, 0x84, 0x7b, 0x9f, 0x20, 0xb2, 0x77, 0x18
@@ -28,7 +28,7 @@ const uint8_t encoded1[32] =
0x14, 0x50, 0x95, 0x89, 0x28, 0x84, 0x57, 0x99, 0x5a, 0x2b, 0x4c, 0xa3, 0x49, 0x0a, 0xa2, 0x07 0x14, 0x50, 0x95, 0x89, 0x28, 0x84, 0x57, 0x99, 0x5a, 0x2b, 0x4c, 0xa3, 0x49, 0x0a, 0xa2, 0x07
}; };
const uint8_t key1[32] = const uint8_t key1[32] =
{ {
0x1e, 0x8a, 0xff, 0xfe, 0xd6, 0xbf, 0x53, 0xfe, 0x27, 0x1a, 0xd5, 0x72, 0x47, 0x32, 0x62, 0xde, 0x1e, 0x8a, 0xff, 0xfe, 0xd6, 0xbf, 0x53, 0xfe, 0x27, 0x1a, 0xd5, 0x72, 0x47, 0x32, 0x62, 0xde,
0xd8, 0xfa, 0xec, 0x68, 0xe5, 0xe6, 0x7e, 0xf4, 0x5e, 0xbb, 0x82, 0xee, 0xba, 0x52, 0x60, 0x4f 0xd8, 0xfa, 0xec, 0x68, 0xe5, 0xe6, 0x7e, 0xf4, 0x5e, 0xbb, 0x82, 0xee, 0xba, 0x52, 0x60, 0x4f
@@ -40,7 +40,7 @@ const uint8_t encoded2[32] =
0xd9, 0x03, 0x65, 0xf2, 0x4a, 0x38, 0xaa, 0x7a, 0xef, 0x1b, 0x97, 0xe2, 0x39, 0x54, 0x10, 0x1b 0xd9, 0x03, 0x65, 0xf2, 0x4a, 0x38, 0xaa, 0x7a, 0xef, 0x1b, 0x97, 0xe2, 0x39, 0x54, 0x10, 0x1b
}; };
const uint8_t key2[32] = const uint8_t key2[32] =
{ {
0x79, 0x4f, 0x05, 0xba, 0x3e, 0x3a, 0x72, 0x95, 0x80, 0x22, 0x46, 0x8c, 0x88, 0x98, 0x1e, 0x0b, 0x79, 0x4f, 0x05, 0xba, 0x3e, 0x3a, 0x72, 0x95, 0x80, 0x22, 0x46, 0x8c, 0x88, 0x98, 0x1e, 0x0b,
0xe5, 0x78, 0x2b, 0xe1, 0xe1, 0x14, 0x5c, 0xe2, 0xc3, 0xc6, 0xfd, 0xe1, 0x6d, 0xed, 0x53, 0x63 0xe5, 0x78, 0x2b, 0xe1, 0xe1, 0x14, 0x5c, 0xe2, 0xc3, 0xc6, 0xfd, 0xe1, 0x6d, 0xed, 0x53, 0x63
@@ -52,7 +52,7 @@ const uint8_t encoded3[32] =
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f
}; };
const uint8_t key3[32] = const uint8_t key3[32] =
{ {
0x9c, 0xdb, 0x52, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x9c, 0xdb, 0x52, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55

View File

@@ -22,13 +22,13 @@ int main() {
assert(req->version == "HTTP/1.0"); assert(req->version == "HTTP/1.0");
assert(req->method == "GET"); assert(req->method == "GET");
assert(req->uri == "/"); assert(req->uri == "/");
assert(req->GetNumHeaders () == 3); assert(req->headers.size() == 3);
assert(req->GetNumHeaders("Host") == 1); assert(req->headers.count("Host") == 1);
assert(req->GetNumHeaders("Accept") == 1); assert(req->headers.count("Accept") == 1);
assert(req->GetNumHeaders("User-Agent") == 1); assert(req->headers.count("User-Agent") == 1);
assert(req->GetHeader("Host") == "inr.i2p"); assert(req->headers.find("Host")->second == "inr.i2p");
assert(req->GetHeader("Accept") == "*/*"); assert(req->headers.find("Accept")->second == "*/*");
assert(req->GetHeader("User-Agent") == "curl/7.26.0"); assert(req->headers.find("User-Agent")->second == "curl/7.26.0");
delete req; delete req;
/* test: parsing request without body */ /* test: parsing request without body */
@@ -41,7 +41,7 @@ int main() {
assert(req->version == "HTTP/1.0"); assert(req->version == "HTTP/1.0");
assert(req->method == "GET"); assert(req->method == "GET");
assert(req->uri == "/"); assert(req->uri == "/");
assert(req->GetNumHeaders () == 0); assert(req->headers.size() == 0);
delete req; delete req;
/* test: parsing request without body */ /* test: parsing request without body */
@@ -74,13 +74,13 @@ int main() {
assert((ret = req->parse(buf, len)) == len); /* no host header */ assert((ret = req->parse(buf, len)) == len); /* no host header */
assert(req->method == "GET"); assert(req->method == "GET");
assert(req->uri == "http://inr.i2p"); assert(req->uri == "http://inr.i2p");
assert(req->GetNumHeaders () == 3); assert(req->headers.size() == 3);
assert(req->GetNumHeaders("Host") == 1); assert(req->headers.count("Host") == 1);
assert(req->GetNumHeaders("Accept") == 1); assert(req->headers.count("Accept") == 1);
assert(req->GetNumHeaders("Accept-Encoding") == 1); assert(req->headers.count("Accept-Encoding") == 1);
assert(req->GetHeader("Host") == "stats.i2p"); assert(req->headers["Host"] == "stats.i2p");
assert(req->GetHeader("Accept") == "*/*"); assert(req->headers["Accept"] == "*/*");
assert(req->GetHeader("Accept-Encoding") == ""); assert(req->headers["Accept-Encoding"] == "");
delete req; delete req;
return 0; return 0;

View File

@@ -15,7 +15,6 @@ int main() {
assert(url->host == "127.0.0.1"); assert(url->host == "127.0.0.1");
assert(url->port == 7070); assert(url->port == 7070);
assert(url->path == "/asdasd"); assert(url->path == "/asdasd");
assert(url->hasquery == true);
assert(url->query == "12345"); assert(url->query == "12345");
assert(url->to_string() == "https://127.0.0.1:7070/asdasd?12345"); assert(url->to_string() == "https://127.0.0.1:7070/asdasd?12345");
delete url; delete url;
@@ -28,7 +27,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 8080); assert(url->port == 8080);
assert(url->path == "/asdasd"); assert(url->path == "/asdasd");
assert(url->hasquery == true);
assert(url->query == "123456"); assert(url->query == "123456");
delete url; delete url;
@@ -40,7 +38,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 0); assert(url->port == 0);
assert(url->path == "/asdasd"); assert(url->path == "/asdasd");
assert(url->hasquery == true);
assert(url->query == "name=value"); assert(url->query == "name=value");
delete url; delete url;
@@ -52,7 +49,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 0); assert(url->port == 0);
assert(url->path == "/asdasd"); assert(url->path == "/asdasd");
assert(url->hasquery == true);
assert(url->query == "name=value1&name=value2"); assert(url->query == "name=value1&name=value2");
delete url; delete url;
@@ -64,7 +60,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 0); assert(url->port == 0);
assert(url->path == "/asdasd"); assert(url->path == "/asdasd");
assert(url->hasquery == true);
assert(url->query == "name1=value1&name2&name3=value2"); assert(url->query == "name1=value1&name2&name3=value2");
assert(url->parse_query(params)); assert(url->parse_query(params));
assert(params.size() == 3); assert(params.size() == 3);
@@ -84,7 +79,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 800); assert(url->port == 800);
assert(url->path == "/asdasd"); assert(url->path == "/asdasd");
assert(url->hasquery == true);
assert(url->query == ""); assert(url->query == "");
delete url; delete url;
@@ -96,7 +90,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 17); assert(url->port == 17);
assert(url->path == ""); assert(url->path == "");
assert(url->hasquery == false);
assert(url->query == ""); assert(url->query == "");
delete url; delete url;
@@ -108,7 +101,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 0); assert(url->port == 0);
assert(url->path == ""); assert(url->path == "");
assert(url->hasquery == false);
assert(url->query == ""); assert(url->query == "");
delete url; delete url;
@@ -120,7 +112,6 @@ int main() {
assert(url->host == "site.com"); assert(url->host == "site.com");
assert(url->port == 84); assert(url->port == 84);
assert(url->path == "/asdasd/@17"); assert(url->path == "/asdasd/@17");
assert(url->hasquery == false);
assert(url->query == ""); assert(url->query == "");
assert(url->frag == "frag"); assert(url->frag == "frag");
delete url; delete url;

View File

@@ -4,21 +4,21 @@
#include "Ed25519.h" #include "Ed25519.h"
const uint8_t k[32] = const uint8_t k[32] =
{ {
0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15,
0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc,
0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4
}; };
const uint8_t u[32] = const uint8_t u[32] =
{ {
0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1,
0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3,
0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c
}; };
uint8_t p[32] = uint8_t p[32] =
{ {
0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea,
0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c,
@@ -36,3 +36,4 @@ int main ()
assert(memcmp (buf, p, 32) == 0); assert(memcmp (buf, p, 32) == 0);
#endif #endif
} }